From 300a9a7c8fc31b5edefe569690d9a03d3853ac3c Mon Sep 17 00:00:00 2001
From: Bruce Rogers <brogers@suse.com>
Date: Mon, 30 Apr 2018 13:27:17 -0600
Subject: [PATCH] xen: add block resize support for xen disks

Provide monitor naming of xen disks, and plumb guest driver
notification through xenstore of resizing instigated via the
monitor.

[BR: FATE#325467]
Signed-off-by: Bruce Rogers <brogers@suse.com>
---
 block/block-backend.c          |  7 +++++++
 blockdev.c                     |  8 ++++++++
 hw/block/xen_disk.c            | 19 +++++++++++++++++++
 include/sysemu/block-backend.h |  2 ++
 qemu-img.c                     |  4 ++++
 qemu-io.c                      |  4 ++++
 qemu-nbd.c                     |  4 ++++
 tests/Makefile.include         |  2 +-
 xen-common-stub.c              |  5 +++++
 xen-common.c                   |  7 +++++++
 10 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 1e70c4dcce..050e7ff466 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1756,6 +1756,13 @@ int blk_truncate(BlockBackend *blk, int64_t offset, Error **errp)
     return bdrv_truncate(blk->root, offset, errp);
 }
 
+void blk_legacy_resize_cb(BlockBackend *blk)
+{
+    if (blk->legacy_dev) {
+        xen_blk_resize_cb(blk->dev);
+    }
+}
+
 static void blk_pdiscard_entry(void *opaque)
 {
     BlkRwCo *rwco = opaque;
diff --git a/blockdev.c b/blockdev.c
index e8a9a65167..33055db813 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2888,6 +2888,7 @@ void qmp_block_resize(bool has_device, const char *device,
     Error *local_err = NULL;
     BlockBackend *blk = NULL;
     BlockDriverState *bs;
+    BlockBackend *cb_blk = NULL;
     AioContext *aio_context;
     int ret;
 
@@ -2899,6 +2900,10 @@ void qmp_block_resize(bool has_device, const char *device,
         return;
     }
 
+    if (has_device) {
+        cb_blk = blk_by_name(device);
+    }
+
     aio_context = bdrv_get_aio_context(bs);
     aio_context_acquire(aio_context);
 
@@ -2925,6 +2930,9 @@ void qmp_block_resize(bool has_device, const char *device,
 
     bdrv_drained_begin(bs);
     ret = blk_truncate(blk, size, errp);
+    if (!ret && cb_blk) {
+        blk_legacy_resize_cb(cb_blk);
+    }
     bdrv_drained_end(bs);
 
 out:
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
index bf76d2d331..e815b7c455 100644
--- a/hw/block/xen_disk.c
+++ b/hw/block/xen_disk.c
@@ -1068,6 +1068,7 @@ static int blk_connect(struct XenDevice *xendev)
     int pers, index, qflags;
     bool readonly = true;
     bool writethrough = true;
+    Error *errp = NULL;
 
     /* read-only ? */
     if (blkdev->directiosafe) {
@@ -1125,6 +1126,13 @@ static int blk_connect(struct XenDevice *xendev)
         blk_ref(blkdev->blk);
     }
     blk_attach_dev_legacy(blkdev->blk, blkdev);
+    if (!monitor_add_blk(blkdev->blk, g_strdup(blkdev->dev), &errp)) {
+        xen_pv_printf(&blkdev->xendev, 0, "error: %s\n",
+                      error_get_pretty(errp));
+        error_free(errp);
+        return -1;
+    }
+
     blkdev->file_size = blk_getlength(blkdev->blk);
     if (blkdev->file_size < 0) {
         BlockDriverState *bs = blk_bs(blkdev->blk);
@@ -1235,6 +1243,7 @@ static void blk_disconnect(struct XenDevice *xendev)
 
     if (blkdev->blk) {
         blk_detach_dev(blkdev->blk, blkdev);
+        monitor_remove_blk(blkdev->blk);
         blk_unref(blkdev->blk);
         blkdev->blk = NULL;
     }
@@ -1299,6 +1308,16 @@ static void blk_event(struct XenDevice *xendev)
     qemu_bh_schedule(blkdev->bh);
 }
 
+extern void xen_blk_resize_update(void *dev);
+void xen_blk_resize_update(void *dev)
+{
+    struct XenBlkDev *blkdev = dev;
+    blkdev->file_size = blk_getlength(blkdev->blk);
+    xenstore_write_be_int64(&blkdev->xendev, "sectors",
+                            blkdev->file_size / blkdev->file_blk);
+    xen_be_set_state(&blkdev->xendev, blkdev->xendev.be_state);
+}
+
 struct XenDevOps xen_blkdev_ops = {
     .size       = sizeof(struct XenBlkDev),
     .flags      = DEVOPS_FLAG_NEED_GNTDEV,
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 0ba4e277b9..ff85560d7a 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -227,6 +227,8 @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
                           int count);
 int blk_truncate(BlockBackend *blk, int64_t offset, Error **errp);
 int blk_pdiscard(BlockBackend *blk, int64_t offset, int count);
+void  blk_legacy_resize_cb(BlockBackend *blk);
+void xen_blk_resize_cb(void *dev);
 int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
                      int64_t pos, int size);
 int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size);
diff --git a/qemu-img.c b/qemu-img.c
index e4a2686f56..f9eacf7b44 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -69,6 +69,10 @@ typedef enum OutputFormat {
 /* Default to cache=writeback as data integrity is not important for qemu-img */
 #define BDRV_DEFAULT_CACHE "writeback"
 
+void xen_blk_resize_cb(void *dev)
+{
+}
+
 static void format_print(void *opaque, const char *name)
 {
     printf(" %s", name);
diff --git a/qemu-io.c b/qemu-io.c
index ed0e2dceaa..d19df80ef9 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -39,6 +39,10 @@ static bool imageOpts;
 
 static ReadLineState *readline_state;
 
+void xen_blk_resize_cb(void *dev)
+{
+}
+
 static int close_f(BlockBackend *blk, int argc, char **argv)
 {
     blk_unref(qemuio_blk);
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 4208829a16..75140d3ea0 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -66,6 +66,10 @@ static QIOChannelSocket *server_ioc;
 static int server_watch = -1;
 static QCryptoTLSCreds *tlscreds;
 
+void xen_blk_resize_cb(void *dev)
+{
+}
+
 static void usage(const char *name)
 {
     (printf) (
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 85187d4b8c..14893f0279 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -530,7 +530,7 @@ test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \
 	$(test-qom-obj-y)
 test-crypto-obj-y = $(crypto-obj-y) $(test-qom-obj-y)
 test-io-obj-y = $(io-obj-y) $(test-crypto-obj-y)
-test-block-obj-y = $(block-obj-y) $(test-io-obj-y) tests/iothread.o
+test-block-obj-y = $(block-obj-y) $(test-io-obj-y) tests/iothread.o xen-common-stub.o
 
 tests/check-qint$(EXESUF): tests/check-qint.o $(test-util-obj-y)
 tests/check-qstring$(EXESUF): tests/check-qstring.o $(test-util-obj-y)
diff --git a/xen-common-stub.c b/xen-common-stub.c
index 09fce2dd36..ed6f3e47c6 100644
--- a/xen-common-stub.c
+++ b/xen-common-stub.c
@@ -8,7 +8,12 @@
 #include "qemu/osdep.h"
 #include "qemu-common.h"
 #include "hw/xen/xen.h"
+#include "sysemu/block-backend.h"
 
 void xenstore_store_pv_console_info(int i, Chardev *chr)
 {
 }
+
+void xen_blk_resize_cb(void *dev)
+{
+}
diff --git a/xen-common.c b/xen-common.c
index fd2c92847e..0a62ea8042 100644
--- a/xen-common.c
+++ b/xen-common.c
@@ -14,6 +14,7 @@
 #include "sysemu/char.h"
 #include "sysemu/accel.h"
 #include "migration/migration.h"
+#include "sysemu/block-backend.h"
 
 //#define DEBUG_XEN
 
@@ -25,6 +26,12 @@
     do { } while (0)
 #endif
 
+extern void xen_blk_resize_update(void *dev);
+void xen_blk_resize_cb(void *dev)
+{
+    xen_blk_resize_update(dev);
+}
+
 static int store_dev_info(int domid, Chardev *cs, const char *string)
 {
     struct xs_handle *xs = NULL;
