diff -r e069e08b56f0 drivers/xen/blkback/xenbus.c --- a/drivers/xen/blkback/xenbus.c Tue Apr 14 21:22:05 2009 -0700 +++ b/drivers/xen/blkback/xenbus.c Tue Apr 14 21:23:38 2009 -0700 @@ -37,6 +37,7 @@ unsigned major; unsigned minor; char *mode; + int cdrom; int group_added; char *nodename; atomic_t refcnt; @@ -50,6 +51,8 @@ static int connect_ring(struct backend_info *); static void backend_changed(struct xenbus_watch *, const char **, unsigned int); +static int blkback_open_bdev(struct backend_info *be); +static void blkback_close_bdev(struct backend_info *be); static int blkback_name(blkif_t *blkif, char *buf) { @@ -349,9 +352,7 @@ down(&blkback_dev_sem); - vbd_free(&blkif->vbd); - blkif->be->major = 0; - blkif->be->minor = 0; + blkback_close_bdev(blkif->be); blkif->remove_requested = 0; if (blkif->be->dev) xenvbd_sysfs_delif(blkif->be->dev); @@ -425,6 +426,10 @@ struct backend_info *be = blkif->be; down(&blkback_dev_sem); + + if (blkif->vbd.bdev) + vbd_free(&blkif->vbd); + if (be->dev) { err = xenbus_write(XBT_NIL, be->dev->nodename, "pause-done", ""); @@ -471,7 +476,8 @@ } else if (xenbus_exists(XBT_NIL, dev->nodename, "pause-done")) { WPRINTK("resuming %s\n", dev->nodename); - blkback_resume(be->blkif); + if (!blkback_open_bdev(be)) + blkback_resume(be->blkif); } } @@ -555,12 +561,25 @@ return err; } +static void blkback_close_bdev(struct backend_info *be) +{ + if (be->major || be->minor) { + vbd_free(&be->blkif->vbd); + be->major = 0; + be->minor = 0; + } + + if (be->mode) { + kfree(be->mode); + be->mode = NULL; + } +} + static int blkback_open_bdev(struct backend_info *be) { int err; char *p; long handle; - int cdrom = 0; unsigned major; unsigned minor; char *device_type; @@ -580,15 +599,16 @@ if ((be->major || be->minor) && ((be->major != major) || (be->minor != minor))) { - printk(KERN_WARNING - "blkback: changing physical device (from %x:%x to " - "%x:%x) not supported.\n", be->major, be->minor, - major, minor); - xenbus_dev_fatal(dev, err, "invalid physical-device change"); - return -EINVAL; + printk(KERN_INFO + "blkback: changing physical device (from %x:%x to %x:%x)\n", + be->major, be->minor, major, minor); } if (!be->mode) { + /* Reopen on resume ignores the vbd info, as we're not + reissuing the frontend information + either. Reconnect will. */ + be->mode = xenbus_read(XBT_NIL, dev->nodename, "mode", NULL); if (IS_ERR(be->mode)) { err = PTR_ERR(be->mode); @@ -596,12 +616,12 @@ xenbus_dev_fatal(dev, err, "reading mode"); return err; } - } - device_type = xenbus_read(XBT_NIL, dev->otherend, "device-type", NULL); - if (!IS_ERR(device_type)) { - cdrom = strcmp(device_type, "cdrom") == 0; - kfree(device_type); + device_type = xenbus_read(XBT_NIL, dev->otherend, "device-type", NULL); + if (!IS_ERR(device_type)) { + be->cdrom = strcmp(device_type, "cdrom") == 0; + kfree(device_type); + } } /* Front end dir is a number, which is used as the handle. */ @@ -609,9 +629,10 @@ handle = simple_strtoul(p, NULL, 0); err = vbd_create(be->blkif, handle, major, minor, - (NULL == strchr(be->mode, 'w')), cdrom); + (NULL == strchr(be->mode, 'w')), be->cdrom); if (err) { xenbus_dev_fatal(dev, err, "creating vbd structure"); + blkback_close_bdev(be); return err; } @@ -652,24 +673,12 @@ } if ((be->major || be->minor) && - ((be->major != major) || (be->minor != minor))) { + ((be->major != major) || (be->minor != minor)) && + !xenbus_exists(XBT_NIL, dev->nodename, "pause-done")) { printk(KERN_WARNING - "blkback: changing physical device (from %x:%x to " - "%x:%x) not supported.\n", be->major, be->minor, + "blkback: attempt to change physical device (from %x:%x to " + "%x:%x) on running blkif.\n", be->major, be->minor, major, minor); - return; - } - - if (be->mode) { - kfree(be->mode); - be->mode = NULL; - } - - be->mode = xenbus_read(XBT_NIL, dev->nodename, "mode", NULL); - if (IS_ERR(be->mode)) { - err = PTR_ERR(be->mode); - be->mode = NULL; - xenbus_dev_fatal(dev, err, "reading mode"); return; } @@ -680,8 +689,7 @@ err = xenvbd_sysfs_addif(dev); if (err) { - vbd_free(&be->blkif->vbd); - be->major = be->minor = 0; + blkback_close_bdev(be); xenbus_dev_fatal(dev, err, "creating sysfs entries"); return; }