Skip to content

Commit 8818efa

Browse files
Eric Rentorvalds
authored andcommitted
ocfs2: fix deadlock caused by recursive locking in xattr
Another deadlock path caused by recursive locking is reported. This kind of issue was introduced since commit 743b5f1 ("ocfs2: take inode lock in ocfs2_iop_set/get_acl()"). Two deadlock paths have been fixed by commit b891fa5 ("ocfs2: fix deadlock issue when taking inode lock at vfs entry points"). Yes, we intend to fix this kind of case in incremental way, because it's hard to find out all possible paths at once. This one can be reproduced like this. On node1, cp a large file from home directory to ocfs2 mountpoint. While on node2, run setfacl/getfacl. Both nodes will hang up there. The backtraces: On node1: __ocfs2_cluster_lock.isra.39+0x357/0x740 [ocfs2] ocfs2_inode_lock_full_nested+0x17d/0x840 [ocfs2] ocfs2_write_begin+0x43/0x1a0 [ocfs2] generic_perform_write+0xa9/0x180 __generic_file_write_iter+0x1aa/0x1d0 ocfs2_file_write_iter+0x4f4/0xb40 [ocfs2] __vfs_write+0xc3/0x130 vfs_write+0xb1/0x1a0 SyS_write+0x46/0xa0 On node2: __ocfs2_cluster_lock.isra.39+0x357/0x740 [ocfs2] ocfs2_inode_lock_full_nested+0x17d/0x840 [ocfs2] ocfs2_xattr_set+0x12e/0xe80 [ocfs2] ocfs2_set_acl+0x22d/0x260 [ocfs2] ocfs2_iop_set_acl+0x65/0xb0 [ocfs2] set_posix_acl+0x75/0xb0 posix_acl_xattr_set+0x49/0xa0 __vfs_setxattr+0x69/0x80 __vfs_setxattr_noperm+0x72/0x1a0 vfs_setxattr+0xa7/0xb0 setxattr+0x12d/0x190 path_setxattr+0x9f/0xb0 SyS_setxattr+0x14/0x20 Fix this one by using ocfs2_inode_{lock|unlock}_tracker, which is exported by commit 439a36b ("ocfs2/dlmglue: prepare tracking logic to avoid recursive cluster lock"). Link: http://lkml.kernel.org/r/20170622014746.5815-1-zren@suse.com Fixes: 743b5f1 ("ocfs2: take inode lock in ocfs2_iop_set/get_acl()") Signed-off-by: Eric Ren <zren@suse.com> Reported-by: Thomas Voegtle <tv@lio96.de> Tested-by: Thomas Voegtle <tv@lio96.de> Reviewed-by: Joseph Qi <jiangqi903@gmail.com> Cc: Mark Fasheh <mfasheh@versity.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 3b7b314 commit 8818efa

File tree

2 files changed

+17
-10
lines changed

2 files changed

+17
-10
lines changed

fs/ocfs2/dlmglue.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2591,6 +2591,10 @@ void ocfs2_inode_unlock_tracker(struct inode *inode,
25912591
struct ocfs2_lock_res *lockres;
25922592

25932593
lockres = &OCFS2_I(inode)->ip_inode_lockres;
2594+
/* had_lock means that the currect process already takes the cluster
2595+
* lock previously. If had_lock is 1, we have nothing to do here, and
2596+
* it will get unlocked where we got the lock.
2597+
*/
25942598
if (!had_lock) {
25952599
ocfs2_remove_holder(lockres, oh);
25962600
ocfs2_inode_unlock(inode, ex);

fs/ocfs2/xattr.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,20 +1328,21 @@ static int ocfs2_xattr_get(struct inode *inode,
13281328
void *buffer,
13291329
size_t buffer_size)
13301330
{
1331-
int ret;
1331+
int ret, had_lock;
13321332
struct buffer_head *di_bh = NULL;
1333+
struct ocfs2_lock_holder oh;
13331334

1334-
ret = ocfs2_inode_lock(inode, &di_bh, 0);
1335-
if (ret < 0) {
1336-
mlog_errno(ret);
1337-
return ret;
1335+
had_lock = ocfs2_inode_lock_tracker(inode, &di_bh, 0, &oh);
1336+
if (had_lock < 0) {
1337+
mlog_errno(had_lock);
1338+
return had_lock;
13381339
}
13391340
down_read(&OCFS2_I(inode)->ip_xattr_sem);
13401341
ret = ocfs2_xattr_get_nolock(inode, di_bh, name_index,
13411342
name, buffer, buffer_size);
13421343
up_read(&OCFS2_I(inode)->ip_xattr_sem);
13431344

1344-
ocfs2_inode_unlock(inode, 0);
1345+
ocfs2_inode_unlock_tracker(inode, 0, &oh, had_lock);
13451346

13461347
brelse(di_bh);
13471348

@@ -3537,11 +3538,12 @@ int ocfs2_xattr_set(struct inode *inode,
35373538
{
35383539
struct buffer_head *di_bh = NULL;
35393540
struct ocfs2_dinode *di;
3540-
int ret, credits, ref_meta = 0, ref_credits = 0;
3541+
int ret, credits, had_lock, ref_meta = 0, ref_credits = 0;
35413542
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
35423543
struct inode *tl_inode = osb->osb_tl_inode;
35433544
struct ocfs2_xattr_set_ctxt ctxt = { NULL, NULL, NULL, };
35443545
struct ocfs2_refcount_tree *ref_tree = NULL;
3546+
struct ocfs2_lock_holder oh;
35453547

35463548
struct ocfs2_xattr_info xi = {
35473549
.xi_name_index = name_index,
@@ -3572,8 +3574,9 @@ int ocfs2_xattr_set(struct inode *inode,
35723574
return -ENOMEM;
35733575
}
35743576

3575-
ret = ocfs2_inode_lock(inode, &di_bh, 1);
3576-
if (ret < 0) {
3577+
had_lock = ocfs2_inode_lock_tracker(inode, &di_bh, 1, &oh);
3578+
if (had_lock < 0) {
3579+
ret = had_lock;
35773580
mlog_errno(ret);
35783581
goto cleanup_nolock;
35793582
}
@@ -3670,7 +3673,7 @@ int ocfs2_xattr_set(struct inode *inode,
36703673
if (ret)
36713674
mlog_errno(ret);
36723675
}
3673-
ocfs2_inode_unlock(inode, 1);
3676+
ocfs2_inode_unlock_tracker(inode, 1, &oh, had_lock);
36743677
cleanup_nolock:
36753678
brelse(di_bh);
36763679
brelse(xbs.xattr_bh);

0 commit comments

Comments
 (0)