+
+/**
+ * Get a 64-bit value representing the version of file data pointed by fd.
+ *
+ * Each write or truncate, flushed on OST, will change this value. You can use
+ * this value to verify if file data was modified. This only checks the file
+ * data, not metadata.
+ *
+ * \param flags 0: no flush pages, usually used it the process has already
+ * taken locks;
+ * LL_DV_RD_FLUSH: OSTs will take LCK_PR to flush dirty pages
+ * from clients;
+ * LL_DV_WR_FLUSH: OSTs will take LCK_PW to flush all caching
+ * pages from clients.
+ *
+ * \retval 0 on success.
+ * \retval -errno on error.
+ */
+int llapi_get_data_version(int fd, __u64 *data_version, __u64 flags)
+{
+ int rc;
+ struct ioc_data_version idv;
+
+ idv.idv_flags = flags;
+
+ rc = ioctl(fd, LL_IOC_DATA_VERSION, &idv);
+ if (rc)
+ rc = -errno;
+ else
+ *data_version = idv.idv_version;
+
+ return rc;
+}
+
+/*
+ * Create a file without any name open it for read/write
+ *
+ * - file is created as if it were a standard file in the given \a directory
+ * - file does not appear in \a directory and mtime does not change because
+ * the filename is handled specially by the Lustre MDS.
+ * - file is removed at final close
+ * - file modes are rw------- since it doesn't make sense to have a read-only
+ * or write-only file that cannot be opened again.
+ * - if user wants another mode it must use fchmod() on the open file, no
+ * security problems arise because it cannot be opened by another process.
+ *
+ * \param[in] directory directory from which to inherit layout/MDT idx
+ * \param[in] idx MDT index on which the file is created,
+ * \a idx == -1 means no specific MDT is requested
+ * \param[in] open_flags standard open(2) flags
+ *
+ * \retval 0 on success.
+ * \retval -errno on error.
+ */
+int llapi_create_volatile_idx(char *directory, int idx, int open_flags)
+{
+ char file_path[PATH_MAX];
+ char filename[PATH_MAX];
+ int fd;
+ int rnumber;
+ int rc;
+
+ rnumber = random();
+ if (idx == -1)
+ snprintf(filename, sizeof(filename),
+ LUSTRE_VOLATILE_HDR"::%.4X", rnumber);
+ else
+ snprintf(filename, sizeof(filename),
+ LUSTRE_VOLATILE_HDR":%.4X:%.4X", idx, rnumber);
+
+ rc = snprintf(file_path, sizeof(file_path),
+ "%s/%s", directory, filename);
+ if (rc >= sizeof(file_path))
+ return -E2BIG;
+
+ fd = open(file_path, O_RDWR | O_CREAT | open_flags, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ llapi_error(LLAPI_MSG_ERROR, errno,
+ "Cannot create volatile file '%s' in '%s'",
+ filename + LUSTRE_VOLATILE_HDR_LEN,
+ directory);
+ return -errno;
+ }
+ /* unlink file in case this wasn't a Lustre filesystem, and the
+ * magic volatile filename wasn't handled as intended. The effect
+ * is the same. */
+ unlink(file_path);
+
+ return fd;
+}
+
+/**
+ * Swap the layouts between 2 file descriptors
+ * the 2 files must be open in write
+ * first fd received the ioctl, second fd is passed as arg
+ * this is assymetric but avoid use of root path for ioctl
+ */
+int llapi_fswap_layouts(int fd1, int fd2, __u64 dv1, __u64 dv2, __u64 flags)
+{
+ struct lustre_swap_layouts lsl;
+ int rc;
+
+ lsl.sl_fd = fd2;
+ lsl.sl_flags = flags;
+
+ do
+ lsl.sl_gid = random();
+ while (lsl.sl_gid == 0);
+
+ lsl.sl_dv1 = dv1;
+ lsl.sl_dv2 = dv2;
+ rc = ioctl(fd1, LL_IOC_LOV_SWAP_LAYOUTS, &lsl);
+ if (rc)
+ rc = -errno;
+ return rc;
+}
+
+/**
+ * Swap the layouts between 2 files
+ * the 2 files are open in write
+ */
+int llapi_swap_layouts(const char *path1, const char *path2,
+ __u64 dv1, __u64 dv2, __u64 flags)
+{
+ int fd1, fd2, rc;
+
+ fd1 = open(path1, O_WRONLY | O_LOV_DELAY_CREATE);
+ if (fd1 < 0) {
+ rc = -errno;
+ llapi_error(LLAPI_MSG_ERROR, rc,
+ "error: cannot open '%s' for write", path1);
+ goto out;
+ }
+
+ fd2 = open(path2, O_WRONLY | O_LOV_DELAY_CREATE);
+ if (fd2 < 0) {
+ rc = -errno;
+ llapi_error(LLAPI_MSG_ERROR, rc,
+ "error: cannot open '%s' for write", path2);
+ goto out_close;
+ }
+
+ rc = llapi_fswap_layouts(fd1, fd2, dv1, dv2, flags);
+ if (rc < 0)
+ llapi_error(LLAPI_MSG_ERROR, rc,
+ "error: cannot swap layout between '%s' and '%s'",
+ path1, path2);
+
+ close(fd2);
+out_close:
+ close(fd1);
+out:
+ return rc;
+}
+
+/**
+ * Attempt to open a file with Lustre file identifier \a fid
+ * and return an open file descriptor.
+ *
+ * \param[in] lustre_dir path within Lustre filesystem containing \a fid
+ * \param[in] fid Lustre file identifier of file to open
+ * \param[in] flags open() flags
+ *
+ * \retval non-negative file descriptor on successful open
+ * \retval -1 if an error occurred
+ */
+int llapi_open_by_fid(const char *lustre_dir, const lustre_fid *fid, int flags)
+{
+ char mntdir[PATH_MAX];
+ char path[PATH_MAX];
+ int rc;
+
+ rc = llapi_search_mounts(lustre_dir, 0, mntdir, NULL);
+ if (rc != 0)
+ return -1;
+
+ snprintf(path, sizeof(path), "%s/.lustre/fid/"DFID, mntdir, PFID(fid));
+ return open(path, flags);
+}
+
+/**
+ * Take group lock.
+ *
+ * \param fd File to lock.
+ * \param gid Group Identifier.
+ *
+ * \retval 0 on success.
+ * \retval -errno on failure.
+ */
+int llapi_group_lock(int fd, int gid)
+{
+ int rc;
+
+ rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
+ if (rc < 0) {
+ rc = -errno;
+ llapi_error(LLAPI_MSG_ERROR, rc, "cannot get group lock");
+ }
+ return rc;
+}
+
+/**
+ * Put group lock.
+ *
+ * \param fd File to unlock.
+ * \param gid Group Identifier.
+ *
+ * \retval 0 on success.
+ * \retval -errno on failure.
+ */
+int llapi_group_unlock(int fd, int gid)
+{
+ int rc;
+
+ rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
+ if (rc < 0) {
+ rc = -errno;
+ llapi_error(LLAPI_MSG_ERROR, rc, "cannot put group lock");
+ }
+ return rc;
+}