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 | |
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>
-rw-r--r-- | drivers/md/md.c | 6 | ||||
-rw-r--r-- | fs/block_dev.c | 102 | ||||
-rw-r--r-- | include/linux/fs.h | 17 |
3 files changed, 107 insertions, 18 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index 2fe32c261922..e4e161372a3e 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -1404,7 +1404,7 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev) | |||
1404 | struct block_device *bdev; | 1404 | struct block_device *bdev; |
1405 | char b[BDEVNAME_SIZE]; | 1405 | char b[BDEVNAME_SIZE]; |
1406 | 1406 | ||
1407 | bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE); | 1407 | bdev = open_partition_by_devnum(dev, FMODE_READ|FMODE_WRITE); |
1408 | if (IS_ERR(bdev)) { | 1408 | if (IS_ERR(bdev)) { |
1409 | printk(KERN_ERR "md: could not open %s.\n", | 1409 | printk(KERN_ERR "md: could not open %s.\n", |
1410 | __bdevname(dev, b)); | 1410 | __bdevname(dev, b)); |
@@ -1414,7 +1414,7 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev) | |||
1414 | if (err) { | 1414 | if (err) { |
1415 | printk(KERN_ERR "md: could not bd_claim %s.\n", | 1415 | printk(KERN_ERR "md: could not bd_claim %s.\n", |
1416 | bdevname(bdev, b)); | 1416 | bdevname(bdev, b)); |
1417 | blkdev_put(bdev); | 1417 | blkdev_put_partition(bdev); |
1418 | return err; | 1418 | return err; |
1419 | } | 1419 | } |
1420 | rdev->bdev = bdev; | 1420 | rdev->bdev = bdev; |
@@ -1428,7 +1428,7 @@ static void unlock_rdev(mdk_rdev_t *rdev) | |||
1428 | if (!bdev) | 1428 | if (!bdev) |
1429 | MD_BUG(); | 1429 | MD_BUG(); |
1430 | bd_release(bdev); | 1430 | bd_release(bdev); |
1431 | blkdev_put(bdev); | 1431 | blkdev_put_partition(bdev); |
1432 | } | 1432 | } |
1433 | 1433 | ||
1434 | void md_autodetect_dev(dev_t dev); | 1434 | void md_autodetect_dev(dev_t dev); |
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); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index e26de68059af..134b32068246 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -436,6 +436,21 @@ struct block_device { | |||
436 | }; | 436 | }; |
437 | 437 | ||
438 | /* | 438 | /* |
439 | * bdev->bd_mutex nesting subclasses for the lock validator: | ||
440 | * | ||
441 | * 0: normal | ||
442 | * 1: 'whole' | ||
443 | * 2: 'partition' | ||
444 | */ | ||
445 | enum bdev_bd_mutex_lock_class | ||
446 | { | ||
447 | BD_MUTEX_NORMAL, | ||
448 | BD_MUTEX_WHOLE, | ||
449 | BD_MUTEX_PARTITION | ||
450 | }; | ||
451 | |||
452 | |||
453 | /* | ||
439 | * Radix-tree tags, for tagging dirty and writeback pages within the pagecache | 454 | * Radix-tree tags, for tagging dirty and writeback pages within the pagecache |
440 | * radix trees | 455 | * radix trees |
441 | */ | 456 | */ |
@@ -1425,6 +1440,7 @@ extern void bd_set_size(struct block_device *, loff_t size); | |||
1425 | extern void bd_forget(struct inode *inode); | 1440 | extern void bd_forget(struct inode *inode); |
1426 | extern void bdput(struct block_device *); | 1441 | extern void bdput(struct block_device *); |
1427 | extern struct block_device *open_by_devnum(dev_t, unsigned); | 1442 | extern struct block_device *open_by_devnum(dev_t, unsigned); |
1443 | extern struct block_device *open_partition_by_devnum(dev_t, unsigned); | ||
1428 | extern const struct file_operations def_blk_fops; | 1444 | extern const struct file_operations def_blk_fops; |
1429 | extern const struct address_space_operations def_blk_aops; | 1445 | extern const struct address_space_operations def_blk_aops; |
1430 | extern const struct file_operations def_chr_fops; | 1446 | extern const struct file_operations def_chr_fops; |
@@ -1435,6 +1451,7 @@ extern int blkdev_ioctl(struct inode *, struct file *, unsigned, unsigned long); | |||
1435 | extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long); | 1451 | extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long); |
1436 | extern int blkdev_get(struct block_device *, mode_t, unsigned); | 1452 | extern int blkdev_get(struct block_device *, mode_t, unsigned); |
1437 | extern int blkdev_put(struct block_device *); | 1453 | extern int blkdev_put(struct block_device *); |
1454 | extern int blkdev_put_partition(struct block_device *); | ||
1438 | extern int bd_claim(struct block_device *, void *); | 1455 | extern int bd_claim(struct block_device *, void *); |
1439 | extern void bd_release(struct block_device *); | 1456 | extern void bd_release(struct block_device *); |
1440 | #ifdef CONFIG_SYSFS | 1457 | #ifdef CONFIG_SYSFS |