diff options
| -rw-r--r-- | fs/block_dev.c | 127 |
1 files changed, 48 insertions, 79 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index fc48912354d1..269bfbbd10fc 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
| @@ -772,79 +772,6 @@ static struct block_device *bd_start_claiming(struct block_device *bdev, | |||
| 772 | } | 772 | } |
| 773 | } | 773 | } |
| 774 | 774 | ||
| 775 | /* releases bdev_lock */ | ||
| 776 | static void __bd_abort_claiming(struct block_device *whole, void *holder) | ||
| 777 | { | ||
| 778 | BUG_ON(whole->bd_claiming != holder); | ||
| 779 | whole->bd_claiming = NULL; | ||
| 780 | wake_up_bit(&whole->bd_claiming, 0); | ||
| 781 | |||
| 782 | spin_unlock(&bdev_lock); | ||
| 783 | bdput(whole); | ||
| 784 | } | ||
| 785 | |||
| 786 | /** | ||
| 787 | * bd_abort_claiming - abort claiming a block device | ||
| 788 | * @whole: whole block device returned by bd_start_claiming() | ||
| 789 | * @holder: holder trying to claim @bdev | ||
| 790 | * | ||
| 791 | * Abort a claiming block started by bd_start_claiming(). Note that | ||
| 792 | * @whole is not the block device to be claimed but the whole device | ||
| 793 | * returned by bd_start_claiming(). | ||
| 794 | * | ||
| 795 | * CONTEXT: | ||
| 796 | * Grabs and releases bdev_lock. | ||
| 797 | */ | ||
| 798 | static void bd_abort_claiming(struct block_device *whole, void *holder) | ||
| 799 | { | ||
| 800 | spin_lock(&bdev_lock); | ||
| 801 | __bd_abort_claiming(whole, holder); /* releases bdev_lock */ | ||
| 802 | } | ||
| 803 | |||
| 804 | /* increment holders when we have a legitimate claim. requires bdev_lock */ | ||
| 805 | static void __bd_claim(struct block_device *bdev, struct block_device *whole, | ||
| 806 | void *holder) | ||
| 807 | { | ||
| 808 | /* note that for a whole device bd_holders | ||
| 809 | * will be incremented twice, and bd_holder will | ||
| 810 | * be set to bd_may_claim before being set to holder | ||
| 811 | */ | ||
| 812 | whole->bd_holders++; | ||
| 813 | whole->bd_holder = bd_may_claim; | ||
| 814 | bdev->bd_holders++; | ||
| 815 | bdev->bd_holder = holder; | ||
| 816 | } | ||
| 817 | |||
| 818 | /** | ||
| 819 | * bd_finish_claiming - finish claiming a block device | ||
| 820 | * @bdev: block device of interest (passed to bd_start_claiming()) | ||
| 821 | * @whole: whole block device returned by bd_start_claiming() | ||
| 822 | * @holder: holder trying to claim @bdev | ||
| 823 | * | ||
| 824 | * Finish a claiming block started by bd_start_claiming(). | ||
| 825 | * | ||
| 826 | * CONTEXT: | ||
| 827 | * Grabs and releases bdev_lock. | ||
| 828 | */ | ||
| 829 | static void bd_finish_claiming(struct block_device *bdev, | ||
| 830 | struct block_device *whole, void *holder) | ||
| 831 | { | ||
| 832 | spin_lock(&bdev_lock); | ||
| 833 | BUG_ON(!bd_may_claim(bdev, whole, holder)); | ||
| 834 | __bd_claim(bdev, whole, holder); | ||
| 835 | __bd_abort_claiming(whole, holder); /* not actually an abort */ | ||
| 836 | } | ||
| 837 | |||
| 838 | static void bd_release(struct block_device *bdev) | ||
| 839 | { | ||
| 840 | spin_lock(&bdev_lock); | ||
| 841 | if (!--bdev->bd_contains->bd_holders) | ||
| 842 | bdev->bd_contains->bd_holder = NULL; | ||
| 843 | if (!--bdev->bd_holders) | ||
| 844 | bdev->bd_holder = NULL; | ||
| 845 | spin_unlock(&bdev_lock); | ||
| 846 | } | ||
| 847 | |||
| 848 | #ifdef CONFIG_SYSFS | 775 | #ifdef CONFIG_SYSFS |
| 849 | static int add_symlink(struct kobject *from, struct kobject *to) | 776 | static int add_symlink(struct kobject *from, struct kobject *to) |
| 850 | { | 777 | { |
| @@ -1223,10 +1150,30 @@ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder) | |||
| 1223 | res = __blkdev_get(bdev, mode, 0); | 1150 | res = __blkdev_get(bdev, mode, 0); |
| 1224 | 1151 | ||
| 1225 | if (whole) { | 1152 | if (whole) { |
| 1226 | if (res == 0) | 1153 | /* finish claiming */ |
| 1227 | bd_finish_claiming(bdev, whole, holder); | 1154 | spin_lock(&bdev_lock); |
| 1228 | else | 1155 | |
| 1229 | bd_abort_claiming(whole, holder); | 1156 | if (res == 0) { |
| 1157 | BUG_ON(!bd_may_claim(bdev, whole, holder)); | ||
| 1158 | /* | ||
| 1159 | * Note that for a whole device bd_holders | ||
| 1160 | * will be incremented twice, and bd_holder | ||
| 1161 | * will be set to bd_may_claim before being | ||
| 1162 | * set to holder | ||
| 1163 | */ | ||
| 1164 | whole->bd_holders++; | ||
| 1165 | whole->bd_holder = bd_may_claim; | ||
| 1166 | bdev->bd_holders++; | ||
| 1167 | bdev->bd_holder = holder; | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | /* tell others that we're done */ | ||
| 1171 | BUG_ON(whole->bd_claiming != holder); | ||
| 1172 | whole->bd_claiming = NULL; | ||
| 1173 | wake_up_bit(&whole->bd_claiming, 0); | ||
| 1174 | |||
| 1175 | spin_unlock(&bdev_lock); | ||
| 1176 | bdput(whole); | ||
| 1230 | } | 1177 | } |
| 1231 | 1178 | ||
| 1232 | return res; | 1179 | return res; |
| @@ -1272,6 +1219,7 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) | |||
| 1272 | bdev->bd_part_count--; | 1219 | bdev->bd_part_count--; |
| 1273 | 1220 | ||
| 1274 | if (!--bdev->bd_openers) { | 1221 | if (!--bdev->bd_openers) { |
| 1222 | WARN_ON_ONCE(bdev->bd_holders); | ||
| 1275 | sync_blockdev(bdev); | 1223 | sync_blockdev(bdev); |
| 1276 | kill_bdev(bdev); | 1224 | kill_bdev(bdev); |
| 1277 | } | 1225 | } |
| @@ -1303,10 +1251,31 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) | |||
| 1303 | int blkdev_put(struct block_device *bdev, fmode_t mode) | 1251 | int blkdev_put(struct block_device *bdev, fmode_t mode) |
| 1304 | { | 1252 | { |
| 1305 | if (mode & FMODE_EXCL) { | 1253 | if (mode & FMODE_EXCL) { |
| 1254 | bool bdev_free; | ||
| 1255 | |||
| 1256 | /* | ||
| 1257 | * Release a claim on the device. The holder fields | ||
| 1258 | * are protected with bdev_lock. bd_mutex is to | ||
| 1259 | * synchronize disk_holder unlinking. | ||
| 1260 | */ | ||
| 1306 | mutex_lock(&bdev->bd_mutex); | 1261 | mutex_lock(&bdev->bd_mutex); |
| 1307 | bd_release(bdev); | 1262 | spin_lock(&bdev_lock); |
| 1308 | if (!bdev->bd_holders) | 1263 | |
| 1264 | WARN_ON_ONCE(--bdev->bd_holders < 0); | ||
| 1265 | WARN_ON_ONCE(--bdev->bd_contains->bd_holders < 0); | ||
| 1266 | |||
| 1267 | /* bd_contains might point to self, check in a separate step */ | ||
| 1268 | if ((bdev_free = !bdev->bd_holders)) | ||
| 1269 | bdev->bd_holder = NULL; | ||
| 1270 | if (!bdev->bd_contains->bd_holders) | ||
| 1271 | bdev->bd_contains->bd_holder = NULL; | ||
| 1272 | |||
| 1273 | spin_unlock(&bdev_lock); | ||
| 1274 | |||
| 1275 | /* if this was the last claim, holder link should go too */ | ||
| 1276 | if (bdev_free) | ||
| 1309 | bd_unlink_disk_holder(bdev); | 1277 | bd_unlink_disk_holder(bdev); |
| 1278 | |||
| 1310 | mutex_unlock(&bdev->bd_mutex); | 1279 | mutex_unlock(&bdev->bd_mutex); |
| 1311 | } | 1280 | } |
| 1312 | return __blkdev_put(bdev, mode, 0); | 1281 | return __blkdev_put(bdev, mode, 0); |
