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