diff options
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r-- | fs/block_dev.c | 768 |
1 files changed, 293 insertions, 475 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 771f23527010..333a7bb4cb9c 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -433,7 +433,7 @@ static void init_once(void *foo) | |||
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 | 435 | #ifdef CONFIG_SYSFS |
436 | INIT_LIST_HEAD(&bdev->bd_holder_list); | 436 | INIT_LIST_HEAD(&bdev->bd_holder_disks); |
437 | #endif | 437 | #endif |
438 | inode_init_once(&ei->vfs_inode); | 438 | inode_init_once(&ei->vfs_inode); |
439 | /* Initialize mutex for freeze. */ | 439 | /* Initialize mutex for freeze. */ |
@@ -473,7 +473,7 @@ static const struct super_operations bdev_sops = { | |||
473 | static struct dentry *bd_mount(struct file_system_type *fs_type, | 473 | static struct dentry *bd_mount(struct file_system_type *fs_type, |
474 | int flags, const char *dev_name, void *data) | 474 | int flags, const char *dev_name, void *data) |
475 | { | 475 | { |
476 | return mount_pseudo(fs_type, "bdev:", &bdev_sops, 0x62646576); | 476 | return mount_pseudo(fs_type, "bdev:", &bdev_sops, NULL, 0x62646576); |
477 | } | 477 | } |
478 | 478 | ||
479 | static struct file_system_type bd_type = { | 479 | static struct file_system_type bd_type = { |
@@ -669,7 +669,7 @@ static bool bd_may_claim(struct block_device *bdev, struct block_device *whole, | |||
669 | else if (bdev->bd_contains == bdev) | 669 | else if (bdev->bd_contains == bdev) |
670 | return true; /* is a whole device which isn't held */ | 670 | return true; /* is a whole device which isn't held */ |
671 | 671 | ||
672 | else if (whole->bd_holder == bd_claim) | 672 | else if (whole->bd_holder == bd_may_claim) |
673 | return true; /* is a partition of a device that is being partitioned */ | 673 | return true; /* is a partition of a device that is being partitioned */ |
674 | else if (whole->bd_holder != NULL) | 674 | else if (whole->bd_holder != NULL) |
675 | return false; /* is a partition of a held device */ | 675 | return false; /* is a partition of a held device */ |
@@ -781,439 +781,142 @@ static struct block_device *bd_start_claiming(struct block_device *bdev, | |||
781 | } | 781 | } |
782 | } | 782 | } |
783 | 783 | ||
784 | /* releases bdev_lock */ | 784 | #ifdef CONFIG_SYSFS |
785 | static void __bd_abort_claiming(struct block_device *whole, void *holder) | 785 | struct bd_holder_disk { |
786 | { | 786 | struct list_head list; |
787 | BUG_ON(whole->bd_claiming != holder); | 787 | struct gendisk *disk; |
788 | whole->bd_claiming = NULL; | 788 | int refcnt; |
789 | wake_up_bit(&whole->bd_claiming, 0); | 789 | }; |
790 | |||
791 | spin_unlock(&bdev_lock); | ||
792 | bdput(whole); | ||
793 | } | ||
794 | |||
795 | /** | ||
796 | * bd_abort_claiming - abort claiming a block device | ||
797 | * @whole: whole block device returned by bd_start_claiming() | ||
798 | * @holder: holder trying to claim @bdev | ||
799 | * | ||
800 | * Abort a claiming block started by bd_start_claiming(). Note that | ||
801 | * @whole is not the block device to be claimed but the whole device | ||
802 | * returned by bd_start_claiming(). | ||
803 | * | ||
804 | * CONTEXT: | ||
805 | * Grabs and releases bdev_lock. | ||
806 | */ | ||
807 | static void bd_abort_claiming(struct block_device *whole, void *holder) | ||
808 | { | ||
809 | spin_lock(&bdev_lock); | ||
810 | __bd_abort_claiming(whole, holder); /* releases bdev_lock */ | ||
811 | } | ||
812 | |||
813 | /* increment holders when we have a legitimate claim. requires bdev_lock */ | ||
814 | static void __bd_claim(struct block_device *bdev, struct block_device *whole, | ||
815 | void *holder) | ||
816 | { | ||
817 | /* note that for a whole device bd_holders | ||
818 | * will be incremented twice, and bd_holder will | ||
819 | * be set to bd_claim before being set to holder | ||
820 | */ | ||
821 | whole->bd_holders++; | ||
822 | whole->bd_holder = bd_claim; | ||
823 | bdev->bd_holders++; | ||
824 | bdev->bd_holder = holder; | ||
825 | } | ||
826 | |||
827 | /** | ||
828 | * bd_finish_claiming - finish claiming a block device | ||
829 | * @bdev: block device of interest (passed to bd_start_claiming()) | ||
830 | * @whole: whole block device returned by bd_start_claiming() | ||
831 | * @holder: holder trying to claim @bdev | ||
832 | * | ||
833 | * Finish a claiming block started by bd_start_claiming(). | ||
834 | * | ||
835 | * CONTEXT: | ||
836 | * Grabs and releases bdev_lock. | ||
837 | */ | ||
838 | static void bd_finish_claiming(struct block_device *bdev, | ||
839 | struct block_device *whole, void *holder) | ||
840 | { | ||
841 | spin_lock(&bdev_lock); | ||
842 | BUG_ON(!bd_may_claim(bdev, whole, holder)); | ||
843 | __bd_claim(bdev, whole, holder); | ||
844 | __bd_abort_claiming(whole, holder); /* not actually an abort */ | ||
845 | } | ||
846 | 790 | ||
847 | /** | 791 | static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev, |
848 | * bd_claim - claim a block device | 792 | struct gendisk *disk) |
849 | * @bdev: block device to claim | ||
850 | * @holder: holder trying to claim @bdev | ||
851 | * | ||
852 | * Try to claim @bdev which must have been opened successfully. | ||
853 | * | ||
854 | * CONTEXT: | ||
855 | * Might sleep. | ||
856 | * | ||
857 | * RETURNS: | ||
858 | * 0 if successful, -EBUSY if @bdev is already claimed. | ||
859 | */ | ||
860 | int bd_claim(struct block_device *bdev, void *holder) | ||
861 | { | 793 | { |
862 | struct block_device *whole = bdev->bd_contains; | 794 | struct bd_holder_disk *holder; |
863 | int res; | ||
864 | 795 | ||
865 | might_sleep(); | 796 | list_for_each_entry(holder, &bdev->bd_holder_disks, list) |
866 | 797 | if (holder->disk == disk) | |
867 | spin_lock(&bdev_lock); | 798 | return holder; |
868 | res = bd_prepare_to_claim(bdev, whole, holder); | 799 | return NULL; |
869 | if (res == 0) | ||
870 | __bd_claim(bdev, whole, holder); | ||
871 | spin_unlock(&bdev_lock); | ||
872 | |||
873 | return res; | ||
874 | } | ||
875 | EXPORT_SYMBOL(bd_claim); | ||
876 | |||
877 | void bd_release(struct block_device *bdev) | ||
878 | { | ||
879 | spin_lock(&bdev_lock); | ||
880 | if (!--bdev->bd_contains->bd_holders) | ||
881 | bdev->bd_contains->bd_holder = NULL; | ||
882 | if (!--bdev->bd_holders) | ||
883 | bdev->bd_holder = NULL; | ||
884 | spin_unlock(&bdev_lock); | ||
885 | } | 800 | } |
886 | 801 | ||
887 | EXPORT_SYMBOL(bd_release); | ||
888 | |||
889 | #ifdef CONFIG_SYSFS | ||
890 | /* | ||
891 | * Functions for bd_claim_by_kobject / bd_release_from_kobject | ||
892 | * | ||
893 | * If a kobject is passed to bd_claim_by_kobject() | ||
894 | * and the kobject has a parent directory, | ||
895 | * following symlinks are created: | ||
896 | * o from the kobject to the claimed bdev | ||
897 | * o from "holders" directory of the bdev to the parent of the kobject | ||
898 | * bd_release_from_kobject() removes these symlinks. | ||
899 | * | ||
900 | * Example: | ||
901 | * If /dev/dm-0 maps to /dev/sda, kobject corresponding to | ||
902 | * /sys/block/dm-0/slaves is passed to bd_claim_by_kobject(), then: | ||
903 | * /sys/block/dm-0/slaves/sda --> /sys/block/sda | ||
904 | * /sys/block/sda/holders/dm-0 --> /sys/block/dm-0 | ||
905 | */ | ||
906 | |||
907 | static int add_symlink(struct kobject *from, struct kobject *to) | 802 | static int add_symlink(struct kobject *from, struct kobject *to) |
908 | { | 803 | { |
909 | if (!from || !to) | ||
910 | return 0; | ||
911 | return sysfs_create_link(from, to, kobject_name(to)); | 804 | return sysfs_create_link(from, to, kobject_name(to)); |
912 | } | 805 | } |
913 | 806 | ||
914 | static void del_symlink(struct kobject *from, struct kobject *to) | 807 | static void del_symlink(struct kobject *from, struct kobject *to) |
915 | { | 808 | { |
916 | if (!from || !to) | ||
917 | return; | ||
918 | sysfs_remove_link(from, kobject_name(to)); | 809 | sysfs_remove_link(from, kobject_name(to)); |
919 | } | 810 | } |
920 | 811 | ||
921 | /* | ||
922 | * 'struct bd_holder' contains pointers to kobjects symlinked by | ||
923 | * bd_claim_by_kobject. | ||
924 | * It's connected to bd_holder_list which is protected by bdev->bd_sem. | ||
925 | */ | ||
926 | struct bd_holder { | ||
927 | struct list_head list; /* chain of holders of the bdev */ | ||
928 | int count; /* references from the holder */ | ||
929 | struct kobject *sdir; /* holder object, e.g. "/block/dm-0/slaves" */ | ||
930 | struct kobject *hdev; /* e.g. "/block/dm-0" */ | ||
931 | struct kobject *hdir; /* e.g. "/block/sda/holders" */ | ||
932 | struct kobject *sdev; /* e.g. "/block/sda" */ | ||
933 | }; | ||
934 | |||
935 | /* | ||
936 | * Get references of related kobjects at once. | ||
937 | * Returns 1 on success. 0 on failure. | ||
938 | * | ||
939 | * Should call bd_holder_release_dirs() after successful use. | ||
940 | */ | ||
941 | static int bd_holder_grab_dirs(struct block_device *bdev, | ||
942 | struct bd_holder *bo) | ||
943 | { | ||
944 | if (!bdev || !bo) | ||
945 | return 0; | ||
946 | |||
947 | bo->sdir = kobject_get(bo->sdir); | ||
948 | if (!bo->sdir) | ||
949 | return 0; | ||
950 | |||
951 | bo->hdev = kobject_get(bo->sdir->parent); | ||
952 | if (!bo->hdev) | ||
953 | goto fail_put_sdir; | ||
954 | |||
955 | bo->sdev = kobject_get(&part_to_dev(bdev->bd_part)->kobj); | ||
956 | if (!bo->sdev) | ||
957 | goto fail_put_hdev; | ||
958 | |||
959 | bo->hdir = kobject_get(bdev->bd_part->holder_dir); | ||
960 | if (!bo->hdir) | ||
961 | goto fail_put_sdev; | ||
962 | |||
963 | return 1; | ||
964 | |||
965 | fail_put_sdev: | ||
966 | kobject_put(bo->sdev); | ||
967 | fail_put_hdev: | ||
968 | kobject_put(bo->hdev); | ||
969 | fail_put_sdir: | ||
970 | kobject_put(bo->sdir); | ||
971 | |||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | /* Put references of related kobjects at once. */ | ||
976 | static void bd_holder_release_dirs(struct bd_holder *bo) | ||
977 | { | ||
978 | kobject_put(bo->hdir); | ||
979 | kobject_put(bo->sdev); | ||
980 | kobject_put(bo->hdev); | ||
981 | kobject_put(bo->sdir); | ||
982 | } | ||
983 | |||
984 | static struct bd_holder *alloc_bd_holder(struct kobject *kobj) | ||
985 | { | ||
986 | struct bd_holder *bo; | ||
987 | |||
988 | bo = kzalloc(sizeof(*bo), GFP_KERNEL); | ||
989 | if (!bo) | ||
990 | return NULL; | ||
991 | |||
992 | bo->count = 1; | ||
993 | bo->sdir = kobj; | ||
994 | |||
995 | return bo; | ||
996 | } | ||
997 | |||
998 | static void free_bd_holder(struct bd_holder *bo) | ||
999 | { | ||
1000 | kfree(bo); | ||
1001 | } | ||
1002 | |||
1003 | /** | 812 | /** |
1004 | * find_bd_holder - find matching struct bd_holder from the block device | 813 | * bd_link_disk_holder - create symlinks between holding disk and slave bdev |
814 | * @bdev: the claimed slave bdev | ||
815 | * @disk: the holding disk | ||
1005 | * | 816 | * |
1006 | * @bdev: struct block device to be searched | 817 | * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT. |
1007 | * @bo: target struct bd_holder | ||
1008 | * | 818 | * |
1009 | * Returns matching entry with @bo in @bdev->bd_holder_list. | 819 | * This functions creates the following sysfs symlinks. |
1010 | * If found, increment the reference count and return the pointer. | 820 | * |
1011 | * If not found, returns NULL. | 821 | * - from "slaves" directory of the holder @disk to the claimed @bdev |
1012 | */ | 822 | * - from "holders" directory of the @bdev to the holder @disk |
1013 | static struct bd_holder *find_bd_holder(struct block_device *bdev, | 823 | * |
1014 | struct bd_holder *bo) | 824 | * For example, if /dev/dm-0 maps to /dev/sda and disk for dm-0 is |
1015 | { | 825 | * passed to bd_link_disk_holder(), then: |
1016 | struct bd_holder *tmp; | ||
1017 | |||
1018 | list_for_each_entry(tmp, &bdev->bd_holder_list, list) | ||
1019 | if (tmp->sdir == bo->sdir) { | ||
1020 | tmp->count++; | ||
1021 | return tmp; | ||
1022 | } | ||
1023 | |||
1024 | return NULL; | ||
1025 | } | ||
1026 | |||
1027 | /** | ||
1028 | * add_bd_holder - create sysfs symlinks for bd_claim() relationship | ||
1029 | * | 826 | * |
1030 | * @bdev: block device to be bd_claimed | 827 | * /sys/block/dm-0/slaves/sda --> /sys/block/sda |
1031 | * @bo: preallocated and initialized by alloc_bd_holder() | 828 | * /sys/block/sda/holders/dm-0 --> /sys/block/dm-0 |
1032 | * | 829 | * |
1033 | * Add @bo to @bdev->bd_holder_list, create symlinks. | 830 | * The caller must have claimed @bdev before calling this function and |
831 | * ensure that both @bdev and @disk are valid during the creation and | ||
832 | * lifetime of these symlinks. | ||
1034 | * | 833 | * |
1035 | * Returns 0 if symlinks are created. | 834 | * CONTEXT: |
1036 | * Returns -ve if something fails. | 835 | * Might sleep. |
836 | * | ||
837 | * RETURNS: | ||
838 | * 0 on success, -errno on failure. | ||
1037 | */ | 839 | */ |
1038 | static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo) | 840 | int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk) |
1039 | { | 841 | { |
1040 | int err; | 842 | struct bd_holder_disk *holder; |
843 | int ret = 0; | ||
1041 | 844 | ||
1042 | if (!bo) | 845 | mutex_lock(&bdev->bd_mutex); |
1043 | return -EINVAL; | ||
1044 | 846 | ||
1045 | if (!bd_holder_grab_dirs(bdev, bo)) | 847 | WARN_ON_ONCE(!bdev->bd_holder); |
1046 | return -EBUSY; | ||
1047 | 848 | ||
1048 | err = add_symlink(bo->sdir, bo->sdev); | 849 | /* FIXME: remove the following once add_disk() handles errors */ |
1049 | if (err) | 850 | if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir)) |
1050 | return err; | 851 | goto out_unlock; |
1051 | 852 | ||
1052 | err = add_symlink(bo->hdir, bo->hdev); | 853 | holder = bd_find_holder_disk(bdev, disk); |
1053 | if (err) { | 854 | if (holder) { |
1054 | del_symlink(bo->sdir, bo->sdev); | 855 | holder->refcnt++; |
1055 | return err; | 856 | goto out_unlock; |
1056 | } | 857 | } |
1057 | 858 | ||
1058 | list_add_tail(&bo->list, &bdev->bd_holder_list); | 859 | holder = kzalloc(sizeof(*holder), GFP_KERNEL); |
1059 | return 0; | 860 | if (!holder) { |
1060 | } | 861 | ret = -ENOMEM; |
1061 | 862 | goto out_unlock; | |
1062 | /** | ||
1063 | * del_bd_holder - delete sysfs symlinks for bd_claim() relationship | ||
1064 | * | ||
1065 | * @bdev: block device to be bd_claimed | ||
1066 | * @kobj: holder's kobject | ||
1067 | * | ||
1068 | * If there is matching entry with @kobj in @bdev->bd_holder_list | ||
1069 | * and no other bd_claim() from the same kobject, | ||
1070 | * remove the struct bd_holder from the list, delete symlinks for it. | ||
1071 | * | ||
1072 | * Returns a pointer to the struct bd_holder when it's removed from the list | ||
1073 | * and ready to be freed. | ||
1074 | * Returns NULL if matching claim isn't found or there is other bd_claim() | ||
1075 | * by the same kobject. | ||
1076 | */ | ||
1077 | static struct bd_holder *del_bd_holder(struct block_device *bdev, | ||
1078 | struct kobject *kobj) | ||
1079 | { | ||
1080 | struct bd_holder *bo; | ||
1081 | |||
1082 | list_for_each_entry(bo, &bdev->bd_holder_list, list) { | ||
1083 | if (bo->sdir == kobj) { | ||
1084 | bo->count--; | ||
1085 | BUG_ON(bo->count < 0); | ||
1086 | if (!bo->count) { | ||
1087 | list_del(&bo->list); | ||
1088 | del_symlink(bo->sdir, bo->sdev); | ||
1089 | del_symlink(bo->hdir, bo->hdev); | ||
1090 | bd_holder_release_dirs(bo); | ||
1091 | return bo; | ||
1092 | } | ||
1093 | break; | ||
1094 | } | ||
1095 | } | 863 | } |
1096 | 864 | ||
1097 | return NULL; | 865 | INIT_LIST_HEAD(&holder->list); |
1098 | } | 866 | holder->disk = disk; |
1099 | 867 | holder->refcnt = 1; | |
1100 | /** | ||
1101 | * bd_claim_by_kobject - bd_claim() with additional kobject signature | ||
1102 | * | ||
1103 | * @bdev: block device to be claimed | ||
1104 | * @holder: holder's signature | ||
1105 | * @kobj: holder's kobject | ||
1106 | * | ||
1107 | * Do bd_claim() and if it succeeds, create sysfs symlinks between | ||
1108 | * the bdev and the holder's kobject. | ||
1109 | * Use bd_release_from_kobject() when relesing the claimed bdev. | ||
1110 | * | ||
1111 | * Returns 0 on success. (same as bd_claim()) | ||
1112 | * Returns errno on failure. | ||
1113 | */ | ||
1114 | static int bd_claim_by_kobject(struct block_device *bdev, void *holder, | ||
1115 | struct kobject *kobj) | ||
1116 | { | ||
1117 | int err; | ||
1118 | struct bd_holder *bo, *found; | ||
1119 | |||
1120 | if (!kobj) | ||
1121 | return -EINVAL; | ||
1122 | |||
1123 | bo = alloc_bd_holder(kobj); | ||
1124 | if (!bo) | ||
1125 | return -ENOMEM; | ||
1126 | 868 | ||
1127 | mutex_lock(&bdev->bd_mutex); | 869 | ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); |
870 | if (ret) | ||
871 | goto out_free; | ||
1128 | 872 | ||
1129 | err = bd_claim(bdev, holder); | 873 | ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); |
1130 | if (err) | 874 | if (ret) |
1131 | goto fail; | 875 | goto out_del; |
1132 | 876 | ||
1133 | found = find_bd_holder(bdev, bo); | 877 | list_add(&holder->list, &bdev->bd_holder_disks); |
1134 | if (found) | 878 | goto out_unlock; |
1135 | goto fail; | ||
1136 | 879 | ||
1137 | err = add_bd_holder(bdev, bo); | 880 | out_del: |
1138 | if (err) | 881 | del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); |
1139 | bd_release(bdev); | 882 | out_free: |
1140 | else | 883 | kfree(holder); |
1141 | bo = NULL; | 884 | out_unlock: |
1142 | fail: | ||
1143 | mutex_unlock(&bdev->bd_mutex); | 885 | mutex_unlock(&bdev->bd_mutex); |
1144 | free_bd_holder(bo); | 886 | return ret; |
1145 | return err; | ||
1146 | } | 887 | } |
888 | EXPORT_SYMBOL_GPL(bd_link_disk_holder); | ||
1147 | 889 | ||
1148 | /** | 890 | /** |
1149 | * bd_release_from_kobject - bd_release() with additional kobject signature | 891 | * bd_unlink_disk_holder - destroy symlinks created by bd_link_disk_holder() |
892 | * @bdev: the calimed slave bdev | ||
893 | * @disk: the holding disk | ||
1150 | * | 894 | * |
1151 | * @bdev: block device to be released | 895 | * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT. |
1152 | * @kobj: holder's kobject | ||
1153 | * | 896 | * |
1154 | * Do bd_release() and remove sysfs symlinks created by bd_claim_by_kobject(). | 897 | * CONTEXT: |
898 | * Might sleep. | ||
1155 | */ | 899 | */ |
1156 | static void bd_release_from_kobject(struct block_device *bdev, | 900 | void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk) |
1157 | struct kobject *kobj) | ||
1158 | { | 901 | { |
1159 | if (!kobj) | 902 | struct bd_holder_disk *holder; |
1160 | return; | ||
1161 | 903 | ||
1162 | mutex_lock(&bdev->bd_mutex); | 904 | mutex_lock(&bdev->bd_mutex); |
1163 | bd_release(bdev); | ||
1164 | free_bd_holder(del_bd_holder(bdev, kobj)); | ||
1165 | mutex_unlock(&bdev->bd_mutex); | ||
1166 | } | ||
1167 | 905 | ||
1168 | /** | 906 | holder = bd_find_holder_disk(bdev, disk); |
1169 | * bd_claim_by_disk - wrapper function for bd_claim_by_kobject() | ||
1170 | * | ||
1171 | * @bdev: block device to be claimed | ||
1172 | * @holder: holder's signature | ||
1173 | * @disk: holder's gendisk | ||
1174 | * | ||
1175 | * Call bd_claim_by_kobject() with getting @disk->slave_dir. | ||
1176 | */ | ||
1177 | int bd_claim_by_disk(struct block_device *bdev, void *holder, | ||
1178 | struct gendisk *disk) | ||
1179 | { | ||
1180 | return bd_claim_by_kobject(bdev, holder, kobject_get(disk->slave_dir)); | ||
1181 | } | ||
1182 | EXPORT_SYMBOL_GPL(bd_claim_by_disk); | ||
1183 | 907 | ||
1184 | /** | 908 | if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) { |
1185 | * bd_release_from_disk - wrapper function for bd_release_from_kobject() | 909 | del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); |
1186 | * | 910 | del_symlink(bdev->bd_part->holder_dir, |
1187 | * @bdev: block device to be claimed | 911 | &disk_to_dev(disk)->kobj); |
1188 | * @disk: holder's gendisk | 912 | list_del_init(&holder->list); |
1189 | * | 913 | kfree(holder); |
1190 | * Call bd_release_from_kobject() and put @disk->slave_dir. | 914 | } |
1191 | */ | ||
1192 | void bd_release_from_disk(struct block_device *bdev, struct gendisk *disk) | ||
1193 | { | ||
1194 | bd_release_from_kobject(bdev, disk->slave_dir); | ||
1195 | kobject_put(disk->slave_dir); | ||
1196 | } | ||
1197 | EXPORT_SYMBOL_GPL(bd_release_from_disk); | ||
1198 | #endif | ||
1199 | 915 | ||
1200 | /* | 916 | mutex_unlock(&bdev->bd_mutex); |
1201 | * Tries to open block device by device number. Use it ONLY if you | ||
1202 | * really do not have anything better - i.e. when you are behind a | ||
1203 | * truly sucky interface and all you are given is a device number. _Never_ | ||
1204 | * to be used for internal purposes. If you ever need it - reconsider | ||
1205 | * your API. | ||
1206 | */ | ||
1207 | struct block_device *open_by_devnum(dev_t dev, fmode_t mode) | ||
1208 | { | ||
1209 | struct block_device *bdev = bdget(dev); | ||
1210 | int err = -ENOMEM; | ||
1211 | if (bdev) | ||
1212 | err = blkdev_get(bdev, mode); | ||
1213 | return err ? ERR_PTR(err) : bdev; | ||
1214 | } | 917 | } |
1215 | 918 | EXPORT_SYMBOL_GPL(bd_unlink_disk_holder); | |
1216 | EXPORT_SYMBOL(open_by_devnum); | 919 | #endif |
1217 | 920 | ||
1218 | /** | 921 | /** |
1219 | * flush_disk - invalidates all buffer-cache entries on a disk | 922 | * flush_disk - invalidates all buffer-cache entries on a disk |
@@ -1309,10 +1012,11 @@ int check_disk_change(struct block_device *bdev) | |||
1309 | { | 1012 | { |
1310 | struct gendisk *disk = bdev->bd_disk; | 1013 | struct gendisk *disk = bdev->bd_disk; |
1311 | const struct block_device_operations *bdops = disk->fops; | 1014 | const struct block_device_operations *bdops = disk->fops; |
1015 | unsigned int events; | ||
1312 | 1016 | ||
1313 | if (!bdops->media_changed) | 1017 | events = disk_clear_events(disk, DISK_EVENT_MEDIA_CHANGE | |
1314 | return 0; | 1018 | DISK_EVENT_EJECT_REQUEST); |
1315 | if (!bdops->media_changed(bdev->bd_disk)) | 1019 | if (!(events & DISK_EVENT_MEDIA_CHANGE)) |
1316 | return 0; | 1020 | return 0; |
1317 | 1021 | ||
1318 | flush_disk(bdev); | 1022 | flush_disk(bdev); |
@@ -1475,17 +1179,171 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | |||
1475 | return ret; | 1179 | return ret; |
1476 | } | 1180 | } |
1477 | 1181 | ||
1478 | int blkdev_get(struct block_device *bdev, fmode_t mode) | 1182 | /** |
1183 | * blkdev_get - open a block device | ||
1184 | * @bdev: block_device to open | ||
1185 | * @mode: FMODE_* mask | ||
1186 | * @holder: exclusive holder identifier | ||
1187 | * | ||
1188 | * Open @bdev with @mode. If @mode includes %FMODE_EXCL, @bdev is | ||
1189 | * open with exclusive access. Specifying %FMODE_EXCL with %NULL | ||
1190 | * @holder is invalid. Exclusive opens may nest for the same @holder. | ||
1191 | * | ||
1192 | * On success, the reference count of @bdev is unchanged. On failure, | ||
1193 | * @bdev is put. | ||
1194 | * | ||
1195 | * CONTEXT: | ||
1196 | * Might sleep. | ||
1197 | * | ||
1198 | * RETURNS: | ||
1199 | * 0 on success, -errno on failure. | ||
1200 | */ | ||
1201 | int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder) | ||
1479 | { | 1202 | { |
1480 | return __blkdev_get(bdev, mode, 0); | 1203 | struct block_device *whole = NULL; |
1204 | int res; | ||
1205 | |||
1206 | WARN_ON_ONCE((mode & FMODE_EXCL) && !holder); | ||
1207 | |||
1208 | if ((mode & FMODE_EXCL) && holder) { | ||
1209 | whole = bd_start_claiming(bdev, holder); | ||
1210 | if (IS_ERR(whole)) { | ||
1211 | bdput(bdev); | ||
1212 | return PTR_ERR(whole); | ||
1213 | } | ||
1214 | } | ||
1215 | |||
1216 | res = __blkdev_get(bdev, mode, 0); | ||
1217 | |||
1218 | /* __blkdev_get() may alter read only status, check it afterwards */ | ||
1219 | if (!res && (mode & FMODE_WRITE) && bdev_read_only(bdev)) { | ||
1220 | __blkdev_put(bdev, mode, 0); | ||
1221 | res = -EACCES; | ||
1222 | } | ||
1223 | |||
1224 | if (whole) { | ||
1225 | /* finish claiming */ | ||
1226 | mutex_lock(&bdev->bd_mutex); | ||
1227 | spin_lock(&bdev_lock); | ||
1228 | |||
1229 | if (!res) { | ||
1230 | BUG_ON(!bd_may_claim(bdev, whole, holder)); | ||
1231 | /* | ||
1232 | * Note that for a whole device bd_holders | ||
1233 | * will be incremented twice, and bd_holder | ||
1234 | * will be set to bd_may_claim before being | ||
1235 | * set to holder | ||
1236 | */ | ||
1237 | whole->bd_holders++; | ||
1238 | whole->bd_holder = bd_may_claim; | ||
1239 | bdev->bd_holders++; | ||
1240 | bdev->bd_holder = holder; | ||
1241 | } | ||
1242 | |||
1243 | /* tell others that we're done */ | ||
1244 | BUG_ON(whole->bd_claiming != holder); | ||
1245 | whole->bd_claiming = NULL; | ||
1246 | wake_up_bit(&whole->bd_claiming, 0); | ||
1247 | |||
1248 | spin_unlock(&bdev_lock); | ||
1249 | |||
1250 | /* | ||
1251 | * Block event polling for write claims. Any write | ||
1252 | * holder makes the write_holder state stick until all | ||
1253 | * are released. This is good enough and tracking | ||
1254 | * individual writeable reference is too fragile given | ||
1255 | * the way @mode is used in blkdev_get/put(). | ||
1256 | */ | ||
1257 | if (!res && (mode & FMODE_WRITE) && !bdev->bd_write_holder) { | ||
1258 | bdev->bd_write_holder = true; | ||
1259 | disk_block_events(bdev->bd_disk); | ||
1260 | } | ||
1261 | |||
1262 | mutex_unlock(&bdev->bd_mutex); | ||
1263 | bdput(whole); | ||
1264 | } | ||
1265 | |||
1266 | return res; | ||
1481 | } | 1267 | } |
1482 | EXPORT_SYMBOL(blkdev_get); | 1268 | EXPORT_SYMBOL(blkdev_get); |
1483 | 1269 | ||
1270 | /** | ||
1271 | * blkdev_get_by_path - open a block device by name | ||
1272 | * @path: path to the block device to open | ||
1273 | * @mode: FMODE_* mask | ||
1274 | * @holder: exclusive holder identifier | ||
1275 | * | ||
1276 | * Open the blockdevice described by the device file at @path. @mode | ||
1277 | * and @holder are identical to blkdev_get(). | ||
1278 | * | ||
1279 | * On success, the returned block_device has reference count of one. | ||
1280 | * | ||
1281 | * CONTEXT: | ||
1282 | * Might sleep. | ||
1283 | * | ||
1284 | * RETURNS: | ||
1285 | * Pointer to block_device on success, ERR_PTR(-errno) on failure. | ||
1286 | */ | ||
1287 | struct block_device *blkdev_get_by_path(const char *path, fmode_t mode, | ||
1288 | void *holder) | ||
1289 | { | ||
1290 | struct block_device *bdev; | ||
1291 | int err; | ||
1292 | |||
1293 | bdev = lookup_bdev(path); | ||
1294 | if (IS_ERR(bdev)) | ||
1295 | return bdev; | ||
1296 | |||
1297 | err = blkdev_get(bdev, mode, holder); | ||
1298 | if (err) | ||
1299 | return ERR_PTR(err); | ||
1300 | |||
1301 | return bdev; | ||
1302 | } | ||
1303 | EXPORT_SYMBOL(blkdev_get_by_path); | ||
1304 | |||
1305 | /** | ||
1306 | * blkdev_get_by_dev - open a block device by device number | ||
1307 | * @dev: device number of block device to open | ||
1308 | * @mode: FMODE_* mask | ||
1309 | * @holder: exclusive holder identifier | ||
1310 | * | ||
1311 | * Open the blockdevice described by device number @dev. @mode and | ||
1312 | * @holder are identical to blkdev_get(). | ||
1313 | * | ||
1314 | * Use it ONLY if you really do not have anything better - i.e. when | ||
1315 | * you are behind a truly sucky interface and all you are given is a | ||
1316 | * device number. _Never_ to be used for internal purposes. If you | ||
1317 | * ever need it - reconsider your API. | ||
1318 | * | ||
1319 | * On success, the returned block_device has reference count of one. | ||
1320 | * | ||
1321 | * CONTEXT: | ||
1322 | * Might sleep. | ||
1323 | * | ||
1324 | * RETURNS: | ||
1325 | * Pointer to block_device on success, ERR_PTR(-errno) on failure. | ||
1326 | */ | ||
1327 | struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder) | ||
1328 | { | ||
1329 | struct block_device *bdev; | ||
1330 | int err; | ||
1331 | |||
1332 | bdev = bdget(dev); | ||
1333 | if (!bdev) | ||
1334 | return ERR_PTR(-ENOMEM); | ||
1335 | |||
1336 | err = blkdev_get(bdev, mode, holder); | ||
1337 | if (err) | ||
1338 | return ERR_PTR(err); | ||
1339 | |||
1340 | return bdev; | ||
1341 | } | ||
1342 | EXPORT_SYMBOL(blkdev_get_by_dev); | ||
1343 | |||
1484 | static int blkdev_open(struct inode * inode, struct file * filp) | 1344 | static int blkdev_open(struct inode * inode, struct file * filp) |
1485 | { | 1345 | { |
1486 | struct block_device *whole = NULL; | ||
1487 | struct block_device *bdev; | 1346 | struct block_device *bdev; |
1488 | int res; | ||
1489 | 1347 | ||
1490 | /* | 1348 | /* |
1491 | * Preserve backwards compatibility and allow large file access | 1349 | * Preserve backwards compatibility and allow large file access |
@@ -1506,26 +1364,9 @@ static int blkdev_open(struct inode * inode, struct file * filp) | |||
1506 | if (bdev == NULL) | 1364 | if (bdev == NULL) |
1507 | return -ENOMEM; | 1365 | return -ENOMEM; |
1508 | 1366 | ||
1509 | if (filp->f_mode & FMODE_EXCL) { | ||
1510 | whole = bd_start_claiming(bdev, filp); | ||
1511 | if (IS_ERR(whole)) { | ||
1512 | bdput(bdev); | ||
1513 | return PTR_ERR(whole); | ||
1514 | } | ||
1515 | } | ||
1516 | |||
1517 | filp->f_mapping = bdev->bd_inode->i_mapping; | 1367 | filp->f_mapping = bdev->bd_inode->i_mapping; |
1518 | 1368 | ||
1519 | res = blkdev_get(bdev, filp->f_mode); | 1369 | return blkdev_get(bdev, filp->f_mode, filp); |
1520 | |||
1521 | if (whole) { | ||
1522 | if (res == 0) | ||
1523 | bd_finish_claiming(bdev, whole, filp); | ||
1524 | else | ||
1525 | bd_abort_claiming(whole, filp); | ||
1526 | } | ||
1527 | |||
1528 | return res; | ||
1529 | } | 1370 | } |
1530 | 1371 | ||
1531 | static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) | 1372 | static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) |
@@ -1539,6 +1380,7 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) | |||
1539 | bdev->bd_part_count--; | 1380 | bdev->bd_part_count--; |
1540 | 1381 | ||
1541 | if (!--bdev->bd_openers) { | 1382 | if (!--bdev->bd_openers) { |
1383 | WARN_ON_ONCE(bdev->bd_holders); | ||
1542 | sync_blockdev(bdev); | 1384 | sync_blockdev(bdev); |
1543 | kill_bdev(bdev); | 1385 | kill_bdev(bdev); |
1544 | } | 1386 | } |
@@ -1569,6 +1411,44 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) | |||
1569 | 1411 | ||
1570 | int blkdev_put(struct block_device *bdev, fmode_t mode) | 1412 | int blkdev_put(struct block_device *bdev, fmode_t mode) |
1571 | { | 1413 | { |
1414 | if (mode & FMODE_EXCL) { | ||
1415 | bool bdev_free; | ||
1416 | |||
1417 | /* | ||
1418 | * Release a claim on the device. The holder fields | ||
1419 | * are protected with bdev_lock. bd_mutex is to | ||
1420 | * synchronize disk_holder unlinking. | ||
1421 | */ | ||
1422 | mutex_lock(&bdev->bd_mutex); | ||
1423 | spin_lock(&bdev_lock); | ||
1424 | |||
1425 | WARN_ON_ONCE(--bdev->bd_holders < 0); | ||
1426 | WARN_ON_ONCE(--bdev->bd_contains->bd_holders < 0); | ||
1427 | |||
1428 | /* bd_contains might point to self, check in a separate step */ | ||
1429 | if ((bdev_free = !bdev->bd_holders)) | ||
1430 | bdev->bd_holder = NULL; | ||
1431 | if (!bdev->bd_contains->bd_holders) | ||
1432 | bdev->bd_contains->bd_holder = NULL; | ||
1433 | |||
1434 | spin_unlock(&bdev_lock); | ||
1435 | |||
1436 | /* | ||
1437 | * If this was the last claim, remove holder link and | ||
1438 | * unblock evpoll if it was a write holder. | ||
1439 | */ | ||
1440 | if (bdev_free) { | ||
1441 | if (bdev->bd_write_holder) { | ||
1442 | disk_unblock_events(bdev->bd_disk); | ||
1443 | bdev->bd_write_holder = false; | ||
1444 | } else | ||
1445 | disk_check_events(bdev->bd_disk); | ||
1446 | } | ||
1447 | |||
1448 | mutex_unlock(&bdev->bd_mutex); | ||
1449 | } else | ||
1450 | disk_check_events(bdev->bd_disk); | ||
1451 | |||
1572 | return __blkdev_put(bdev, mode, 0); | 1452 | return __blkdev_put(bdev, mode, 0); |
1573 | } | 1453 | } |
1574 | EXPORT_SYMBOL(blkdev_put); | 1454 | EXPORT_SYMBOL(blkdev_put); |
@@ -1576,8 +1456,7 @@ EXPORT_SYMBOL(blkdev_put); | |||
1576 | static int blkdev_close(struct inode * inode, struct file * filp) | 1456 | static int blkdev_close(struct inode * inode, struct file * filp) |
1577 | { | 1457 | { |
1578 | struct block_device *bdev = I_BDEV(filp->f_mapping->host); | 1458 | struct block_device *bdev = I_BDEV(filp->f_mapping->host); |
1579 | if (bdev->bd_holder == filp) | 1459 | |
1580 | bd_release(bdev); | ||
1581 | return blkdev_put(bdev, filp->f_mode); | 1460 | return blkdev_put(bdev, filp->f_mode); |
1582 | } | 1461 | } |
1583 | 1462 | ||
@@ -1722,67 +1601,6 @@ fail: | |||
1722 | } | 1601 | } |
1723 | EXPORT_SYMBOL(lookup_bdev); | 1602 | EXPORT_SYMBOL(lookup_bdev); |
1724 | 1603 | ||
1725 | /** | ||
1726 | * open_bdev_exclusive - open a block device by name and set it up for use | ||
1727 | * | ||
1728 | * @path: special file representing the block device | ||
1729 | * @mode: FMODE_... combination to pass be used | ||
1730 | * @holder: owner for exclusion | ||
1731 | * | ||
1732 | * Open the blockdevice described by the special file at @path, claim it | ||
1733 | * for the @holder. | ||
1734 | */ | ||
1735 | struct block_device *open_bdev_exclusive(const char *path, fmode_t mode, void *holder) | ||
1736 | { | ||
1737 | struct block_device *bdev, *whole; | ||
1738 | int error; | ||
1739 | |||
1740 | bdev = lookup_bdev(path); | ||
1741 | if (IS_ERR(bdev)) | ||
1742 | return bdev; | ||
1743 | |||
1744 | whole = bd_start_claiming(bdev, holder); | ||
1745 | if (IS_ERR(whole)) { | ||
1746 | bdput(bdev); | ||
1747 | return whole; | ||
1748 | } | ||
1749 | |||
1750 | error = blkdev_get(bdev, mode); | ||
1751 | if (error) | ||
1752 | goto out_abort_claiming; | ||
1753 | |||
1754 | error = -EACCES; | ||
1755 | if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) | ||
1756 | goto out_blkdev_put; | ||
1757 | |||
1758 | bd_finish_claiming(bdev, whole, holder); | ||
1759 | return bdev; | ||
1760 | |||
1761 | out_blkdev_put: | ||
1762 | blkdev_put(bdev, mode); | ||
1763 | out_abort_claiming: | ||
1764 | bd_abort_claiming(whole, holder); | ||
1765 | return ERR_PTR(error); | ||
1766 | } | ||
1767 | |||
1768 | EXPORT_SYMBOL(open_bdev_exclusive); | ||
1769 | |||
1770 | /** | ||
1771 | * close_bdev_exclusive - close a blockdevice opened by open_bdev_exclusive() | ||
1772 | * | ||
1773 | * @bdev: blockdevice to close | ||
1774 | * @mode: mode, must match that used to open. | ||
1775 | * | ||
1776 | * This is the counterpart to open_bdev_exclusive(). | ||
1777 | */ | ||
1778 | void close_bdev_exclusive(struct block_device *bdev, fmode_t mode) | ||
1779 | { | ||
1780 | bd_release(bdev); | ||
1781 | blkdev_put(bdev, mode); | ||
1782 | } | ||
1783 | |||
1784 | EXPORT_SYMBOL(close_bdev_exclusive); | ||
1785 | |||
1786 | int __invalidate_device(struct block_device *bdev) | 1604 | int __invalidate_device(struct block_device *bdev) |
1787 | { | 1605 | { |
1788 | struct super_block *sb = get_super(bdev); | 1606 | struct super_block *sb = get_super(bdev); |