Whamcloud - gitweb
LU-14612 utils: Add functions llapi_group_lock64/unlock64()
[fs/lustre-release.git] / lustre / utils / liblustreapi_swap.c
1 /*
2  * LGPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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
11  *
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.
16  *
17  * LGPL HEADER END
18  */
19 /*
20  * Copyright (c) 2012 Commissariat a l'energie atomique et aux energies
21  * alternatives
22  * Copyright (c) 2017, 2021, DDN Storage Corporation.
23  */
24 /*
25  * This file is part of Lustre, http://www.lustre.org/
26  */
27 /*
28  * lustreapi library for file layout swapping.
29  */
30
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <sys/time.h>
34 #include <sys/ioctl.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <lustre/lustreapi.h>
39
40 /**
41  * Get a 64-bit value representing the version of file data pointed by fd.
42  *
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
45  * data, not metadata.
46  *
47  * \param  flags  0: no flush pages, usually used it the process has already
48  *                  taken locks;
49  *                LL_DV_RD_FLUSH: OSTs will take LCK_PR to flush dirty pages
50  *                  from clients;
51  *                LL_DV_WR_FLUSH: OSTs will take LCK_PW to flush all caching
52  *                  pages from clients.
53  *
54  * \retval 0 on success.
55  * \retval -errno on error.
56  */
57 int llapi_get_data_version(int fd, __u64 *data_version, __u64 flags)
58 {
59         int rc;
60         struct ioc_data_version idv;
61
62         idv.idv_flags = (__u32)flags;
63
64         rc = ioctl(fd, LL_IOC_DATA_VERSION, &idv);
65         if (rc)
66                 rc = -errno;
67         else
68                 *data_version = idv.idv_version;
69
70         return rc;
71 }
72
73 /*
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.
77  *
78  * It actually fetches the least layout version from the objects.
79  */
80 int llapi_get_ost_layout_version(int fd, __u32 *layout_version)
81 {
82         int rc;
83         struct ioc_data_version idv = { 0 };
84
85         rc = ioctl(fd, LL_IOC_DATA_VERSION, &idv);
86         if (rc)
87                 rc = -errno;
88         else
89                 *layout_version = idv.idv_layout_version;
90
91         return rc;
92 }
93
94 /*
95  * Create a file without any name and open it for read/write
96  *
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
101  *
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.
107  *
108  * \retval      a file descriptor on success.
109  * \retval      -errno on error.
110  */
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)
114 {
115         char file_path[PATH_MAX];
116         int saved_errno = errno;
117         int fd;
118         unsigned int rnumber;
119         int rc;
120
121         do {
122                 rnumber = random();
123                 if (mdt_idx == -1)
124                         rc = snprintf(file_path, sizeof(file_path),
125                                       "%s/" LUSTRE_VOLATILE_HDR "::%.4X",
126                                       directory, rnumber);
127                 else
128                         rc = snprintf(file_path, sizeof(file_path),
129                                       "%s/" LUSTRE_VOLATILE_HDR ":%.4X:%.4X",
130                                       directory, mdt_idx, rnumber);
131
132                 if (rc < 0 || rc >= sizeof(file_path))
133                         return -ENAMETOOLONG;
134
135                 /*
136                  * Either open O_WRONLY or O_RDWR, creating RDONLY
137                  * is non-sensical here
138                  */
139                 if ((open_flags & O_ACCMODE) == O_RDONLY)
140                         open_flags = O_RDWR | (open_flags & ~O_ACCMODE);
141
142                 open_flags |= O_CREAT | O_EXCL | O_NOFOLLOW;
143
144                 if (stripe_param != NULL) {
145                         fd = llapi_file_open_param(file_path, open_flags,
146                                                    mode, stripe_param);
147                         if (fd < 0)
148                                 rc = fd;
149                 } else {
150                         fd = open(file_path, open_flags, mode);
151                         if (fd < 0)
152                                 rc = -errno;
153                 }
154         } while (fd < 0 && rc == -EEXIST);
155
156         if (fd < 0) {
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,
161                             directory);
162                 return rc;
163         }
164
165         /*
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
169          * return -ENOENT.
170          */
171         (void)unlink(file_path);
172
173         /*
174          * Since we are returning successfully we restore errno (and
175          * mask out possible EEXIST from open() and ENOENT from unlink().
176          */
177         errno = saved_errno;
178
179         return fd;
180 }
181
182 /*
183  * Create a file without any name open it for read/write
184  *
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.
193  *
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
198  *
199  * \retval      a file descriptor on success.
200  * \retval      -errno on error.
201  */
202 int llapi_create_volatile_idx(const char *directory, int mdt_idx,
203                               int open_flags)
204 {
205         return llapi_create_volatile_param(directory, mdt_idx, open_flags,
206                                            S_IRUSR | S_IWUSR, NULL);
207 }
208
209 /**
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
214  */
215 int llapi_fswap_layouts_grouplock(int fd1, int fd2, __u64 dv1, __u64 dv2,
216                                   int gid, __u64 flags)
217 {
218         struct lustre_swap_layouts      lsl;
219         struct stat                     st1;
220         struct stat                     st2;
221         int                             rc;
222
223         if (flags & (SWAP_LAYOUTS_KEEP_ATIME | SWAP_LAYOUTS_KEEP_MTIME)) {
224                 rc = fstat(fd1, &st1);
225                 if (rc < 0)
226                         return -errno;
227
228                 rc = fstat(fd2, &st2);
229                 if (rc < 0)
230                         return -errno;
231         }
232         lsl.sl_fd = fd2;
233         lsl.sl_flags = flags;
234         lsl.sl_gid = gid;
235         lsl.sl_dv1 = dv1;
236         lsl.sl_dv2 = dv2;
237         rc = ioctl(fd1, LL_IOC_LOV_SWAP_LAYOUTS, &lsl);
238         if (rc < 0)
239                 return -errno;
240
241         if (flags & (SWAP_LAYOUTS_KEEP_ATIME | SWAP_LAYOUTS_KEEP_MTIME)) {
242                 struct timeval  tv1[2];
243                 struct timeval  tv2[2];
244
245                 memset(tv1, 0, sizeof(tv1));
246                 memset(tv2, 0, sizeof(tv2));
247
248                 if (flags & SWAP_LAYOUTS_KEEP_ATIME) {
249                         tv1[0].tv_sec = st1.st_atime;
250                         tv2[0].tv_sec = st2.st_atime;
251                 } else {
252                         tv1[0].tv_sec = st2.st_atime;
253                         tv2[0].tv_sec = st1.st_atime;
254                 }
255
256                 if (flags & SWAP_LAYOUTS_KEEP_MTIME) {
257                         tv1[1].tv_sec = st1.st_mtime;
258                         tv2[1].tv_sec = st2.st_mtime;
259                 } else {
260                         tv1[1].tv_sec = st2.st_mtime;
261                         tv2[1].tv_sec = st1.st_mtime;
262                 }
263
264                 rc = futimes(fd1, tv1);
265                 if (rc < 0)
266                         return -errno;
267
268                 rc = futimes(fd2, tv2);
269                 if (rc < 0)
270                         return -errno;
271         }
272
273         return 0;
274 }
275
276 int llapi_fswap_layouts(int fd1, int fd2, __u64 dv1, __u64 dv2, __u64 flags)
277 {
278         int     rc;
279         int     grp_id;
280
281         do
282                 grp_id = random();
283         while (grp_id == 0);
284
285         rc = llapi_fswap_layouts_grouplock(fd1, fd2, dv1, dv2, grp_id, flags);
286         if (rc < 0)
287                 return rc;
288
289         return 0;
290 }
291
292 /**
293  * Swap the layouts between 2 files
294  * the 2 files are open in write
295  */
296 int llapi_swap_layouts(const char *path1, const char *path2,
297                        __u64 dv1, __u64 dv2, __u64 flags)
298 {
299         int     fd1, fd2, rc;
300
301         fd1 = open(path1, O_WRONLY | O_LOV_DELAY_CREATE);
302         if (fd1 < 0) {
303                 rc = -errno;
304                 llapi_error(LLAPI_MSG_ERROR, rc,
305                             "error: cannot open '%s' for write", path1);
306                 goto out;
307         }
308
309         fd2 = open(path2, O_WRONLY | O_LOV_DELAY_CREATE);
310         if (fd2 < 0) {
311                 rc = -errno;
312                 llapi_error(LLAPI_MSG_ERROR, rc,
313                             "error: cannot open '%s' for write", path2);
314                 goto out_close;
315         }
316
317         rc = llapi_fswap_layouts(fd1, fd2, dv1, dv2, flags);
318         if (rc < 0)
319                 llapi_error(LLAPI_MSG_ERROR, rc,
320                             "error: cannot swap layout between '%s' and '%s'",
321                             path1, path2);
322
323         close(fd2);
324 out_close:
325         close(fd1);
326 out:
327         return rc;
328 }
329
330 /**
331  * Take group lock.
332  *
333  * \param fd   File to lock.
334  * \param gid  Group Identifier.
335  *
336  * \retval 0 on success.
337  * \retval -errno on failure.
338  */
339 int llapi_group_lock(int fd, int gid)
340 {
341         int rc;
342
343         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
344         if (rc < 0) {
345                 rc = -errno;
346                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get group lock");
347         }
348         return rc;
349 }
350
351 int llapi_group_lock64(int fd, __u64 gid)
352 {
353         int rc;
354
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.
358          */
359         BUILD_BUG_ON(sizeof(long) != sizeof(__u64));
360         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
361         if (rc < 0) {
362                 rc = -errno;
363                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get group lock");
364         }
365         return rc;
366 }
367
368 /**
369  * Put group lock.
370  *
371  * \param fd   File to unlock.
372  * \param gid  Group Identifier.
373  *
374  * \retval 0 on success.
375  * \retval -errno on failure.
376  */
377 int llapi_group_unlock(int fd, int gid)
378 {
379         int rc;
380
381         rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
382         if (rc < 0) {
383                 rc = -errno;
384                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot put group lock");
385         }
386         return rc;
387 }
388
389 int llapi_group_unlock64(int fd, __u64 gid)
390 {
391         int rc;
392
393         rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
394         if (rc < 0) {
395                 rc = -errno;
396                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot put group lock");
397         }
398         return rc;
399 }