aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2006-07-03 03:25:33 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-07-03 18:27:10 -0400
commit663d440eaa496db903cc58be04b9b602ba45e43b (patch)
tree8af6967e175693f1c163a106a1d84be7a1bd0bfc
parent2b2d5493e10051694ae3a57ea6a153e3cb4d4488 (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.c6
-rw-r--r--fs/block_dev.c102
-rw-r--r--include/linux/fs.h17
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
1434void md_autodetect_dev(dev_t dev); 1434void 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
823EXPORT_SYMBOL(open_by_devnum); 823EXPORT_SYMBOL(open_by_devnum);
824 824
825static int
826blkdev_get_partition(struct block_device *bdev, mode_t mode, unsigned flags);
827
828struct 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
838EXPORT_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}
869EXPORT_SYMBOL(bd_set_size); 885EXPORT_SYMBOL(bd_set_size);
870 886
871static int do_open(struct block_device *bdev, struct file *file) 887static int
888blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags);
889
890static int
891do_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
991EXPORT_SYMBOL(blkdev_get); 1013EXPORT_SYMBOL(blkdev_get);
992 1014
1015static int
1016blkdev_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
1034static int
1035blkdev_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
993static int blkdev_open(struct inode * inode, struct file * filp) 1053static 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
1022int blkdev_put(struct block_device *bdev) 1082static 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
1125int blkdev_put(struct block_device *bdev)
1126{
1127 return __blkdev_put(bdev, BD_MUTEX_NORMAL);
1128}
1129
1065EXPORT_SYMBOL(blkdev_put); 1130EXPORT_SYMBOL(blkdev_put);
1066 1131
1132int blkdev_put_partition(struct block_device *bdev)
1133{
1134 return __blkdev_put(bdev, BD_MUTEX_PARTITION);
1135}
1136
1137EXPORT_SYMBOL(blkdev_put_partition);
1138
1067static int blkdev_close(struct inode * inode, struct file * filp) 1139static 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 */
445enum 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);
1425extern void bd_forget(struct inode *inode); 1440extern void bd_forget(struct inode *inode);
1426extern void bdput(struct block_device *); 1441extern void bdput(struct block_device *);
1427extern struct block_device *open_by_devnum(dev_t, unsigned); 1442extern struct block_device *open_by_devnum(dev_t, unsigned);
1443extern struct block_device *open_partition_by_devnum(dev_t, unsigned);
1428extern const struct file_operations def_blk_fops; 1444extern const struct file_operations def_blk_fops;
1429extern const struct address_space_operations def_blk_aops; 1445extern const struct address_space_operations def_blk_aops;
1430extern const struct file_operations def_chr_fops; 1446extern const struct file_operations def_chr_fops;
@@ -1435,6 +1451,7 @@ extern int blkdev_ioctl(struct inode *, struct file *, unsigned, unsigned long);
1435extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long); 1451extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long);
1436extern int blkdev_get(struct block_device *, mode_t, unsigned); 1452extern int blkdev_get(struct block_device *, mode_t, unsigned);
1437extern int blkdev_put(struct block_device *); 1453extern int blkdev_put(struct block_device *);
1454extern int blkdev_put_partition(struct block_device *);
1438extern int bd_claim(struct block_device *, void *); 1455extern int bd_claim(struct block_device *, void *);
1439extern void bd_release(struct block_device *); 1456extern void bd_release(struct block_device *);
1440#ifdef CONFIG_SYSFS 1457#ifdef CONFIG_SYSFS