diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2006-08-27 04:23:31 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-08-27 14:01:29 -0400 |
commit | 6946bd636364effce06ea46fe8f8cd6e2edb004e (patch) | |
tree | f910a0c27dbb36ad94e228c9a7509051c2ce57ae /fs | |
parent | 7334bb4ae931159384acf168eacb0d5d6e0d083c (diff) |
[PATCH] lockdep: fix blkdev_open() warning
On Wed, 2006-08-09 at 07:57 +0200, Rolf Eike Beer wrote:
> =============================================
> [ INFO: possible recursive locking detected ]
> ---------------------------------------------
> parted/7929 is trying to acquire lock:
> (&bdev->bd_mutex){--..}, at: [<c105eb8d>] __blkdev_put+0x1e/0x13c
>
> but task is already holding lock:
> (&bdev->bd_mutex){--..}, at: [<c105eec6>] do_open+0x72/0x3a8
>
> other info that might help us debug this:
> 1 lock held by parted/7929:
> #0: (&bdev->bd_mutex){--..}, at: [<c105eec6>] do_open+0x72/0x3a8
> stack backtrace:
> [<c1003aad>] show_trace_log_lvl+0x58/0x15b
> [<c100495f>] show_trace+0xd/0x10
> [<c1004979>] dump_stack+0x17/0x1a
> [<c102dee5>] __lock_acquire+0x753/0x99c
> [<c102e3b0>] lock_acquire+0x4a/0x6a
> [<c1204501>] mutex_lock_nested+0xc8/0x20c
> [<c105eb8d>] __blkdev_put+0x1e/0x13c
> [<c105ecc4>] blkdev_put+0xa/0xc
> [<c105f18a>] do_open+0x336/0x3a8
> [<c105f21b>] blkdev_open+0x1f/0x4c
> [<c1057b40>] __dentry_open+0xc7/0x1aa
> [<c1057c91>] nameidata_to_filp+0x1c/0x2e
> [<c1057cd1>] do_filp_open+0x2e/0x35
> [<c1057dd7>] do_sys_open+0x38/0x68
> [<c1057e33>] sys_open+0x16/0x18
> [<c1002845>] sysenter_past_esp+0x56/0x8d
OK, I'm having a look here; its all new to me so bear with me.
blkdev_open() calls
do_open(bdev, ...,BD_MUTEX_NORMAL) and takes
mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_NORMAL)
then something fails, and we're thrown to:
out_first: where
if (bdev != bdev->bd_contains)
blkdev_put(bdev->bd_contains) which is
__blkdev_put(bdev->bd_contains, BD_MUTEX_NORMAL) which does
mutex_lock_nested(&bdev->bd_contains->bd_mutex, BD_MUTEX_NORMAL) <--- lockdep trigger
When going to out_first, dbev->bd_contains is either bdev or whole, and
since we take the branch it must be whole. So it seems to me the
following patch would be the right one:
[akpm@osdl.org: compile fix]
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Acked-by: NeilBrown <neilb@suse.de>
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 | 114 |
1 files changed, 56 insertions, 58 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 37534573960b..045f98854f14 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -884,6 +884,61 @@ void bd_set_size(struct block_device *bdev, loff_t size) | |||
884 | } | 884 | } |
885 | EXPORT_SYMBOL(bd_set_size); | 885 | EXPORT_SYMBOL(bd_set_size); |
886 | 886 | ||
887 | static int __blkdev_put(struct block_device *bdev, unsigned int subclass) | ||
888 | { | ||
889 | int ret = 0; | ||
890 | struct inode *bd_inode = bdev->bd_inode; | ||
891 | struct gendisk *disk = bdev->bd_disk; | ||
892 | |||
893 | mutex_lock_nested(&bdev->bd_mutex, subclass); | ||
894 | lock_kernel(); | ||
895 | if (!--bdev->bd_openers) { | ||
896 | sync_blockdev(bdev); | ||
897 | kill_bdev(bdev); | ||
898 | } | ||
899 | if (bdev->bd_contains == bdev) { | ||
900 | if (disk->fops->release) | ||
901 | ret = disk->fops->release(bd_inode, NULL); | ||
902 | } else { | ||
903 | mutex_lock_nested(&bdev->bd_contains->bd_mutex, | ||
904 | subclass + 1); | ||
905 | bdev->bd_contains->bd_part_count--; | ||
906 | mutex_unlock(&bdev->bd_contains->bd_mutex); | ||
907 | } | ||
908 | if (!bdev->bd_openers) { | ||
909 | struct module *owner = disk->fops->owner; | ||
910 | |||
911 | put_disk(disk); | ||
912 | module_put(owner); | ||
913 | |||
914 | if (bdev->bd_contains != bdev) { | ||
915 | kobject_put(&bdev->bd_part->kobj); | ||
916 | bdev->bd_part = NULL; | ||
917 | } | ||
918 | bdev->bd_disk = NULL; | ||
919 | bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; | ||
920 | if (bdev != bdev->bd_contains) | ||
921 | __blkdev_put(bdev->bd_contains, subclass + 1); | ||
922 | bdev->bd_contains = NULL; | ||
923 | } | ||
924 | unlock_kernel(); | ||
925 | mutex_unlock(&bdev->bd_mutex); | ||
926 | bdput(bdev); | ||
927 | return ret; | ||
928 | } | ||
929 | |||
930 | int blkdev_put(struct block_device *bdev) | ||
931 | { | ||
932 | return __blkdev_put(bdev, BD_MUTEX_NORMAL); | ||
933 | } | ||
934 | EXPORT_SYMBOL(blkdev_put); | ||
935 | |||
936 | int blkdev_put_partition(struct block_device *bdev) | ||
937 | { | ||
938 | return __blkdev_put(bdev, BD_MUTEX_PARTITION); | ||
939 | } | ||
940 | EXPORT_SYMBOL(blkdev_put_partition); | ||
941 | |||
887 | static int | 942 | static int |
888 | blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags); | 943 | blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags); |
889 | 944 | ||
@@ -980,7 +1035,7 @@ out_first: | |||
980 | bdev->bd_disk = NULL; | 1035 | bdev->bd_disk = NULL; |
981 | bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; | 1036 | bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; |
982 | if (bdev != bdev->bd_contains) | 1037 | if (bdev != bdev->bd_contains) |
983 | blkdev_put(bdev->bd_contains); | 1038 | __blkdev_put(bdev->bd_contains, BD_MUTEX_WHOLE); |
984 | bdev->bd_contains = NULL; | 1039 | bdev->bd_contains = NULL; |
985 | put_disk(disk); | 1040 | put_disk(disk); |
986 | module_put(owner); | 1041 | module_put(owner); |
@@ -1079,63 +1134,6 @@ static int blkdev_open(struct inode * inode, struct file * filp) | |||
1079 | return res; | 1134 | return res; |
1080 | } | 1135 | } |
1081 | 1136 | ||
1082 | static int __blkdev_put(struct block_device *bdev, unsigned int subclass) | ||
1083 | { | ||
1084 | int ret = 0; | ||
1085 | struct inode *bd_inode = bdev->bd_inode; | ||
1086 | struct gendisk *disk = bdev->bd_disk; | ||
1087 | |||
1088 | mutex_lock_nested(&bdev->bd_mutex, subclass); | ||
1089 | lock_kernel(); | ||
1090 | if (!--bdev->bd_openers) { | ||
1091 | sync_blockdev(bdev); | ||
1092 | kill_bdev(bdev); | ||
1093 | } | ||
1094 | if (bdev->bd_contains == bdev) { | ||
1095 | if (disk->fops->release) | ||
1096 | ret = disk->fops->release(bd_inode, NULL); | ||
1097 | } else { | ||
1098 | mutex_lock_nested(&bdev->bd_contains->bd_mutex, | ||
1099 | subclass + 1); | ||
1100 | bdev->bd_contains->bd_part_count--; | ||
1101 | mutex_unlock(&bdev->bd_contains->bd_mutex); | ||
1102 | } | ||
1103 | if (!bdev->bd_openers) { | ||
1104 | struct module *owner = disk->fops->owner; | ||
1105 | |||
1106 | put_disk(disk); | ||
1107 | module_put(owner); | ||
1108 | |||
1109 | if (bdev->bd_contains != bdev) { | ||
1110 | kobject_put(&bdev->bd_part->kobj); | ||
1111 | bdev->bd_part = NULL; | ||
1112 | } | ||
1113 | bdev->bd_disk = NULL; | ||
1114 | bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; | ||
1115 | if (bdev != bdev->bd_contains) | ||
1116 | __blkdev_put(bdev->bd_contains, subclass + 1); | ||
1117 | bdev->bd_contains = NULL; | ||
1118 | } | ||
1119 | unlock_kernel(); | ||
1120 | mutex_unlock(&bdev->bd_mutex); | ||
1121 | bdput(bdev); | ||
1122 | return ret; | ||
1123 | } | ||
1124 | |||
1125 | int blkdev_put(struct block_device *bdev) | ||
1126 | { | ||
1127 | return __blkdev_put(bdev, BD_MUTEX_NORMAL); | ||
1128 | } | ||
1129 | |||
1130 | EXPORT_SYMBOL(blkdev_put); | ||
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 | |||
1139 | static int blkdev_close(struct inode * inode, struct file * filp) | 1137 | static int blkdev_close(struct inode * inode, struct file * filp) |
1140 | { | 1138 | { |
1141 | struct block_device *bdev = I_BDEV(filp->f_mapping->host); | 1139 | struct block_device *bdev = I_BDEV(filp->f_mapping->host); |