aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2010-11-13 05:55:17 -0500
committerTejun Heo <tj@kernel.org>2010-11-13 05:55:17 -0500
commite525fd89d380c4a94c0d63913a1dd1a593ed25e7 (patch)
treed226ef40d3f99e42fcf272ad432585cbd641ebec /fs
parente09b457bdb7e8d23fc54dcef0930ac697d8de895 (diff)
block: make blkdev_get/put() handle exclusive access
Over time, block layer has accumulated a set of APIs dealing with bdev open, close, claim and release. * blkdev_get/put() are the primary open and close functions. * bd_claim/release() deal with exclusive open. * open/close_bdev_exclusive() are combination of open and claim and the other way around, respectively. * bd_link/unlink_disk_holder() to create and remove holder/slave symlinks. * open_by_devnum() wraps bdget() + blkdev_get(). The interface is a bit confusing and the decoupling of open and claim makes it impossible to properly guarantee exclusive access as in-kernel open + claim sequence can disturb the existing exclusive open even before the block layer knows the current open if for another exclusive access. Reorganize the interface such that, * blkdev_get() is extended to include exclusive access management. @holder argument is added and, if is @FMODE_EXCL specified, it will gain exclusive access atomically w.r.t. other exclusive accesses. * blkdev_put() is similarly extended. It now takes @mode argument and if @FMODE_EXCL is set, it releases an exclusive access. Also, when the last exclusive claim is released, the holder/slave symlinks are removed automatically. * bd_claim/release() and close_bdev_exclusive() are no longer necessary and either made static or removed. * bd_link_disk_holder() remains the same but bd_unlink_disk_holder() is no longer necessary and removed. * open_bdev_exclusive() becomes a simple wrapper around lookup_bdev() and blkdev_get(). It also has an unexpected extra bdev_read_only() test which probably should be moved into blkdev_get(). * open_by_devnum() is modified to take @holder argument and pass it to blkdev_get(). Most of bdev open/close operations are unified into blkdev_get/put() and most exclusive accesses are tested atomically at the open time (as it should). This cleans up code and removes some, both valid and invalid, but unnecessary all the same, corner cases. open_bdev_exclusive() and open_by_devnum() can use further cleanup - rename to blkdev_get_by_path() and blkdev_get_by_devt() and drop special features. Well, let's leave them for another day. Most conversions are straight-forward. drbd conversion is a bit more involved as there was some reordering, but the logic should stay the same. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Neil Brown <neilb@suse.de> Acked-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> Acked-by: Mike Snitzer <snitzer@redhat.com> Acked-by: Philipp Reisner <philipp.reisner@linbit.com> Cc: Peter Osterlund <petero2@telia.com> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Jan Kara <jack@suse.cz> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andreas Dilger <adilger.kernel@dilger.ca> Cc: "Theodore Ts'o" <tytso@mit.edu> Cc: Mark Fasheh <mfasheh@suse.com> Cc: Joel Becker <joel.becker@oracle.com> Cc: Alex Elder <aelder@sgi.com> Cc: Christoph Hellwig <hch@infradead.org> Cc: dm-devel@redhat.com Cc: drbd-dev@lists.linbit.com Cc: Leo Chen <leochen@broadcom.com> Cc: Scott Branden <sbranden@broadcom.com> Cc: Chris Mason <chris.mason@oracle.com> Cc: Steven Whitehouse <swhiteho@redhat.com> Cc: Dave Kleikamp <shaggy@linux.vnet.ibm.com> Cc: Joern Engel <joern@logfs.org> Cc: reiserfs-devel@vger.kernel.org Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/block_dev.c149
-rw-r--r--fs/btrfs/volumes.c14
-rw-r--r--fs/ext3/super.c12
-rw-r--r--fs/ext4/super.c12
-rw-r--r--fs/gfs2/ops_fstype.c4
-rw-r--r--fs/jfs/jfs_logmgr.c17
-rw-r--r--fs/logfs/dev_bdev.c4
-rw-r--r--fs/nilfs2/super.c4
-rw-r--r--fs/ocfs2/cluster/heartbeat.c2
-rw-r--r--fs/partitions/check.c2
-rw-r--r--fs/reiserfs/journal.c17
-rw-r--r--fs/super.c14
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c2
13 files changed, 87 insertions, 166 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 9329068684d2..fc48912354d1 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -660,7 +660,7 @@ static bool bd_may_claim(struct block_device *bdev, struct block_device *whole,
660 else if (bdev->bd_contains == bdev) 660 else if (bdev->bd_contains == bdev)
661 return true; /* is a whole device which isn't held */ 661 return true; /* is a whole device which isn't held */
662 662
663 else if (whole->bd_holder == bd_claim) 663 else if (whole->bd_holder == bd_may_claim)
664 return true; /* is a partition of a device that is being partitioned */ 664 return true; /* is a partition of a device that is being partitioned */
665 else if (whole->bd_holder != NULL) 665 else if (whole->bd_holder != NULL)
666 return false; /* is a partition of a held device */ 666 return false; /* is a partition of a held device */
@@ -807,10 +807,10 @@ static void __bd_claim(struct block_device *bdev, struct block_device *whole,
807{ 807{
808 /* note that for a whole device bd_holders 808 /* note that for a whole device bd_holders
809 * will be incremented twice, and bd_holder will 809 * will be incremented twice, and bd_holder will
810 * be set to bd_claim before being set to holder 810 * be set to bd_may_claim before being set to holder
811 */ 811 */
812 whole->bd_holders++; 812 whole->bd_holders++;
813 whole->bd_holder = bd_claim; 813 whole->bd_holder = bd_may_claim;
814 bdev->bd_holders++; 814 bdev->bd_holders++;
815 bdev->bd_holder = holder; 815 bdev->bd_holder = holder;
816} 816}
@@ -835,37 +835,7 @@ static void bd_finish_claiming(struct block_device *bdev,
835 __bd_abort_claiming(whole, holder); /* not actually an abort */ 835 __bd_abort_claiming(whole, holder); /* not actually an abort */
836} 836}
837 837
838/** 838static void bd_release(struct block_device *bdev)
839 * bd_claim - claim a block device
840 * @bdev: block device to claim
841 * @holder: holder trying to claim @bdev
842 *
843 * Try to claim @bdev which must have been opened successfully.
844 *
845 * CONTEXT:
846 * Might sleep.
847 *
848 * RETURNS:
849 * 0 if successful, -EBUSY if @bdev is already claimed.
850 */
851int bd_claim(struct block_device *bdev, void *holder)
852{
853 struct block_device *whole = bdev->bd_contains;
854 int res;
855
856 might_sleep();
857
858 spin_lock(&bdev_lock);
859 res = bd_prepare_to_claim(bdev, whole, holder);
860 if (res == 0)
861 __bd_claim(bdev, whole, holder);
862 spin_unlock(&bdev_lock);
863
864 return res;
865}
866EXPORT_SYMBOL(bd_claim);
867
868void bd_release(struct block_device *bdev)
869{ 839{
870 spin_lock(&bdev_lock); 840 spin_lock(&bdev_lock);
871 if (!--bdev->bd_contains->bd_holders) 841 if (!--bdev->bd_contains->bd_holders)
@@ -875,8 +845,6 @@ void bd_release(struct block_device *bdev)
875 spin_unlock(&bdev_lock); 845 spin_unlock(&bdev_lock);
876} 846}
877 847
878EXPORT_SYMBOL(bd_release);
879
880#ifdef CONFIG_SYSFS 848#ifdef CONFIG_SYSFS
881static int add_symlink(struct kobject *from, struct kobject *to) 849static int add_symlink(struct kobject *from, struct kobject *to)
882{ 850{
@@ -943,7 +911,7 @@ out_unlock:
943} 911}
944EXPORT_SYMBOL_GPL(bd_link_disk_holder); 912EXPORT_SYMBOL_GPL(bd_link_disk_holder);
945 913
946void bd_unlink_disk_holder(struct block_device *bdev) 914static void bd_unlink_disk_holder(struct block_device *bdev)
947{ 915{
948 struct gendisk *disk = bdev->bd_holder_disk; 916 struct gendisk *disk = bdev->bd_holder_disk;
949 917
@@ -954,7 +922,9 @@ void bd_unlink_disk_holder(struct block_device *bdev)
954 del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); 922 del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
955 del_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); 923 del_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
956} 924}
957EXPORT_SYMBOL_GPL(bd_unlink_disk_holder); 925#else
926static inline void bd_unlink_disk_holder(struct block_device *bdev)
927{ }
958#endif 928#endif
959 929
960/* 930/*
@@ -964,12 +934,12 @@ EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);
964 * to be used for internal purposes. If you ever need it - reconsider 934 * to be used for internal purposes. If you ever need it - reconsider
965 * your API. 935 * your API.
966 */ 936 */
967struct block_device *open_by_devnum(dev_t dev, fmode_t mode) 937struct block_device *open_by_devnum(dev_t dev, fmode_t mode, void *holder)
968{ 938{
969 struct block_device *bdev = bdget(dev); 939 struct block_device *bdev = bdget(dev);
970 int err = -ENOMEM; 940 int err = -ENOMEM;
971 if (bdev) 941 if (bdev)
972 err = blkdev_get(bdev, mode); 942 err = blkdev_get(bdev, mode, holder);
973 return err ? ERR_PTR(err) : bdev; 943 return err ? ERR_PTR(err) : bdev;
974} 944}
975 945
@@ -1235,17 +1205,37 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
1235 return ret; 1205 return ret;
1236} 1206}
1237 1207
1238int blkdev_get(struct block_device *bdev, fmode_t mode) 1208int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder)
1239{ 1209{
1240 return __blkdev_get(bdev, mode, 0); 1210 struct block_device *whole = NULL;
1211 int res;
1212
1213 WARN_ON_ONCE((mode & FMODE_EXCL) && !holder);
1214
1215 if ((mode & FMODE_EXCL) && holder) {
1216 whole = bd_start_claiming(bdev, holder);
1217 if (IS_ERR(whole)) {
1218 bdput(bdev);
1219 return PTR_ERR(whole);
1220 }
1221 }
1222
1223 res = __blkdev_get(bdev, mode, 0);
1224
1225 if (whole) {
1226 if (res == 0)
1227 bd_finish_claiming(bdev, whole, holder);
1228 else
1229 bd_abort_claiming(whole, holder);
1230 }
1231
1232 return res;
1241} 1233}
1242EXPORT_SYMBOL(blkdev_get); 1234EXPORT_SYMBOL(blkdev_get);
1243 1235
1244static int blkdev_open(struct inode * inode, struct file * filp) 1236static int blkdev_open(struct inode * inode, struct file * filp)
1245{ 1237{
1246 struct block_device *whole = NULL;
1247 struct block_device *bdev; 1238 struct block_device *bdev;
1248 int res;
1249 1239
1250 /* 1240 /*
1251 * Preserve backwards compatibility and allow large file access 1241 * Preserve backwards compatibility and allow large file access
@@ -1266,26 +1256,9 @@ static int blkdev_open(struct inode * inode, struct file * filp)
1266 if (bdev == NULL) 1256 if (bdev == NULL)
1267 return -ENOMEM; 1257 return -ENOMEM;
1268 1258
1269 if (filp->f_mode & FMODE_EXCL) {
1270 whole = bd_start_claiming(bdev, filp);
1271 if (IS_ERR(whole)) {
1272 bdput(bdev);
1273 return PTR_ERR(whole);
1274 }
1275 }
1276
1277 filp->f_mapping = bdev->bd_inode->i_mapping; 1259 filp->f_mapping = bdev->bd_inode->i_mapping;
1278 1260
1279 res = blkdev_get(bdev, filp->f_mode); 1261 return blkdev_get(bdev, filp->f_mode, filp);
1280
1281 if (whole) {
1282 if (res == 0)
1283 bd_finish_claiming(bdev, whole, filp);
1284 else
1285 bd_abort_claiming(whole, filp);
1286 }
1287
1288 return res;
1289} 1262}
1290 1263
1291static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) 1264static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part)
@@ -1329,6 +1302,13 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part)
1329 1302
1330int blkdev_put(struct block_device *bdev, fmode_t mode) 1303int blkdev_put(struct block_device *bdev, fmode_t mode)
1331{ 1304{
1305 if (mode & FMODE_EXCL) {
1306 mutex_lock(&bdev->bd_mutex);
1307 bd_release(bdev);
1308 if (!bdev->bd_holders)
1309 bd_unlink_disk_holder(bdev);
1310 mutex_unlock(&bdev->bd_mutex);
1311 }
1332 return __blkdev_put(bdev, mode, 0); 1312 return __blkdev_put(bdev, mode, 0);
1333} 1313}
1334EXPORT_SYMBOL(blkdev_put); 1314EXPORT_SYMBOL(blkdev_put);
@@ -1336,8 +1316,7 @@ EXPORT_SYMBOL(blkdev_put);
1336static int blkdev_close(struct inode * inode, struct file * filp) 1316static int blkdev_close(struct inode * inode, struct file * filp)
1337{ 1317{
1338 struct block_device *bdev = I_BDEV(filp->f_mapping->host); 1318 struct block_device *bdev = I_BDEV(filp->f_mapping->host);
1339 if (bdev->bd_holder == filp) 1319
1340 bd_release(bdev);
1341 return blkdev_put(bdev, filp->f_mode); 1320 return blkdev_put(bdev, filp->f_mode);
1342} 1321}
1343 1322
@@ -1494,55 +1473,27 @@ EXPORT_SYMBOL(lookup_bdev);
1494 */ 1473 */
1495struct block_device *open_bdev_exclusive(const char *path, fmode_t mode, void *holder) 1474struct block_device *open_bdev_exclusive(const char *path, fmode_t mode, void *holder)
1496{ 1475{
1497 struct block_device *bdev, *whole; 1476 struct block_device *bdev;
1498 int error; 1477 int error;
1499 1478
1500 bdev = lookup_bdev(path); 1479 bdev = lookup_bdev(path);
1501 if (IS_ERR(bdev)) 1480 if (IS_ERR(bdev))
1502 return bdev; 1481 return bdev;
1503 1482
1504 whole = bd_start_claiming(bdev, holder); 1483 error = blkdev_get(bdev, mode | FMODE_EXCL, holder);
1505 if (IS_ERR(whole)) {
1506 bdput(bdev);
1507 return whole;
1508 }
1509
1510 error = blkdev_get(bdev, mode);
1511 if (error) 1484 if (error)
1512 goto out_abort_claiming; 1485 return ERR_PTR(error);
1513 1486
1514 error = -EACCES; 1487 if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) {
1515 if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) 1488 blkdev_put(bdev, mode);
1516 goto out_blkdev_put; 1489 return ERR_PTR(-EACCES);
1490 }
1517 1491
1518 bd_finish_claiming(bdev, whole, holder);
1519 return bdev; 1492 return bdev;
1520
1521out_blkdev_put:
1522 blkdev_put(bdev, mode);
1523out_abort_claiming:
1524 bd_abort_claiming(whole, holder);
1525 return ERR_PTR(error);
1526} 1493}
1527 1494
1528EXPORT_SYMBOL(open_bdev_exclusive); 1495EXPORT_SYMBOL(open_bdev_exclusive);
1529 1496
1530/**
1531 * close_bdev_exclusive - close a blockdevice opened by open_bdev_exclusive()
1532 *
1533 * @bdev: blockdevice to close
1534 * @mode: mode, must match that used to open.
1535 *
1536 * This is the counterpart to open_bdev_exclusive().
1537 */
1538void close_bdev_exclusive(struct block_device *bdev, fmode_t mode)
1539{
1540 bd_release(bdev);
1541 blkdev_put(bdev, mode);
1542}
1543
1544EXPORT_SYMBOL(close_bdev_exclusive);
1545
1546int __invalidate_device(struct block_device *bdev) 1497int __invalidate_device(struct block_device *bdev)
1547{ 1498{
1548 struct super_block *sb = get_super(bdev); 1499 struct super_block *sb = get_super(bdev);
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index d39596224d21..f1b729d3b883 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -489,7 +489,7 @@ again:
489 continue; 489 continue;
490 490
491 if (device->bdev) { 491 if (device->bdev) {
492 close_bdev_exclusive(device->bdev, device->mode); 492 blkdev_put(device->bdev, device->mode | FMODE_EXCL);
493 device->bdev = NULL; 493 device->bdev = NULL;
494 fs_devices->open_devices--; 494 fs_devices->open_devices--;
495 } 495 }
@@ -523,7 +523,7 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
523 523
524 list_for_each_entry(device, &fs_devices->devices, dev_list) { 524 list_for_each_entry(device, &fs_devices->devices, dev_list) {
525 if (device->bdev) { 525 if (device->bdev) {
526 close_bdev_exclusive(device->bdev, device->mode); 526 blkdev_put(device->bdev, device->mode | FMODE_EXCL);
527 fs_devices->open_devices--; 527 fs_devices->open_devices--;
528 } 528 }
529 if (device->writeable) { 529 if (device->writeable) {
@@ -638,7 +638,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
638error_brelse: 638error_brelse:
639 brelse(bh); 639 brelse(bh);
640error_close: 640error_close:
641 close_bdev_exclusive(bdev, flags); 641 blkdev_put(bdev, flags | FMODE_EXCL);
642error: 642error:
643 continue; 643 continue;
644 } 644 }
@@ -716,7 +716,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
716 716
717 brelse(bh); 717 brelse(bh);
718error_close: 718error_close:
719 close_bdev_exclusive(bdev, flags); 719 blkdev_put(bdev, flags | FMODE_EXCL);
720error: 720error:
721 mutex_unlock(&uuid_mutex); 721 mutex_unlock(&uuid_mutex);
722 return ret; 722 return ret;
@@ -1244,7 +1244,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
1244 root->fs_info->fs_devices->latest_bdev = next_device->bdev; 1244 root->fs_info->fs_devices->latest_bdev = next_device->bdev;
1245 1245
1246 if (device->bdev) { 1246 if (device->bdev) {
1247 close_bdev_exclusive(device->bdev, device->mode); 1247 blkdev_put(device->bdev, device->mode | FMODE_EXCL);
1248 device->bdev = NULL; 1248 device->bdev = NULL;
1249 device->fs_devices->open_devices--; 1249 device->fs_devices->open_devices--;
1250 } 1250 }
@@ -1287,7 +1287,7 @@ error_brelse:
1287 brelse(bh); 1287 brelse(bh);
1288error_close: 1288error_close:
1289 if (bdev) 1289 if (bdev)
1290 close_bdev_exclusive(bdev, FMODE_READ); 1290 blkdev_put(bdev, FMODE_READ | FMODE_EXCL);
1291out: 1291out:
1292 mutex_unlock(&root->fs_info->volume_mutex); 1292 mutex_unlock(&root->fs_info->volume_mutex);
1293 mutex_unlock(&uuid_mutex); 1293 mutex_unlock(&uuid_mutex);
@@ -1565,7 +1565,7 @@ out:
1565 mutex_unlock(&root->fs_info->volume_mutex); 1565 mutex_unlock(&root->fs_info->volume_mutex);
1566 return ret; 1566 return ret;
1567error: 1567error:
1568 close_bdev_exclusive(bdev, 0); 1568 blkdev_put(bdev, FMODE_EXCL);
1569 if (seeding_dev) { 1569 if (seeding_dev) {
1570 mutex_unlock(&uuid_mutex); 1570 mutex_unlock(&uuid_mutex);
1571 up_write(&sb->s_umount); 1571 up_write(&sb->s_umount);
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 2fedaf8b5012..23e7513dba9c 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -347,7 +347,7 @@ static struct block_device *ext3_blkdev_get(dev_t dev, struct super_block *sb)
347 struct block_device *bdev; 347 struct block_device *bdev;
348 char b[BDEVNAME_SIZE]; 348 char b[BDEVNAME_SIZE];
349 349
350 bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE); 350 bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb);
351 if (IS_ERR(bdev)) 351 if (IS_ERR(bdev))
352 goto fail; 352 goto fail;
353 return bdev; 353 return bdev;
@@ -364,8 +364,7 @@ fail:
364 */ 364 */
365static int ext3_blkdev_put(struct block_device *bdev) 365static int ext3_blkdev_put(struct block_device *bdev)
366{ 366{
367 bd_release(bdev); 367 return blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
368 return blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
369} 368}
370 369
371static int ext3_blkdev_remove(struct ext3_sb_info *sbi) 370static int ext3_blkdev_remove(struct ext3_sb_info *sbi)
@@ -2136,13 +2135,6 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb,
2136 if (bdev == NULL) 2135 if (bdev == NULL)
2137 return NULL; 2136 return NULL;
2138 2137
2139 if (bd_claim(bdev, sb)) {
2140 ext3_msg(sb, KERN_ERR,
2141 "error: failed to claim external journal device");
2142 blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
2143 return NULL;
2144 }
2145
2146 blocksize = sb->s_blocksize; 2138 blocksize = sb->s_blocksize;
2147 hblock = bdev_logical_block_size(bdev); 2139 hblock = bdev_logical_block_size(bdev);
2148 if (blocksize < hblock) { 2140 if (blocksize < hblock) {
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 61182fe6254e..5dd0b3e76fa8 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -647,7 +647,7 @@ static struct block_device *ext4_blkdev_get(dev_t dev, struct super_block *sb)
647 struct block_device *bdev; 647 struct block_device *bdev;
648 char b[BDEVNAME_SIZE]; 648 char b[BDEVNAME_SIZE];
649 649
650 bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE); 650 bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb);
651 if (IS_ERR(bdev)) 651 if (IS_ERR(bdev))
652 goto fail; 652 goto fail;
653 return bdev; 653 return bdev;
@@ -663,8 +663,7 @@ fail:
663 */ 663 */
664static int ext4_blkdev_put(struct block_device *bdev) 664static int ext4_blkdev_put(struct block_device *bdev)
665{ 665{
666 bd_release(bdev); 666 return blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
667 return blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
668} 667}
669 668
670static int ext4_blkdev_remove(struct ext4_sb_info *sbi) 669static int ext4_blkdev_remove(struct ext4_sb_info *sbi)
@@ -3758,13 +3757,6 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb,
3758 if (bdev == NULL) 3757 if (bdev == NULL)
3759 return NULL; 3758 return NULL;
3760 3759
3761 if (bd_claim(bdev, sb)) {
3762 ext4_msg(sb, KERN_ERR,
3763 "failed to claim external journal device");
3764 blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
3765 return NULL;
3766 }
3767
3768 blocksize = sb->s_blocksize; 3760 blocksize = sb->s_blocksize;
3769 hblock = bdev_logical_block_size(bdev); 3761 hblock = bdev_logical_block_size(bdev);
3770 if (blocksize < hblock) { 3762 if (blocksize < hblock) {
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index 3eb1393f7b81..c1f0763a022b 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1298,7 +1298,7 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags,
1298 goto error_bdev; 1298 goto error_bdev;
1299 1299
1300 if (s->s_root) 1300 if (s->s_root)
1301 close_bdev_exclusive(bdev, mode); 1301 blkdev_put(bdev, mode | FMODE_EXCL);
1302 1302
1303 memset(&args, 0, sizeof(args)); 1303 memset(&args, 0, sizeof(args));
1304 args.ar_quota = GFS2_QUOTA_DEFAULT; 1304 args.ar_quota = GFS2_QUOTA_DEFAULT;
@@ -1342,7 +1342,7 @@ error_super:
1342 deactivate_locked_super(s); 1342 deactivate_locked_super(s);
1343 return ERR_PTR(error); 1343 return ERR_PTR(error);
1344error_bdev: 1344error_bdev:
1345 close_bdev_exclusive(bdev, mode); 1345 blkdev_put(bdev, mode | FMODE_EXCL);
1346 return ERR_PTR(error); 1346 return ERR_PTR(error);
1347} 1347}
1348 1348
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
index e1b8493b9aaa..5a290f22dcc3 100644
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -1120,16 +1120,13 @@ int lmLogOpen(struct super_block *sb)
1120 * file systems to log may have n-to-1 relationship; 1120 * file systems to log may have n-to-1 relationship;
1121 */ 1121 */
1122 1122
1123 bdev = open_by_devnum(sbi->logdev, FMODE_READ|FMODE_WRITE); 1123 bdev = open_by_devnum(sbi->logdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL,
1124 log);
1124 if (IS_ERR(bdev)) { 1125 if (IS_ERR(bdev)) {
1125 rc = -PTR_ERR(bdev); 1126 rc = -PTR_ERR(bdev);
1126 goto free; 1127 goto free;
1127 } 1128 }
1128 1129
1129 if ((rc = bd_claim(bdev, log))) {
1130 goto close;
1131 }
1132
1133 log->bdev = bdev; 1130 log->bdev = bdev;
1134 memcpy(log->uuid, sbi->loguuid, sizeof(log->uuid)); 1131 memcpy(log->uuid, sbi->loguuid, sizeof(log->uuid));
1135 1132
@@ -1137,7 +1134,7 @@ int lmLogOpen(struct super_block *sb)
1137 * initialize log: 1134 * initialize log:
1138 */ 1135 */
1139 if ((rc = lmLogInit(log))) 1136 if ((rc = lmLogInit(log)))
1140 goto unclaim; 1137 goto close;
1141 1138
1142 list_add(&log->journal_list, &jfs_external_logs); 1139 list_add(&log->journal_list, &jfs_external_logs);
1143 1140
@@ -1163,11 +1160,8 @@ journal_found:
1163 list_del(&log->journal_list); 1160 list_del(&log->journal_list);
1164 lbmLogShutdown(log); 1161 lbmLogShutdown(log);
1165 1162
1166 unclaim:
1167 bd_release(bdev);
1168
1169 close: /* close external log device */ 1163 close: /* close external log device */
1170 blkdev_put(bdev, FMODE_READ|FMODE_WRITE); 1164 blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
1171 1165
1172 free: /* free log descriptor */ 1166 free: /* free log descriptor */
1173 mutex_unlock(&jfs_log_mutex); 1167 mutex_unlock(&jfs_log_mutex);
@@ -1512,8 +1506,7 @@ int lmLogClose(struct super_block *sb)
1512 bdev = log->bdev; 1506 bdev = log->bdev;
1513 rc = lmLogShutdown(log); 1507 rc = lmLogShutdown(log);
1514 1508
1515 bd_release(bdev); 1509 blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
1516 blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
1517 1510
1518 kfree(log); 1511 kfree(log);
1519 1512
diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c
index 92ca6fbe09bd..734b9025858e 100644
--- a/fs/logfs/dev_bdev.c
+++ b/fs/logfs/dev_bdev.c
@@ -300,7 +300,7 @@ static int bdev_write_sb(struct super_block *sb, struct page *page)
300 300
301static void bdev_put_device(struct logfs_super *s) 301static void bdev_put_device(struct logfs_super *s)
302{ 302{
303 close_bdev_exclusive(s->s_bdev, FMODE_READ|FMODE_WRITE); 303 blkdev_put(s->s_bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
304} 304}
305 305
306static int bdev_can_write_buf(struct super_block *sb, u64 ofs) 306static int bdev_can_write_buf(struct super_block *sb, u64 ofs)
@@ -331,7 +331,7 @@ int logfs_get_sb_bdev(struct logfs_super *p, struct file_system_type *type,
331 331
332 if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) { 332 if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
333 int mtdnr = MINOR(bdev->bd_dev); 333 int mtdnr = MINOR(bdev->bd_dev);
334 close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE); 334 blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
335 return logfs_get_sb_mtd(p, mtdnr); 335 return logfs_get_sb_mtd(p, mtdnr);
336 } 336 }
337 337
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index f804d41ec9d3..756a6798d7c8 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -1233,7 +1233,7 @@ nilfs_mount(struct file_system_type *fs_type, int flags,
1233 } 1233 }
1234 1234
1235 if (!s_new) 1235 if (!s_new)
1236 close_bdev_exclusive(sd.bdev, mode); 1236 blkdev_put(sd.bdev, mode | FMODE_EXCL);
1237 1237
1238 return root_dentry; 1238 return root_dentry;
1239 1239
@@ -1242,7 +1242,7 @@ nilfs_mount(struct file_system_type *fs_type, int flags,
1242 1242
1243 failed: 1243 failed:
1244 if (!s_new) 1244 if (!s_new)
1245 close_bdev_exclusive(sd.bdev, mode); 1245 blkdev_put(sd.bdev, mode | FMODE_EXCL);
1246 return ERR_PTR(err); 1246 return ERR_PTR(err);
1247} 1247}
1248 1248
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index 52c7557f3e25..d0a2721eaceb 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -1674,7 +1674,7 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg,
1674 goto out; 1674 goto out;
1675 1675
1676 reg->hr_bdev = I_BDEV(filp->f_mapping->host); 1676 reg->hr_bdev = I_BDEV(filp->f_mapping->host);
1677 ret = blkdev_get(reg->hr_bdev, FMODE_WRITE | FMODE_READ); 1677 ret = blkdev_get(reg->hr_bdev, FMODE_WRITE | FMODE_READ, NULL);
1678 if (ret) { 1678 if (ret) {
1679 reg->hr_bdev = NULL; 1679 reg->hr_bdev = NULL;
1680 goto out; 1680 goto out;
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 0a8b0ad0c7e2..2e6501d034ab 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -549,7 +549,7 @@ void register_disk(struct gendisk *disk)
549 goto exit; 549 goto exit;
550 550
551 bdev->bd_invalidated = 1; 551 bdev->bd_invalidated = 1;
552 err = blkdev_get(bdev, FMODE_READ); 552 err = blkdev_get(bdev, FMODE_READ, NULL);
553 if (err < 0) 553 if (err < 0)
554 goto exit; 554 goto exit;
555 blkdev_put(bdev, FMODE_READ); 555 blkdev_put(bdev, FMODE_READ);
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 076c8b194682..b488136f5ace 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -2552,8 +2552,6 @@ static int release_journal_dev(struct super_block *super,
2552 result = 0; 2552 result = 0;
2553 2553
2554 if (journal->j_dev_bd != NULL) { 2554 if (journal->j_dev_bd != NULL) {
2555 if (journal->j_dev_bd->bd_dev != super->s_dev)
2556 bd_release(journal->j_dev_bd);
2557 result = blkdev_put(journal->j_dev_bd, journal->j_dev_mode); 2555 result = blkdev_put(journal->j_dev_bd, journal->j_dev_mode);
2558 journal->j_dev_bd = NULL; 2556 journal->j_dev_bd = NULL;
2559 } 2557 }
@@ -2571,7 +2569,7 @@ static int journal_init_dev(struct super_block *super,
2571{ 2569{
2572 int result; 2570 int result;
2573 dev_t jdev; 2571 dev_t jdev;
2574 fmode_t blkdev_mode = FMODE_READ | FMODE_WRITE; 2572 fmode_t blkdev_mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
2575 char b[BDEVNAME_SIZE]; 2573 char b[BDEVNAME_SIZE];
2576 2574
2577 result = 0; 2575 result = 0;
@@ -2585,7 +2583,9 @@ static int journal_init_dev(struct super_block *super,
2585 2583
2586 /* there is no "jdev" option and journal is on separate device */ 2584 /* there is no "jdev" option and journal is on separate device */
2587 if ((!jdev_name || !jdev_name[0])) { 2585 if ((!jdev_name || !jdev_name[0])) {
2588 journal->j_dev_bd = open_by_devnum(jdev, blkdev_mode); 2586 if (jdev == super->s_dev)
2587 blkdev_mode &= ~FMODE_EXCL;
2588 journal->j_dev_bd = open_by_devnum(jdev, blkdev_mode, journal);
2589 journal->j_dev_mode = blkdev_mode; 2589 journal->j_dev_mode = blkdev_mode;
2590 if (IS_ERR(journal->j_dev_bd)) { 2590 if (IS_ERR(journal->j_dev_bd)) {
2591 result = PTR_ERR(journal->j_dev_bd); 2591 result = PTR_ERR(journal->j_dev_bd);
@@ -2594,15 +2594,8 @@ static int journal_init_dev(struct super_block *super,
2594 "cannot init journal device '%s': %i", 2594 "cannot init journal device '%s': %i",
2595 __bdevname(jdev, b), result); 2595 __bdevname(jdev, b), result);
2596 return result; 2596 return result;
2597 } else if (jdev != super->s_dev) { 2597 } else if (jdev != super->s_dev)
2598 result = bd_claim(journal->j_dev_bd, journal);
2599 if (result) {
2600 blkdev_put(journal->j_dev_bd, blkdev_mode);
2601 return result;
2602 }
2603
2604 set_blocksize(journal->j_dev_bd, super->s_blocksize); 2598 set_blocksize(journal->j_dev_bd, super->s_blocksize);
2605 }
2606 2599
2607 return 0; 2600 return 0;
2608 } 2601 }
diff --git a/fs/super.c b/fs/super.c
index ca696155cd9a..22374bf0ba87 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -801,13 +801,13 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
801 801
802 /* 802 /*
803 * s_umount nests inside bd_mutex during 803 * s_umount nests inside bd_mutex during
804 * __invalidate_device(). close_bdev_exclusive() 804 * __invalidate_device(). blkdev_put() acquires
805 * acquires bd_mutex and can't be called under 805 * bd_mutex and can't be called under s_umount. Drop
806 * s_umount. Drop s_umount temporarily. This is safe 806 * s_umount temporarily. This is safe as we're
807 * as we're holding an active reference. 807 * holding an active reference.
808 */ 808 */
809 up_write(&s->s_umount); 809 up_write(&s->s_umount);
810 close_bdev_exclusive(bdev, mode); 810 blkdev_put(bdev, mode | FMODE_EXCL);
811 down_write(&s->s_umount); 811 down_write(&s->s_umount);
812 } else { 812 } else {
813 char b[BDEVNAME_SIZE]; 813 char b[BDEVNAME_SIZE];
@@ -831,7 +831,7 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
831error_s: 831error_s:
832 error = PTR_ERR(s); 832 error = PTR_ERR(s);
833error_bdev: 833error_bdev:
834 close_bdev_exclusive(bdev, mode); 834 blkdev_put(bdev, mode | FMODE_EXCL);
835error: 835error:
836 return ERR_PTR(error); 836 return ERR_PTR(error);
837} 837}
@@ -862,7 +862,7 @@ void kill_block_super(struct super_block *sb)
862 bdev->bd_super = NULL; 862 bdev->bd_super = NULL;
863 generic_shutdown_super(sb); 863 generic_shutdown_super(sb);
864 sync_blockdev(bdev); 864 sync_blockdev(bdev);
865 close_bdev_exclusive(bdev, mode); 865 blkdev_put(bdev, mode | FMODE_EXCL);
866} 866}
867 867
868EXPORT_SYMBOL(kill_block_super); 868EXPORT_SYMBOL(kill_block_super);
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 9f3a78fe6ae4..a1a6e5ceea67 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -623,7 +623,7 @@ xfs_blkdev_put(
623 struct block_device *bdev) 623 struct block_device *bdev)
624{ 624{
625 if (bdev) 625 if (bdev)
626 close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE); 626 blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
627} 627}
628 628
629/* 629/*