diff options
author | Alex Elder <elder@inktank.com> | 2013-05-31 16:17:01 -0400 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2013-07-03 18:32:41 -0400 |
commit | 751cc0e3cfabdda87c4c21519253c6751e97a8d4 (patch) | |
tree | 8d4761447d8b8c2e8da9b7d6dd83e9bb8a63bc6e | |
parent | 4974341eb99861720d54db9337bf1fe78eb8b9d0 (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.c | 53 |
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 | ||
5093 | static 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 | |||
5110 | static void rbd_dev_device_release(struct device *dev) | 5093 | static 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) |