]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
xen-blkback: implement swapping of active vbd
authorAnkur Arora <ankur.a.arora@oracle.com>
Thu, 30 Aug 2018 10:34:54 +0000 (03:34 -0700)
committerBrian Maly <brian.maly@oracle.com>
Mon, 8 Oct 2018 15:43:36 +0000 (11:43 -0400)
Currently we disallow any change of major:minor of the vbd once created.
The danger is in the user switching backends where the contents of the
backend device are dissimilar.
However, changing the vbd can be quite useful -- for instance by switching
from a backend which is not multi-pathed (or raid'd) to one that is.

As for blkback itself, it is used purely as a passthrough device so there
is no state outside struct vbd which would be impacted with this change.

This patch allows a vbd swap, communicating the state of the swap via the
xenbus paths:

.../vbd/<domain>/51712/oracle/active-physical-device = "<major>:<minor>"
.../vbd/<domain>/51712/oracle/physical-device-change-status = "<error>"

Orabug: 28651655

Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
Reviewed-by: Bhavesh Davda <bhavesh.davda@oracle.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Signed-off-by: Brian Maly <brian.maly@oracle.com>
drivers/block/xen-blkback/xenbus.c
include/xen/interface/io/blkif.h

index 61de4777e2725785b29458ccb9ec0e765bd91bf9..50ca4f591d525091b3ed37bb575821518e1364ff 100644 (file)
@@ -86,6 +86,19 @@ static int blkback_name(struct xen_blkif *blkif, char *buf)
        return 0;
 }
 
+static int
+flush_bdev_mapping(struct xenbus_device *dev, struct xen_vbd *vbd)
+{
+       int err;
+
+       err = filemap_write_and_wait(vbd->bdev->bd_inode->i_mapping);
+
+       if (!err)
+               invalidate_inode_pages2(vbd->bdev->bd_inode->i_mapping);
+
+       return err;
+}
+
 static void xen_update_blkif_status(struct xen_blkif *blkif)
 {
        int err;
@@ -112,12 +125,11 @@ static void xen_update_blkif_status(struct xen_blkif *blkif)
                return;
        }
 
-       err = filemap_write_and_wait(blkif->vbd.bdev->bd_inode->i_mapping);
+       err = flush_bdev_mapping(blkif->be->dev, &blkif->vbd);
        if (err) {
                xenbus_dev_error(blkif->be->dev, err, "block flush");
                return;
        }
-       invalidate_inode_pages2(blkif->vbd.bdev->bd_inode->i_mapping);
 
        for (i = 0; i < blkif->nr_rings; i++) {
                ring = &blkif->rings[i];
@@ -447,13 +459,11 @@ static void xen_vbd_free(struct xen_vbd *vbd)
 }
 
 static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle,
