Whamcloud - gitweb
LU-12373 pcc: uncache the pcc copies when remove a PCC backend
[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         ssize_t result = 0;
117         ssize_t page_size;
118         int rc;
119
120         page_size = sysconf(_SC_PAGESIZE);
121         if (page_size < 0) {
122                 rc = -errno;
123                 return rc;
124         }
125
126         rc = llapi_mirror_set(fd, id);
127         if (rc < 0)
128                 return rc;
129
130         while (count > 0) {
131                 ssize_t bytes_read;
132
133                 bytes_read = pread(fd, buf, count, pos);
134                 if (!bytes_read) /* end of file */
135                         break;
136
137                 if (bytes_read < 0) {
138                         result = -errno;
139                         llapi_error(LLAPI_MSG_WARN, result,
140                                     "fail to pread %ld-%ld of mirror %u",
141                                     pos, count, id);
142                         break;
143                 }
144
145                 result += bytes_read;
146                 pos += bytes_read;
147                 buf += bytes_read;
148                 count -= bytes_read;
149
150                 if (bytes_read & (page_size - 1)) /* end of file */
151                         break;
152         }
153
154         (void) llapi_mirror_clear(fd);
155
156         return result;
157 }
158
159 ssize_t llapi_mirror_write(int fd, unsigned int id, const void *buf,
160                            size_t count, off_t pos)
161 {
162         ssize_t result = 0;
163         ssize_t page_size;
164         int rc;
165
166         page_size = sysconf(_SC_PAGESIZE);
167         if (page_size < 0)
168                 return -EINVAL;
169
170         if (((unsigned long)buf & (page_size - 1)) || pos & (page_size - 1))
171                 return -EINVAL;
172
173         rc = llapi_mirror_set(fd, id);
174         if (rc < 0)
175                 return rc;
176
177         while (count > 0) {
178                 ssize_t bytes_written;
179
180                 if (pos & (page_size - 1)) {
181                         result = -EINVAL;
182                         break;
183                 }
184
185                 bytes_written = pwrite(fd, buf, count, pos);
186                 if (bytes_written < 0) {
187                         result = -errno;
188                         llapi_error(LLAPI_MSG_WARN, result,
189                                     "fail to pwrite %ld-%ld of mirror %u",
190                                     pos, count, id);
191                         break;
192                 }
193
194                 result += bytes_written;
195                 pos += bytes_written;
196                 buf += bytes_written;
197                 count -= bytes_written;
198         }
199
200         (void) llapi_mirror_clear(fd);
201
202         return result;
203 }
204
205 int llapi_mirror_truncate(int fd, unsigned int id, off_t length)
206 {
207         int rc;
208
209         rc = llapi_mirror_set(fd, id);
210         if (rc < 0)
211                 return rc;
212
213         rc = ftruncate(fd, length);
214         if (rc < 0) {
215                 rc = -errno;
216                 llapi_error(LLAPI_MSG_WARN, rc,
217                             "fail to ftruncate mirror %u to %ld", id, length);
218         }
219
220         (void) llapi_mirror_clear(fd);
221
222         return rc;
223 }
224
225 int llapi_mirror_punch(int fd, unsigned int id, off_t start, size_t length)
226 {
227         int rc;
228
229         rc = llapi_mirror_set(fd, id);
230         if (rc < 0)
231                 return rc;
232
233         rc = llapi_hole_punch(fd, start, length);
234         (void) llapi_mirror_clear(fd);
235
236         return rc;
237 }
238
239 bool llapi_mirror_is_sparse(int fd, unsigned int id)
240 {
241         bool sparse;
242         int rc;
243
244         rc = llapi_mirror_set(fd, id);
245         if (rc < 0)
246                 return false;
247
248         sparse = llapi_file_is_sparse(fd);
249         (void) llapi_mirror_clear(fd);
250
251         return sparse;
252 }
253
254 /**
255  * Seek data in a specified mirror with @id. This function looks for the
256  * first data segment from given offset and returns its offset and length
257  *
258  * \param fd    file descriptor, should be opened with O_DIRECT
259  * \param id    mirror id to be read from
260  * \param pos   position for start data seek from
261  * \param size  size of data segment found
262  *
263  * \result >= 0 Number of bytes has been read
264  * \result < 0  The last seen error
265  */
266 off_t llapi_mirror_data_seek(int fd, unsigned int id, off_t pos, size_t *size)
267 {
268         off_t data_off;
269         int rc;
270
271         rc = llapi_mirror_set(fd, id);
272         if (rc < 0)
273                 return rc;
274
275         data_off = llapi_data_seek(fd, pos, size);
276         (void) llapi_mirror_clear(fd);
277
278         return data_off;
279 }
280
281 /**
282  * Copy data contents from source mirror @src to multiple destinations
283  * pointed by @dst. The destination array @dst will be altered to store
284  * successfully copied mirrors.
285  *
286  * \param fd    file descriptor, should be opened with O_DIRECT
287  * \param src   source mirror id, usually a valid mirror
288  * \param dst   an array of destination mirror ids
289  * \param count number of elements in array @dst
290  *
291  * \result > 0  Number of mirrors successfully copied
292  * \result < 0  The last seen error
293  */
294 ssize_t llapi_mirror_copy_many(int fd, __u16 src, __u16 *dst, size_t count)
295 {
296         const size_t buflen = 4 * 1024 * 1024; /* 4M */
297         void *buf;
298         off_t pos = 0;
299         off_t data_end = 0;
300         ssize_t page_size;
301         ssize_t result = 0;
302         bool eof = false;
303         bool sparse;
304         int nr;
305         int i;
306         int rc;
307
308         if (!count)
309                 return 0;
310
311         page_size = sysconf(_SC_PAGESIZE);
312         if (page_size < 0) {
313                 rc = -errno;
314                 return rc;
315         }
316
317         rc = posix_memalign(&buf, page_size, buflen);
318         if (rc) /* error code is returned directly */
319                 return -rc;
320
321         sparse = llapi_mirror_is_sparse(fd, src);
322
323         nr = count;
324         if (sparse) {
325                 /* for sparse src we have to be sure that dst has no
326                  * data in src holes, so truncate it first
327                  */
328                 for (i = 0; i < nr; i++) {
329                         rc = llapi_mirror_truncate(fd, dst[i], pos);
330                         if (rc < 0) {
331                                 result = rc;
332                                 /* exclude the failed one */
333                                 dst[i] = dst[--nr];
334                                 i--;
335                                 continue;
336                         }
337                 }
338                 if (!nr) {
339                         free(buf);
340                         return result;
341                 }
342         }
343
344         while (!eof) {
345                 off_t data_off;
346                 ssize_t bytes_read;
347                 size_t to_write, to_read;
348
349                 if (sparse && pos >= data_end) {
350                         size_t data_size;
351
352                         data_off = llapi_mirror_data_seek(fd, src, pos,
353                                                           &data_size);
354                         if (data_off < 0) {
355                                 /* Non-fatal, switch to full copy */
356                                 sparse = false;
357                                 continue;
358                         }
359                         if (!data_size) {
360                                 /* hole at the end of file, set pos to the
361                                  * data_off, so truncate block at the end
362                                  * will set final dst size.
363                                  */
364                                 pos = data_off;
365                                 break;
366                         }
367
368                         data_end = data_off + data_size;
369                         /* align by page */
370                         pos = data_off & ~(page_size - 1);
371                         data_end = ((data_end - 1) | (page_size - 1)) + 1;
372                         to_read = MIN(data_end - pos, buflen);
373                 } else {
374                         to_read = buflen;
375                 }
376
377                 bytes_read = llapi_mirror_read(fd, src, buf, to_read, pos);
378                 if (!bytes_read) { /* end of file */
379                         break;
380                 } else if (bytes_read < 0) {
381                         result = bytes_read;
382                         nr = 0;
383                         llapi_error(LLAPI_MSG_ERROR, result,
384                                     "error reading bytes %ld-%ld of mirror %u",
385                                     pos, to_read, src);
386                         break;
387                 }
388
389                 /* round up to page align to make direct IO happy.
390                  * this implies the last segment to write. */
391                 to_write = ((bytes_read - 1) | (page_size - 1)) + 1;
392
393                 for (i = 0; i < nr; i++) {
394                         ssize_t written;
395
396                         written = llapi_mirror_write(fd, dst[i], buf,
397                                                       to_write, pos);
398                         if (written < 0) {
399                                 result = written;
400
401                                 /* this mirror is not written succesfully,
402                                  * get rid of it from the array */
403                                 dst[i] = dst[--nr];
404                                 i--;
405                                 continue;
406                         }
407                         assert(written == to_write);
408                 }
409                 pos += bytes_read;
410                 eof = bytes_read < to_read;
411         }
412
413         free(buf);
414
415         if (nr > 0) {
416                 for (i = 0; i < nr; i++) {
417                         rc = llapi_mirror_truncate(fd, dst[i], pos);
418                         if (rc < 0) {
419                                 result = rc;
420
421                                 /* exclude the failed one */
422                                 dst[i] = dst[--nr];
423                                 --i;
424                                 continue;
425                         }
426                 }
427         }
428
429         return nr > 0 ? nr : result;
430 }
431
432 /**
433  * Copy data contents from source mirror @src to target mirror @dst.
434  *
435  * \param fd    file descriptor, should be opened with O_DIRECT
436  * \param src   source mirror id, usually a valid mirror
437  * \param dst   mirror id of copy destination
438  * \param pos   start file pos
439  * \param count number of bytes to be copied
440  *
441  * \result > 0  Number of mirrors successfully copied
442  * \result < 0  The last seen error
443  */
444 int llapi_mirror_copy(int fd, unsigned int src, unsigned int dst, off_t pos,
445                       size_t count)
446 {
447         const size_t buflen = 4 * 1024 * 1024; /* 4M */
448         ssize_t result = 0;
449         ssize_t page_size;
450         void *buf;
451         int rc;
452
453         if (!count)
454                 return 0;
455
456         page_size = sysconf(_SC_PAGESIZE);
457         if (page_size < 0)
458                 return -EINVAL;
459
460         if (pos & (page_size - 1) || !dst)
461                 return -EINVAL;
462
463         if (count != OBD_OBJECT_EOF && count & (page_size - 1))
464                 return -EINVAL;
465
466         rc = posix_memalign(&buf, page_size, buflen);
467         if (rc) /* error code is returned directly */
468                 return -rc;
469
470         while (result < count) {
471                 ssize_t bytes_read, bytes_written;
472                 size_t to_read, to_write;
473
474                 to_read = MIN(buflen, count - result);
475                 if (src == 0)
476                         bytes_read = pread(fd, buf, to_read, pos);
477                 else
478                         bytes_read = llapi_mirror_read(fd, src, buf, to_read,
479                                                         pos);
480                 if (!bytes_read) { /* end of file */
481                         break;
482                 } else if (bytes_read < 0) {
483                         result = bytes_read;
484                         llapi_error(LLAPI_MSG_ERROR, result,
485                                     "error reading bytes %ld-%ld of mirror %u",
486                                     pos, to_read, src);
487                         break;
488                 }
489
490                 /* round up to page align to make direct IO happy.
491                  * this implies the last segment to write. */
492                 to_write = (bytes_read + page_size - 1) & ~(page_size - 1);
493
494                 bytes_written = llapi_mirror_write(fd, dst, buf, to_write,
495                                                     pos);
496                 if (bytes_written < 0) {
497                         result = bytes_written;
498                         llapi_error(LLAPI_MSG_ERROR, result,
499                                     "error writing bytes %ld-%ld of mirror %u",
500                                     pos, to_write, dst);
501                         break;
502                 }
503
504                 assert(bytes_written == to_write);
505
506                 pos += bytes_read;
507                 result += bytes_read;
508
509                 if (bytes_read < to_read) /* short read occurred */
510                         break;
511         }
512
513         free(buf);
514
515         if (result > 0 && pos & (page_size - 1)) {
516                 rc = llapi_mirror_truncate(fd, dst, pos);
517                 if (rc < 0) {
518                         llapi_error(LLAPI_MSG_ERROR, result,
519                                     "error truncating mirror %u to %ld",
520                                     dst, pos);
521                         result = rc;
522                 }
523         }
524
525         return result;
526 }