ceph: explicitly reference rename old_dentry parent dir in request
We carry a pin on the parent directory for the rename source and dest dentries. For the source it's r_locked_dir; we need to explicitly reference the old_dentry parent as well, since the dentry's d_parent may change between when the request was created and pinned and when it is freed. Reviewed-by: Yehuda Sadeh <yehuda@hq.newdream.net> Signed-off-by: Sage Weil <sage@newdream.net>
This commit is contained in:
@@ -102,7 +102,7 @@ static int mdsc_show(struct seq_file *s, void *p)
|
|||||||
path = NULL;
|
path = NULL;
|
||||||
spin_lock(&req->r_old_dentry->d_lock);
|
spin_lock(&req->r_old_dentry->d_lock);
|
||||||
seq_printf(s, " #%llx/%.*s (%s)",
|
seq_printf(s, " #%llx/%.*s (%s)",
|
||||||
ceph_ino(req->r_old_dentry->d_parent->d_inode),
|
ceph_ino(req->r_old_dentry_dir),
|
||||||
req->r_old_dentry->d_name.len,
|
req->r_old_dentry->d_name.len,
|
||||||
req->r_old_dentry->d_name.name,
|
req->r_old_dentry->d_name.name,
|
||||||
path ? path : "");
|
path ? path : "");
|
||||||
|
@@ -811,6 +811,7 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir,
|
|||||||
req->r_dentry = dget(dentry);
|
req->r_dentry = dget(dentry);
|
||||||
req->r_num_caps = 2;
|
req->r_num_caps = 2;
|
||||||
req->r_old_dentry = dget(old_dentry); /* or inode? hrm. */
|
req->r_old_dentry = dget(old_dentry); /* or inode? hrm. */
|
||||||
|
req->r_old_dentry_dir = ceph_get_dentry_parent_inode(old_dentry);
|
||||||
req->r_locked_dir = dir;
|
req->r_locked_dir = dir;
|
||||||
req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
|
req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
|
||||||
req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
|
req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
|
||||||
@@ -909,6 +910,7 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||||||
req->r_dentry = dget(new_dentry);
|
req->r_dentry = dget(new_dentry);
|
||||||
req->r_num_caps = 2;
|
req->r_num_caps = 2;
|
||||||
req->r_old_dentry = dget(old_dentry);
|
req->r_old_dentry = dget(old_dentry);
|
||||||
|
req->r_old_dentry_dir = ceph_get_dentry_parent_inode(old_dentry);
|
||||||
req->r_locked_dir = new_dir;
|
req->r_locked_dir = new_dir;
|
||||||
req->r_old_dentry_drop = CEPH_CAP_FILE_SHARED;
|
req->r_old_dentry_drop = CEPH_CAP_FILE_SHARED;
|
||||||
req->r_old_dentry_unless = CEPH_CAP_FILE_EXCL;
|
req->r_old_dentry_unless = CEPH_CAP_FILE_EXCL;
|
||||||
|
@@ -483,22 +483,26 @@ void ceph_mdsc_release_request(struct kref *kref)
|
|||||||
destroy_reply_info(&req->r_reply_info);
|
destroy_reply_info(&req->r_reply_info);
|
||||||
}
|
}
|
||||||
if (req->r_inode) {
|
if (req->r_inode) {
|
||||||
ceph_put_cap_refs(ceph_inode(req->r_inode),
|
ceph_put_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN);
|
||||||
CEPH_CAP_PIN);
|
|
||||||
iput(req->r_inode);
|
iput(req->r_inode);
|
||||||
}
|
}
|
||||||
if (req->r_locked_dir)
|
if (req->r_locked_dir)
|
||||||
ceph_put_cap_refs(ceph_inode(req->r_locked_dir),
|
ceph_put_cap_refs(ceph_inode(req->r_locked_dir), CEPH_CAP_PIN);
|
||||||
CEPH_CAP_PIN);
|
|
||||||
if (req->r_target_inode)
|
if (req->r_target_inode)
|
||||||
iput(req->r_target_inode);
|
iput(req->r_target_inode);
|
||||||
if (req->r_dentry)
|
if (req->r_dentry)
|
||||||
dput(req->r_dentry);
|
dput(req->r_dentry);
|
||||||
if (req->r_old_dentry) {
|
if (req->r_old_dentry) {
|
||||||
ceph_put_cap_refs(
|
/*
|
||||||
ceph_inode(req->r_old_dentry->d_parent->d_inode),
|
* track (and drop pins for) r_old_dentry_dir
|
||||||
|
* separately, since r_old_dentry's d_parent may have
|
||||||
|
* changed between the dir mutex being dropped and
|
||||||
|
* this request being freed.
|
||||||
|
*/
|
||||||
|
ceph_put_cap_refs(ceph_inode(req->r_old_dentry_dir),
|
||||||
CEPH_CAP_PIN);
|
CEPH_CAP_PIN);
|
||||||
dput(req->r_old_dentry);
|
dput(req->r_old_dentry);
|
||||||
|
iput(req->r_old_dentry_dir);
|
||||||
}
|
}
|
||||||
kfree(req->r_path1);
|
kfree(req->r_path1);
|
||||||
kfree(req->r_path2);
|
kfree(req->r_path2);
|
||||||
@@ -1931,8 +1935,7 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
|
|||||||
if (req->r_locked_dir)
|
if (req->r_locked_dir)
|
||||||
ceph_get_cap_refs(ceph_inode(req->r_locked_dir), CEPH_CAP_PIN);
|
ceph_get_cap_refs(ceph_inode(req->r_locked_dir), CEPH_CAP_PIN);
|
||||||
if (req->r_old_dentry)
|
if (req->r_old_dentry)
|
||||||
ceph_get_cap_refs(
|
ceph_get_cap_refs(ceph_inode(req->r_old_dentry_dir),
|
||||||
ceph_inode(req->r_old_dentry->d_parent->d_inode),
|
|
||||||
CEPH_CAP_PIN);
|
CEPH_CAP_PIN);
|
||||||
|
|
||||||
/* issue */
|
/* issue */
|
||||||
|
@@ -171,6 +171,7 @@ struct ceph_mds_request {
|
|||||||
struct inode *r_inode; /* arg1 */
|
struct inode *r_inode; /* arg1 */
|
||||||
struct dentry *r_dentry; /* arg1 */
|
struct dentry *r_dentry; /* arg1 */
|
||||||
struct dentry *r_old_dentry; /* arg2: rename from or link from */
|
struct dentry *r_old_dentry; /* arg2: rename from or link from */
|
||||||
|
struct inode *r_old_dentry_dir; /* arg2: old dentry's parent dir */
|
||||||
char *r_path1, *r_path2;
|
char *r_path1, *r_path2;
|
||||||
struct ceph_vino r_ino1, r_ino2;
|
struct ceph_vino r_ino1, r_ino2;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user