Commit 2bf996ac authored by Yan, Zheng's avatar Yan, Zheng Committed by Ilya Dryomov

ceph: cleanup splice_dentry()

splice_dentry() may drop the original dentry and return other
dentry. It relies on its caller to update pointer that points
to the dropped dentry. This is error-prone.
Signed-off-by: default avatar"Yan, Zheng" <zyan@redhat.com>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent 8fe28cb5
...@@ -1098,8 +1098,9 @@ static void update_dentry_lease(struct dentry *dentry, ...@@ -1098,8 +1098,9 @@ static void update_dentry_lease(struct dentry *dentry,
* splice a dentry to an inode. * splice a dentry to an inode.
* caller must hold directory i_mutex for this to be safe. * caller must hold directory i_mutex for this to be safe.
*/ */
static struct dentry *splice_dentry(struct dentry *dn, struct inode *in) static int splice_dentry(struct dentry **pdn, struct inode *in)
{ {
struct dentry *dn = *pdn;
struct dentry *realdn; struct dentry *realdn;
BUG_ON(d_inode(dn)); BUG_ON(d_inode(dn));
...@@ -1132,28 +1133,23 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in) ...@@ -1132,28 +1133,23 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in)
if (IS_ERR(realdn)) { if (IS_ERR(realdn)) {
pr_err("splice_dentry error %ld %p inode %p ino %llx.%llx\n", pr_err("splice_dentry error %ld %p inode %p ino %llx.%llx\n",
PTR_ERR(realdn), dn, in, ceph_vinop(in)); PTR_ERR(realdn), dn, in, ceph_vinop(in));
dn = realdn; return PTR_ERR(realdn);
/* }
* Caller should release 'dn' in the case of error.
* If 'req->r_dentry' is passed to this function, if (realdn) {
* caller should leave 'req->r_dentry' untouched.
*/
goto out;
} else if (realdn) {
dout("dn %p (%d) spliced with %p (%d) " dout("dn %p (%d) spliced with %p (%d) "
"inode %p ino %llx.%llx\n", "inode %p ino %llx.%llx\n",
dn, d_count(dn), dn, d_count(dn),
realdn, d_count(realdn), realdn, d_count(realdn),
d_inode(realdn), ceph_vinop(d_inode(realdn))); d_inode(realdn), ceph_vinop(d_inode(realdn)));
dput(dn); dput(dn);
dn = realdn; *pdn = realdn;
} else { } else {
BUG_ON(!ceph_dentry(dn)); BUG_ON(!ceph_dentry(dn));
dout("dn %p attached to %p ino %llx.%llx\n", dout("dn %p attached to %p ino %llx.%llx\n",
dn, d_inode(dn), ceph_vinop(d_inode(dn))); dn, d_inode(dn), ceph_vinop(d_inode(dn)));
} }
out: return 0;
return dn;
} }
/* /*
...@@ -1340,7 +1336,12 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) ...@@ -1340,7 +1336,12 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
dout("dn %p gets new offset %lld\n", req->r_old_dentry, dout("dn %p gets new offset %lld\n", req->r_old_dentry,
ceph_dentry(req->r_old_dentry)->offset); ceph_dentry(req->r_old_dentry)->offset);
dn = req->r_old_dentry; /* use old_dentry */ /* swap r_dentry and r_old_dentry in case that
* splice_dentry() gets called later. This is safe
* because no other place will use them */
req->r_dentry = req->r_old_dentry;
req->r_old_dentry = dn;
dn = req->r_dentry;
} }
/* null dentry? */ /* null dentry? */
...@@ -1365,12 +1366,10 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) ...@@ -1365,12 +1366,10 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
if (d_really_is_negative(dn)) { if (d_really_is_negative(dn)) {
ceph_dir_clear_ordered(dir); ceph_dir_clear_ordered(dir);
ihold(in); ihold(in);
dn = splice_dentry(dn, in); err = splice_dentry(&req->r_dentry, in);
if (IS_ERR(dn)) { if (err < 0)
err = PTR_ERR(dn);
goto done; goto done;
} dn = req->r_dentry; /* may have spliced */
req->r_dentry = dn; /* may have spliced */
} else if (d_really_is_positive(dn) && d_inode(dn) != in) { } else if (d_really_is_positive(dn) && d_inode(dn) != in) {
dout(" %p links to %p %llx.%llx, not %llx.%llx\n", dout(" %p links to %p %llx.%llx, not %llx.%llx\n",
dn, d_inode(dn), ceph_vinop(d_inode(dn)), dn, d_inode(dn), ceph_vinop(d_inode(dn)),
...@@ -1390,22 +1389,18 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) ...@@ -1390,22 +1389,18 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
} else if ((req->r_op == CEPH_MDS_OP_LOOKUPSNAP || } else if ((req->r_op == CEPH_MDS_OP_LOOKUPSNAP ||
req->r_op == CEPH_MDS_OP_MKSNAP) && req->r_op == CEPH_MDS_OP_MKSNAP) &&
!test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags)) { !test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags)) {
struct dentry *dn = req->r_dentry;
struct inode *dir = req->r_parent; struct inode *dir = req->r_parent;
/* fill out a snapdir LOOKUPSNAP dentry */ /* fill out a snapdir LOOKUPSNAP dentry */
BUG_ON(!dn);
BUG_ON(!dir); BUG_ON(!dir);
BUG_ON(ceph_snap(dir) != CEPH_SNAPDIR); BUG_ON(ceph_snap(dir) != CEPH_SNAPDIR);
dout(" linking snapped dir %p to dn %p\n", in, dn); BUG_ON(!req->r_dentry);
dout(" linking snapped dir %p to dn %p\n", in, req->r_dentry);
ceph_dir_clear_ordered(dir); ceph_dir_clear_ordered(dir);
ihold(in); ihold(in);
dn = splice_dentry(dn, in); err = splice_dentry(&req->r_dentry, in);
if (IS_ERR(dn)) { if (err < 0)
err = PTR_ERR(dn);
goto done; goto done;
}
req->r_dentry = dn; /* may have spliced */
} else if (rinfo->head->is_dentry) { } else if (rinfo->head->is_dentry) {
struct ceph_vino *ptvino = NULL; struct ceph_vino *ptvino = NULL;
...@@ -1669,8 +1664,6 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, ...@@ -1669,8 +1664,6 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
} }
if (d_really_is_negative(dn)) { if (d_really_is_negative(dn)) {
struct dentry *realdn;
if (ceph_security_xattr_deadlock(in)) { if (ceph_security_xattr_deadlock(in)) {
dout(" skip splicing dn %p to inode %p" dout(" skip splicing dn %p to inode %p"
" (security xattr deadlock)\n", dn, in); " (security xattr deadlock)\n", dn, in);
...@@ -1679,13 +1672,9 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, ...@@ -1679,13 +1672,9 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
goto next_item; goto next_item;
} }
realdn = splice_dentry(dn, in); err = splice_dentry(&dn, in);
if (IS_ERR(realdn)) { if (err < 0)
err = PTR_ERR(realdn);
d_drop(dn);
goto next_item; goto next_item;
}
dn = realdn;
} }
ceph_dentry(dn)->offset = rde->offset; ceph_dentry(dn)->offset = rde->offset;
...@@ -1701,8 +1690,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, ...@@ -1701,8 +1690,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
err = ret; err = ret;
} }
next_item: next_item:
if (dn) dput(dn);
dput(dn);
} }
out: out:
if (err == 0 && skipped == 0) { if (err == 0 && skipped == 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment