qemu-block
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-block] [PATCH v2 7/9] blkdebug: Add pass-through write_zero and di


From: Eric Blake
Subject: [Qemu-block] [PATCH v2 7/9] blkdebug: Add pass-through write_zero and discard support
Date: Thu, 17 Nov 2016 14:14:00 -0600

In order to test the effects of artificial geometry constraints
on operations like write zero or discard, we first need blkdebug
to manage these actions.  Ideally, it would be nice to let these
operations also react to injected errors like read/write/flush,
but it is not trivial to turn bdrv_aio error injection (where
we return BlockAIOCB*) into bdrv_co (where we return int), not
to mention the fact that I don't want to conflict with Kevin's
concurrent work on refactoring away from bdrv_aio.  So for now,
the operations merely have a TODO comment for adding error
injection.

However, one thing we CAN test is the contract promised by the
block layer; namely, if a device has specified limits on
alignment or maximum size, then those limits must be obeyed (for
now, the blkdebug driver merely inherits limits from whatever it
is wrapping, but the next patch will further enhance it to allow
specific limit overrides).

Tested by setting up an NBD server with export 'foo', then invoking:
$ ./qemu-io
qemu-io> open -o driver=blkdebug blkdebug::nbd://localhost:10809/foo
qemu-io> d 0 15M
qemu-io> w -z 0 15M

Pre-patch, the server never sees the discard (it was silently
eaten by the block layer); post-patch it is passed across the
wire.  Likewise, pre-patch the write is always passed with
NBD_WRITE (with 15M of zeroes on the wire), while post-patch
it can utilize NBD_WRITE_ZEROES (for less traffic).

Signed-off-by: Eric Blake <address@hidden>
---
 block/blkdebug.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/block/blkdebug.c b/block/blkdebug.c
index 0a47977..d45826d 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -1,6 +1,7 @@
 /*
  * Block protocol for I/O error injection
  *
+ * Copyright (C) 2016 Red Hat, Inc.
  * Copyright (c) 2010 Kevin Wolf <address@hidden>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -383,6 +384,11 @@ static int blkdebug_open(BlockDriverState *bs, QDict 
*options, int flags,
         goto out;
     }

+    bs->supported_write_flags = BDRV_REQ_FUA &
+        bs->file->bs->supported_write_flags;
+    bs->supported_zero_flags = (BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
+        bs->file->bs->supported_zero_flags;
+
     /* Set request alignment */
     align = qemu_opt_get_size(opts, "align", 0);
     if (align < INT_MAX && is_power_of_2(align)) {
@@ -522,6 +528,59 @@ static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
 }


+static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs,
+                                                  int64_t offset, int count,
+                                                  BdrvRequestFlags flags)
+{
+    uint32_t align = MAX(bs->bl.request_alignment,
+                         bs->bl.pwrite_zeroes_alignment);
+
+    /* Regardless of whether the lower layer has a finer granularity,
+     * we want to treat any unaligned request as unsupported, and
+     * check that the block layer never hands us anything crossing an
+     * alignment boundary.  */
+    if (count < align) {
+        return -ENOTSUP;
+    }
+    assert(QEMU_IS_ALIGNED(offset, align));
+    assert(QEMU_IS_ALIGNED(count, align));
+    if (bs->bl.max_pwrite_zeroes) {
+        assert(count <= bs->bl.max_pwrite_zeroes);
+    }
+
+    /* TODO: Support rule injection? */
+
+    return bdrv_co_pwrite_zeroes(bs->file, offset, count, flags);
+}
+
+
+static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
+                                             int64_t offset, int count)
+{
+    uint32_t align = bs->bl.pdiscard_alignment;
+
+    /* Only pass through requests that are larger than requested
+     * minimum alignment, and ensure that unaligned requests do not
+     * cross optimum discard boundaries. */
+    if (count < bs->bl.request_alignment) {
+        return -ENOTSUP;
+    }
+    assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment));
+    assert(QEMU_IS_ALIGNED(count, bs->bl.request_alignment));
+    if (align && count >= align) {
+        assert(QEMU_IS_ALIGNED(offset, align));
+        assert(QEMU_IS_ALIGNED(count, align));
+    }
+    if (bs->bl.max_pdiscard) {
+        assert(count <= bs->bl.max_pdiscard);
+    }
+
+    /* TODO: Support rule injection? */
+
+    return bdrv_co_pdiscard(bs->file->bs, offset, count);
+}
+
+
 static void blkdebug_close(BlockDriverState *bs)
 {
     BDRVBlkdebugState *s = bs->opaque;
@@ -773,6 +832,8 @@ static BlockDriver bdrv_blkdebug = {
     .bdrv_aio_readv         = blkdebug_aio_readv,
     .bdrv_aio_writev        = blkdebug_aio_writev,
     .bdrv_aio_flush         = blkdebug_aio_flush,
+    .bdrv_co_pwrite_zeroes  = blkdebug_co_pwrite_zeroes,
+    .bdrv_co_pdiscard       = blkdebug_co_pdiscard,

     .bdrv_debug_event           = blkdebug_debug_event,
     .bdrv_debug_breakpoint      = blkdebug_debug_breakpoint,
-- 
2.7.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]