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
commite09b457bdb7e8d23fc54dcef0930ac697d8de895 (patch)
tree41035bf61a8acb08292d01c0f66e5450502688af /fs
parent37004c42f7240035bc2726c340c4efa726b4818e (diff)
block: simplify holder symlink handling
Code to manage symlinks in /sys/block/*/{holders|slaves} are overly complex with multiple holder considerations, redundant extra references to all involved kobjects, unused generic kobject holder support and unnecessary mixup with bd_claim/release functionalities. Strip it down to what's necessary (single gendisk holder) and make it use a separate interface. This is a step for cleaning up bd_claim/release. This patch makes dm-table slightly more complex but it will be simplified again with further changes. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Neil Brown <neilb@suse.de> Acked-by: Mike Snitzer <snitzer@redhat.com> Cc: dm-devel@redhat.com
Diffstat (limited to 'fs')
-rw-r--r--fs/block_dev.c322
1 files changed, 44 insertions, 278 deletions
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/*