mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 16:40:59 +07:00
ocfs2: revert using ocfs2_acl_chmod to avoid inode cluster lock hang
Commit743b5f1434
("ocfs2: take inode lock in ocfs2_iop_set/get_acl()") introduced this issue. ocfs2_setattr called by chmod command holds cluster wide inode lock when calling posix_acl_chmod. This latter function in turn calls ocfs2_iop_get_acl and ocfs2_iop_set_acl. These two are also called directly from vfs layer for getfacl/setfacl commands and therefore acquire the cluster wide inode lock. If a remote conversion request comes after the first inode lock in ocfs2_setattr, OCFS2_LOCK_BLOCKED will be set. And this will cause the second call to inode lock from the ocfs2_iop_get_acl() to block indefinetly. The deleted version of ocfs2_acl_chmod() calls __posix_acl_chmod() which does not call back into the filesystem. Therefore, we restore ocfs2_acl_chmod(), modify it slightly for locking as needed, and use that instead. Fixes:743b5f1434
("ocfs2: take inode lock in ocfs2_iop_set/get_acl()") Signed-off-by: Tariq Saeed <tariq.x.saeed@oracle.com> Signed-off-by: Junxiao Bi <junxiao.bi@oracle.com> Cc: Mark Fasheh <mfasheh@suse.de> Cc: Joel Becker <jlbec@evilplan.org> Cc: Joseph Qi <joseph.qi@huawei.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
422ce5a975
commit
5ee0fbd50f
@ -322,3 +322,27 @@ struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type)
|
|||||||
brelse(di_bh);
|
brelse(di_bh);
|
||||||
return acl;
|
return acl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ocfs2_acl_chmod(struct inode *inode, struct buffer_head *bh)
|
||||||
|
{
|
||||||
|
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||||||
|
struct posix_acl *acl;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (S_ISLNK(inode->i_mode))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, bh);
|
||||||
|
if (IS_ERR(acl) || !acl)
|
||||||
|
return PTR_ERR(acl);
|
||||||
|
ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS,
|
||||||
|
acl, NULL, NULL);
|
||||||
|
posix_acl_release(acl);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -35,5 +35,6 @@ int ocfs2_set_acl(handle_t *handle,
|
|||||||
struct posix_acl *acl,
|
struct posix_acl *acl,
|
||||||
struct ocfs2_alloc_context *meta_ac,
|
struct ocfs2_alloc_context *meta_ac,
|
||||||
struct ocfs2_alloc_context *data_ac);
|
struct ocfs2_alloc_context *data_ac);
|
||||||
|
extern int ocfs2_acl_chmod(struct inode *, struct buffer_head *);
|
||||||
|
|
||||||
#endif /* OCFS2_ACL_H */
|
#endif /* OCFS2_ACL_H */
|
||||||
|
@ -1268,20 +1268,20 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
|
|||||||
if (size_change)
|
if (size_change)
|
||||||
ocfs2_rw_unlock(inode, 1);
|
ocfs2_rw_unlock(inode, 1);
|
||||||
bail:
|
bail:
|
||||||
brelse(bh);
|
|
||||||
|
|
||||||
/* Release quota pointers in case we acquired them */
|
/* Release quota pointers in case we acquired them */
|
||||||
for (qtype = 0; qtype < OCFS2_MAXQUOTAS; qtype++)
|
for (qtype = 0; qtype < OCFS2_MAXQUOTAS; qtype++)
|
||||||
dqput(transfer_to[qtype]);
|
dqput(transfer_to[qtype]);
|
||||||
|
|
||||||
if (!status && attr->ia_valid & ATTR_MODE) {
|
if (!status && attr->ia_valid & ATTR_MODE) {
|
||||||
status = posix_acl_chmod(inode, inode->i_mode);
|
status = ocfs2_acl_chmod(inode, bh);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
mlog_errno(status);
|
mlog_errno(status);
|
||||||
}
|
}
|
||||||
if (inode_locked)
|
if (inode_locked)
|
||||||
ocfs2_inode_unlock(inode, 1);
|
ocfs2_inode_unlock(inode, 1);
|
||||||
|
|
||||||
|
brelse(bh);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user