4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the GNU Lesser General Public License
8 * (LGPL) version 2.1 or (at your discretion) any later version.
9 * (LGPL) version 2.1 accompanies this distribution, and is available at
10 * http://www.gnu.org/licenses/lgpl-2.1.html
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
20 * Copyright (c) 2012 Commissariat a l'energie atomique et aux energies
22 * Copyright (c) 2017, 2021, DDN Storage Corporation.
25 * This file is part of Lustre, http://www.lustre.org/
28 * lustreapi library for file layout swapping.
34 #include <sys/ioctl.h>
35 #include <sys/types.h>
38 #include <lustre/lustreapi.h>
41 * Get a 64-bit value representing the version of file data pointed by fd.
43 * Each write or truncate, flushed on OST, will change this value. You can use
44 * this value to verify if file data was modified. This only checks the file
47 * \param flags 0: no flush pages, usually used it the process has already
49 * LL_DV_RD_FLUSH: OSTs will take LCK_PR to flush dirty pages
51 * LL_DV_WR_FLUSH: OSTs will take LCK_PW to flush all caching
54 * \retval 0 on success.
55 * \retval -errno on error.
57 int llapi_get_data_version(int fd, __u64 *data_version, __u64 flags)
60 struct ioc_data_version idv;
62 idv.idv_flags = (__u32)flags;
64 rc = ioctl(fd, LL_IOC_DATA_VERSION, &idv);
68 *data_version = idv.idv_version;
74 * Fetch layout version from OST objects. Layout version on OST objects are
75 * only set when the file is a mirrored file AND after the file has been
76 * written at least once.
78 * It actually fetches the least layout version from the objects.
80 int llapi_get_ost_layout_version(int fd, __u32 *layout_version)
83 struct ioc_data_version idv = { 0 };
85 rc = ioctl(fd, LL_IOC_DATA_VERSION, &idv);
89 *layout_version = idv.idv_layout_version;
95 * Create a file without any name and open it for read/write
97 * - file is created as if it were a standard file in the given \a directory
98 * - file does not appear in \a directory and mtime does not change because
99 * the filename is handled specially by the Lustre MDS.
100 * - file is destroyed at final close
102 * \param[in] directory directory from which to inherit layout/MDT idx
103 * \param[in] mdt_idx MDT index on which the file is created,
104 * \a idx == -1 means no specific MDT is requested
105 * \param[in] mode standard open(2) mode
106 * \param[in] stripe_param stripe parameters. May be NULL.
108 * \retval a file descriptor on success.
109 * \retval -errno on error.
111 int llapi_create_volatile_param(const char *directory, int mdt_idx,
112 int open_flags, mode_t mode,
113 const struct llapi_stripe_param *stripe_param)
115 char file_path[PATH_MAX];
116 int saved_errno = errno;
118 unsigned int rnumber;
124 rc = snprintf(file_path, sizeof(file_path),
125 "%s/" LUSTRE_VOLATILE_HDR "::%.4X",
128 rc = snprintf(file_path, sizeof(file_path),
129 "%s/" LUSTRE_VOLATILE_HDR ":%.4X:%.4X",
130 directory, mdt_idx, rnumber);
132 if (rc < 0 || rc >= sizeof(file_path))
133 return -ENAMETOOLONG;
136 * Either open O_WRONLY or O_RDWR, creating RDONLY
137 * is non-sensical here
139 if ((open_flags & O_ACCMODE) == O_RDONLY)
140 open_flags = O_RDWR | (open_flags & ~O_ACCMODE);
142 open_flags |= O_CREAT | O_EXCL | O_NOFOLLOW;
144 if (stripe_param != NULL) {
145 fd = llapi_file_open_param(file_path, open_flags,
150 fd = open(file_path, open_flags, mode);
154 } while (fd < 0 && rc == -EEXIST);
157 llapi_error(LLAPI_MSG_ERROR, rc,
158 "Cannot create volatile file '%s' in '%s'",
159 file_path + strlen(directory) + 1 +
160 LUSTRE_VOLATILE_HDR_LEN,
166 * Unlink file in case this wasn't a Lustre filesystem and the magic
167 * volatile filename wasn't handled as intended. The effect is the
168 * same. If volatile open was supported then we expect unlink() to
171 (void)unlink(file_path);
174 * Since we are returning successfully we restore errno (and
175 * mask out possible EEXIST from open() and ENOENT from unlink().
183 * Create a file without any name open it for read/write
185 * - file is created as if it were a standard file in the given \a directory
186 * - file does not appear in \a directory and mtime does not change because
187 * the filename is handled specially by the Lustre MDS.
188 * - file is removed at final close
189 * - file modes are rw------- since it doesn't make sense to have a read-only
190 * or write-only file that cannot be opened again.
191 * - if user wants another mode it must use fchmod() on the open file, no
192 * security problems arise because it cannot be opened by another process.
194 * \param[in] directory directory from which to inherit layout/MDT idx
195 * \param[in] idx MDT index on which the file is created,
196 * \a idx == -1 means no specific MDT is requested
197 * \param[in] open_flags standard open(2) flags
199 * \retval a file descriptor on success.
200 * \retval -errno on error.
202 int llapi_create_volatile_idx(const char *directory, int mdt_idx,
205 return llapi_create_volatile_param(directory, mdt_idx, open_flags,
206 S_IRUSR | S_IWUSR, NULL);
210 * Swap the layouts between 2 file descriptors
211 * the 2 files must be open for writing
212 * first fd received the ioctl, second fd is passed as arg
213 * this is assymetric but avoid use of root path for ioctl
215 int llapi_fswap_layouts_grouplock(int fd1, int fd2, __u64 dv1, __u64 dv2,
216 int gid, __u64 flags)
218 struct lustre_swap_layouts lsl;
223 if (flags & (SWAP_LAYOUTS_KEEP_ATIME | SWAP_LAYOUTS_KEEP_MTIME)) {
224 rc = fstat(fd1, &st1);
228 rc = fstat(fd2, &st2);
233 lsl.sl_flags = flags;
237 rc = ioctl(fd1, LL_IOC_LOV_SWAP_LAYOUTS, &lsl);
241 if (flags & (SWAP_LAYOUTS_KEEP_ATIME | SWAP_LAYOUTS_KEEP_MTIME)) {
242 struct timeval tv1[2];
243 struct timeval tv2[2];
245 memset(tv1, 0, sizeof(tv1));
246 memset(tv2, 0, sizeof(tv2));
248 if (flags & SWAP_LAYOUTS_KEEP_ATIME) {
249 tv1[0].tv_sec = st1.st_atime;
250 tv2[0].tv_sec = st2.st_atime;
252 tv1[0].tv_sec = st2.st_atime;
253 tv2[0].tv_sec = st1.st_atime;
256 if (flags & SWAP_LAYOUTS_KEEP_MTIME) {
257 tv1[1].tv_sec = st1.st_mtime;
258 tv2[1].tv_sec = st2.st_mtime;
260 tv1[1].tv_sec = st2.st_mtime;
261 tv2[1].tv_sec = st1.st_mtime;
264 rc = futimes(fd1, tv1);
268 rc = futimes(fd2, tv2);
276 int llapi_fswap_layouts(int fd1, int fd2, __u64 dv1, __u64 dv2, __u64 flags)
285 rc = llapi_fswap_layouts_grouplock(fd1, fd2, dv1, dv2, grp_id, flags);
293 * Swap the layouts between 2 files
294 * the 2 files are open in write
296 int llapi_swap_layouts(const char *path1, const char *path2,
297 __u64 dv1, __u64 dv2, __u64 flags)
301 fd1 = open(path1, O_WRONLY | O_LOV_DELAY_CREATE);
304 llapi_error(LLAPI_MSG_ERROR, rc,
305 "error: cannot open '%s' for write", path1);
309 fd2 = open(path2, O_WRONLY | O_LOV_DELAY_CREATE);
312 llapi_error(LLAPI_MSG_ERROR, rc,
313 "error: cannot open '%s' for write", path2);
317 rc = llapi_fswap_layouts(fd1, fd2, dv1, dv2, flags);
319 llapi_error(LLAPI_MSG_ERROR, rc,
320 "error: cannot swap layout between '%s' and '%s'",
333 * \param fd File to lock.
334 * \param gid Group Identifier.
336 * \retval 0 on success.
337 * \retval -errno on failure.
339 int llapi_group_lock(int fd, int gid)
343 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
346 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get group lock");
351 int llapi_group_lock64(int fd, __u64 gid)
355 /* If this is ever compiled on a 32-bit system then a new
356 * LL_IOC_GROUP_LOCK64 will need to be defined that takes
357 * __u64 as an argument. That may never happen again.
359 BUILD_BUG_ON(sizeof(long) != sizeof(__u64));
360 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
363 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get group lock");
371 * \param fd File to unlock.
372 * \param gid Group Identifier.
374 * \retval 0 on success.
375 * \retval -errno on failure.
377 int llapi_group_unlock(int fd, int gid)
381 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
384 llapi_error(LLAPI_MSG_ERROR, rc, "cannot put group lock");
389 int llapi_group_unlock64(int fd, __u64 gid)
393 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
396 llapi_error(LLAPI_MSG_ERROR, rc, "cannot put group lock");