aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAshish Samant <ashish.samant@oracle.com>2018-05-11 19:02:07 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-05-11 20:28:45 -0400
commite4383029201470523c3ffe339bd7d57e9b4a7d65 (patch)
tree4299fa734f9decf395158470afcb72aa2adb73e5
parent27ae357fa82be5ab73b2ef8d39dcb8ca2563483a (diff)
ocfs2: take inode cluster lock before moving reflinked inode from orphan dir
While reflinking an inode, we create a new inode in orphan directory, then take EX lock on it, reflink the original inode to orphan inode and release EX lock. Once the lock is released another node could request it in EX mode from ocfs2_recover_orphans() which causes downconvert of the lock, on this node, to NL mode. Later we attempt to initialize security acl for the orphan inode and move it to the reflink destination. However, while doing this we dont take EX lock on the inode. This could potentially cause problems because we could be starting transaction, accessing journal and modifying metadata of the inode while holding NL lock and with another node holding EX lock on the inode. Fix this by taking orphan inode cluster lock in EX mode before initializing security and moving orphan inode to reflink destination. Use the __tracker variant while taking inode lock to avoid recursive locking in the ocfs2_init_security_and_acl() call chain. Link: http://lkml.kernel.org/r/1523475107-7639-1-git-send-email-ashish.samant@oracle.com Signed-off-by: Ashish Samant <ashish.samant@oracle.com> Reviewed-by: Joseph Qi <jiangqi903@gmail.com> Reviewed-by: Junxiao Bi <junxiao.bi@oracle.com> Acked-by: Jun Piao <piaojun@huawei.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Changwei Ge <ge.changwei@h3c.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/ocfs2/refcounttree.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 01c6b3894406..7869622af22a 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -4250,10 +4250,11 @@ out:
4250static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir, 4250static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir,
4251 struct dentry *new_dentry, bool preserve) 4251 struct dentry *new_dentry, bool preserve)
4252{ 4252{
4253 int error; 4253 int error, had_lock;
4254 struct inode *inode = d_inode(old_dentry); 4254 struct inode *inode = d_inode(old_dentry);
4255 struct buffer_head *old_bh = NULL; 4255 struct buffer_head *old_bh = NULL;
4256 struct inode *new_orphan_inode = NULL; 4256 struct inode *new_orphan_inode = NULL;
4257 struct ocfs2_lock_holder oh;
4257 4258
4258 if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) 4259 if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb)))
4259 return -EOPNOTSUPP; 4260 return -EOPNOTSUPP;
@@ -4295,6 +4296,14 @@ static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir,
4295 goto out; 4296 goto out;
4296 } 4297 }
4297 4298
4299 had_lock = ocfs2_inode_lock_tracker(new_orphan_inode, NULL, 1,
4300 &oh);
4301 if (had_lock < 0) {
4302 error = had_lock;
4303 mlog_errno(error);
4304 goto out;
4305 }
4306
4298 /* If the security isn't preserved, we need to re-initialize them. */ 4307 /* If the security isn't preserved, we need to re-initialize them. */
4299 if (!preserve) { 4308 if (!preserve) {
4300 error = ocfs2_init_security_and_acl(dir, new_orphan_inode, 4309 error = ocfs2_init_security_and_acl(dir, new_orphan_inode,
@@ -4302,14 +4311,15 @@ static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir,
4302 if (error) 4311 if (error)
4303 mlog_errno(error); 4312 mlog_errno(error);
4304 } 4313 }
4305out:
4306 if (!error) { 4314 if (!error) {
4307 error = ocfs2_mv_orphaned_inode_to_new(dir, new_orphan_inode, 4315 error = ocfs2_mv_orphaned_inode_to_new(dir, new_orphan_inode,
4308 new_dentry); 4316 new_dentry);
4309 if (error) 4317 if (error)
4310 mlog_errno(error); 4318 mlog_errno(error);
4311 } 4319 }
4320 ocfs2_inode_unlock_tracker(new_orphan_inode, 1, &oh, had_lock);
4312 4321
4322out:
4313 if (new_orphan_inode) { 4323 if (new_orphan_inode) {
4314 /* 4324 /*
4315 * We need to open_unlock the inode no matter whether we 4325 * We need to open_unlock the inode no matter whether we