aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/md/dm-table.c23
-rw-r--r--drivers/md/md.c4
-rw-r--r--fs/block_dev.c322
-rw-r--r--include/linux/fs.h16
4 files changed, 74 insertions, 291 deletions
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 90267f8d64ee..2c876ffc63df 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -328,12 +328,22 @@ static int open_dev(struct dm_dev_internal *d, dev_t dev,
328 bdev = open_by_devnum(dev, d->dm_dev.mode); 328 bdev = open_by_devnum(dev, d->dm_dev.mode);
329 if (IS_ERR(bdev)) 329 if (IS_ERR(bdev))
330 return PTR_ERR(bdev); 330 return PTR_ERR(bdev);
331 r = bd_claim_by_disk(bdev, _claim_ptr, dm_disk(md)); 331
332 if (r) 332 r = bd_claim(bdev, _claim_ptr);
333 if (r) {
333 blkdev_put(bdev, d->dm_dev.mode); 334 blkdev_put(bdev, d->dm_dev.mode);
334 else 335 return r;
335 d->dm_dev.bdev = bdev; 336 }
336 return r; 337
338 r = bd_link_disk_holder(bdev, dm_disk(md));
339 if (r) {
340 bd_release(bdev);
341 blkdev_put(bdev, d->dm_dev.mode);
342 return r;
343 }
344
345 d->dm_dev.bdev = bdev;
346 return 0;
337} 347}
338 348
339/* 349/*
@@ -344,7 +354,8 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
344 if (!d->dm_dev.bdev) 354 if (!d->dm_dev.bdev)
345 return; 355 return;
346 356
347 bd_release_from_disk(d->dm_dev.bdev, dm_disk(md)); 357 bd_unlink_disk_holder(d->dm_dev.bdev);
358 bd_release(d->dm_dev.bdev);
348 blkdev_put(d->dm_dev.bdev, d->dm_dev.mode); 359 blkdev_put(d->dm_dev.bdev, d->dm_dev.mode);
349 d->dm_dev.bdev = NULL; 360 d->dm_dev.bdev = NULL;
350} 361}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 4e957f3140a8..c47644fca1a1 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1880,7 +1880,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
1880 rdev->sysfs_state = sysfs_get_dirent_safe(rdev->kobj.sd, "state"); 1880 rdev->sysfs_state = sysfs_get_dirent_safe(rdev->kobj.sd, "state");
1881 1881
1882 list_add_rcu(&rdev->same_set, &mddev->disks); 1882 list_add_rcu(&rdev->same_set, &mddev->disks);
1883 bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk); 1883 bd_link_disk_holder(rdev->bdev, mddev->gendisk);
1884 1884
1885 /* May as well allow recovery to be retried once */ 1885 /* May as well allow recovery to be retried once */
1886 mddev->recovery_disabled = 0; 1886 mddev->recovery_disabled = 0;
@@ -1907,7 +1907,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
1907 MD_BUG(); 1907 MD_BUG();
1908 return; 1908 return;
1909 } 1909 }
1910 bd_release_from_disk(rdev->bdev, rdev->mddev->gendisk); 1910 bd_unlink_disk_holder(rdev->bdev);
1911 list_del_rcu(&rdev->same_set); 1911 list_del_rcu(&rdev->same_set);
1912 printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b)); 1912 printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
1913 rdev->mddev = NULL; 1913 rdev->mddev = NULL;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 06e8ff12b97c..9329068684d2 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -426,9 +426,6 @@ static void init_once(void *foo)
426 mutex_init(&bdev->bd_mutex); 426 mutex_init(&bdev->bd_mutex);
427 INIT_LIST_HEAD(&bdev->bd_inodes); 427 INIT_LIST_HEAD(&bdev->bd_inodes);
428 INIT_LIST_HEAD(&bdev->bd_list); 428 INIT_LIST_HEAD(&bdev->bd_list);
429#ifdef CONFIG_SYSFS
430 INIT_LIST_HEAD(&bdev->bd_holder_list);
431#endif
432 inode_init_once(&ei->vfs_inode); 429 inode_init_once(&ei->vfs_inode);
433 /* Initialize mutex for freeze. */ 430 /* Initialize mutex for freeze. */
434 mutex_init(&bdev->bd_fsfreeze_mutex); 431 mutex_init(&bdev->bd_fsfreeze_mutex);
@@ -881,314 +878,83 @@ void bd_release(struct block_device *bdev)
881EXPORT_SYMBOL(bd_release); 878EXPORT_SYMBOL(bd_release);
882 879
883#ifdef CONFIG_SYSFS 880#ifdef CONFIG_SYSFS
884/*
885 * Functions for bd_claim_by_kobject / bd_release_from_kobject
886 *
887 * If a kobject is passed to bd_claim_by_kobject()
888 * and the kobject has a parent directory,
889 * following symlinks are created:
890 * o from the kobject to the claimed bdev
891 * o from "holders" directory of the bdev to the parent of the kobject
892 * bd_release_from_kobject() removes these symlinks.
893 *
894 * Example:
895 * If /dev/dm-0 maps to /dev/sda, kobject corresponding to
896 * /sys/block/dm-0/slaves is passed to bd_claim_by_kobject(), then:
897 * /sys/block/dm-0/slaves/sda --> /sys/block/sda
898 * /sys/block/sda/holders/dm-0 --> /sys/block/dm-0
899 */
900
901static int add_symlink(struct kobject *from, struct kobject *to) 881static int add_symlink(struct kobject *from, struct kobject *to)
902{ 882{
903 if (!from || !to)
904 return 0;
905 return sysfs_create_link(from, to, kobject_name(to)); 883 return sysfs_create_link(from, to, kobject_name(to));
906} 884}
907 885
908static void del_symlink(struct kobject *from, struct kobject *to) 886static void del_symlink(struct kobject *from, struct kobject *to)
909{ 887{
910 if (!from || !to)
911 return;
912 sysfs_remove_link(from, kobject_name(to)); 888 sysfs_remove_link(from, kobject_name(to));
913} 889}
914 890
915/*
916 * 'struct bd_holder' contains pointers to kobjects symlinked by
917 * bd_claim_by_kobject.
918 * It's connected to bd_holder_list which is protected by bdev->bd_sem.
919 */
920struct bd_holder {
921 struct list_head list; /* chain of holders of the bdev */
922 int count; /* references from the holder */
923 struct kobject *sdir; /* holder object, e.g. "/block/dm-0/slaves" */
924 struct kobject *hdev; /* e.g. "/block/dm-0" */
925 struct kobject *hdir; /* e.g. "/block/sda/holders" */
926 struct kobject *sdev; /* e.g. "/block/sda" */
927};
928
929/*
930 * Get references of related kobjects at once.
931 * Returns 1 on success. 0 on failure.
932 *
933 * Should call bd_holder_release_dirs() after successful use.
934 */
935static int bd_holder_grab_dirs(struct block_device *bdev,
936 struct bd_holder *bo)
937{
938 if (!bdev || !bo)
939 return 0;
940
941 bo->sdir = kobject_get(bo->sdir);
942 if (!bo->sdir)
943 return 0;
944
945 bo->hdev = kobject_get(bo->sdir->parent);
946 if (!bo->hdev)
947 goto fail_put_sdir;
948
949 bo->sdev = kobject_get(&part_to_dev(bdev->bd_part)->kobj);
950 if (!bo->sdev)
951 goto fail_put_hdev;
952
953 bo->hdir = kobject_get(bdev->bd_part->holder_dir);
954 if (!bo->hdir)
955 goto fail_put_sdev;
956
957 return 1;
958
959fail_put_sdev:
960 kobject_put(bo->sdev);
961fail_put_hdev:
962 kobject_put(bo->hdev);
963fail_put_sdir:
964 kobject_put(bo->sdir);
965
966 return 0;
967}
968
969/* Put references of related kobjects at once. */
970static void bd_holder_release_dirs(struct bd_holder *bo)
971{
972 kobject_put(bo->hdir);
973 kobject_put(bo->sdev);
974 kobject_put(bo->hdev);
975 kobject_put(bo->sdir);
976}
977
978static struct bd_holder *alloc_bd_holder(struct kobject *kobj)
979{
980 struct bd_holder *bo;
981
982 bo = kzalloc(sizeof(*bo), GFP_KERNEL);
983 if (!bo)
984 return NULL;
985
986 bo->count = 1;
987 bo->sdir = kobj;
988
989 return bo;
990}
991
992static void free_bd_holder(struct bd_holder *bo)
993{
994 kfree(bo);
995}
996
997/** 891/**
998 * find_bd_holder - find matching struct bd_holder from the block device 892 * bd_link_disk_holder - create symlinks between holding disk and slave bdev
893 * @bdev: the claimed slave bdev
894 * @disk: the holding disk
999 * 895 *
1000 * @bdev: struct block device to be searched 896 * This functions creates the following sysfs symlinks.
1001 * @bo: target struct bd_holder
1002 * 897 *
1003 * Returns matching entry with @bo in @bdev->bd_holder_list. 898 * - from "slaves" directory of the holder @disk to the claimed @bdev
1004 * If found, increment the reference count and return the pointer. 899 * - from "holders" directory of the @bdev to the holder @disk
1005 * If not found, returns NULL.
1006 */
1007static struct bd_holder *find_bd_holder(struct block_device *bdev,
1008 struct bd_holder *bo)
1009{
1010 struct bd_holder *tmp;
1011
1012 list_for_each_entry(tmp, &bdev->bd_holder_list, list)
1013 if (tmp->sdir == bo->sdir) {
1014 tmp->count++;
1015 return tmp;
1016 }
1017
1018 return NULL;
1019}
1020
1021/**
1022 * add_bd_holder - create sysfs symlinks for bd_claim() relationship
1023 * 900 *
1024 * @bdev: block device to be bd_claimed 901 * For example, if /dev/dm-0 maps to /dev/sda and disk for dm-0 is
1025 * @bo: preallocated and initialized by alloc_bd_holder() 902 * passed to bd_link_disk_holder(), then:
1026 * 903 *
1027 * Add @bo to @bdev->bd_holder_list, create symlinks. 904 * /sys/block/dm-0/slaves/sda --> /sys/block/sda
905 * /sys/block/sda/holders/dm-0 --> /sys/block/dm-0
1028 * 906 *
1029 * Returns 0 if symlinks are created. 907 * The caller must have claimed @bdev before calling this function and
1030 * Returns -ve if something fails. 908 * ensure that both @bdev and @disk are valid during the creation and
1031 */ 909 * lifetime of these symlinks.
1032static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo)
1033{
1034 int err;
1035
1036 if (!bo)
1037 return -EINVAL;
1038
1039 if (!bd_holder_grab_dirs(bdev, bo))
1040 return -EBUSY;
1041
1042 err = add_symlink(bo->sdir, bo->sdev);
1043 if (err)
1044 return err;
1045
1046 err = add_symlink(bo->hdir, bo->hdev);
1047 if (err) {
1048 del_symlink(bo->sdir, bo->sdev);
1049 return err;
1050 }
1051
1052 list_add_tail(&bo->list, &bdev->bd_holder_list);
1053 return 0;
1054}
1055
1056/**
1057 * del_bd_holder - delete sysfs symlinks for bd_claim() relationship
1058 *
1059 * @bdev: block device to be bd_claimed
1060 * @kobj: holder's kobject
1061 *
1062 * If there is matching entry with @kobj in @bdev->bd_holder_list
1063 * and no other bd_claim() from the same kobject,
1064 * remove the struct bd_holder from the list, delete symlinks for it.
1065 *
1066 * Returns a pointer to the struct bd_holder when it's removed from the list
1067 * and ready to be freed.
1068 * Returns NULL if matching claim isn't found or there is other bd_claim()
1069 * by the same kobject.
1070 */
1071static struct bd_holder *del_bd_holder(struct block_device *bdev,
1072 struct kobject *kobj)
1073{
1074 struct bd_holder *bo;
1075
1076 list_for_each_entry(bo, &bdev->bd_holder_list, list) {
1077 if (bo->sdir == kobj) {
1078 bo->count--;
1079 BUG_ON(bo->count < 0);
1080 if (!bo->count) {
1081 list_del(&bo->list);
1082 del_symlink(bo->sdir, bo->sdev);
1083 del_symlink(bo->hdir, bo->hdev);
1084 bd_holder_release_dirs(bo);
1085 return bo;
1086 }
1087 break;
1088 }
1089 }
1090
1091 return NULL;
1092}
1093
1094/**
1095 * bd_claim_by_kobject - bd_claim() with additional kobject signature
1096 *
1097 * @bdev: block device to be claimed
1098 * @holder: holder's signature
1099 * @kobj: holder's kobject
1100 * 910 *
1101 * Do bd_claim() and if it succeeds, create sysfs symlinks between 911 * CONTEXT:
1102 * the bdev and the holder's kobject. 912 * Might sleep.
1103 * Use bd_release_from_kobject() when relesing the claimed bdev.
1104 * 913 *
1105 * Returns 0 on success. (same as bd_claim()) 914 * RETURNS:
1106 * Returns errno on failure. 915 * 0 on success, -errno on failure.
1107 */ 916 */
1108static int bd_claim_by_kobject(struct block_device *bdev, void *holder, 917int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
1109 struct kobject *kobj)
1110{ 918{
1111 int err; 919 int ret = 0;
1112 struct bd_holder *bo, *found;
1113
1114 if (!kobj)
1115 return -EINVAL;
1116
1117 bo = alloc_bd_holder(kobj);
1118 if (!bo)
1119 return -ENOMEM;
1120 920
1121 mutex_lock(&bdev->bd_mutex); 921 mutex_lock(&bdev->bd_mutex);
1122 922
1123 err = bd_claim(bdev, holder); 923 WARN_ON_ONCE(!bdev->bd_holder || bdev->bd_holder_disk);
1124 if (err)
1125 goto fail;
1126 924
1127 found = find_bd_holder(bdev, bo); 925 /* FIXME: remove the following once add_disk() handles errors */
1128 if (found) 926 if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir))
1129 goto fail; 927 goto out_unlock;
1130 928
1131 err = add_bd_holder(bdev, bo); 929 ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
1132 if (err) 930 if (ret)
1133 bd_release(bdev); 931 goto out_unlock;
1134 else
1135 bo = NULL;
1136fail:
1137 mutex_unlock(&bdev->bd_mutex);
1138 free_bd_holder(bo);
1139 return err;
1140}
1141 932
1142/** 933 ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
1143 * bd_release_from_kobject - bd_release() with additional kobject signature 934 if (ret) {
1144 * 935 del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
1145 * @bdev: block device to be released 936 goto out_unlock;
1146 * @kobj: holder's kobject 937 }
1147 *
1148 * Do bd_release() and remove sysfs symlinks created by bd_claim_by_kobject().
1149 */
1150static void bd_release_from_kobject(struct block_device *bdev,
1151 struct kobject *kobj)
1152{
1153 if (!kobj)
1154 return;
1155 938
1156 mutex_lock(&bdev->bd_mutex); 939 bdev->bd_holder_disk = disk;
1157 bd_release(bdev); 940out_unlock:
1158 free_bd_holder(del_bd_holder(bdev, kobj));
1159 mutex_unlock(&bdev->bd_mutex); 941 mutex_unlock(&bdev->bd_mutex);
942 return ret;
1160} 943}
944EXPORT_SYMBOL_GPL(bd_link_disk_holder);
1161 945
1162/** 946void bd_unlink_disk_holder(struct block_device *bdev)
1163 * bd_claim_by_disk - wrapper function for bd_claim_by_kobject()
1164 *
1165 * @bdev: block device to be claimed
1166 * @holder: holder's signature
1167 * @disk: holder's gendisk
1168 *
1169 * Call bd_claim_by_kobject() with getting @disk->slave_dir.
1170 */
1171int bd_claim_by_disk(struct block_device *bdev, void *holder,
1172 struct gendisk *disk)
1173{ 947{
1174 return bd_claim_by_kobject(bdev, holder, kobject_get(disk->slave_dir)); 948 struct gendisk *disk = bdev->bd_holder_disk;
1175}
1176EXPORT_SYMBOL_GPL(bd_claim_by_disk);
1177 949
1178/** 950 bdev->bd_holder_disk = NULL;
1179 * bd_release_from_disk - wrapper function for bd_release_from_kobject() 951 if (!disk)
1180 * 952 return;
1181 * @bdev: block device to be claimed 953
1182 * @disk: holder's gendisk 954 del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
1183 * 955 del_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
1184 * Call bd_release_from_kobject() and put @disk->slave_dir.
1185 */
1186void bd_release_from_disk(struct block_device *bdev, struct gendisk *disk)
1187{
1188 bd_release_from_kobject(bdev, disk->slave_dir);
1189 kobject_put(disk->slave_dir);
1190} 956}
1191EXPORT_SYMBOL_GPL(bd_release_from_disk); 957EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);
1192#endif 958#endif
1193 959
1194/* 960/*
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 334d68a17108..66b7f2c5d7e9 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -663,7 +663,7 @@ struct block_device {
663 void * bd_holder; 663 void * bd_holder;
664 int bd_holders; 664 int bd_holders;
665#ifdef CONFIG_SYSFS 665#ifdef CONFIG_SYSFS
666 struct list_head bd_holder_list; 666 struct gendisk * bd_holder_disk; /* for sysfs slave linkng */
667#endif 667#endif
668 struct block_device * bd_contains; 668 struct block_device * bd_contains;
669 unsigned bd_block_size; 669 unsigned bd_block_size;
@@ -2042,11 +2042,17 @@ extern int blkdev_put(struct block_device *, fmode_t);
2042extern int bd_claim(struct block_device *, void *); 2042extern int bd_claim(struct block_device *, void *);
2043extern void bd_release(struct block_device *); 2043extern void bd_release(struct block_device *);
2044#ifdef CONFIG_SYSFS 2044#ifdef CONFIG_SYSFS
2045extern int bd_claim_by_disk(struct block_device *, void *, struct gendisk *); 2045extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk);
2046extern void bd_release_from_disk(struct block_device *, struct gendisk *); 2046extern void bd_unlink_disk_holder(struct block_device *bdev);
2047#else 2047#else
2048#define bd_claim_by_disk(bdev, holder, disk) bd_claim(bdev, holder) 2048static inline int bd_link_disk_holder(struct block_device *bdev,
2049#define bd_release_from_disk(bdev, disk) bd_release(bdev) 2049 struct gendisk *disk)
2050{
2051 return 0;
2052}
2053static inline void bd_unlink_disk_holder(struct block_device *bdev)
2054{
2055}
2050#endif 2056#endif
2051#endif 2057#endif
2052 2058