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 /drivers/block/rbd.c | |
| 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>
Diffstat (limited to 'drivers/block/rbd.c')
| -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) |
