diff options
author | Ingo Molnar <mingo@elte.hu> | 2006-07-03 03:25:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-07-03 18:27:10 -0400 |
commit | 663d440eaa496db903cc58be04b9b602ba45e43b (patch) | |
tree | 8af6967e175693f1c163a106a1d84be7a1bd0bfc /fs | |
parent | 2b2d5493e10051694ae3a57ea6a153e3cb4d4488 (diff) |
[PATCH] lockdep: annotate blkdev nesting
Teach special (recursive) locking code to the lock validator.
Effects on non-lockdep kernels:
- the introduction of the following function variants:
extern struct block_device *open_partition_by_devnum(dev_t, unsigned);
extern int blkdev_put_partition(struct block_device *);
static int
blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags);
which on non-lockdep are the same as open_by_devnum(), blkdev_put()
and blkdev_get().
- a subclass parameter to do_open(). [unused on non-lockdep]
- a subclass parameter to __blkdev_put(), which is a new internal
function for the main blkdev_put*() functions. [parameter unused
on non-lockdep kernels, except for two sanity check WARN_ON()s]
these functions carry no semantical difference - they only express
object dependencies towards the lockdep subsystem.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Cc: Neil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/block_dev.c | 102 |
1 files changed, 87 insertions, 15 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 9633a490dab0..37534573960b 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -739,7 +739,7 @@ static int bd_claim_by_kobject(struct block_device *bdev, void *holder, | |||
739 | if (!bo) | 739 | if (!bo) |
740 | return -ENOMEM; | 740 | return -ENOMEM; |
741 | 741 | ||
742 | mutex_lock(&bdev->bd_mutex); | 742 | mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION); |
743 | res = bd_claim(bdev, holder); | 743 | res = bd_claim(bdev, holder); |
744 | if (res || !add_bd_holder(bdev, bo)) | 744 | if (res || !add_bd_holder(bdev, bo)) |
745 | free_bd_holder(bo); | 745 | free_bd_holder(bo); |
@@ -764,7 +764,7 @@ static void bd_release_from_kobject(struct block_device *bdev, | |||
764 | if (!kobj) | 764 | if (!kobj) |
765 | return; | 765 | return; |
766 | 766 | ||
767 | mutex_lock(&bdev->bd_mutex); | 767 | mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION); |
768 | bd_release(bdev); | 768 | bd_release(bdev); |
769 | if ((bo = del_bd_holder(bdev, kobj))) | 769 | if ((bo = del_bd_holder(bdev, kobj))) |
770 | free_bd_holder(bo); | 770 | free_bd_holder(bo); |
@@ -822,6 +822,22 @@ struct block_device *open_by_devnum(dev_t dev, unsigned mode) | |||
822 | 822 | ||
823 | EXPORT_SYMBOL(open_by_devnum); | 823 | EXPORT_SYMBOL(open_by_devnum); |
824 | 824 | ||
825 | static int | ||
826 | blkdev_get_partition(struct block_device *bdev, mode_t mode, unsigned flags); | ||
827 | |||
828 | struct block_device *open_partition_by_devnum(dev_t dev, unsigned mode) | ||
829 | { | ||
830 | struct block_device *bdev = bdget(dev); | ||
831 | int err = -ENOMEM; | ||
832 | int flags = mode & FMODE_WRITE ? O_RDWR : O_RDONLY; | ||
833 | if (bdev) | ||
834 | err = blkdev_get_partition(bdev, mode, flags); | ||
835 | return err ? ERR_PTR(err) : bdev; | ||
836 | } | ||
837 | |||
838 | EXPORT_SYMBOL(open_partition_by_devnum); | ||
839 | |||
840 | |||
825 | /* | 841 | /* |
826 | * This routine checks whether a removable media has been changed, | 842 | * This routine checks whether a removable media has been changed, |
827 | * and invalidates all buffer-cache-entries in that case. This | 843 | * and invalidates all buffer-cache-entries in that case. This |
@@ -868,7 +884,11 @@ void bd_set_size(struct block_device *bdev, loff_t size) | |||
868 | } | 884 | } |
869 | EXPORT_SYMBOL(bd_set_size); | 885 | EXPORT_SYMBOL(bd_set_size); |
870 | 886 | ||
871 | static int do_open(struct block_device *bdev, struct file *file) | 887 | static int |
888 | blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags); | ||
889 | |||
890 | static int | ||
891 | do_open(struct block_device *bdev, struct file *file, unsigned int subclass) | ||
872 | { | 892 | { |
873 | struct module *owner = NULL; | 893 | struct module *owner = NULL; |
874 | struct gendisk *disk; | 894 | struct gendisk *disk; |
@@ -885,7 +905,8 @@ static int do_open(struct block_device *bdev, struct file *file) | |||
885 | } | 905 | } |
886 | owner = disk->fops->owner; | 906 | owner = disk->fops->owner; |
887 | 907 | ||
888 | mutex_lock(&bdev->bd_mutex); | 908 | mutex_lock_nested(&bdev->bd_mutex, subclass); |
909 | |||
889 | if (!bdev->bd_openers) { | 910 | if (!bdev->bd_openers) { |
890 | bdev->bd_disk = disk; | 911 | bdev->bd_disk = disk; |
891 | bdev->bd_contains = bdev; | 912 | bdev->bd_contains = bdev; |
@@ -912,11 +933,11 @@ static int do_open(struct block_device *bdev, struct file *file) | |||
912 | ret = -ENOMEM; | 933 | ret = -ENOMEM; |
913 | if (!whole) | 934 | if (!whole) |
914 | goto out_first; | 935 | goto out_first; |
915 | ret = blkdev_get(whole, file->f_mode, file->f_flags); | 936 | ret = blkdev_get_whole(whole, file->f_mode, file->f_flags); |
916 | if (ret) | 937 | if (ret) |
917 | goto out_first; | 938 | goto out_first; |
918 | bdev->bd_contains = whole; | 939 | bdev->bd_contains = whole; |
919 | mutex_lock(&whole->bd_mutex); | 940 | mutex_lock_nested(&whole->bd_mutex, BD_MUTEX_WHOLE); |
920 | whole->bd_part_count++; | 941 | whole->bd_part_count++; |
921 | p = disk->part[part - 1]; | 942 | p = disk->part[part - 1]; |
922 | bdev->bd_inode->i_data.backing_dev_info = | 943 | bdev->bd_inode->i_data.backing_dev_info = |
@@ -944,7 +965,8 @@ static int do_open(struct block_device *bdev, struct file *file) | |||
944 | if (bdev->bd_invalidated) | 965 | if (bdev->bd_invalidated) |
945 | rescan_partitions(bdev->bd_disk, bdev); | 966 | rescan_partitions(bdev->bd_disk, bdev); |
946 | } else { | 967 | } else { |
947 | mutex_lock(&bdev->bd_contains->bd_mutex); | 968 | mutex_lock_nested(&bdev->bd_contains->bd_mutex, |
969 | BD_MUTEX_PARTITION); | ||
948 | bdev->bd_contains->bd_part_count++; | 970 | bdev->bd_contains->bd_part_count++; |
949 | mutex_unlock(&bdev->bd_contains->bd_mutex); | 971 | mutex_unlock(&bdev->bd_contains->bd_mutex); |
950 | } | 972 | } |
@@ -985,11 +1007,49 @@ int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags) | |||
985 | fake_file.f_dentry = &fake_dentry; | 1007 | fake_file.f_dentry = &fake_dentry; |
986 | fake_dentry.d_inode = bdev->bd_inode; | 1008 | fake_dentry.d_inode = bdev->bd_inode; |
987 | 1009 | ||
988 | return do_open(bdev, &fake_file); | 1010 | return do_open(bdev, &fake_file, BD_MUTEX_NORMAL); |
989 | } | 1011 | } |
990 | 1012 | ||
991 | EXPORT_SYMBOL(blkdev_get); | 1013 | EXPORT_SYMBOL(blkdev_get); |
992 | 1014 | ||
1015 | static int | ||
1016 | blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags) | ||
1017 | { | ||
1018 | /* | ||
1019 | * This crockload is due to bad choice of ->open() type. | ||
1020 | * It will go away. | ||
1021 | * For now, block device ->open() routine must _not_ | ||
1022 | * examine anything in 'inode' argument except ->i_rdev. | ||
1023 | */ | ||
1024 | struct file fake_file = {}; | ||
1025 | struct dentry fake_dentry = {}; | ||
1026 | fake_file.f_mode = mode; | ||
1027 | fake_file.f_flags = flags; | ||
1028 | fake_file.f_dentry = &fake_dentry; | ||
1029 | fake_dentry.d_inode = bdev->bd_inode; | ||
1030 | |||
1031 | return do_open(bdev, &fake_file, BD_MUTEX_WHOLE); | ||
1032 | } | ||
1033 | |||
1034 | static int | ||
1035 | blkdev_get_partition(struct block_device *bdev, mode_t mode, unsigned flags) | ||
1036 | { | ||
1037 | /* | ||
1038 | * This crockload is due to bad choice of ->open() type. | ||
1039 | * It will go away. | ||
1040 | * For now, block device ->open() routine must _not_ | ||
1041 | * examine anything in 'inode' argument except ->i_rdev. | ||
1042 | */ | ||
1043 | struct file fake_file = {}; | ||
1044 | struct dentry fake_dentry = {}; | ||
1045 | fake_file.f_mode = mode; | ||
1046 | fake_file.f_flags = flags; | ||
1047 | fake_file.f_dentry = &fake_dentry; | ||
1048 | fake_dentry.d_inode = bdev->bd_inode; | ||
1049 | |||
1050 | return do_open(bdev, &fake_file, BD_MUTEX_PARTITION); | ||
1051 | } | ||
1052 | |||
993 | static int blkdev_open(struct inode * inode, struct file * filp) | 1053 | static int blkdev_open(struct inode * inode, struct file * filp) |
994 | { | 1054 | { |
995 | struct block_device *bdev; | 1055 | struct block_device *bdev; |
@@ -1005,7 +1065,7 @@ static int blkdev_open(struct inode * inode, struct file * filp) | |||
1005 | 1065 | ||
1006 | bdev = bd_acquire(inode); | 1066 | bdev = bd_acquire(inode); |
1007 | 1067 | ||
1008 | res = do_open(bdev, filp); | 1068 | res = do_open(bdev, filp, BD_MUTEX_NORMAL); |
1009 | if (res) | 1069 | if (res) |
1010 | return res; | 1070 | return res; |
1011 | 1071 | ||
@@ -1019,13 +1079,13 @@ static int blkdev_open(struct inode * inode, struct file * filp) | |||
1019 | return res; | 1079 | return res; |
1020 | } | 1080 | } |
1021 | 1081 | ||
1022 | int blkdev_put(struct block_device *bdev) | 1082 | static int __blkdev_put(struct block_device *bdev, unsigned int subclass) |
1023 | { | 1083 | { |
1024 | int ret = 0; | 1084 | int ret = 0; |
1025 | struct inode *bd_inode = bdev->bd_inode; | 1085 | struct inode *bd_inode = bdev->bd_inode; |
1026 | struct gendisk *disk = bdev->bd_disk; | 1086 | struct gendisk *disk = bdev->bd_disk; |
1027 | 1087 | ||
1028 | mutex_lock(&bdev->bd_mutex); | 1088 | mutex_lock_nested(&bdev->bd_mutex, subclass); |
1029 | lock_kernel(); | 1089 | lock_kernel(); |
1030 | if (!--bdev->bd_openers) { | 1090 | if (!--bdev->bd_openers) { |
1031 | sync_blockdev(bdev); | 1091 | sync_blockdev(bdev); |
@@ -1035,7 +1095,8 @@ int blkdev_put(struct block_device *bdev) | |||
1035 | if (disk->fops->release) | 1095 | if (disk->fops->release) |
1036 | ret = disk->fops->release(bd_inode, NULL); | 1096 | ret = disk->fops->release(bd_inode, NULL); |
1037 | } else { | 1097 | } else { |
1038 | mutex_lock(&bdev->bd_contains->bd_mutex); | 1098 | mutex_lock_nested(&bdev->bd_contains->bd_mutex, |
1099 | subclass + 1); | ||
1039 | bdev->bd_contains->bd_part_count--; | 1100 | bdev->bd_contains->bd_part_count--; |
1040 | mutex_unlock(&bdev->bd_contains->bd_mutex); | 1101 | mutex_unlock(&bdev->bd_contains->bd_mutex); |
1041 | } | 1102 | } |
@@ -1051,9 +1112,8 @@ int blkdev_put(struct block_device *bdev) | |||
1051 | } | 1112 | } |
1052 | bdev->bd_disk = NULL; | 1113 | bdev->bd_disk = NULL; |
1053 | bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; | 1114 | bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; |
1054 | if (bdev != bdev->bd_contains) { | 1115 | if (bdev != bdev->bd_contains) |
1055 | blkdev_put(bdev->bd_contains); | 1116 | __blkdev_put(bdev->bd_contains, subclass + 1); |
1056 | } | ||
1057 | bdev->bd_contains = NULL; | 1117 | bdev->bd_contains = NULL; |
1058 | } | 1118 | } |
1059 | unlock_kernel(); | 1119 | unlock_kernel(); |
@@ -1062,8 +1122,20 @@ int blkdev_put(struct block_device *bdev) | |||
1062 | return ret; | 1122 | return ret; |
1063 | } | 1123 | } |
1064 | 1124 | ||
1125 | int blkdev_put(struct block_device *bdev) | ||
1126 | { | ||
1127 | return __blkdev_put(bdev, BD_MUTEX_NORMAL); | ||
1128 | } | ||
1129 | |||
1065 | EXPORT_SYMBOL(blkdev_put); | 1130 | EXPORT_SYMBOL(blkdev_put); |
1066 | 1131 | ||
1132 | int blkdev_put_partition(struct block_device *bdev) | ||
1133 | { | ||
1134 | return __blkdev_put(bdev, BD_MUTEX_PARTITION); | ||
1135 | } | ||
1136 | |||
1137 | EXPORT_SYMBOL(blkdev_put_partition); | ||
1138 | |||
1067 | static int blkdev_close(struct inode * inode, struct file * filp) | 1139 | static int blkdev_close(struct inode * inode, struct file * filp) |
1068 | { | 1140 | { |
1069 | struct block_device *bdev = I_BDEV(filp->f_mapping->host); | 1141 | struct block_device *bdev = I_BDEV(filp->f_mapping->host); |