]> Git Repo - qemu.git/blame - block/blklogwrites.c
block/crypto: Fix memory leak in create error path
[qemu.git] / block / blklogwrites.c
CommitLineData
bfcc224e
AV
1/*
2 * Write logging blk driver based on blkverify and blkdebug.
3 *
4 * Copyright (c) 2017 Tuomas Tynkkynen <[email protected]>
5 * Copyright (c) 2018 Aapo Vienamo <[email protected]>
6 * Copyright (c) 2018 Ari Sundholm <[email protected]>
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_int.h"
16#include "qapi/qmp/qdict.h"
17#include "qapi/qmp/qstring.h"
18#include "qemu/cutils.h"
19#include "qemu/option.h"
20
21/* Disk format stuff - taken from Linux drivers/md/dm-log-writes.c */
22
23#define LOG_FLUSH_FLAG (1 << 0)
24#define LOG_FUA_FLAG (1 << 1)
25#define LOG_DISCARD_FLAG (1 << 2)
26#define LOG_MARK_FLAG (1 << 3)
27
28#define WRITE_LOG_VERSION 1ULL
29#define WRITE_LOG_MAGIC 0x6a736677736872ULL
30
31/* All fields are little-endian. */
32struct log_write_super {
33 uint64_t magic;
34 uint64_t version;
35 uint64_t nr_entries;
36 uint32_t sectorsize;
37} QEMU_PACKED;
38
39struct log_write_entry {
40 uint64_t sector;
41 uint64_t nr_sectors;
42 uint64_t flags;
43 uint64_t data_len;
44} QEMU_PACKED;
45
46/* End of disk format structures. */
47
48typedef struct {
49 BdrvChild *log_file;
50 uint32_t sectorsize;
51 uint32_t sectorbits;
52 uint64_t cur_log_sector;
53 uint64_t nr_entries;
54} BDRVBlkLogWritesState;
55
56static QemuOptsList runtime_opts = {
57 .name = "blklogwrites",
58 .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
59 .desc = {
60 {
61 .name = "log-sector-size",
62 .type = QEMU_OPT_SIZE,
63 .help = "Log sector size",
64 },
65 { /* end of list */ }
66 },
67};
68
69static inline uint32_t blk_log_writes_log2(uint32_t value)
70{
71 assert(value > 0);
72 return 31 - clz32(value);
73}
74
75static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
76 Error **errp)
77{
78 BDRVBlkLogWritesState *s = bs->opaque;
79 QemuOpts *opts;
80 Error *local_err = NULL;
81 int ret;
82 int64_t log_sector_size;
83
84 opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
85 qemu_opts_absorb_qdict(opts, options, &local_err);
86 if (local_err) {
87 ret = -EINVAL;
88 error_propagate(errp, local_err);
89 goto fail;
90 }
91
92 /* Open the file */
93 bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
94 &local_err);
95 if (local_err) {
96 ret = -EINVAL;
97 error_propagate(errp, local_err);
98 goto fail;
99 }
100
101 log_sector_size = qemu_opt_get_size(opts, "log-sector-size",
102 BDRV_SECTOR_SIZE);
103
104 if (log_sector_size < 0 || log_sector_size > (1ull << 23) ||
105 !is_power_of_2(log_sector_size))
106 {
107 ret = -EINVAL;
108 error_setg(errp, "Invalid log sector size %"PRId64, log_sector_size);
109 goto fail;
110 }
111
112 s->sectorsize = log_sector_size;
113 s->sectorbits = blk_log_writes_log2(log_sector_size);
114 s->cur_log_sector = 1;
115 s->nr_entries = 0;
116
117 /* Open the log file */
118 s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_file, false,
119 &local_err);
120 if (local_err) {
121 ret = -EINVAL;
122 error_propagate(errp, local_err);
123 goto fail;
124 }
125
126 ret = 0;
127fail:
128 if (ret < 0) {
129 bdrv_unref_child(bs, bs->file);
130 bs->file = NULL;
131 }
132 qemu_opts_del(opts);
133 return ret;
134}
135
136static void blk_log_writes_close(BlockDriverState *bs)
137{
138 BDRVBlkLogWritesState *s = bs->opaque;
139
140 bdrv_unref_child(bs, s->log_file);
141 s->log_file = NULL;
142}
143
144static int64_t blk_log_writes_getlength(BlockDriverState *bs)
145{
146 return bdrv_getlength(bs->file->bs);
147}
148
149static void blk_log_writes_refresh_filename(BlockDriverState *bs,
150 QDict *options)
151{
152 BDRVBlkLogWritesState *s = bs->opaque;
153
154 /* bs->file->bs has already been refreshed */
155 bdrv_refresh_filename(s->log_file->bs);
156
157 if (bs->file->bs->full_open_options
158 && s->log_file->bs->full_open_options)
159 {
160 QDict *opts = qdict_new();
161 qdict_put_str(opts, "driver", "blklogwrites");
162
163 qobject_ref(bs->file->bs->full_open_options);
164 qdict_put_obj(opts, "file", QOBJECT(bs->file->bs->full_open_options));
165 qobject_ref(s->log_file->bs->full_open_options);
166 qdict_put_obj(opts, "log",
167 QOBJECT(s->log_file->bs->full_open_options));
168 qdict_put_int(opts, "log-sector-size", s->sectorsize);
169
170 bs->full_open_options = opts;
171 }
172}
173
174static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c,
175 const BdrvChildRole *role,
176 BlockReopenQueue *ro_q,
177 uint64_t perm, uint64_t shrd,
178 uint64_t *nperm, uint64_t *nshrd)
179{
180 if (!c) {
181 *nperm = perm & DEFAULT_PERM_PASSTHROUGH;
182 *nshrd = (shrd & DEFAULT_PERM_PASSTHROUGH) | DEFAULT_PERM_UNCHANGED;
183 return;
184 }
185
186 if (!strcmp(c->name, "log")) {
187 bdrv_format_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd);
188 } else {
189 bdrv_filter_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd);
190 }
191}
192
193static void blk_log_writes_refresh_limits(BlockDriverState *bs, Error **errp)
194{
195 BDRVBlkLogWritesState *s = bs->opaque;
196 bs->bl.request_alignment = s->sectorsize;
197}
198
199static int coroutine_fn
200blk_log_writes_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
201 QEMUIOVector *qiov, int flags)
202{
203 return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
204}
205
206typedef struct BlkLogWritesFileReq {
207 BlockDriverState *bs;
208 uint64_t offset;
209 uint64_t bytes;
210 int file_flags;
211 QEMUIOVector *qiov;
212 int (*func)(struct BlkLogWritesFileReq *r);
213 int file_ret;
214} BlkLogWritesFileReq;
215
216typedef struct {
217 BlockDriverState *bs;
218 QEMUIOVector *qiov;
219 struct log_write_entry entry;
220 uint64_t zero_size;
221 int log_ret;
222} BlkLogWritesLogReq;
223
224static void coroutine_fn blk_log_writes_co_do_log(BlkLogWritesLogReq *lr)
225{
226 BDRVBlkLogWritesState *s = lr->bs->opaque;
227 uint64_t cur_log_offset = s->cur_log_sector << s->sectorbits;
228
229 s->nr_entries++;
230 s->cur_log_sector +=
231 ROUND_UP(lr->qiov->size, s->sectorsize) >> s->sectorbits;
232
233 lr->log_ret = bdrv_co_pwritev(s->log_file, cur_log_offset, lr->qiov->size,
234 lr->qiov, 0);
235
236 /* Logging for the "write zeroes" operation */
237 if (lr->log_ret == 0 && lr->zero_size) {
238 cur_log_offset = s->cur_log_sector << s->sectorbits;
239 s->cur_log_sector +=
240 ROUND_UP(lr->zero_size, s->sectorsize) >> s->sectorbits;
241
242 lr->log_ret = bdrv_co_pwrite_zeroes(s->log_file, cur_log_offset,
243 lr->zero_size, 0);
244 }
245
246 /* Update super block on flush */
247 if (lr->log_ret == 0 && lr->entry.flags & LOG_FLUSH_FLAG) {
248 struct log_write_super super = {
249 .magic = cpu_to_le64(WRITE_LOG_MAGIC),
250 .version = cpu_to_le64(WRITE_LOG_VERSION),
251 .nr_entries = cpu_to_le64(s->nr_entries),
252 .sectorsize = cpu_to_le32(s->sectorsize),
253 };
254 void *zeroes = g_malloc0(s->sectorsize - sizeof(super));
255 QEMUIOVector qiov;
256
257 qemu_iovec_init(&qiov, 2);
258 qemu_iovec_add(&qiov, &super, sizeof(super));
259 qemu_iovec_add(&qiov, zeroes, s->sectorsize - sizeof(super));
260
261 lr->log_ret =
262 bdrv_co_pwritev(s->log_file, 0, s->sectorsize, &qiov, 0);
263 if (lr->log_ret == 0) {
264 lr->log_ret = bdrv_co_flush(s->log_file->bs);
265 }
266 qemu_iovec_destroy(&qiov);
267 g_free(zeroes);
268 }
269}
270
271static void coroutine_fn blk_log_writes_co_do_file(BlkLogWritesFileReq *fr)
272{
273 fr->file_ret = fr->func(fr);
274}
275
276static int coroutine_fn
277blk_log_writes_co_log(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
278 QEMUIOVector *qiov, int flags,
279 int (*file_func)(BlkLogWritesFileReq *r),
280 uint64_t entry_flags, bool is_zero_write)
281{
282 QEMUIOVector log_qiov;
283 size_t niov = qiov ? qiov->niov : 0;
284 BDRVBlkLogWritesState *s = bs->opaque;
285 BlkLogWritesFileReq fr = {
286 .bs = bs,
287 .offset = offset,
288 .bytes = bytes,
289 .file_flags = flags,
290 .qiov = qiov,
291 .func = file_func,
292 };
293 BlkLogWritesLogReq lr = {
294 .bs = bs,
295 .qiov = &log_qiov,
296 .entry = {
297 .sector = cpu_to_le64(offset >> s->sectorbits),
298 .nr_sectors = cpu_to_le64(bytes >> s->sectorbits),
299 .flags = cpu_to_le64(entry_flags),
300 .data_len = 0,
301 },
302 .zero_size = is_zero_write ? bytes : 0,
303 };
304 void *zeroes = g_malloc0(s->sectorsize - sizeof(lr.entry));
305
306 assert((1 << s->sectorbits) == s->sectorsize);
307 assert(bs->bl.request_alignment == s->sectorsize);
308 assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment));
309 assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment));
310
311 qemu_iovec_init(&log_qiov, niov + 2);
312 qemu_iovec_add(&log_qiov, &lr.entry, sizeof(lr.entry));
313 qemu_iovec_add(&log_qiov, zeroes, s->sectorsize - sizeof(lr.entry));
314 if (qiov) {
315 qemu_iovec_concat(&log_qiov, qiov, 0, qiov->size);
316 }
317
318 blk_log_writes_co_do_file(&fr);
319 blk_log_writes_co_do_log(&lr);
320
321 qemu_iovec_destroy(&log_qiov);
322 g_free(zeroes);
323
324 if (lr.log_ret < 0) {
325 return lr.log_ret;
326 }
327
328 return fr.file_ret;
329}
330
331static int coroutine_fn
332blk_log_writes_co_do_file_pwritev(BlkLogWritesFileReq *fr)
333{
334 return bdrv_co_pwritev(fr->bs->file, fr->offset, fr->bytes,
335 fr->qiov, fr->file_flags);
336}
337
338static int coroutine_fn
339blk_log_writes_co_do_file_pwrite_zeroes(BlkLogWritesFileReq *fr)
340{
341 return bdrv_co_pwrite_zeroes(fr->bs->file, fr->offset, fr->bytes,
342 fr->file_flags);
343}
344
345static int coroutine_fn blk_log_writes_co_do_file_flush(BlkLogWritesFileReq *fr)
346{
347 return bdrv_co_flush(fr->bs->file->bs);
348}
349
350static int coroutine_fn
351blk_log_writes_co_do_file_pdiscard(BlkLogWritesFileReq *fr)
352{
353 return bdrv_co_pdiscard(fr->bs->file->bs, fr->offset, fr->bytes);
354}
355
356static int coroutine_fn
357blk_log_writes_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
358 QEMUIOVector *qiov, int flags)
359{
360 return blk_log_writes_co_log(bs, offset, bytes, qiov, flags,
361 blk_log_writes_co_do_file_pwritev, 0, false);
362}
363
364static int coroutine_fn
365blk_log_writes_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes,
366 BdrvRequestFlags flags)
367{
368 return blk_log_writes_co_log(bs, offset, bytes, NULL, flags,
369 blk_log_writes_co_do_file_pwrite_zeroes, 0,
370 true);
371}
372
373static int coroutine_fn blk_log_writes_co_flush_to_disk(BlockDriverState *bs)
374{
375 return blk_log_writes_co_log(bs, 0, 0, NULL, 0,
376 blk_log_writes_co_do_file_flush,
377 LOG_FLUSH_FLAG, false);
378}
379
380static int coroutine_fn
381blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
382{
383 return blk_log_writes_co_log(bs, offset, count, NULL, 0,
384 blk_log_writes_co_do_file_pdiscard,
385 LOG_DISCARD_FLAG, false);
386}
387
388static BlockDriver bdrv_blk_log_writes = {
389 .format_name = "blklogwrites",
390 .instance_size = sizeof(BDRVBlkLogWritesState),
391
392 .bdrv_open = blk_log_writes_open,
393 .bdrv_close = blk_log_writes_close,
394 .bdrv_getlength = blk_log_writes_getlength,
395 .bdrv_refresh_filename = blk_log_writes_refresh_filename,
396 .bdrv_child_perm = blk_log_writes_child_perm,
397 .bdrv_refresh_limits = blk_log_writes_refresh_limits,
398
399 .bdrv_co_preadv = blk_log_writes_co_preadv,
400 .bdrv_co_pwritev = blk_log_writes_co_pwritev,
401 .bdrv_co_pwrite_zeroes = blk_log_writes_co_pwrite_zeroes,
402 .bdrv_co_flush_to_disk = blk_log_writes_co_flush_to_disk,
403 .bdrv_co_pdiscard = blk_log_writes_co_pdiscard,
404 .bdrv_co_block_status = bdrv_co_block_status_from_file,
405
406 .is_filter = true,
407};
408
409static void bdrv_blk_log_writes_init(void)
410{
411 bdrv_register(&bdrv_blk_log_writes);
412}
413
414block_init(bdrv_blk_log_writes_init);
This page took 0.062791 seconds and 4 git commands to generate.