master
c 616 lines 19.3 KB
Raw
1 /*
2 * Write logging blk driver based on blkverify and blkdebug.
3 *
4 * Copyright (c) 2017 Tuomas Tynkkynen <tuomas@tuxera.com>
5 * Copyright (c) 2018 Aapo Vienamo <aapo@tuxera.com>
6 * Copyright (c) 2018-2024 Ari Sundholm <ari@tuxera.com>
7 *
8 * This work is licensed under the terms of the GNU GPL, version 2 or later.
9 * See the COPYING file in the top-level directory.
10 */
11
12 #include "qemu/osdep.h"
13 #include "qapi/error.h"
14 #include "qemu/sockets.h" /* for EINPROGRESS on Windows */
15 #include "block/block-io.h"
16 #include "block/block_int.h"
17 #include "qobject/qdict.h"
18 #include "qobject/qstring.h"
19 #include "qemu/bswap.h"
20 #include "qemu/cutils.h"
21 #include "qemu/module.h"
22 #include "qemu/option.h"
23
24 /* Disk format stuff - taken from Linux drivers/md/dm-log-writes.c */
25
26 #define LOG_FLUSH_FLAG (1 << 0)
27 #define LOG_FUA_FLAG (1 << 1)
28 #define LOG_DISCARD_FLAG (1 << 2)
29 #define LOG_MARK_FLAG (1 << 3)
30 #define LOG_FLAG_MASK (LOG_FLUSH_FLAG \
31 | LOG_FUA_FLAG \
32 | LOG_DISCARD_FLAG \
33 | LOG_MARK_FLAG)
34
35 #define WRITE_LOG_VERSION 1ULL
36 #define WRITE_LOG_MAGIC 0x6a736677736872ULL
37
38 /* All fields are little-endian. */
39 struct log_write_super {
40 uint64_t magic;
41 uint64_t version;
42 uint64_t nr_entries;
43 uint32_t sectorsize;
44 } QEMU_PACKED;
45
46 struct log_write_entry {
47 uint64_t sector;
48 uint64_t nr_sectors;
49 uint64_t flags;
50 uint64_t data_len;
51 } QEMU_PACKED;
52
53 /* End of disk format structures. */
54
55 typedef struct {
56 BdrvChild *log_file;
57 uint32_t sectorsize;
58 uint32_t sectorbits;
59 uint64_t update_interval;
60
61 /*
62 * The mutable state of the driver, consisting of the current log sector
63 * and the number of log entries.
64 *
65 * May be read and/or written from multiple threads, and the mutex must be
66 * held when accessing these fields.
67 */
68 uint64_t cur_log_sector;
69 uint64_t nr_entries;
70 QemuMutex mutex;
71
72 /*
73 * The super block sequence number. Non-zero if a super block update is in
74 * progress.
75 *
76 * The mutex must be held when accessing this field.
77 */
78 uint64_t super_update_seq;
79
80 /*
81 * A coroutine-aware queue to serialize super block updates.
82 *
83 * Used with the mutex to ensure that only one thread be updating the super
84 * block at a time.
85 */
86 CoQueue super_update_queue;
87 } BDRVBlkLogWritesState;
88
89 static QemuOptsList runtime_opts = {
90 .name = "blklogwrites",
91 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
92 .desc = {
93 {
94 .name = "log-append",
95 .type = QEMU_OPT_BOOL,
96 .help = "Append to an existing log",
97 },
98 {
99 .name = "log-sector-size",
100 .type = QEMU_OPT_SIZE,
101 .help = "Log sector size",
102 },
103 {
104 .name = "log-super-update-interval",
105 .type = QEMU_OPT_NUMBER,
106 .help = "Log superblock update interval (# of write requests)",
107 },
108 { /* end of list */ }
109 },
110 };
111
112 static inline uint32_t blk_log_writes_log2(uint32_t value)
113 {
114 assert(value > 0);
115 return 31 - clz32(value);
116 }
117
118 static inline bool blk_log_writes_sector_size_valid(uint32_t sector_size)
119 {
120 return is_power_of_2(sector_size) &&
121 sector_size >= sizeof(struct log_write_super) &&
122 sector_size >= sizeof(struct log_write_entry) &&
123 sector_size < (1ull << 24);
124 }
125
126 static uint64_t blk_log_writes_find_cur_log_sector(BdrvChild *log,
127 uint32_t sector_size,
128 uint64_t nr_entries,
129 Error **errp)
130 {
131 uint64_t cur_sector = 1;
132 uint64_t cur_idx = 0;
133 uint32_t sector_bits = blk_log_writes_log2(sector_size);
134 struct log_write_entry cur_entry;
135
136 while (cur_idx < nr_entries) {
137 int read_ret = bdrv_pread(log, cur_sector << sector_bits,
138 sizeof(cur_entry), &cur_entry, 0);
139 if (read_ret < 0) {
140 error_setg_errno(errp, -read_ret,
141 "Failed to read log entry %"PRIu64, cur_idx);
142 return (uint64_t)-1ull;
143 }
144
145 if (cur_entry.flags & ~cpu_to_le64(LOG_FLAG_MASK)) {
146 error_setg(errp, "Invalid flags 0x%"PRIx64" in log entry %"PRIu64,
147 le64_to_cpu(cur_entry.flags), cur_idx);
148 return (uint64_t)-1ull;
149 }
150
151 /* Account for the sector of the entry itself */
152 ++cur_sector;
153
154 /*
155 * Account for the data of the write.
156 * For discards, this data is not present.
157 */
158 if (!(cur_entry.flags & cpu_to_le64(LOG_DISCARD_FLAG))) {
159 cur_sector += le64_to_cpu(cur_entry.nr_sectors);
160 }
161
162 ++cur_idx;
163 }
164
165 return cur_sector;
166 }
167
168 static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
169 Error **errp)
170 {
171 BDRVBlkLogWritesState *s = bs->opaque;
172 QemuOpts *opts;
173 Error *local_err = NULL;
174 int ret;
175 uint64_t log_sector_size;
176 bool log_append;
177
178 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
179 if (!qemu_opts_absorb_qdict(opts, options, errp)) {
180 ret = -EINVAL;
181 goto fail;
182 }
183
184 /* Open the file */
185 ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
186 if (ret < 0) {
187 goto fail;
188 }
189
190 /* Open the log file */
191 s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_of_bds,
192 BDRV_CHILD_METADATA, false, errp);
193 if (!s->log_file) {
194 ret = -EINVAL;
195 goto fail;
196 }
197
198 qemu_mutex_init(&s->mutex);
199 qemu_co_queue_init(&s->super_update_queue);
200
201 log_append = qemu_opt_get_bool(opts, "log-append", false);
202
203 if (log_append) {
204 struct log_write_super log_sb = { 0, 0, 0, 0 };
205
206 if (qemu_opt_find(opts, "log-sector-size")) {
207 ret = -EINVAL;
208 error_setg(errp, "log-append and log-sector-size are mutually "
209 "exclusive");
210 goto fail_log;
211 }
212
213 /* Read log superblock or fake one for an empty log */
214 if (!bdrv_getlength(s->log_file->bs)) {
215 log_sb.magic = cpu_to_le64(WRITE_LOG_MAGIC);
216 log_sb.version = cpu_to_le64(WRITE_LOG_VERSION);
217 log_sb.nr_entries = cpu_to_le64(0);
218 log_sb.sectorsize = cpu_to_le32(BDRV_SECTOR_SIZE);
219 } else {
220 ret = bdrv_pread(s->log_file, 0, sizeof(log_sb), &log_sb, 0);
221 if (ret < 0) {
222 error_setg_errno(errp, -ret, "Could not read log superblock");
223 goto fail_log;
224 }
225 }
226
227 if (log_sb.magic != cpu_to_le64(WRITE_LOG_MAGIC)) {
228 ret = -EINVAL;
229 error_setg(errp, "Invalid log superblock magic");
230 goto fail_log;
231 }
232
233 if (log_sb.version != cpu_to_le64(WRITE_LOG_VERSION)) {
234 ret = -EINVAL;
235 error_setg(errp, "Unsupported log version %"PRIu64,
236 le64_to_cpu(log_sb.version));
237 goto fail_log;
238 }
239
240 log_sector_size = le32_to_cpu(log_sb.sectorsize);
241 s->cur_log_sector = 1;
242 s->nr_entries = 0;
243
244 if (blk_log_writes_sector_size_valid(log_sector_size)) {
245 s->cur_log_sector =
246 blk_log_writes_find_cur_log_sector(s->log_file, log_sector_size,
247 le64_to_cpu(log_sb.nr_entries), &local_err);
248 if (local_err) {
249 ret = -EINVAL;
250 error_propagate(errp, local_err);
251 goto fail_log;
252 }
253
254 s->nr_entries = le64_to_cpu(log_sb.nr_entries);
255 }
256 } else {
257 log_sector_size = qemu_opt_get_size(opts, "log-sector-size",
258 BDRV_SECTOR_SIZE);
259 s->cur_log_sector = 1;
260 s->nr_entries = 0;
261 }
262
263 s->super_update_seq = 0;
264
265 if (!blk_log_writes_sector_size_valid(log_sector_size)) {
266 ret = -EINVAL;
267 error_setg(errp, "Invalid log sector size %"PRIu64, log_sector_size);
268 goto fail_log;
269 }
270
271 s->sectorsize = log_sector_size;
272 s->sectorbits = blk_log_writes_log2(log_sector_size);
273 s->update_interval = qemu_opt_get_number(opts, "log-super-update-interval",
274 4096);
275 if (!s->update_interval) {
276 ret = -EINVAL;
277 error_setg(errp, "Invalid log superblock update interval %"PRIu64,
278 s->update_interval);
279 goto fail_log;
280 }
281
282 ret = 0;
283 fail_log:
284 if (ret < 0) {
285 bdrv_graph_wrlock_drained();
286 bdrv_unref_child(bs, s->log_file);
287 bdrv_graph_wrunlock();
288 s->log_file = NULL;
289 qemu_mutex_destroy(&s->mutex);
290 }
291 fail:
292 qemu_opts_del(opts);
293 return ret;
294 }
295
296 static void blk_log_writes_close(BlockDriverState *bs)
297 {
298 BDRVBlkLogWritesState *s = bs->opaque;
299
300 bdrv_graph_wrlock_drained();
301 bdrv_unref_child(bs, s->log_file);
302 s->log_file = NULL;
303 bdrv_graph_wrunlock();
304 qemu_mutex_destroy(&s->mutex);
305 }
306
307 static int64_t coroutine_fn GRAPH_RDLOCK
308 blk_log_writes_co_getlength(BlockDriverState *bs)
309 {
310 return bdrv_co_getlength(bs->file->bs);
311 }
312
313 static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c,
314 BdrvChildRole role,
315 BlockReopenQueue *ro_q,
316 uint64_t perm, uint64_t shrd,
317 uint64_t *nperm, uint64_t *nshrd)
318 {
319 if (!c) {
320 *nperm = perm & DEFAULT_PERM_PASSTHROUGH;
321 *nshrd = (shrd & DEFAULT_PERM_PASSTHROUGH) | DEFAULT_PERM_UNCHANGED;
322 return;
323 }
324
325 bdrv_default_perms(bs, c, role, ro_q, perm, shrd,
326 nperm, nshrd);
327 }
328
329 static void blk_log_writes_refresh_limits(BlockDriverState *bs, Error **errp)
330 {
331 const BDRVBlkLogWritesState *s = bs->opaque;
332 bs->bl.request_alignment = s->sectorsize;
333 }
334
335 static int coroutine_fn GRAPH_RDLOCK
336 blk_log_writes_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
337 QEMUIOVector *qiov, BdrvRequestFlags flags)
338 {
339 return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
340 }
341
342 typedef struct BlkLogWritesFileReq {
343 BlockDriverState *bs;
344 uint64_t offset;
345 uint64_t bytes;
346 int file_flags;
347 QEMUIOVector *qiov;
348 int GRAPH_RDLOCK_PTR (*func)(struct BlkLogWritesFileReq *r);
349 int file_ret;
350 } BlkLogWritesFileReq;
351
352 typedef struct {
353 BlockDriverState *bs;
354 QEMUIOVector *qiov;
355 struct log_write_entry entry;
356 uint64_t zero_size;
357 int log_ret;
358 } BlkLogWritesLogReq;
359
360 static void coroutine_fn GRAPH_RDLOCK
361 blk_log_writes_co_do_log(BlkLogWritesLogReq *lr)
362 {
363 BDRVBlkLogWritesState *s = lr->bs->opaque;
364
365 /*
366 * Determine the offsets and sizes of different parts of the entry, and
367 * update the state of the driver.
368 *
369 * This needs to be done in one go, before any actual I/O is done, as the
370 * log entry may have to be written in two parts, and the state of the
371 * driver may be modified by other driver operations while waiting for the
372 * I/O to complete.
373 */
374 qemu_mutex_lock(&s->mutex);
375 const uint64_t entry_start_sector = s->cur_log_sector;
376 const uint64_t entry_offset = entry_start_sector << s->sectorbits;
377 const uint64_t qiov_aligned_size = ROUND_UP(lr->qiov->size, s->sectorsize);
378 const uint64_t entry_aligned_size = qiov_aligned_size +
379 ROUND_UP(lr->zero_size, s->sectorsize);
380 const uint64_t entry_nr_sectors = entry_aligned_size >> s->sectorbits;
381 const uint64_t entry_seq = s->nr_entries + 1;
382
383 s->nr_entries = entry_seq;
384 s->cur_log_sector += entry_nr_sectors;
385 qemu_mutex_unlock(&s->mutex);
386
387 /*
388 * Write the log entry. Note that if this is a "write zeroes" operation,
389 * only the entry header is written here, with the zeroing being done
390 * separately below.
391 */
392 lr->log_ret = bdrv_co_pwritev(s->log_file, entry_offset, lr->qiov->size,
393 lr->qiov, 0);
394
395 /* Logging for the "write zeroes" operation */
396 if (lr->log_ret == 0 && lr->zero_size) {
397 const uint64_t zeroes_offset = entry_offset + qiov_aligned_size;
398
399 lr->log_ret = bdrv_co_pwrite_zeroes(s->log_file, zeroes_offset,
400 lr->zero_size, 0);
401 }
402
403 /* Update super block on flush or every update interval */
404 if (lr->log_ret == 0 && ((lr->entry.flags & LOG_FLUSH_FLAG)
405 || (entry_seq % s->update_interval == 0)))
406 {
407 struct log_write_super super = {
408 .magic = cpu_to_le64(WRITE_LOG_MAGIC),
409 .version = cpu_to_le64(WRITE_LOG_VERSION),
410 .nr_entries = 0, /* updated below */
411 .sectorsize = cpu_to_le32(s->sectorsize),
412 };
413 void *zeroes;
414 QEMUIOVector qiov;
415
416 /*
417 * Wait if a super block update is already in progress.
418 * Bail out if a newer update got its turn before us.
419 */
420 WITH_QEMU_LOCK_GUARD(&s->mutex) {
421 CoQueueWaitFlags wait_flags = 0;
422 while (s->super_update_seq) {
423 if (entry_seq < s->super_update_seq) {
424 return;
425 }
426 qemu_co_queue_wait_flags(&s->super_update_queue,
427 &s->mutex, wait_flags);
428
429 /*
430 * In case the wait condition remains true after wakeup,
431 * to avoid starvation, make sure that this request is
432 * scheduled to rerun next by pushing it to the front of the
433 * queue.
434 */
435 wait_flags = CO_QUEUE_WAIT_FRONT;
436 }
437 s->super_update_seq = entry_seq;
438 super.nr_entries = cpu_to_le64(s->nr_entries);
439 }
440
441 zeroes = g_malloc0(s->sectorsize - sizeof(super));
442
443 qemu_iovec_init(&qiov, 2);
444 qemu_iovec_add(&qiov, &super, sizeof(super));
445 qemu_iovec_add(&qiov, zeroes, s->sectorsize - sizeof(super));
446
447 lr->log_ret =
448 bdrv_co_pwritev(s->log_file, 0, s->sectorsize, &qiov, 0);
449 if (lr->log_ret == 0) {
450 lr->log_ret = bdrv_co_flush(s->log_file->bs);
451 }
452
453 /* The super block has been updated. Let another request have a go. */
454 qemu_mutex_lock(&s->mutex);
455 s->super_update_seq = 0;
456 (void) qemu_co_queue_next(&s->super_update_queue);
457 qemu_mutex_unlock(&s->mutex);
458
459 qemu_iovec_destroy(&qiov);
460 g_free(zeroes);
461 }
462 }
463
464 static void coroutine_fn GRAPH_RDLOCK
465 blk_log_writes_co_do_file(BlkLogWritesFileReq *fr)
466 {
467 fr->file_ret = fr->func(fr);
468 }
469
470 static int coroutine_fn GRAPH_RDLOCK
471 blk_log_writes_co_log(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
472 QEMUIOVector *qiov, int flags,
473 int /*GRAPH_RDLOCK*/ (*file_func)(BlkLogWritesFileReq *r),
474 uint64_t entry_flags, bool is_zero_write)
475 {
476 QEMUIOVector log_qiov;
477 size_t niov = qiov ? qiov->niov : 0;
478 const BDRVBlkLogWritesState *s = bs->opaque;
479 BlkLogWritesFileReq fr = {
480 .bs = bs,
481 .offset = offset,
482 .bytes = bytes,
483 .file_flags = flags,
484 .qiov = qiov,
485 .func = file_func,
486 };
487 BlkLogWritesLogReq lr = {
488 .bs = bs,
489 .qiov = &log_qiov,
490 .entry = {
491 .sector = cpu_to_le64(offset >> s->sectorbits),
492 .nr_sectors = cpu_to_le64(bytes >> s->sectorbits),
493 .flags = cpu_to_le64(entry_flags),
494 .data_len = 0,
495 },
496 .zero_size = is_zero_write ? bytes : 0,
497 };
498 void *zeroes = g_malloc0(s->sectorsize - sizeof(lr.entry));
499
500 assert((1 << s->sectorbits) == s->sectorsize);
501 assert(bs->bl.request_alignment == s->sectorsize);
502 assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment));
503 assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment));
504
505 qemu_iovec_init(&log_qiov, niov + 2);
506 qemu_iovec_add(&log_qiov, &lr.entry, sizeof(lr.entry));
507 qemu_iovec_add(&log_qiov, zeroes, s->sectorsize - sizeof(lr.entry));
508 if (qiov) {
509 qemu_iovec_concat(&log_qiov, qiov, 0, qiov->size);
510 }
511
512 blk_log_writes_co_do_file(&fr);
513 blk_log_writes_co_do_log(&lr);
514
515 qemu_iovec_destroy(&log_qiov);
516 g_free(zeroes);
517
518 if (lr.log_ret < 0) {
519 return lr.log_ret;
520 }
521
522 return fr.file_ret;
523 }
524
525 static int coroutine_fn GRAPH_RDLOCK
526 blk_log_writes_co_do_file_pwritev(BlkLogWritesFileReq *fr)
527 {
528 return bdrv_co_pwritev(fr->bs->file, fr->offset, fr->bytes,
529 fr->qiov, fr->file_flags);
530 }
531
532 static int coroutine_fn GRAPH_RDLOCK
533 blk_log_writes_co_do_file_pwrite_zeroes(BlkLogWritesFileReq *fr)
534 {
535 return bdrv_co_pwrite_zeroes(fr->bs->file, fr->offset, fr->bytes,
536 fr->file_flags);
537 }
538
539 static int coroutine_fn GRAPH_RDLOCK
540 blk_log_writes_co_do_file_flush(BlkLogWritesFileReq *fr)
541 {
542 return bdrv_co_flush(fr->bs->file->bs);
543 }
544
545 static int coroutine_fn GRAPH_RDLOCK
546 blk_log_writes_co_do_file_pdiscard(BlkLogWritesFileReq *fr)
547 {
548 return bdrv_co_pdiscard(fr->bs->file, fr->offset, fr->bytes);
549 }
550
551 static int coroutine_fn GRAPH_RDLOCK
552 blk_log_writes_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
553 QEMUIOVector *qiov, BdrvRequestFlags flags)
554 {
555 return blk_log_writes_co_log(bs, offset, bytes, qiov, flags,
556 blk_log_writes_co_do_file_pwritev, 0, false);
557 }
558
559 static int coroutine_fn GRAPH_RDLOCK
560 blk_log_writes_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
561 int64_t bytes, BdrvRequestFlags flags)
562 {
563 return blk_log_writes_co_log(bs, offset, bytes, NULL, flags,
564 blk_log_writes_co_do_file_pwrite_zeroes, 0,
565 true);
566 }
567
568 static int coroutine_fn GRAPH_RDLOCK
569 blk_log_writes_co_flush_to_disk(BlockDriverState *bs)
570 {
571 return blk_log_writes_co_log(bs, 0, 0, NULL, 0,
572 blk_log_writes_co_do_file_flush,
573 LOG_FLUSH_FLAG, false);
574 }
575
576 static int coroutine_fn GRAPH_RDLOCK
577 blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
578 {
579 return blk_log_writes_co_log(bs, offset, bytes, NULL, 0,
580 blk_log_writes_co_do_file_pdiscard,
581 LOG_DISCARD_FLAG, false);
582 }
583
584 static const char *const blk_log_writes_strong_runtime_opts[] = {
585 "log-append",
586 "log-sector-size",
587
588 NULL
589 };
590
591 static BlockDriver bdrv_blk_log_writes = {
592 .format_name = "blklogwrites",
593 .instance_size = sizeof(BDRVBlkLogWritesState),
594
595 .bdrv_open = blk_log_writes_open,
596 .bdrv_close = blk_log_writes_close,
597 .bdrv_co_getlength = blk_log_writes_co_getlength,
598 .bdrv_child_perm = blk_log_writes_child_perm,
599 .bdrv_refresh_limits = blk_log_writes_refresh_limits,
600
601 .bdrv_co_preadv = blk_log_writes_co_preadv,
602 .bdrv_co_pwritev = blk_log_writes_co_pwritev,
603 .bdrv_co_pwrite_zeroes = blk_log_writes_co_pwrite_zeroes,
604 .bdrv_co_flush_to_disk = blk_log_writes_co_flush_to_disk,
605 .bdrv_co_pdiscard = blk_log_writes_co_pdiscard,
606
607 .is_filter = true,
608 .strong_runtime_opts = blk_log_writes_strong_runtime_opts,
609 };
610
611 static void bdrv_blk_log_writes_init(void)
612 {
613 bdrv_register(&bdrv_blk_log_writes);
614 }
615
616 block_init(bdrv_blk_log_writes_init);