diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-12-30 01:12:03 -0500 |
---|---|---|
committer | Frederic Weisbecker <fweisbec@gmail.com> | 2010-01-01 19:57:32 -0500 |
commit | c674905ca74ad0ae5b048afb1ef68663a0d7e987 (patch) | |
tree | 3f269bdda58519c012cf0505e36cee158ec7064b | |
parent | 3f14fea6bbd3444dd46a2af3a2e219e792616645 (diff) |
reiserfs: Fix unwanted recursive reiserfs lock in reiserfs_unlink()
reiserfs_unlink() may or may not be called under the reiserfs
lock.
But it also takes the reiserfs lock and can then acquire it
recursively which leads to do_journal_begin_r() that fails to
relax the reiserfs lock before grabbing the journal mutex,
creating an unexpected lock inversion.
We need to ensure reiserfs_unlink() won't get the reiserfs lock
recursively using reiserfs_write_lock_once().
This fixes the following warning that precedes a lock inversion
report (reiserfs lock <-> journal mutex).
------------[ cut here ]------------
WARNING: at fs/reiserfs/lock.c:95 reiserfs_lock_check_recursive+0x3a/0x50()
Hardware name: MS-7418
Unwanted recursive reiserfs lock!
Pid: 3208, comm: dbench Not tainted 2.6.32-atom #177
Call Trace:
[<c114327a>] ? reiserfs_lock_check_recursive+0x3a/0x50
[<c114327a>] ? reiserfs_lock_check_recursive+0x3a/0x50
[<c10373a7>] warn_slowpath_common+0x67/0xc0
[<c114327a>] ? reiserfs_lock_check_recursive+0x3a/0x50
[<c1037446>] warn_slowpath_fmt+0x26/0x30
[<c114327a>] reiserfs_lock_check_recursive+0x3a/0x50
[<c113c213>] do_journal_begin_r+0x83/0x360
[<c105eb16>] ? __lock_acquire+0x1296/0x19e0
[<c1142a57>] ? xattr_unlink+0x57/0xb0
[<c113c670>] journal_begin+0x80/0x130
[<c1116d5d>] reiserfs_unlink+0x7d/0x2d0
[<c1142a57>] ? xattr_unlink+0x57/0xb0
[<c1142a57>] ? xattr_unlink+0x57/0xb0
[<c1142a57>] ? xattr_unlink+0x57/0xb0
[<c1142a64>] xattr_unlink+0x64/0xb0
[<c1143169>] delete_one_xattr+0x29/0x100
[<c11427ab>] reiserfs_for_each_xattr+0x10b/0x290
[<c1143140>] ? delete_one_xattr+0x0/0x100
[<c1401ca9>] ? mutex_lock_nested+0x299/0x340
[<c11429aa>] reiserfs_delete_xattrs+0x1a/0x60
[<c11432f9>] ? reiserfs_write_lock_once+0x29/0x50
[<c111ea1f>] reiserfs_delete_inode+0x9f/0x150
[<c11b0d0f>] ? _atomic_dec_and_lock+0x4f/0x70
[<c111e980>] ? reiserfs_delete_inode+0x0/0x150
[<c10c9c32>] generic_delete_inode+0xa2/0x170
[<c10c9d4f>] generic_drop_inode+0x4f/0x70
[<c10c8b07>] iput+0x47/0x50
[<c10c0965>] do_unlinkat+0xd5/0x160
[<c10505c6>] ? up_read+0x16/0x30
[<c1022ab7>] ? do_page_fault+0x187/0x330
[<c1002fd8>] ? restore_all_notrace+0x0/0x18
[<c1022930>] ? do_page_fault+0x0/0x330
[<c105cbe4>] ? trace_hardirqs_on_caller+0x124/0x170
[<c10c0a00>] sys_unlink+0x10/0x20
[<c1002ec4>] sysenter_do_call+0x12/0x32
---[ end trace 2e35d71a6cc69d0c ]---
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Tested-by: Christian Kujau <lists@nerdbynature.de>
Cc: Alexander Beregalov <a.beregalov@gmail.com>
Cc: Chris Mason <chris.mason@oracle.com>
Cc: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | fs/reiserfs/namei.c | 7 |
1 files changed, 4 insertions, 3 deletions
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index e296ff72a6cc..9d4dcf0b07cb 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c | |||
@@ -921,6 +921,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry) | |||
921 | struct reiserfs_transaction_handle th; | 921 | struct reiserfs_transaction_handle th; |
922 | int jbegin_count; | 922 | int jbegin_count; |
923 | unsigned long savelink; | 923 | unsigned long savelink; |
924 | int depth; | ||
924 | 925 | ||
925 | inode = dentry->d_inode; | 926 | inode = dentry->d_inode; |
926 | 927 | ||
@@ -932,7 +933,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry) | |||
932 | JOURNAL_PER_BALANCE_CNT * 2 + 2 + | 933 | JOURNAL_PER_BALANCE_CNT * 2 + 2 + |
933 | 4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb); | 934 | 4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb); |
934 | 935 | ||
935 | reiserfs_write_lock(dir->i_sb); | 936 | depth = reiserfs_write_lock_once(dir->i_sb); |
936 | retval = journal_begin(&th, dir->i_sb, jbegin_count); | 937 | retval = journal_begin(&th, dir->i_sb, jbegin_count); |
937 | if (retval) | 938 | if (retval) |
938 | goto out_unlink; | 939 | goto out_unlink; |
@@ -993,7 +994,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry) | |||
993 | 994 | ||
994 | retval = journal_end(&th, dir->i_sb, jbegin_count); | 995 | retval = journal_end(&th, dir->i_sb, jbegin_count); |
995 | reiserfs_check_path(&path); | 996 | reiserfs_check_path(&path); |
996 | reiserfs_write_unlock(dir->i_sb); | 997 | reiserfs_write_unlock_once(dir->i_sb, depth); |
997 | return retval; | 998 | return retval; |
998 | 999 | ||
999 | end_unlink: | 1000 | end_unlink: |
@@ -1003,7 +1004,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry) | |||
1003 | if (err) | 1004 | if (err) |
1004 | retval = err; | 1005 | retval = err; |
1005 | out_unlink: | 1006 | out_unlink: |
1006 | reiserfs_write_unlock(dir->i_sb); | 1007 | reiserfs_write_unlock_once(dir->i_sb, depth); |
1007 | return retval; | 1008 | return retval; |
1008 | } | 1009 | } |
1009 | 1010 | ||