aboutsummaryrefslogtreecommitdiffstats
path: root/fs/block_dev.c
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 /fs/block_dev.c
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>
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r--fs/block_dev.c93
1 files changed, 75 insertions, 18 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c
index fe3f59c14a02..333a7bb4cb9c 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;