Whamcloud - gitweb
LU-17000 utils: handle_yaml_no_op() has wrong signature
[fs/lustre-release.git] / lustre / utils / liblustreapi_mirror.c
1 // SPDX-License-Identifier: LGPL-2.1+
2 /*
3  * Copyright (c) 2017, Intel Corporation.
4  */
5 /*
6  * This file is part of Lustre, http://www.lustre.org/
7  *
8  * library for creating and managing File Level Redundancy (FLR) mirrors
9  *
10  * Author: Jinshan Xiong <jinshan.xiong@intel.com>
11  */
12
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <stddef.h>
17 #include <sys/ioctl.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <errno.h>
21 #include <dirent.h>
22 #include <stdarg.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <sys/xattr.h>
26 #include <assert.h>
27 #include <sys/param.h>
28
29 #include <libcfs/util/ioctl.h>
30 #include <lustre/lustreapi.h>
31 #include <linux/lustre/lustre_ioctl.h>
32
33 /**
34  * Set the mirror id for the opening file pointed by @fd, once the mirror
35  * is set successfully, the policy to choose mirrors will be disabed and the
36  * following I/O from this file descriptor will be led to this dedicated
37  * mirror @id.
38  * If @id is zero, it will clear the mirror id setting.
39  *
40  * \param fd    file descriptor, must be opened with O_DIRECT
41  * \param id    mirror id
42  *
43  * \retval      0 on success.
44  * \retval      -errno on failure.
45  */
46 int llapi_mirror_set(int fd, unsigned int id)
47 {
48         struct stat stbuf;
49         int rc;
50
51         rc = ioctl(fd, LL_IOC_FLR_SET_MIRROR, id);
52         if (rc < 0) {
53                 rc = -errno;
54                 return rc;
55         }
56
57         if (!id)
58                 return 0;
59
60         /* in the current implementation, llite doesn't verify if the mirror
61          * id is valid, it has to be verified in an I/O context so the fstat()
62          * call is to verify that the mirror id is correct. */
63         rc = fstat(fd, &stbuf);
64         if (rc < 0) {
65                 rc = -errno;
66
67                 (void) ioctl(fd, LL_IOC_FLR_SET_MIRROR, 0);
68         }
69
70         return rc;
71 }
72
73 /**
74  * Clear mirror id setting.
75  *
76  * \See llapi_mirror_set() for details.
77  */
78 int llapi_mirror_clear(int fd)
79 {
80         return llapi_mirror_set(fd, 0);
81 }
82
83 /**
84  * Read data from a specified mirror with @id. This function won't read
85  * partial read result; either file end is reached, or number of @count bytes
86  * is read, or an error will be returned.
87  *
88  * \param fd    file descriptor, should be opened with O_DIRECT
89  * \param id    mirror id to be read from
90  * \param buf   read buffer
91  * \param count number of bytes to be read
92  * \param pos   file postion where the read starts
93  *
94  * \result >= 0 Number of bytes has been read
95  * \result < 0  The last seen error
96  */
97 ssize_t llapi_mirror_read(int fd, unsigned int id, void *buf, size_t count,
98                           off_t pos)
99 {
100         ssize_t result = 0;
101         ssize_t page_size;
102         int rc;
103
104         page_size = sysconf(_SC_PAGESIZE);
105         if (page_size < 0) {
106                 rc = -errno;
107                 return rc;
108         }
109
110         rc = llapi_mirror_set(fd, id);
111         if (rc < 0)
112                 return rc;
113
114         while (count > 0) {
115                 ssize_t bytes_read;
116
117                 bytes_read = pread(fd, buf, count, pos);
118                 if (!bytes_read) /* end of file */
119                         break;
120
121                 if (bytes_read < 0) {
122                         result = -errno;
123                         llapi_error(LLAPI_MSG_WARN, result,
124                                     "fail to pread %ld-%ld of mirror %u",
125                                     pos, count, id);
126                         break;
127                 }
128
129                 result += bytes_read;
130                 pos += bytes_read;
131                 buf += bytes_read;
132                 count -= bytes_read;
133
134                 if (bytes_read & (page_size - 1)) /* end of file */
135                         break;
136         }
137
138         (void) llapi_mirror_clear(fd);
139
140         return result;
141 }
142
143 ssize_t llapi_mirror_write(int fd, unsigned int id, const void *buf,
144                            size_t count, off_t pos)
145 {
146         ssize_t result = 0;
147         ssize_t page_size;
148         int rc;
149
150         page_size = sysconf(_SC_PAGESIZE);
151         if (page_size < 0)
152                 return -EINVAL;
153
154         if (((unsigned long)buf & (page_size - 1)) || pos & (page_size - 1))
155                 return -EINVAL;
156
157         rc = llapi_mirror_set(fd, id);
158         if (rc < 0)
159                 return rc;
160
161         while (count > 0) {
162                 ssize_t bytes_written;
163
164                 if (pos & (page_size - 1)) {
165                         result = -EINVAL;
166                         break;
167                 }
168
169                 bytes_written = pwrite(fd, buf, count, pos);
170                 if (bytes_written < 0) {
171                         result = -errno;
172                         llapi_error(LLAPI_MSG_WARN, result,
173                                     "fail to pwrite %ld-%ld of mirror %u",
174                                     pos, count, id);
175                         break;
176                 }
177
178                 result += bytes_written;
179                 pos += bytes_written;
180                 buf += bytes_written;
181                 count -= bytes_written;
182         }
183
184         (void) llapi_mirror_clear(fd);
185
186         return result;
187 }
188
189 int llapi_mirror_truncate(int fd, unsigned int id, off_t length)
190 {
191         int rc;
192
193         rc = llapi_mirror_set(fd, id);
194         if (rc < 0)
195                 return rc;
196
197         rc = ftruncate(fd, length);
198         if (rc < 0) {
199                 rc = -errno;
200                 llapi_error(LLAPI_MSG_WARN, rc,
201                             "fail to ftruncate mirror %u to %ld", id, length);
202         }
203
204         (void) llapi_mirror_clear(fd);
205
206         return rc;
207 }
208
209 int llapi_mirror_punch(int fd, unsigned int id, off_t start, size_t length)
210 {
211         int rc;
212
213         rc = llapi_mirror_set(fd, id);
214         if (rc < 0)
215                 return rc;
216
217         rc = llapi_hole_punch(fd, start, length);
218         (void) llapi_mirror_clear(fd);
219
220         return rc;
221 }
222
223 bool llapi_mirror_is_sparse(int fd, unsigned int id)
224 {
225         bool sparse;
226         int rc;
227
228         rc = llapi_mirror_set(fd, id);
229         if (rc < 0)
230                 return false;
231
232         sparse = llapi_file_is_sparse(fd);
233         (void) llapi_mirror_clear(fd);
234
235         return sparse;
236 }
237
238 /**
239  * Seek data in a specified mirror with @id. This function looks for the
240  * first data segment from given offset and returns its offset and length
241  *
242  * \param fd    file descriptor, should be opened with O_DIRECT
243  * \param id    mirror id to be read from
244  * \param pos   position for start data seek from
245  * \param size  size of data segment found
246  *
247  * \result >= 0 Number of bytes has been read
248  * \result < 0  The last seen error
249  */
250 off_t llapi_mirror_data_seek(int fd, unsigned int id, off_t pos, size_t *size)
251 {
252         off_t data_off;
253         int rc;
254
255         rc = llapi_mirror_set(fd, id);
256         if (rc < 0)
257                 return rc;
258
259         data_off = llapi_data_seek(fd, pos, size);
260         (void) llapi_mirror_clear(fd);
261
262         return data_off;
263 }
264
265 /**
266  * Copy data contents from source mirror @src to multiple destinations
267  * pointed by @dst. The destination array @dst will be altered to store
268  * successfully copied mirrors.
269  *
270  * \param fd    file descriptor, should be opened with O_DIRECT
271  * \param src   source mirror id, usually a valid mirror
272  * \param dst   an array of destination mirror ids
273  * \param count number of elements in array @dst
274  *
275  * \result > 0  Number of mirrors successfully copied
276  * \result < 0  The last seen error
277  */
278 ssize_t llapi_mirror_copy_many(int fd, __u16 src, __u16 *dst, size_t count)
279 {
280         const size_t buflen = 4 * 1024 * 1024; /* 4M */
281         void *buf;
282         off_t pos = 0;
283         off_t data_end = 0;
284         ssize_t page_size;
285         ssize_t result = 0;
286         bool eof = false;
287         bool sparse;
288         int nr;
289         int i;
290         int rc;
291
292         if (!count)
293                 return 0;
294
295         page_size = sysconf(_SC_PAGESIZE);
296         if (page_size < 0) {
297                 rc = -errno;
298                 return rc;
299         }
300
301         rc = posix_memalign(&buf, page_size, buflen);
302         if (rc) /* error code is returned directly */
303                 return -rc;
304
305         sparse = llapi_mirror_is_sparse(fd, src);
306
307         nr = count;
308         if (sparse) {
309                 /* for sparse src we have to be sure that dst has no
310                  * data in src holes, so truncate it first
311                  */
312                 for (i = 0; i < nr; i++) {
313                         rc = llapi_mirror_truncate(fd, dst[i], pos);
314                         if (rc < 0) {
315                                 result = rc;
316                                 /* exclude the failed one */
317                                 dst[i] = dst[--nr];
318                                 i--;
319                                 continue;
320                         }
321                 }
322                 if (!nr) {
323                         free(buf);
324                         return result;
325                 }
326         }
327
328         while (!eof) {
329                 off_t data_off;
330                 ssize_t bytes_read;
331                 size_t to_write, to_read;
332
333                 if (sparse && pos >= data_end) {
334                         size_t data_size;
335
336                         data_off = llapi_mirror_data_seek(fd, src, pos,
337                                                           &data_size);
338                         if (data_off < 0) {
339                                 /* Non-fatal, switch to full copy */
340                                 sparse = false;
341                                 continue;
342                         }
343                         if (!data_size) {
344                                 /* hole at the end of file, set pos to the
345                                  * data_off, so truncate block at the end
346                                  * will set final dst size.
347                                  */
348                                 pos = data_off;
349                                 break;
350                         }
351
352                         data_end = data_off + data_size;
353                         /* align by page */
354                         pos = data_off & ~(page_size - 1);
355                         data_end = ((data_end - 1) | (page_size - 1)) + 1;
356                         to_read = MIN(data_end - pos, buflen);
357                 } else {
358                         to_read = buflen;
359                 }
360
361                 bytes_read = llapi_mirror_read(fd, src, buf, to_read, pos);
362                 if (!bytes_read) { /* end of file */
363                         break;
364                 } else if (bytes_read < 0) {
365                         result = bytes_read;
366                         nr = 0;
367                         llapi_error(LLAPI_MSG_ERROR, result,
368                                     "error reading bytes %ld-%ld of mirror %u",
369                                     pos, to_read, src);
370                         break;
371                 }
372
373                 /* round up to page align to make direct IO happy.
374                  * this implies the last segment to write. */
375                 to_write = ((bytes_read - 1) | (page_size - 1)) + 1;
376
377                 for (i = 0; i < nr; i++) {
378                         ssize_t written;
379
380                         written = llapi_mirror_write(fd, dst[i], buf,
381                                                       to_write, pos);
382                         if (written < 0) {
383                                 result = written;
384
385                                 /* this mirror is not written succesfully,
386                                  * get rid of it from the array */
387                                 dst[i] = dst[--nr];
388                                 i--;
389                                 continue;
390                         }
391                         assert(written == to_write);
392                 }
393                 pos += bytes_read;
394                 eof = bytes_read < to_read;
395         }
396
397         free(buf);
398
399         if (nr > 0) {
400                 for (i = 0; i < nr; i++) {
401                         rc = llapi_mirror_truncate(fd, dst[i], pos);
402                         if (rc < 0) {
403                                 result = rc;
404
405                                 /* exclude the failed one */
406                                 dst[i] = dst[--nr];
407                                 --i;
408                                 continue;
409                         }
410                 }
411         }
412
413         return nr > 0 ? nr : result;
414 }
415
416 /**
417  * Copy data contents from source mirror @src to target mirror @dst.
418  *
419  * \param fd    file descriptor, should be opened with O_DIRECT
420  * \param src   source mirror id, usually a valid mirror
421  * \param dst   mirror id of copy destination
422  * \param pos   start file pos
423  * \param count number of bytes to be copied
424  *
425  * \result > 0  Number of mirrors successfully copied
426  * \result < 0  The last seen error
427  */
428 int llapi_mirror_copy(int fd, unsigned int src, unsigned int dst, off_t pos,
429                       size_t count)
430 {
431         const size_t buflen = 4 * 1024 * 1024; /* 4M */
432         ssize_t result = 0;
433         ssize_t page_size;
434         void *buf;
435         int rc;
436
437         if (!count)
438                 return 0;
439
440         page_size = sysconf(_SC_PAGESIZE);
441         if (page_size < 0)
442                 return -EINVAL;
443
444         if (pos & (page_size - 1) || !dst)
445                 return -EINVAL;
446
447         if (count != OBD_OBJECT_EOF && count & (page_size - 1))
448                 return -EINVAL;
449
450         rc = posix_memalign(&buf, page_size, buflen);
451         if (rc) /* error code is returned directly */
452                 return -rc;
453
454         while (result < count) {
455                 ssize_t bytes_read, bytes_written;
456                 size_t to_read, to_write;
457
458                 to_read = MIN(buflen, count - result);
459                 if (src == 0)
460                         bytes_read = pread(fd, buf, to_read, pos);
461                 else
462                         bytes_read = llapi_mirror_read(fd, src, buf, to_read,
463                                                         pos);
464                 if (!bytes_read) { /* end of file */
465                         break;
466                 } else if (bytes_read < 0) {
467                         result = bytes_read;
468                         llapi_error(LLAPI_MSG_ERROR, result,
469                                     "error reading bytes %ld-%ld of mirror %u",
470                                     pos, to_read, src);
471                         break;
472                 }
473
474                 /* round up to page align to make direct IO happy.
475                  * this implies the last segment to write. */
476                 to_write = (bytes_read + page_size - 1) & ~(page_size - 1);
477
478                 bytes_written = llapi_mirror_write(fd, dst, buf, to_write,
479                                                     pos);
480                 if (bytes_written < 0) {
481                         result = bytes_written;
482                         llapi_error(LLAPI_MSG_ERROR, result,
483                                     "error writing bytes %ld-%ld of mirror %u",
484                                     pos, to_write, dst);
485                         break;
486                 }
487
488                 assert(bytes_written == to_write);
489
490                 pos += bytes_read;
491                 result += bytes_read;
492
493                 if (bytes_read < to_read) /* short read occurred */
494                         break;
495         }
496
497         free(buf);
498
499         if (result > 0) {
500                 rc = llapi_mirror_truncate(fd, dst, pos);
501                 if (rc < 0) {
502                         llapi_error(LLAPI_MSG_ERROR, result,
503                                     "error truncating mirror %u to %ld",
504                                     dst, pos);
505                         result = rc;
506                 }
507         }
508
509         return result;
510 }