From 393514dcd5434b4a215c6230d17d255c0f5a38bc 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          | 11 ++++++++++-
 blockdev.c                     |  8 ++++++++
 hw/block/m25p80.c              |  2 +-
 hw/block/xen_disk.c            | 21 ++++++++++++++++++++-
 include/hw/xen/xen.h           |  1 +
 include/sysemu/block-backend.h |  4 +++-
 qemu-img.c                     |  4 ++++
 qemu-io.c                      |  4 ++++
 qemu-nbd.c                     |  4 ++++
 tests/Makefile                 |  2 +-
 xen-common-stub.c              |  5 +++++
 xen-common.c                   |  7 +++++++
 12 files changed, 68 insertions(+), 5 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index de71d75c3d..b868509c04 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -36,6 +36,7 @@ struct BlockBackend {
     QTAILQ_ENTRY(BlockBackend) monitor_link; /* for monitor_block_backends */
 
     void *dev;                  /* attached device model, if any */
+    bool xen_dev;               /* true if dev is a Xen disk */
     /* TODO change to DeviceState when all users are qdevified */
     const BlockDevOps *dev_ops;
     void *dev_opaque;
@@ -460,11 +461,12 @@ int blk_attach_dev(BlockBackend *blk, void *dev)
  * @blk must not have a device model attached already.
  * TODO qdevified devices don't use this, remove when devices are qdevified
  */
-void blk_attach_dev_nofail(BlockBackend *blk, void *dev)
+void blk_attach_dev_nofail(BlockBackend *blk, void *dev, bool xen_dev)
 {
     if (blk_attach_dev(blk, dev) < 0) {
         abort();
     }
+    blk->xen_dev = xen_dev;
 }
 
 /*
@@ -1483,6 +1485,13 @@ int blk_truncate(BlockBackend *blk, int64_t offset)
     return bdrv_truncate(blk_bs(blk), offset);
 }
 
+void blk_legacy_resize_cb(BlockBackend *blk)
+{
+    if (blk->xen_dev) {
+        xen_blk_resize_cb(blk->dev);
+    }
+}
+
 int blk_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors)
 {
     int ret = blk_check_request(blk, sector_num, nb_sectors);
diff --git a/blockdev.c b/blockdev.c
index 260a6f5e02..b9a02fcebe 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2907,6 +2907,7 @@ void qmp_block_resize(bool has_device, const char *device,
 {
     Error *local_err = NULL;
     BlockDriverState *bs;
+    BlockBackend *cb_blk = NULL;
     AioContext *aio_context;
     int ret;
 
@@ -2918,6 +2919,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);
 
@@ -2942,6 +2947,9 @@ void qmp_block_resize(bool has_device, const char *device,
     ret = bdrv_truncate(bs, size);
     switch (ret) {
     case 0:
+        if (cb_blk) {
+            blk_legacy_resize_cb(cb_blk);
+        }
         break;
     case -ENOMEDIUM:
         error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 906b71257e..d9a9ae699a 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -902,7 +902,7 @@ static int m25p80_init(SSISlave *ss)
     if (dinfo) {
         DB_PRINT_L(0, "Binding to IF_MTD drive\n");
         s->blk = blk_by_legacy_dinfo(dinfo);
-        blk_attach_dev_nofail(s->blk, s);
+        blk_attach_dev_nofail(s->blk, s, false);
 
         s->storage = blk_blockalign(s->blk, s->size);
 
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
index 2ec76f8d83..0920de9f4f 100644
--- a/hw/block/xen_disk.c
+++ b/hw/block/xen_disk.c
@@ -901,6 +901,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) {
@@ -956,7 +957,14 @@ static int blk_connect(struct XenDevice *xendev)
          * so we can blk_unref() unconditionally */
         blk_ref(blkdev->blk);
     }
-    blk_attach_dev_nofail(blkdev->blk, blkdev);
+    blk_attach_dev_nofail(blkdev->blk, blkdev, true);
+    if (!monitor_add_blk(blkdev->blk, g_strdup(blkdev->dev), &errp)) {
+        xen_be_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);
@@ -1059,6 +1067,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;
     }
@@ -1123,6 +1132,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/hw/xen/xen.h b/include/hw/xen/xen.h
index 6eb815aace..dde06e0617 100644
--- a/include/hw/xen/xen.h
+++ b/include/hw/xen/xen.h
@@ -46,4 +46,5 @@ void xen_modified_memory(ram_addr_t start, ram_addr_t length);
 
 void xen_register_framebuffer(struct MemoryRegion *mr);
 
+
 #endif /* QEMU_HW_XEN_H */
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 745f0ef3d9..9f7929f014 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -86,7 +86,7 @@ void blk_iostatus_disable(BlockBackend *blk);
 void blk_iostatus_reset(BlockBackend *blk);
 void blk_iostatus_set_err(BlockBackend *blk, int error);
 int blk_attach_dev(BlockBackend *blk, void *dev);
-void blk_attach_dev_nofail(BlockBackend *blk, void *dev);
+void blk_attach_dev_nofail(BlockBackend *blk, void *dev, bool xen_dev);
 void blk_detach_dev(BlockBackend *blk, void *dev);
 void *blk_get_attached_dev(BlockBackend *blk);
 void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, void *opaque);
@@ -189,6 +189,8 @@ int coroutine_fn blk_co_write_zeroes(BlockBackend *blk, int64_t offset,
 int blk_write_compressed(BlockBackend *blk, int64_t sector_num,
                          const uint8_t *buf, int nb_sectors);
 int blk_truncate(BlockBackend *blk, int64_t offset);
+void  blk_legacy_resize_cb(BlockBackend *blk);
+void xen_blk_resize_cb(void *dev);
 int blk_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors);
 int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
                      int64_t pos, int size);
diff --git a/qemu-img.c b/qemu-img.c
index a04921686d..95bcb74bf0 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -63,6 +63,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 0598251e7c..137ac33909 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -38,6 +38,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 7293e95781..0d76bd0922 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -59,6 +59,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 b/tests/Makefile
index 73d5b40c03..cdb78e382b 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -407,7 +407,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)
+test-block-obj-y = $(block-obj-y) $(test-io-obj-y) 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 699c3f1c64..fc1c794383 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, CharDriverState *chr)
 {
 }
+
+void xen_blk_resize_cb(void *dev)
+{
+}
diff --git a/xen-common.c b/xen-common.c
index e641ad1aef..219b7aac1c 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, CharDriverState *cs, const char *string)
 {
     struct xs_handle *xs = NULL;
