4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * (C) Copyright 2017 Commissariat a l'energie atomique et aux energies
9 * All rights reserved. This program and the accompanying materials
10 * are made available under the terms of the GNU Lesser General Public License
11 * (LGPL) version 2.1 or (at your discretion) any later version.
12 * (LGPL) version 2.1 accompanies this distribution, and is available at
13 * http://www.gnu.org/licenses/lgpl-2.1.html
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
23 * lustre/utils/liblustreapi_chlg.c
25 * lustreapi library for filesystem changelog
27 * Author: Henri Doreau <henri.doreau@cea.fr>
38 #include <sys/types.h>
40 #include <lustre/lustreapi.h>
43 static int chlg_dev_path(char *path, size_t path_len, const char *device)
47 rc = snprintf(path, path_len, "/dev/changelog-%s", device);
57 #define CHANGELOG_PRIV_MAGIC 0xCA8E1080
58 #define CHANGELOG_BUFFER_SZ 4096
61 * Record state for efficient changelog consumption.
62 * Read chunks of CHANGELOG_BUFFER_SZ bytes.
64 struct changelog_private {
65 /* Ensure that the structure is valid and initialized */
67 /* File descriptor on the changelog character device */
69 /* Changelog delivery mode */
70 enum changelog_send_flag clp_send_flags;
71 /* Available bytes in buffer */
73 /* Current position in buffer */
75 /* Read buffer with records read from system */
80 * Start reading from a changelog
82 * @param priv Opaque private control structure
83 * @param flags Start flags (e.g. CHANGELOG_FLAG_JOBID)
84 * @param device Report changes recorded on this MDT
85 * @param startrec Report changes beginning with this record number
86 * (just call llapi_changelog_fini when done; don't need an endrec)
88 int llapi_changelog_start(void **priv, enum changelog_send_flag flags,
89 const char *device, long long startrec)
91 struct changelog_private *cp;
92 static bool warned_jobid;
93 static bool warned_follow;
94 char cdev_path[PATH_MAX];
97 rc = chlg_dev_path(cdev_path, sizeof(cdev_path), device);
101 /* Set up the receiver control struct */
102 cp = calloc(1, sizeof(*cp) + CHANGELOG_BUFFER_SZ);
106 cp->clp_magic = CHANGELOG_PRIV_MAGIC;
107 cp->clp_send_flags = flags;
110 cp->clp_buf_pos = cp->clp_buf;
112 /* Set up the receiver */
113 cp->clp_fd = open(cdev_path, O_RDONLY);
114 if (cp->clp_fd < 0) {
120 rc = lseek(cp->clp_fd, startrec, SEEK_SET);
129 /* CHANGELOG_FLAG_JOBID will eventually become mandatory. Display a
130 * warning if it's missing. */
131 if (!(flags & CHANGELOG_FLAG_JOBID) && !warned_jobid) {
132 llapi_err_noerrno(LLAPI_MSG_WARN, "warning: %s() called "
133 "without CHANGELOG_FLAG_JOBID", __func__);
137 /* Behavior expected by CHANGELOG_FLAG_FOLLOW is not implemented, warn
138 * the user and ignore it. */
139 if (flags & CHANGELOG_FLAG_FOLLOW && !warned_follow) {
140 llapi_err_noerrno(LLAPI_MSG_WARN, "warning: %s() called with "
141 "CHANGELOG_FLAG_FOLLOW (ignored)", __func__);
142 warned_follow = true;
154 /** Finish reading from a changelog */
155 int llapi_changelog_fini(void **priv)
157 struct changelog_private *cp = *priv;
159 if (!cp || (cp->clp_magic != CHANGELOG_PRIV_MAGIC))
168 static ssize_t chlg_read_bulk(struct changelog_private *cp)
172 if (!cp || cp->clp_magic != CHANGELOG_PRIV_MAGIC)
175 rd_bytes = read(cp->clp_fd, cp->clp_buf, CHANGELOG_BUFFER_SZ);
179 cp->clp_buf_pos = cp->clp_buf;
180 cp->clp_buf_len = rd_bytes;
186 * Returns a file descriptor to poll on.
188 * \@param[in] priv Opaque changelog reader structure.
189 * @return valid file descriptor on success, negated errno code on failure.
191 int llapi_changelog_get_fd(void *priv)
193 struct changelog_private *cp = priv;
195 if (!cp || cp->clp_magic != CHANGELOG_PRIV_MAGIC)
201 /** Read the next changelog entry
202 * @param priv Opaque private control structure
203 * @param rech Changelog record handle; record will be allocated here
204 * @return 0 valid message received; rec is set
208 #define DEFAULT_RECORD_FMT (CLF_VERSION | CLF_RENAME)
209 int llapi_changelog_recv(void *priv, struct changelog_rec **rech)
211 struct changelog_private *cp = priv;
212 enum changelog_rec_flags rec_fmt = DEFAULT_RECORD_FMT;
213 struct changelog_rec *tmp;
216 if (!cp || (cp->clp_magic != CHANGELOG_PRIV_MAGIC))
222 *rech = malloc(CR_MAXSIZE);
226 if (cp->clp_send_flags & CHANGELOG_FLAG_JOBID)
227 rec_fmt |= CLF_JOBID;
229 if (cp->clp_buf + cp->clp_buf_len <= cp->clp_buf_pos) {
232 refresh = chlg_read_bulk(cp);
234 /* EOF, CHANGELOG_FLAG_FOLLOW ignored for now LU-7659 */
237 } else if (refresh < 0) {
243 /* TODO check changelog_rec_size */
244 tmp = (struct changelog_rec *)cp->clp_buf_pos;
246 memcpy(*rech, cp->clp_buf_pos,
247 changelog_rec_size(tmp) + tmp->cr_namelen);
249 cp->clp_buf_pos += changelog_rec_size(tmp) + tmp->cr_namelen;
250 changelog_remap_rec(*rech, rec_fmt);
260 /** Release the changelog record when done with it. */
261 int llapi_changelog_free(struct changelog_rec **rech)
268 int llapi_changelog_clear(const char *mdtname, const char *idstr,
271 char dev_path[PATH_MAX];
273 size_t cmd_len = sizeof(cmd);
278 llapi_err_noerrno(LLAPI_MSG_ERROR,
279 "can't purge negative records\n");
283 chlg_dev_path(dev_path, sizeof(dev_path), mdtname);
285 rc = snprintf(cmd, cmd_len, "clear:%s:%lld", idstr, endrec);
286 if (rc >= sizeof(cmd))
291 fd = open(dev_path, O_WRONLY);
294 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'", dev_path);
298 rc = write(fd, cmd, cmd_len);
301 llapi_error(LLAPI_MSG_ERROR, rc,
302 "cannot purge records for '%s'", idstr);