aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2011-01-14 12:43:57 -0500
committerJens Axboe <jaxboe@fusionio.com>2011-01-14 12:44:22 -0500
commit49731baa41df404c2c3f44555869ab387363af43 (patch)
tree5d3476368fa546aebb1c223e9cf1bab5ad80f698
parentc553f8e335c00a7cff3ab3f13e793b13d3f2207f (diff)
block: restore multiple bd_link_disk_holder() support
Commit e09b457b (block: simplify holder symlink handling) incorrectly assumed that there is only one link at maximum. dm may use multiple links and expects block layer to track reference count for each link, which is different from and unrelated to the exclusive device holder identified by @holder when the device is opened. Remove the single holder assumption and automatic removal of the link and revive the per-link reference count tracking. The code essentially behaves the same as before commit e09b457b sans the unnecessary kobject reference count dancing. While at it, note that this facility should not be used by anyone else than the current ones. Sysfs symlinks shouldn't be abused like this and the whole thing doesn't belong in the block layer at all. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: Milan Broz <mbroz@redhat.com> Cc: Jun'ichi Nomura <j-nomura@ce.jp.nec.com> Cc: Neil Brown <neilb@suse.de> Cc: linux-raid@vger.kernel.org Cc: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
-rw-r--r--drivers/md/dm-table.c1
-rw-r--r--drivers/md/md.c1
-rw-r--r--fs/block_dev.c93
-rw-r--r--include/linux/fs.h8
4 files changed, 84 insertions, 19 deletions
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index dffa0ac7c4f..38e4eb1bb96 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -350,6 +350,7 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
350 if (!d->dm_dev.bdev) 350 if (!d->dm_dev.bdev)
351 return; 351 return;
352 352
353 bd_unlink_disk_holder(d->dm_dev.bdev, dm_disk(md));
353 blkdev_put(d->dm_dev.bdev, d->dm_dev.mode | FMODE_EXCL); 354 blkdev_put(d->dm_dev.bdev, d->dm_dev.mode | FMODE_EXCL);
354 d->dm_dev.bdev = NULL; 355 d->dm_dev.bdev = NULL;
355} 356}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index cf8594c5ea2..b76cfc89e1b 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1912,6 +1912,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
1912 MD_BUG(); 1912 MD_BUG();
1913 return; 1913 return;
1914 } 1914 }
1915 bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk);
1915 list_del_rcu(&rdev->same_set); 1916 list_del_rcu(&rdev->same_set);
1916 printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b)); 1917 printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
1917 rdev->mddev = NULL; 1918 rdev->mddev = NULL;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index fe3f59c14a0..333a7bb4cb9 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -432,6 +432,9 @@ static void init_once(void *foo)
432 mutex_init(&bdev->bd_mutex); 432 mutex_init(&bdev->bd_mutex);
433 INIT_LIST_HEAD(&bdev->bd_inodes); 433 INIT_LIST_HEAD(&bdev->bd_inodes);
434 INIT_LIST_HEAD(&bdev->bd_list); 434 INIT_LIST_HEAD(&bdev->bd_list);
435#ifdef CONFIG_SYSFS
436 INIT_LIST_HEAD(&bdev->bd_holder_disks);
437#endif
435 inode_init_once(&ei->vfs_inode); 438 inode_init_once(&ei->vfs_inode);
436 /* Initialize mutex for freeze. */ 439 /* Initialize mutex for freeze. */
437 mutex_init(&bdev->bd_fsfreeze_mutex); 440 mutex_init(&bdev->bd_fsfreeze_mutex);
@@ -779,6 +782,23 @@ static struct block_device *bd_start_claiming(struct block_device *bdev,
779} 782}
780 783
781#ifdef CONFIG_SYSFS 784#ifdef CONFIG_SYSFS
785struct bd_holder_disk {
786 struct list_head list;
787 struct gendisk *disk;
788 int refcnt;
789};
790
791static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev,
792 struct gendisk *disk)
793{
794 struct bd_holder_disk *holder;
795
796 list_for_each_entry(holder, &bdev->bd_holder_disks, list)
797 if (holder->disk == disk)
798 return holder;
799 return NULL;
800}
801
782static int add_symlink(struct kobject *from, struct kobject *to) 802static int add_symlink(struct kobject *from, struct kobject *to)
783{ 803{
784 return sysfs_create_link(from, to, kobject_name(to)); 804 return sysfs_create_link(from, to, kobject_name(to));
@@ -794,6 +814,8 @@ static void del_symlink(struct kobject *from, struct kobject *to)
794 * @bdev: the claimed slave bdev 814 * @bdev: the claimed slave bdev
795 * @disk: the holding disk 815 * @disk: the holding disk
796 * 816 *
817 * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
818 *
797 * This functions creates the following sysfs symlinks. 819 * This functions creates the following sysfs symlinks.
798 * 820 *
799 * - from "slaves" directory of the holder @disk to the claimed @bdev 821 * - from "slaves" directory of the holder @disk to the claimed @bdev
@@ -817,47 +839,83 @@ static void del_symlink(struct kobject *from, struct kobject *to)
817 */ 839 */
818int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk) 840int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
819{ 841{
842 struct bd_holder_disk *holder;
820 int ret = 0; 843 int ret = 0;
821 844
822 mutex_lock(&bdev->bd_mutex); 845 mutex_lock(&bdev->bd_mutex);
823 846
824 WARN_ON_ONCE(!bdev->bd_holder || bdev->bd_holder_disk); 847 WARN_ON_ONCE(!bdev->bd_holder);
825 848
826 /* FIXME: remove the following once add_disk() handles errors */ 849 /* FIXME: remove the following once add_disk() handles errors */
827 if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir)) 850 if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir))
828 goto out_unlock; 851 goto out_unlock;
829 852
830 ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); 853 holder = bd_find_holder_disk(bdev, disk);
831 if (ret) 854 if (holder) {
855 holder->refcnt++;
832 goto out_unlock; 856 goto out_unlock;
857 }
833 858
834 ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); 859 holder = kzalloc(sizeof(*holder), GFP_KERNEL);
835 if (ret) { 860 if (!holder) {
836 del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); 861 ret = -ENOMEM;
837 goto out_unlock; 862 goto out_unlock;
838 } 863 }
839 864
840 bdev->bd_holder_disk = disk; 865 INIT_LIST_HEAD(&holder->list);
866 holder->disk = disk;
867 holder->refcnt = 1;
868
869 ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
870 if (ret)
871 goto out_free;
872
873 ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
874 if (ret)
875 goto out_del;
876
877 list_add(&holder->list, &bdev->bd_holder_disks);
878 goto out_unlock;
879
880out_del:
881 del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
882out_free:
883 kfree(holder);
841out_unlock: 884out_unlock:
842 mutex_unlock(&bdev->bd_mutex); 885 mutex_unlock(&bdev->bd_mutex);
843 return ret; 886 return ret;
844} 887}
845EXPORT_SYMBOL_GPL(bd_link_disk_holder); 888EXPORT_SYMBOL_GPL(bd_link_disk_holder);
846 889
847static void bd_unlink_disk_holder(struct block_device *bdev) 890/**
891 * bd_unlink_disk_holder - destroy symlinks created by bd_link_disk_holder()
892 * @bdev: the calimed slave bdev
893 * @disk: the holding disk
894 *
895 * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
896 *
897 * CONTEXT:
898 * Might sleep.
899 */
900void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk)
848{ 901{
849 struct gendisk *disk = bdev->bd_holder_disk; 902 struct bd_holder_disk *holder;
850 903
851 bdev->bd_holder_disk = NULL; 904 mutex_lock(&bdev->bd_mutex);
852 if (!disk)
853 return;
854 905
855 del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); 906 holder = bd_find_holder_disk(bdev, disk);
856 del_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); 907
908 if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) {
909 del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
910 del_symlink(bdev->bd_part->holder_dir,
911 &disk_to_dev(disk)->kobj);
912 list_del_init(&holder->list);
913 kfree(holder);
914 }
915
916 mutex_unlock(&bdev->bd_mutex);
857} 917}
858#else 918EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);
859static inline void bd_unlink_disk_holder(struct block_device *bdev)
860{ }
861#endif 919#endif
862 920
863/** 921/**
@@ -1380,7 +1438,6 @@ int blkdev_put(struct block_device *bdev, fmode_t mode)
1380 * unblock evpoll if it was a write holder. 1438 * unblock evpoll if it was a write holder.
1381 */ 1439 */
1382 if (bdev_free) { 1440 if (bdev_free) {
1383 bd_unlink_disk_holder(bdev);
1384 if (bdev->bd_write_holder) { 1441 if (bdev->bd_write_holder) {
1385 disk_unblock_events(bdev->bd_disk); 1442 disk_unblock_events(bdev->bd_disk);
1386 bdev->bd_write_holder = false; 1443 bdev->bd_write_holder = false;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 3984f2358d1..fb2190349cd 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -666,7 +666,7 @@ struct block_device {
666 int bd_holders; 666 int bd_holders;
667 bool bd_write_holder; 667 bool bd_write_holder;
668#ifdef CONFIG_SYSFS 668#ifdef CONFIG_SYSFS
669 struct gendisk * bd_holder_disk; /* for sysfs slave linkng */ 669 struct list_head bd_holder_disks;
670#endif 670#endif
671 struct block_device * bd_contains; 671 struct block_device * bd_contains;
672 unsigned bd_block_size; 672 unsigned bd_block_size;
@@ -2058,12 +2058,18 @@ extern struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode,
2058extern int blkdev_put(struct block_device *bdev, fmode_t mode); 2058extern int blkdev_put(struct block_device *bdev, fmode_t mode);
2059#ifdef CONFIG_SYSFS 2059#ifdef CONFIG_SYSFS
2060extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk); 2060extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk);
2061extern void bd_unlink_disk_holder(struct block_device *bdev,
2062 struct gendisk *disk);
2061#else 2063#else
2062static inline int bd_link_disk_holder(struct block_device *bdev, 2064static inline int bd_link_disk_holder(struct block_device *bdev,
2063 struct gendisk *disk) 2065 struct gendisk *disk)
2064{ 2066{
2065 return 0; 2067 return 0;
2066} 2068}
2069static inline void bd_unlink_disk_holder(struct block_device *bdev,
2070 struct gendisk *disk)
2071{
2072}
2067#endif 2073#endif
2068#endif 2074#endif
2069 2075