diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2010-01-04 16:04:01 -0500 |
---|---|---|
committer | Frederic Weisbecker <fweisbec@gmail.com> | 2010-01-05 01:59:38 -0500 |
commit | 5fe1533fda8ae005541bd418a7a8bc4fa0cda522 (patch) | |
tree | 411dd7c99f884e914a34ce91d8f282bbc70c63c8 /fs/reiserfs | |
parent | f3e22f48f37c1e14441c9f72ca8e63b1d4516745 (diff) |
reiserfs: Fix recursive lock on lchown
On chown, reiserfs will call reiserfs_setattr() to change the owner
of the given inode, but it may also recursively call
reiserfs_setattr() to propagate the owner change to the private xattr
files for this inode.
Hence, the reiserfs lock may be acquired twice which is not wanted
as reiserfs_setattr() calls journal_begin() that is going to try to
relax the lock in order to safely acquire the journal mutex.
Using reiserfs_write_lock_once() from reiserfs_setattr() solves
the problem.
This fixes the following warning, that precedes a lockdep report.
WARNING: at fs/reiserfs/lock.c:95 reiserfs_lock_check_recursive+0x3f/0x50()
Hardware name: MS-7418
Unwanted recursive reiserfs lock!
Pid: 4189, comm: fsstress Not tainted 2.6.33-rc2-tip-atom+ #195
Call Trace:
[<c1178bff>] ? reiserfs_lock_check_recursive+0x3f/0x50
[<c1178bff>] ? reiserfs_lock_check_recursive+0x3f/0x50
[<c103f7ac>] warn_slowpath_common+0x6c/0xc0
[<c1178bff>] ? reiserfs_lock_check_recursive+0x3f/0x50
[<c103f84b>] warn_slowpath_fmt+0x2b/0x30
[<c1178bff>] reiserfs_lock_check_recursive+0x3f/0x50
[<c1172ae3>] do_journal_begin_r+0x83/0x350
[<c1172f2d>] journal_begin+0x7d/0x140
[<c106509a>] ? in_group_p+0x2a/0x30
[<c10fda71>] ? inode_change_ok+0x91/0x140
[<c115007d>] reiserfs_setattr+0x15d/0x2e0
[<c10f9bf3>] ? dput+0xe3/0x140
[<c1465adc>] ? _raw_spin_unlock+0x2c/0x50
[<c117831d>] chown_one_xattr+0xd/0x10
[<c11780a3>] reiserfs_for_each_xattr+0x113/0x2c0
[<c1178310>] ? chown_one_xattr+0x0/0x10
[<c14641e9>] ? mutex_lock_nested+0x2a9/0x350
[<c117826f>] reiserfs_chown_xattrs+0x1f/0x60
[<c106509a>] ? in_group_p+0x2a/0x30
[<c10fda71>] ? inode_change_ok+0x91/0x140
[<c1150046>] reiserfs_setattr+0x126/0x2e0
[<c1177c20>] ? reiserfs_getxattr+0x0/0x90
[<c11b0d57>] ? cap_inode_need_killpriv+0x37/0x50
[<c10fde01>] notify_change+0x151/0x330
[<c10e659f>] chown_common+0x6f/0x90
[<c10e67bd>] sys_lchown+0x6d/0x80
[<c1002ccc>] sysenter_do_call+0x12/0x32
---[ end trace 7c2b77224c1442fc ]---
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: 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>
Diffstat (limited to 'fs/reiserfs')
-rw-r--r-- | fs/reiserfs/inode.c | 8 |
1 files changed, 5 insertions, 3 deletions
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index bd615dfe4ec7..47dbfb18877a 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c | |||
@@ -3052,13 +3052,14 @@ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb, | |||
3052 | int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) | 3052 | int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) |
3053 | { | 3053 | { |
3054 | struct inode *inode = dentry->d_inode; | 3054 | struct inode *inode = dentry->d_inode; |
3055 | int error; | ||
3056 | unsigned int ia_valid; | 3055 | unsigned int ia_valid; |
3056 | int depth; | ||
3057 | int error; | ||
3057 | 3058 | ||
3058 | /* must be turned off for recursive notify_change calls */ | 3059 | /* must be turned off for recursive notify_change calls */ |
3059 | ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID); | 3060 | ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID); |
3060 | 3061 | ||
3061 | reiserfs_write_lock(inode->i_sb); | 3062 | depth = reiserfs_write_lock_once(inode->i_sb); |
3062 | if (attr->ia_valid & ATTR_SIZE) { | 3063 | if (attr->ia_valid & ATTR_SIZE) { |
3063 | /* version 2 items will be caught by the s_maxbytes check | 3064 | /* version 2 items will be caught by the s_maxbytes check |
3064 | ** done for us in vmtruncate | 3065 | ** done for us in vmtruncate |
@@ -3149,7 +3150,8 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
3149 | } | 3150 | } |
3150 | 3151 | ||
3151 | out: | 3152 | out: |
3152 | reiserfs_write_unlock(inode->i_sb); | 3153 | reiserfs_write_unlock_once(inode->i_sb, depth); |
3154 | |||
3153 | return error; | 3155 | return error; |
3154 | } | 3156 | } |
3155 | 3157 | ||