From 5fe1533fda8ae005541bd418a7a8bc4fa0cda522 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 4 Jan 2010 22:04:01 +0100 Subject: 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: [] ? reiserfs_lock_check_recursive+0x3f/0x50 [] ? reiserfs_lock_check_recursive+0x3f/0x50 [] warn_slowpath_common+0x6c/0xc0 [] ? reiserfs_lock_check_recursive+0x3f/0x50 [] warn_slowpath_fmt+0x2b/0x30 [] reiserfs_lock_check_recursive+0x3f/0x50 [] do_journal_begin_r+0x83/0x350 [] journal_begin+0x7d/0x140 [] ? in_group_p+0x2a/0x30 [] ? inode_change_ok+0x91/0x140 [] reiserfs_setattr+0x15d/0x2e0 [] ? dput+0xe3/0x140 [] ? _raw_spin_unlock+0x2c/0x50 [] chown_one_xattr+0xd/0x10 [] reiserfs_for_each_xattr+0x113/0x2c0 [] ? chown_one_xattr+0x0/0x10 [] ? mutex_lock_nested+0x2a9/0x350 [] reiserfs_chown_xattrs+0x1f/0x60 [] ? in_group_p+0x2a/0x30 [] ? inode_change_ok+0x91/0x140 [] reiserfs_setattr+0x126/0x2e0 [] ? reiserfs_getxattr+0x0/0x90 [] ? cap_inode_need_killpriv+0x37/0x50 [] notify_change+0x151/0x330 [] chown_common+0x6f/0x90 [] sys_lchown+0x6d/0x80 [] sysenter_do_call+0x12/0x32 ---[ end trace 7c2b77224c1442fc ]--- Signed-off-by: Frederic Weisbecker Cc: Christian Kujau Cc: Alexander Beregalov Cc: Chris Mason Cc: Ingo Molnar --- fs/reiserfs/inode.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'fs/reiserfs') 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, int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; - int error; unsigned int ia_valid; + int depth; + int error; /* must be turned off for recursive notify_change calls */ ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID); - reiserfs_write_lock(inode->i_sb); + depth = reiserfs_write_lock_once(inode->i_sb); if (attr->ia_valid & ATTR_SIZE) { /* version 2 items will be caught by the s_maxbytes check ** done for us in vmtruncate @@ -3149,7 +3150,8 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) } out: - reiserfs_write_unlock(inode->i_sb); + reiserfs_write_unlock_once(inode->i_sb, depth); + return error; } -- cgit v1.2.3