diff --git a/drivers/xen/blkback/blkback.c b/drivers/xen/blkback/blkback.c index a2ac7189cc0acc19aa523d63830e371393f09554..6d897664802d92257caa3c1443cbd9adc71b7a81 100644 --- a/drivers/xen/blkback/blkback.c +++ b/drivers/xen/blkback/blkback.c @@ -207,6 +207,7 @@ static void print_stats(blkif_t *blkif) int blkif_schedule(void *arg) { blkif_t *blkif = arg; + struct vbd *vbd = &blkif->vbd; blkif_get(blkif); @@ -216,6 +217,8 @@ int blkif_schedule(void *arg) while (!kthread_should_stop()) { if (try_to_freeze()) continue; + if (unlikely(vbd->size != vbd_size(vbd))) + vbd_resize(blkif); wait_event_interruptible( blkif->wq, diff --git a/drivers/xen/blkback/common.h b/drivers/xen/blkback/common.h index aaf36485bc019a8234fde172767117a2f42d5842..cebcc2b7e9f63a46f21882b7665106b0c36f488e 100644 --- a/drivers/xen/blkback/common.h +++ b/drivers/xen/blkback/common.h @@ -52,6 +52,7 @@ struct vbd { unsigned char type; /* VDISK_xxx */ u32 pdevice; /* phys device that this vbd maps to */ struct block_device *bdev; + sector_t size; /* Cached size parameter */ }; struct backend_info; @@ -98,6 +99,7 @@ blkif_t *blkif_alloc(domid_t domid); void blkif_disconnect(blkif_t *blkif); void blkif_free(blkif_t *blkif); int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn); +void vbd_resize(blkif_t *blkif); #define blkif_get(_b) (atomic_inc(&(_b)->refcnt)) #define blkif_put(_b) \ diff --git a/drivers/xen/blkback/vbd.c b/drivers/xen/blkback/vbd.c index 410c2eac5ad7f819c2ab7c8762523914f1693eb5..0635c54079f84a9fbce43647f5c64617fb9a79e0 100644 --- a/drivers/xen/blkback/vbd.c +++ b/drivers/xen/blkback/vbd.c @@ -73,6 +73,7 @@ int vbd_create(blkif_t *blkif, blkif_vdev_t handle, unsigned major, } vbd->bdev = bdev; + vbd->size = vbd_size(vbd); if (vbd->bdev->bd_disk == NULL) { DPRINTK("vbd_creat: device %08x doesn't exist.\n", @@ -116,3 +117,45 @@ int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation) out: return rc; } + +void vbd_resize(blkif_t *blkif) +{ + struct vbd *vbd = &blkif->vbd; + struct xenbus_transaction xbt; + int err; + struct xenbus_device *dev = blkif->be->dev; + unsigned long long new_size = vbd_size(vbd); + + printk(KERN_INFO "VBD Resize: new size %Lu\n", new_size); + vbd->size = new_size; +again: + err = xenbus_transaction_start(&xbt); + if (err) { + printk(KERN_WARNING "Error starting transaction"); + return; + } + err = xenbus_printf(xbt, dev->nodename, "sectors", "%Lu", + vbd_size(vbd)); + if (err) { + printk(KERN_WARNING "Error writing new size"); + goto abort; + } + /* + * Write the current state; we will use this to synchronize + * the front-end. If the current state is "connected" the + * front-end will get the new size information online. + */ + err = xenbus_printf(xbt, dev->nodename, "state", "%d", dev->state); + if (err) { + printk(KERN_WARNING "Error writing the state"); + goto abort; + } + + err = xenbus_transaction_end(xbt, 0); + if (err == -EAGAIN) + goto again; + if (err) + printk(KERN_WARNING "Error ending transaction"); +abort: + xenbus_transaction_end(xbt, 1); +}