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>
39 #include <sys/ioctl.h>
41 #include <lustre/lustreapi.h>
42 #include <linux/lustre/lustre_ioctl.h>
45 static int chlg_dev_path(char *path, size_t path_len, const char *device)
49 rc = snprintf(path, path_len, "/dev/changelog-%s", device);
59 #define CHANGELOG_PRIV_MAGIC 0xCA8E1080
60 #define CHANGELOG_BUFFER_SZ 4096
63 * Record state for efficient changelog consumption.
64 * Read chunks of CHANGELOG_BUFFER_SZ bytes.
66 struct changelog_private {
67 /* Ensure that the structure is valid and initialized */
69 /* File descriptor on the changelog character device */
71 /* Changelog delivery mode */
72 enum changelog_send_flag clp_send_flags;
73 /* Changelog extra flags */
74 enum changelog_send_extra_flag clp_send_extra_flags;
75 /* Available bytes in buffer */
77 /* Current position in buffer */
79 /* Read buffer with records read from system */
84 * Start reading from a changelog
86 * @param priv Opaque private control structure
87 * @param flags Start flags (e.g. CHANGELOG_FLAG_JOBID)
88 * @param device Report changes recorded on this MDT
89 * @param startrec Report changes beginning with this record number
90 * (just call llapi_changelog_fini when done; don't need an endrec)
92 int llapi_changelog_start(void **priv, enum changelog_send_flag flags,
93 const char *device, long long startrec)
95 struct changelog_private *cp;
96 static bool warned_extra_flags;
97 static bool warned_jobid;
98 char cdev_path[PATH_MAX];
101 rc = chlg_dev_path(cdev_path, sizeof(cdev_path), device);
105 /* Set up the receiver control struct */
106 cp = calloc(1, sizeof(*cp) + CHANGELOG_BUFFER_SZ);
110 cp->clp_magic = CHANGELOG_PRIV_MAGIC;
111 cp->clp_send_flags = flags;
114 cp->clp_buf_pos = cp->clp_buf;
116 /* Set up the receiver */
117 cp->clp_fd = open(cdev_path, O_RDONLY);
118 if (cp->clp_fd < 0) {
126 res = lseek(cp->clp_fd, startrec, SEEK_SET);
127 if (res == (off_t)-1) {
135 /* CHANGELOG_FLAG_EXTRA_FLAGS will eventually become mandatory.
136 * If it wasn't specified, display a warning here.
137 * Code elsewhere will remove the corresponding extension.
139 if (!(flags & CHANGELOG_FLAG_EXTRA_FLAGS) && !warned_extra_flags) {
140 llapi_err_noerrno(LLAPI_MSG_WARN,
141 "warning: %s() called without CHANGELOG_FLAG_EXTRA_FLAGS",
143 warned_extra_flags = true;
146 /* CHANGELOG_FLAG_JOBID will eventually become mandatory. Display a
147 * warning if it's missing. */
148 if (!(flags & CHANGELOG_FLAG_JOBID) && !warned_jobid) {
149 llapi_err_noerrno(LLAPI_MSG_WARN, "warning: %s() called "
150 "without CHANGELOG_FLAG_JOBID", __func__);
154 if (flags & CHANGELOG_FLAG_FOLLOW) {
156 rc = ioctl(cp->clp_fd, OBD_IOC_CHLG_POLL, 1);
158 llapi_err_noerrno(LLAPI_MSG_ERROR, "can't enable "
159 "CHANGELOG_FLAG_FOLLOW");
171 /** Finish reading from a changelog */
172 int llapi_changelog_fini(void **priv)
174 struct changelog_private *cp = *priv;
176 if (!cp || (cp->clp_magic != CHANGELOG_PRIV_MAGIC))
185 static ssize_t chlg_read_bulk(struct changelog_private *cp)
189 if (!cp || cp->clp_magic != CHANGELOG_PRIV_MAGIC)
192 rd_bytes = read(cp->clp_fd, cp->clp_buf, CHANGELOG_BUFFER_SZ);
196 cp->clp_buf_pos = cp->clp_buf;
197 cp->clp_buf_len = rd_bytes;
203 * Returns a file descriptor to poll on.
205 * \@param[in] priv Opaque changelog reader structure.
206 * @return valid file descriptor on success, negated errno code on failure.
208 int llapi_changelog_get_fd(void *priv)
210 struct changelog_private *cp = priv;
212 if (!cp || cp->clp_magic != CHANGELOG_PRIV_MAGIC)
218 /** Read the next changelog entry
219 * @param priv Opaque private control structure
220 * @param rech Changelog record handle; record will be allocated here
221 * @return 0 valid message received; rec is set
225 #define DEFAULT_RECORD_FMT (CLF_VERSION | CLF_RENAME)
226 int llapi_changelog_recv(void *priv, struct changelog_rec **rech)
228 struct changelog_private *cp = priv;
229 enum changelog_rec_flags rec_fmt = DEFAULT_RECORD_FMT;
230 enum changelog_rec_extra_flags rec_extra_fmt = CLFE_INVALID;
231 struct changelog_rec *tmp;
234 if (!cp || (cp->clp_magic != CHANGELOG_PRIV_MAGIC))
240 *rech = malloc(CR_MAXSIZE);
244 if (cp->clp_send_flags & CHANGELOG_FLAG_JOBID)
245 rec_fmt |= CLF_JOBID;
247 if (cp->clp_send_flags & CHANGELOG_FLAG_EXTRA_FLAGS) {
248 rec_fmt |= CLF_EXTRA_FLAGS;
249 if (cp->clp_send_extra_flags & CHANGELOG_EXTRA_FLAG_UIDGID)
250 rec_extra_fmt |= CLFE_UIDGID;
251 if (cp->clp_send_extra_flags & CHANGELOG_EXTRA_FLAG_NID)
252 rec_extra_fmt |= CLFE_NID;
253 if (cp->clp_send_extra_flags & CHANGELOG_EXTRA_FLAG_OMODE)
254 rec_extra_fmt |= CLFE_OPEN;
255 if (cp->clp_send_extra_flags & CHANGELOG_EXTRA_FLAG_XATTR)
256 rec_extra_fmt |= CLFE_XATTR;
259 if (cp->clp_buf + cp->clp_buf_len <= cp->clp_buf_pos) {
262 refresh = chlg_read_bulk(cp);
264 /* EOF, CHANGELOG_FLAG_FOLLOW ignored for now LU-7659 */
267 } else if (refresh < 0) {
273 /* TODO check changelog_rec_size */
274 tmp = (struct changelog_rec *)cp->clp_buf_pos;
276 memcpy(*rech, cp->clp_buf_pos,
277 changelog_rec_size(tmp) + tmp->cr_namelen);
279 cp->clp_buf_pos += changelog_rec_size(tmp) + tmp->cr_namelen;
280 changelog_remap_rec(*rech, rec_fmt, rec_extra_fmt);
290 /** Release the changelog record when done with it. */
291 int llapi_changelog_free(struct changelog_rec **rech)
298 int llapi_changelog_in_buf(void *priv)
300 struct changelog_private *cp = priv;
301 if (cp->clp_buf + cp->clp_buf_len > cp->clp_buf_pos)
306 int llapi_changelog_clear(const char *mdtname, const char *idstr,
309 char dev_path[PATH_MAX];
311 size_t cmd_len = sizeof(cmd);
312 char *dashp, *clidp = NULL;
317 llapi_err_noerrno(LLAPI_MSG_ERROR,
318 "can't purge negative records\n");
322 chlg_dev_path(dev_path, sizeof(dev_path), mdtname);
324 dashp = strchr(idstr, '-');
326 clidp = strndup(idstr, dashp - idstr);
331 rc = snprintf(cmd, cmd_len, "clear:%s:%lld", dashp ? clidp : idstr,
333 if (rc >= sizeof(cmd)) {
339 fd = open(dev_path, O_WRONLY);
342 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'", dev_path);
346 rc = write(fd, cmd, cmd_len);
349 llapi_error(LLAPI_MSG_ERROR, rc,
350 "cannot purge records for '%s'", idstr);
364 * Set extra flags for reading changelogs
366 * @param priv Opaque private control structure
367 * @param extra_flags Read extra flags (e.g. CHANGELOG_EXTRA_FLAG_UIDGID)
369 * Just call this function right after llapi_changelog_start().
371 int llapi_changelog_set_xflags(void *priv,
372 enum changelog_send_extra_flag extra_flags)
374 struct changelog_private *cp = priv;
375 static bool warned_uidgid;
377 if (!cp || cp->clp_magic != CHANGELOG_PRIV_MAGIC)
380 cp->clp_send_extra_flags = extra_flags;
382 /* CHANGELOG_EXTRA_FLAG_UIDGID will eventually become mandatory.
383 * If it wasn't specified, display a warning here.
384 * Code elsewhere will remove the corresponding extension.
386 if (!(extra_flags & CHANGELOG_EXTRA_FLAG_UIDGID) && !warned_uidgid) {
387 llapi_err_noerrno(LLAPI_MSG_WARN,
388 "warning: %s() called without CHANGELOG_EXTRA_FLAG_UIDGID",
390 warned_uidgid = true;