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 |
