aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Elder <elder@inktank.com>2013-05-31 16:17:01 -0400
committerSage Weil <sage@inktank.com>2013-07-03 18:32:41 -0400
commit751cc0e3cfabdda87c4c21519253c6751e97a8d4 (patch)
tree8d4761447d8b8c2e8da9b7d6dd83e9bb8a63bc6e
parent4974341eb99861720d54db9337bf1fe78eb8b9d0 (diff)
rbd: set removing flag while holding list lock
When unmapping a device, its id is supplied, and that is used to look up which rbd device should be unmapped. Looking up the device involves searching the rbd device list while holding a spinlock that protects access to that list. Currently all of this is done under protection of the control lock, but that protection is going away soon. To ensure the rbd_dev is still valid (still on the list) while setting its REMOVING flag, do so while still holding the list lock. To do so, get rid of __rbd_get_dev(), and open code what it did in the one place it was used. Signed-off-by: Alex Elder <elder@inktank.com> Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
-rw-r--r--drivers/block/rbd.c53
1 files changed, 22 insertions, 31 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index fd2795d1136a..9eead4879c90 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -5090,23 +5090,6 @@ err_out_module:
5090 return (ssize_t)rc; 5090 return (ssize_t)rc;
5091} 5091}
5092 5092
5093static struct rbd_device *__rbd_get_dev(unsigned long dev_id)
5094{
5095 struct list_head *tmp;
5096 struct rbd_device *rbd_dev;
5097
5098 spin_lock(&rbd_dev_list_lock);
5099 list_for_each(tmp, &rbd_dev_list) {
5100 rbd_dev = list_entry(tmp, struct rbd_device, node);
5101 if (rbd_dev->dev_id == dev_id) {
5102 spin_unlock(&rbd_dev_list_lock);
5103 return rbd_dev;
5104 }
5105 }
5106 spin_unlock(&rbd_dev_list_lock);
5107 return NULL;
5108}
5109
5110static void rbd_dev_device_release(struct device *dev) 5093static void rbd_dev_device_release(struct device *dev)
5111{ 5094{
5112 struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); 5095 struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
@@ -5151,7 +5134,8 @@ static ssize_t rbd_remove(struct bus_type *bus,
5151 size_t count) 5134 size_t count)
5152{ 5135{
5153 struct rbd_device *rbd_dev = NULL; 5136 struct rbd_device *rbd_dev = NULL;
5154 int target_id; 5137 struct list_head *tmp;
5138 int dev_id;
5155 unsigned long ul; 5139 unsigned long ul;
5156 int ret; 5140 int ret;
5157 5141
@@ -5160,26 +5144,33 @@ static ssize_t rbd_remove(struct bus_type *bus,
5160 return ret; 5144 return ret;
5161 5145
5162 /* convert to int; abort if we lost anything in the conversion */ 5146 /* convert to int; abort if we lost anything in the conversion */
5163 target_id = (int) ul; 5147 dev_id = (int)ul;
5164 if (target_id != ul) 5148 if (dev_id != ul)
5165 return -EINVAL; 5149 return -EINVAL;
5166 5150
5167 mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); 5151 mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
5168 5152
5169 rbd_dev = __rbd_get_dev(target_id); 5153 ret = -ENOENT;
5170 if (!rbd_dev) { 5154 spin_lock(&rbd_dev_list_lock);
5171 ret = -ENOENT; 5155 list_for_each(tmp, &rbd_dev_list) {
5172 goto done; 5156 rbd_dev = list_entry(tmp, struct rbd_device, node);
5157 if (rbd_dev->dev_id == dev_id) {
5158 ret = 0;
5159 break;
5160 }
5173 } 5161 }
5174 5162 if (!ret) {
5175 spin_lock_irq(&rbd_dev->lock); 5163 spin_lock_irq(&rbd_dev->lock);
5176 if (rbd_dev->open_count) 5164 if (rbd_dev->open_count)
5177 ret = -EBUSY; 5165 ret = -EBUSY;
5178 else 5166 else
5179 set_bit(RBD_DEV_FLAG_REMOVING, &rbd_dev->flags); 5167 set_bit(RBD_DEV_FLAG_REMOVING, &rbd_dev->flags);
5180 spin_unlock_irq(&rbd_dev->lock); 5168 spin_unlock_irq(&rbd_dev->lock);
5169 }
5170 spin_unlock(&rbd_dev_list_lock);
5181 if (ret < 0) 5171 if (ret < 0)
5182 goto done; 5172 goto done;
5173
5183 rbd_bus_del_dev(rbd_dev); 5174 rbd_bus_del_dev(rbd_dev);
5184 ret = rbd_dev_header_watch_sync(rbd_dev, false); 5175 ret = rbd_dev_header_watch_sync(rbd_dev, false);
5185 if (ret) 5176 if (ret)