xref: /openbmc/qemu/block/preallocate.c (revision 784155cd)
1 /*
2  * preallocate filter driver
3  *
4  * The driver performs preallocate operation: it is injected above
5  * some node, and before each write over EOF it does additional preallocating
6  * write-zeroes request.
7  *
8  * Copyright (c) 2020 Virtuozzo International GmbH.
9  *
10  * Author:
11  *  Sementsov-Ogievskiy Vladimir <vsementsov@virtuozzo.com>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program. If not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 #include "qemu/osdep.h"
28 
29 #include "qapi/error.h"
30 #include "qemu/module.h"
31 #include "qemu/option.h"
32 #include "qemu/units.h"
33 #include "block/block-io.h"
34 #include "block/block_int.h"
35 
36 
37 typedef struct PreallocateOpts {
38     int64_t prealloc_size;
39     int64_t prealloc_align;
40 } PreallocateOpts;
41 
42 typedef struct BDRVPreallocateState {
43     PreallocateOpts opts;
44 
45     /*
46      * Track real data end, to crop preallocation on close. If < 0 the status is
47      * unknown.
48      *
49      * @data_end is a maximum of file size on open (or when we get write/resize
50      * permissions) and all write request ends after it. So it's safe to
51      * truncate to data_end if it is valid.
52      */
53     int64_t data_end;
54 
55     /*
56      * Start of trailing preallocated area which reads as zero. May be smaller
57      * than data_end, if user does over-EOF write zero operation. If < 0 the
58      * status is unknown.
59      *
60      * If both @zero_start and @file_end are valid, the region
61      * [@zero_start, @file_end) is known to be preallocated zeroes. If @file_end
62      * is not valid, @zero_start doesn't make much sense.
63      */
64     int64_t zero_start;
65 
66     /*
67      * Real end of file. Actually the cache for bdrv_getlength(bs->file->bs),
68      * to avoid extra lseek() calls on each write operation. If < 0 the status
69      * is unknown.
70      */
71     int64_t file_end;
72 
73     /*
74      * All three states @data_end, @zero_start and @file_end are guaranteed to
75      * be invalid (< 0) when we don't have both exclusive BLK_PERM_RESIZE and
76      * BLK_PERM_WRITE permissions on file child.
77      */
78 
79     /* Gives up the resize permission on children when parents don't need it */
80     QEMUBH *drop_resize_bh;
81 } BDRVPreallocateState;
82 
83 static int preallocate_drop_resize(BlockDriverState *bs, Error **errp);
84 static void preallocate_drop_resize_bh(void *opaque);
85 
86 #define PREALLOCATE_OPT_PREALLOC_ALIGN "prealloc-align"
87 #define PREALLOCATE_OPT_PREALLOC_SIZE "prealloc-size"
88 static QemuOptsList runtime_opts = {
89     .name = "preallocate",
90     .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
91     .desc = {
92         {
93             .name = PREALLOCATE_OPT_PREALLOC_ALIGN,
94             .type = QEMU_OPT_SIZE,
95             .help = "on preallocation, align file length to this number, "
96                 "default 1M",
97         },
98         {
99             .name = PREALLOCATE_OPT_PREALLOC_SIZE,
100             .type = QEMU_OPT_SIZE,
101             .help = "how much to preallocate, default 128M",
102         },
103         { /* end of list */ }
104     },
105 };
106 
107 static bool preallocate_absorb_opts(PreallocateOpts *dest, QDict *options,
108                                     BlockDriverState *child_bs, Error **errp)
109 {
110     QemuOpts *opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
111 
112     if (!qemu_opts_absorb_qdict(opts, options, errp)) {
113         return false;
114     }
115 
116     dest->prealloc_align =
117         qemu_opt_get_size(opts, PREALLOCATE_OPT_PREALLOC_ALIGN, 1 * MiB);
118     dest->prealloc_size =
119         qemu_opt_get_size(opts, PREALLOCATE_OPT_PREALLOC_SIZE, 128 * MiB);
120 
121     qemu_opts_del(opts);
122 
123     if (!QEMU_IS_ALIGNED(dest->prealloc_align, BDRV_SECTOR_SIZE)) {
124         error_setg(errp, "prealloc-align parameter of preallocate filter "
125                    "is not aligned to %llu", BDRV_SECTOR_SIZE);
126         return false;
127     }
128 
129     if (!QEMU_IS_ALIGNED(dest->prealloc_align,
130                          child_bs->bl.request_alignment)) {
131         error_setg(errp, "prealloc-align parameter of preallocate filter "
132                    "is not aligned to underlying node request alignment "
133                    "(%" PRIi32 ")", child_bs->bl.request_alignment);
134         return false;
135     }
136 
137     return true;
138 }
139 
140 static int preallocate_open(BlockDriverState *bs, QDict *options, int flags,
141                             Error **errp)
142 {
143     BDRVPreallocateState *s = bs->opaque;
144     int ret;
145 
146     /*
147      * s->data_end and friends should be initialized on permission update.
148      * For this to work, mark them invalid.
149      */
150     s->file_end = s->zero_start = s->data_end = -EINVAL;
151     s->drop_resize_bh = qemu_bh_new(preallocate_drop_resize_bh, bs);
152 
153     ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
154     if (ret < 0) {
155         return ret;
156     }
157 
158     if (!preallocate_absorb_opts(&s->opts, options, bs->file->bs, errp)) {
159         return -EINVAL;
160     }
161 
162     bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
163         (BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
164 
165     bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
166         ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
167             bs->file->bs->supported_zero_flags);
168 
169     return 0;
170 }
171 
172 static int preallocate_truncate_to_real_size(BlockDriverState *bs, Error **errp)
173 {
174     BDRVPreallocateState *s = bs->opaque;
175     int ret;
176 
177     if (s->file_end < 0) {
178         s->file_end = bdrv_getlength(bs->file->bs);
179         if (s->file_end < 0) {
180             error_setg_errno(errp, -s->file_end, "Failed to get file length");
181             return s->file_end;
182         }
183     }
184 
185     if (s->data_end < s->file_end) {
186         ret = bdrv_truncate(bs->file, s->data_end, true, PREALLOC_MODE_OFF, 0,
187                             NULL);
188         if (ret < 0) {
189             error_setg_errno(errp, -ret, "Failed to drop preallocation");
190             s->file_end = ret;
191             return ret;
192         }
193         s->file_end = s->data_end;
194     }
195 
196     return 0;
197 }
198 
199 static void preallocate_close(BlockDriverState *bs)
200 {
201     BDRVPreallocateState *s = bs->opaque;
202 
203     qemu_bh_cancel(s->drop_resize_bh);
204     qemu_bh_delete(s->drop_resize_bh);
205 
206     if (s->data_end >= 0) {
207         preallocate_truncate_to_real_size(bs, NULL);
208     }
209 }
210 
211 
212 /*
213  * Handle reopen.
214  *
215  * We must implement reopen handlers, otherwise reopen just don't work. Handle
216  * new options and don't care about preallocation state, as it is handled in
217  * set/check permission handlers.
218  */
219 
220 static int preallocate_reopen_prepare(BDRVReopenState *reopen_state,
221                                       BlockReopenQueue *queue, Error **errp)
222 {
223     PreallocateOpts *opts = g_new0(PreallocateOpts, 1);
224     int ret;
225 
226     if (!preallocate_absorb_opts(opts, reopen_state->options,
227                                  reopen_state->bs->file->bs, errp)) {
228         g_free(opts);
229         return -EINVAL;
230     }
231 
232     /*
233      * Drop the preallocation already here if reopening read-only. The child
234      * might also be reopened read-only and then scheduling a BH during the
235      * permission update is too late.
236      */
237     if ((reopen_state->flags & BDRV_O_RDWR) == 0) {
238         ret = preallocate_drop_resize(reopen_state->bs, errp);
239         if (ret < 0) {
240             g_free(opts);
241             return ret;
242         }
243     }
244 
245     reopen_state->opaque = opts;
246 
247     return 0;
248 }
249 
250 static void preallocate_reopen_commit(BDRVReopenState *state)
251 {
252     BDRVPreallocateState *s = state->bs->opaque;
253 
254     s->opts = *(PreallocateOpts *)state->opaque;
255 
256     g_free(state->opaque);
257     state->opaque = NULL;
258 }
259 
260 static void preallocate_reopen_abort(BDRVReopenState *state)
261 {
262     g_free(state->opaque);
263     state->opaque = NULL;
264 }
265 
266 static int coroutine_fn GRAPH_RDLOCK
267 preallocate_co_preadv_part(BlockDriverState *bs, int64_t offset, int64_t bytes,
268                            QEMUIOVector *qiov, size_t qiov_offset,
269                            BdrvRequestFlags flags)
270 {
271     return bdrv_co_preadv_part(bs->file, offset, bytes, qiov, qiov_offset,
272                                flags);
273 }
274 
275 static int coroutine_fn GRAPH_RDLOCK
276 preallocate_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
277 {
278     return bdrv_co_pdiscard(bs->file, offset, bytes);
279 }
280 
281 static bool can_write_resize(uint64_t perm)
282 {
283     return (perm & BLK_PERM_WRITE) && (perm & BLK_PERM_RESIZE);
284 }
285 
286 static bool has_prealloc_perms(BlockDriverState *bs)
287 {
288     BDRVPreallocateState *s = bs->opaque;
289 
290     if (can_write_resize(bs->file->perm)) {
291         assert(!(bs->file->shared_perm & BLK_PERM_WRITE));
292         assert(!(bs->file->shared_perm & BLK_PERM_RESIZE));
293         return true;
294     }
295 
296     assert(s->data_end < 0);
297     assert(s->zero_start < 0);
298     assert(s->file_end < 0);
299     return false;
300 }
301 
302 /*
303  * Call on each write. Returns true if @want_merge_zero is true and the region
304  * [offset, offset + bytes) is zeroed (as a result of this call or earlier
305  * preallocation).
306  *
307  * want_merge_zero is used to merge write-zero request with preallocation in
308  * one bdrv_co_pwrite_zeroes() call.
309  */
310 static bool coroutine_fn GRAPH_RDLOCK
311 handle_write(BlockDriverState *bs, int64_t offset, int64_t bytes,
312              bool want_merge_zero)
313 {
314     BDRVPreallocateState *s = bs->opaque;
315     int64_t end = offset + bytes;
316     int64_t prealloc_start, prealloc_end;
317     int ret;
318     uint32_t file_align = bs->file->bs->bl.request_alignment;
319     uint32_t prealloc_align = MAX(s->opts.prealloc_align, file_align);
320 
321     assert(QEMU_IS_ALIGNED(prealloc_align, file_align));
322 
323     if (!has_prealloc_perms(bs)) {
324         /* We don't have state neither should try to recover it */
325         return false;
326     }
327 
328     if (s->data_end < 0) {
329         s->data_end = bdrv_co_getlength(bs->file->bs);
330         if (s->data_end < 0) {
331             return false;
332         }
333 
334         if (s->file_end < 0) {
335             s->file_end = s->data_end;
336         }
337     }
338 
339     if (end <= s->data_end) {
340         return false;
341     }
342 
343     /* We have valid s->data_end, and request writes beyond it. */
344 
345     s->data_end = end;
346     if (s->zero_start < 0 || !want_merge_zero) {
347         s->zero_start = end;
348     }
349 
350     if (s->file_end < 0) {
351         s->file_end = bdrv_co_getlength(bs->file->bs);
352         if (s->file_end < 0) {
353             return false;
354         }
355     }
356 
357     /* Now s->data_end, s->zero_start and s->file_end are valid. */
358 
359     if (end <= s->file_end) {
360         /* No preallocation needed. */
361         return want_merge_zero && offset >= s->zero_start;
362     }
363 
364     /* Now we want new preallocation, as request writes beyond s->file_end. */
365 
366     prealloc_start = QEMU_ALIGN_UP(
367             want_merge_zero ? MIN(offset, s->file_end) : s->file_end,
368             file_align);
369     prealloc_end = QEMU_ALIGN_UP(
370             MAX(prealloc_start, end) + s->opts.prealloc_size,
371             prealloc_align);
372 
373     want_merge_zero = want_merge_zero && (prealloc_start <= offset);
374 
375     ret = bdrv_co_pwrite_zeroes(
376             bs->file, prealloc_start, prealloc_end - prealloc_start,
377             BDRV_REQ_NO_FALLBACK | BDRV_REQ_SERIALISING | BDRV_REQ_NO_WAIT);
378     if (ret < 0) {
379         s->file_end = ret;
380         return false;
381     }
382 
383     s->file_end = prealloc_end;
384     return want_merge_zero;
385 }
386 
387 static int coroutine_fn GRAPH_RDLOCK
388 preallocate_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
389                              int64_t bytes, BdrvRequestFlags flags)
390 {
391     bool want_merge_zero =
392         !(flags & ~(BDRV_REQ_ZERO_WRITE | BDRV_REQ_NO_FALLBACK));
393     if (handle_write(bs, offset, bytes, want_merge_zero)) {
394         return 0;
395     }
396 
397     return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
398 }
399 
400 static int coroutine_fn GRAPH_RDLOCK
401 preallocate_co_pwritev_part(BlockDriverState *bs, int64_t offset, int64_t bytes,
402                             QEMUIOVector *qiov, size_t qiov_offset,
403                             BdrvRequestFlags flags)
404 {
405     handle_write(bs, offset, bytes, false);
406 
407     return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset,
408                                 flags);
409 }
410 
411 static int coroutine_fn GRAPH_RDLOCK
412 preallocate_co_truncate(BlockDriverState *bs, int64_t offset,
413                         bool exact, PreallocMode prealloc,
414                         BdrvRequestFlags flags, Error **errp)
415 {
416     ERRP_GUARD();
417     BDRVPreallocateState *s = bs->opaque;
418     int ret;
419 
420     if (s->data_end >= 0 && offset > s->data_end) {
421         if (s->file_end < 0) {
422             s->file_end = bdrv_co_getlength(bs->file->bs);
423             if (s->file_end < 0) {
424                 error_setg(errp, "failed to get file length");
425                 return s->file_end;
426             }
427         }
428 
429         if (prealloc == PREALLOC_MODE_FALLOC) {
430             /*
431              * If offset <= s->file_end, the task is already done, just
432              * update s->data_end, to move part of "filter preallocation"
433              * to "preallocation requested by user".
434              * Otherwise just proceed to preallocate missing part.
435              */
436             if (offset <= s->file_end) {
437                 s->data_end = offset;
438                 return 0;
439             }
440         } else {
441             /*
442              * We have to drop our preallocation, to
443              * - avoid "Cannot use preallocation for shrinking files" in
444              *   case of offset < file_end
445              * - give PREALLOC_MODE_OFF a chance to keep small disk
446              *   usage
447              * - give PREALLOC_MODE_FULL a chance to actually write the
448              *   whole region as user expects
449              */
450             if (s->file_end > s->data_end) {
451                 ret = bdrv_co_truncate(bs->file, s->data_end, true,
452                                        PREALLOC_MODE_OFF, 0, errp);
453                 if (ret < 0) {
454                     s->file_end = ret;
455                     error_prepend(errp, "preallocate-filter: failed to drop "
456                                   "write-zero preallocation: ");
457                     return ret;
458                 }
459                 s->file_end = s->data_end;
460             }
461         }
462 
463         s->data_end = offset;
464     }
465 
466     ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
467     if (ret < 0) {
468         s->file_end = s->zero_start = s->data_end = ret;
469         return ret;
470     }
471 
472     if (has_prealloc_perms(bs)) {
473         s->file_end = s->zero_start = s->data_end = offset;
474     }
475     return 0;
476 }
477 
478 static int coroutine_fn GRAPH_RDLOCK preallocate_co_flush(BlockDriverState *bs)
479 {
480     return bdrv_co_flush(bs->file->bs);
481 }
482 
483 static int64_t coroutine_fn GRAPH_RDLOCK
484 preallocate_co_getlength(BlockDriverState *bs)
485 {
486     int64_t ret;
487     BDRVPreallocateState *s = bs->opaque;
488 
489     if (s->data_end >= 0) {
490         return s->data_end;
491     }
492 
493     ret = bdrv_co_getlength(bs->file->bs);
494 
495     if (has_prealloc_perms(bs)) {
496         s->file_end = s->zero_start = s->data_end = ret;
497     }
498 
499     return ret;
500 }
501 
502 static int preallocate_drop_resize(BlockDriverState *bs, Error **errp)
503 {
504     BDRVPreallocateState *s = bs->opaque;
505     int ret;
506 
507     if (s->data_end < 0) {
508         return 0;
509     }
510 
511     /*
512      * Before switching children to be read-only, truncate them to remove
513      * the preallocation and let them have the real size.
514      */
515     ret = preallocate_truncate_to_real_size(bs, errp);
516     if (ret < 0) {
517         return ret;
518     }
519 
520     /*
521      * We'll drop our permissions and will allow other users to take write and
522      * resize permissions (see preallocate_child_perm). Anyone will be able to
523      * change the child, so mark all states invalid. We'll regain control if a
524      * parent requests write access again.
525      */
526     s->data_end = s->file_end = s->zero_start = -EINVAL;
527 
528     bdrv_graph_rdlock_main_loop();
529     bdrv_child_refresh_perms(bs, bs->file, NULL);
530     bdrv_graph_rdunlock_main_loop();
531 
532     return 0;
533 }
534 
535 static void preallocate_drop_resize_bh(void *opaque)
536 {
537     /*
538      * In case of errors, we'll simply keep the exclusive lock on the image
539      * indefinitely.
540      */
541     preallocate_drop_resize(opaque, NULL);
542 }
543 
544 static void preallocate_set_perm(BlockDriverState *bs,
545                                  uint64_t perm, uint64_t shared)
546 {
547     BDRVPreallocateState *s = bs->opaque;
548 
549     if (can_write_resize(perm)) {
550         qemu_bh_cancel(s->drop_resize_bh);
551         if (s->data_end < 0) {
552             s->data_end = s->file_end = s->zero_start =
553                 bs->file->bs->total_sectors * BDRV_SECTOR_SIZE;
554         }
555     } else {
556         qemu_bh_schedule(s->drop_resize_bh);
557     }
558 }
559 
560 static void preallocate_child_perm(BlockDriverState *bs, BdrvChild *c,
561     BdrvChildRole role, BlockReopenQueue *reopen_queue,
562     uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared)
563 {
564     BDRVPreallocateState *s = bs->opaque;
565 
566     bdrv_default_perms(bs, c, role, reopen_queue, perm, shared, nperm, nshared);
567 
568     /*
569      * We need exclusive write and resize permissions on the child not only when
570      * the parent can write to it, but also after the parent gave up write
571      * permissions until preallocate_drop_resize() has completed.
572      */
573     if (can_write_resize(perm) || s->data_end != -EINVAL) {
574         *nperm |= BLK_PERM_WRITE | BLK_PERM_RESIZE;
575 
576         /*
577          * Don't share, to keep our states s->file_end, s->data_end and
578          * s->zero_start valid.
579          */
580         *nshared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
581     }
582 }
583 
584 static BlockDriver bdrv_preallocate_filter = {
585     .format_name = "preallocate",
586     .instance_size = sizeof(BDRVPreallocateState),
587 
588     .bdrv_co_getlength    = preallocate_co_getlength,
589     .bdrv_open            = preallocate_open,
590     .bdrv_close           = preallocate_close,
591 
592     .bdrv_reopen_prepare  = preallocate_reopen_prepare,
593     .bdrv_reopen_commit   = preallocate_reopen_commit,
594     .bdrv_reopen_abort    = preallocate_reopen_abort,
595 
596     .bdrv_co_preadv_part = preallocate_co_preadv_part,
597     .bdrv_co_pwritev_part = preallocate_co_pwritev_part,
598     .bdrv_co_pwrite_zeroes = preallocate_co_pwrite_zeroes,
599     .bdrv_co_pdiscard = preallocate_co_pdiscard,
600     .bdrv_co_flush = preallocate_co_flush,
601     .bdrv_co_truncate = preallocate_co_truncate,
602 
603     .bdrv_set_perm = preallocate_set_perm,
604     .bdrv_child_perm = preallocate_child_perm,
605 
606     .is_filter = true,
607 };
608 
609 static void bdrv_preallocate_init(void)
610 {
611     bdrv_register(&bdrv_preallocate_filter);
612 }
613 
614 block_init(bdrv_preallocate_init);
615