-                         struct blkif_params *p)
+                         struct blkif_params *p, struct xen_vbd *vbd)
 {
-       struct xen_vbd *vbd;
        struct block_device *bdev;
        struct request_queue *q;
 
-       vbd = &blkif->vbd;
        vbd->handle   = handle;
        vbd->readonly = p->readonly;
        vbd->type     = 0;
@@ -744,6 +754,26 @@ xenbus_scan_be_params(struct blkif_params *p, struct xenbus_device *dev,
        return 0;
 }
 
+static int
+validate_swap_params(struct backend_info *be, struct blkif_params *p)
+{
+       int err = -EINVAL;
+
+       if (be->params.major != p->major ||
+           be->params.minor != p->minor) {
+               if (be->params.readonly == p->readonly &&
+                   be->params.cdrom == p->cdrom) {
+                       err = 0;
+               }
+       }
+
+       pr_warn("changing physical device (from %x:%x to %x:%x)%s.\n",
+                       be->params.major, be->params.minor,
+                       p->major, p->minor,
+                       err ? " not supported":"");
+       return err;
+}
+
 /*
  * Callback received when the hotplug scripts have placed the physical-device
  * node.  Read it and the mode node, and create a vbd.  If the frontend is
@@ -757,47 +787,75 @@ static void backend_changed(struct xenbus_watch *watch,
                = container_of(watch, struct backend_info, backend_watch);
        struct xenbus_device *dev = be->dev;
        unsigned long handle;
-       struct blkif_params p;
+       struct blkif_params oldp, newp;
+       struct xen_vbd vbd;
+       bool swap = false;
 
        pr_debug("%s %p %d\n", __func__, dev, dev->otherend_id);
 
-       err = xenbus_scan_be_params(&p, dev, &handle);
+       err = xenbus_scan_be_params(&newp, dev, &handle);
        if (err)
                return;
 
        if (be->params.major | be->params.minor) {
-               err = -EINVAL;
-               if (be->params.major != p.major || be->params.minor != p.minor)
-                       pr_warn("changing physical device (from %x:%x to %x:%x) not supported.\n",
-                               be->params.major, be->params.minor,
-                               p.major, p.minor);
-               goto out;
+               err = validate_swap_params(be, &newp);
+               if (err)
+                       goto out;
+               swap = true;
        }
 
-       err = xen_vbd_create(be->blkif, handle, &p);
+       err = xen_vbd_create(be->blkif, handle, &newp, &vbd);
        if (err) {
                xenbus_dev_fatal(dev, err, "creating vbd structure");
                goto out;
        }
 
-       be->params = p;
+       /*
+        * Save the current params: any errors after this
+        * point and we will have to restore them.
+        */
+       oldp = be->params;
+       be->params = newp;
 
-       err = xenvbd_sysfs_addif(dev);
-       if (err) {
+       if (swap) {
+               /* Flush, invalidate extant mappings */
+               err = flush_bdev_mapping(dev, &be->blkif->vbd);
+               if (err) {
+                       /*
+                        * In case of flush error, free the new vbd
+                        * and continue with the old one.
+                        */
+                       xen_vbd_free(&vbd);
+                       xenbus_dev_error(dev, err, "bdev flush error");
+                       goto flush_sysfs_out;
+               }
+
+               /* Free old vbd and switch over to the new one */
                xen_vbd_free(&be->blkif->vbd);
-               xenbus_dev_fatal(dev, err, "creating sysfs entries");
-               goto sysfs_out;
-       }
+               be->blkif->vbd = vbd;
+       } else {
+               be->blkif->vbd = vbd;
 
-       /* We're potentially connected now */
-       xen_update_blkif_status(be->blkif);
+               /* We have a new vbd, add sysfs entries */
+               err = xenvbd_sysfs_addif(dev);
+               if (err) {
+                       xen_vbd_free(&be->blkif->vbd);
+                       xenbus_dev_fatal(dev, err, "creating sysfs entries");
+                       goto flush_sysfs_out;
+               }
+
+               /* We're potentially connected now */
+               xen_update_blkif_status(be->blkif);
+       }
 
-sysfs_out:
+flush_sysfs_out:
        /*
-        * In case of failure reset the params.
+        * In case of failure we continue with the unchanged
+        * vbd (which in case of the !swap case might be NULL.)
+        * Switch over to the saved params.
         */
        if (err)
-               memset(&be->params, 0, sizeof(be->params));
+               be->params = oldp;
 out:
        /*
         * err  = 0: emit new vbd, err = 0 to the xenbus
index c2139acb39243156895b57c51e15f99f466ac144..29949609d98867242090f4cc259a6baf23c942ea 100644 (file)
@@ -81,21 +81,22 @@ typedef uint64_t blkif_sector_t;
  *
  * Volume Swapping:
  *
- * blkback plugs in the backing volume based on changes to the "physical-device"
- * xenstore key.
+ * blkback plugs or swaps in the backing volume based on changes to the
+ * "physical-device" xenstore key.
  *
- * Once the backing volume is plugged in, blkback writes to the
- * "oracle/active-physical-device" with the now active volume, and
- * "oracle/physical-device-status" with the error code. The error
- * code follows backend OS convention. On Linux, defined in
+ * Once the backing volume is plugged or swapped in, blkback writes to the
+ * "oracle/active-physical-device" with the now active volume (or the old device
+ * on failed swap), and "oracle/physical-device-status" with the error code.
+ * The error code follows backend OS convention. On Linux, defined in
  * /usr/include/asm/errno*h.
  *
- * For instance, the toolstack plugging in a guest disk would write:
+ * For instance, a toolstack plugging in or hot-swapping a guest disk would
+ * write:
  *
  * /local/domain/0/backend/vbd/<domid>/51712/physical-device  = "1a:2"
  *
- * And backend would validate and plug in the new physical device and its
- * status (e.g. in case of errors):
+ * This would be validated by the backend which would plug or swap in the new
+ * physical device and update the device and its error status:
  *
  * /local/domain/0/backend/vbd/<domid>/51712/oracle/active-physical-device = "1a:2"
  * /local/domain/0/backend/vbd/<domid>/51712/oracle/physical-device-status = "0"