From: Keir Fraser Date: Thu, 21 Jan 2010 09:08:35 +0000 (+0000) Subject: Fix blk{back,tap} sysfs race X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=ff39e60cebf793f6b463806d709c1d26183cf7e4;p=legacy%2Flinux-2.6.18-xen.git Fix blk{back,tap} sysfs race Read blk{back,tap} statistics info after remove vbd device(s) kernel will crash. Signed-off-by: Joe Jin Acked-by: Jan Beulich --- diff --git a/drivers/xen/blkback/xenbus.c b/drivers/xen/blkback/xenbus.c index 7e689c75..6a5669e9 100644 --- a/drivers/xen/blkback/xenbus.c +++ b/drivers/xen/blkback/xenbus.c @@ -27,6 +27,8 @@ pr_debug("blkback/xenbus (%s:%d) " fmt ".\n", \ __FUNCTION__, __LINE__, ##args) +static DEFINE_RWLOCK(sysfs_read_lock); + struct backend_info { struct xenbus_device *dev; @@ -104,10 +106,19 @@ static void update_blkif_status(blkif_t *blkif) struct device_attribute *attr, \ char *buf) \ { \ - struct xenbus_device *dev = to_xenbus_device(_dev); \ - struct backend_info *be = dev->dev.driver_data; \ + ssize_t ret = -ENODEV; \ + struct xenbus_device *dev; \ + struct backend_info *be; \ \ - return sprintf(buf, format, ##args); \ + if (!get_device(_dev)) \ + return ret; \ + dev = to_xenbus_device(_dev); \ + read_lock(&sysfs_read_lock); \ + if ((be = dev->dev.driver_data) != NULL) \ + ret = sprintf(buf, format, ##args); \ + read_unlock(&sysfs_read_lock); \ + put_device(_dev); \ + return ret; \ } \ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) @@ -173,6 +184,7 @@ static int blkback_remove(struct xenbus_device *dev) DPRINTK(""); + write_lock(&sysfs_read_lock); if (be->major || be->minor) xenvbd_sysfs_delif(dev); @@ -191,6 +203,7 @@ static int blkback_remove(struct xenbus_device *dev) kfree(be); dev->dev.driver_data = NULL; + write_unlock(&sysfs_read_lock); return 0; } diff --git a/drivers/xen/blktap/xenbus.c b/drivers/xen/blktap/xenbus.c index 64534726..86965d89 100644 --- a/drivers/xen/blktap/xenbus.c +++ b/drivers/xen/blktap/xenbus.c @@ -50,6 +50,7 @@ struct backend_info int group_added; }; +static DEFINE_RWLOCK(sysfs_read_lock); static void connect(struct backend_info *); static int connect_ring(struct backend_info *); @@ -122,10 +123,19 @@ static int blktap_name(blkif_t *blkif, char *buf) struct device_attribute *attr, \ char *buf) \ { \ - struct xenbus_device *dev = to_xenbus_device(_dev); \ - struct backend_info *be = dev->dev.driver_data; \ + ssize_t ret = -ENODEV; \ + struct xenbus_device *dev; \ + struct backend_info *be; \ \ - return sprintf(buf, format, ##args); \ + if (!get_device(_dev)) \ + return ret; \ + dev = to_xenbus_device(_dev); \ + read_lock(&sysfs_read_lock); \ + if ((be = dev->dev.driver_data) != NULL) \ + ret = sprintf(buf, format, ##args); \ + read_unlock(&sysfs_read_lock); \ + put_device(_dev); \ + return ret; \ } \ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) @@ -170,6 +180,7 @@ static int blktap_remove(struct xenbus_device *dev) { struct backend_info *be = dev->dev.driver_data; + write_lock(&sysfs_read_lock); if (be->group_added) xentap_sysfs_delif(be->dev); if (be->backend_watch.node) { @@ -187,6 +198,7 @@ static int blktap_remove(struct xenbus_device *dev) } kfree(be); dev->dev.driver_data = NULL; + write_unlock(&sysfs_read_lock); return 0; }