diff options
author | Sage Weil <sage@newdream.net> | 2011-07-26 14:31:14 -0400 |
---|---|---|
committer | Sage Weil <sage@newdream.net> | 2011-07-26 14:31:14 -0400 |
commit | 41b02e1f9bb87b07d792b64aaeb7af3d00d69cd2 (patch) | |
tree | 87c9524ff96cbff2ff29d659cbefd516b553ca1f | |
parent | 4f1772645296a230e04f5c53e79cfb6f841ce634 (diff) |
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>
-rw-r--r-- | fs/ceph/debugfs.c | 2 | ||||
-rw-r--r-- | fs/ceph/dir.c | 2 | ||||
-rw-r--r-- | fs/ceph/mds_client.c | 23 | ||||
-rw-r--r-- | fs/ceph/mds_client.h | 1 |
4 files changed, 17 insertions, 11 deletions
diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c index 0dba6915712b..fb962efdacee 100644 --- a/fs/ceph/debugfs.c +++ b/fs/ceph/debugfs.c | |||
@@ -102,7 +102,7 @@ static int mdsc_show(struct seq_file *s, void *p) | |||
102 | path = NULL; | 102 | path = NULL; |
103 | spin_lock(&req->r_old_dentry->d_lock); | 103 | spin_lock(&req->r_old_dentry->d_lock); |
104 | seq_printf(s, " #%llx/%.*s (%s)", | 104 | seq_printf(s, " #%llx/%.*s (%s)", |
105 | ceph_ino(req->r_old_dentry->d_parent->d_inode), | 105 | ceph_ino(req->r_old_dentry_dir), |
106 | req->r_old_dentry->d_name.len, | 106 | req->r_old_dentry->d_name.len, |
107 | req->r_old_dentry->d_name.name, | 107 | req->r_old_dentry->d_name.name, |
108 | path ? path : ""); | 108 | path ? path : ""); |
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 33a19df72288..7263f825d426 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -811,6 +811,7 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir, | |||
811 | req->r_dentry = dget(dentry); | 811 | req->r_dentry = dget(dentry); |
812 | req->r_num_caps = 2; | 812 | req->r_num_caps = 2; |
813 | req->r_old_dentry = dget(old_dentry); /* or inode? hrm. */ | 813 | req->r_old_dentry = dget(old_dentry); /* or inode? hrm. */ |
814 | req->r_old_dentry_dir = ceph_get_dentry_parent_inode(old_dentry); | ||
814 | req->r_locked_dir = dir; | 815 | req->r_locked_dir = dir; |
815 | req->r_dentry_drop = CEPH_CAP_FILE_SHARED; | 816 | req->r_dentry_drop = CEPH_CAP_FILE_SHARED; |
816 | req->r_dentry_unless = CEPH_CAP_FILE_EXCL; | 817 | req->r_dentry_unless = CEPH_CAP_FILE_EXCL; |
@@ -909,6 +910,7 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
909 | req->r_dentry = dget(new_dentry); | 910 | req->r_dentry = dget(new_dentry); |
910 | req->r_num_caps = 2; | 911 | req->r_num_caps = 2; |
911 | req->r_old_dentry = dget(old_dentry); | 912 | req->r_old_dentry = dget(old_dentry); |
913 | req->r_old_dentry_dir = ceph_get_dentry_parent_inode(old_dentry); | ||
912 | req->r_locked_dir = new_dir; | 914 | req->r_locked_dir = new_dir; |
913 | req->r_old_dentry_drop = CEPH_CAP_FILE_SHARED; | 915 | req->r_old_dentry_drop = CEPH_CAP_FILE_SHARED; |
914 | req->r_old_dentry_unless = CEPH_CAP_FILE_EXCL; | 916 | req->r_old_dentry_unless = CEPH_CAP_FILE_EXCL; |
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 8a09cd5a659e..66a8939cc518 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
@@ -483,22 +483,26 @@ void ceph_mdsc_release_request(struct kref *kref) | |||
483 | destroy_reply_info(&req->r_reply_info); | 483 | destroy_reply_info(&req->r_reply_info); |
484 | } | 484 | } |
485 | if (req->r_inode) { | 485 | if (req->r_inode) { |
486 | ceph_put_cap_refs(ceph_inode(req->r_inode), | 486 | ceph_put_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN); |
487 | CEPH_CAP_PIN); | ||
488 | iput(req->r_inode); | 487 | iput(req->r_inode); |
489 | } | 488 | } |
490 | if (req->r_locked_dir) | 489 | if (req->r_locked_dir) |
491 | ceph_put_cap_refs(ceph_inode(req->r_locked_dir), | 490 | ceph_put_cap_refs(ceph_inode(req->r_locked_dir), CEPH_CAP_PIN); |
492 | CEPH_CAP_PIN); | ||
493 | if (req->r_target_inode) | 491 | if (req->r_target_inode) |
494 | iput(req->r_target_inode); | 492 | iput(req->r_target_inode); |
495 | if (req->r_dentry) | 493 | if (req->r_dentry) |
496 | dput(req->r_dentry); | 494 | dput(req->r_dentry); |
497 | if (req->r_old_dentry) { | 495 | if (req->r_old_dentry) { |
498 | ceph_put_cap_refs( | 496 | /* |
499 | ceph_inode(req->r_old_dentry->d_parent->d_inode), | 497 | * track (and drop pins for) r_old_dentry_dir |
500 | CEPH_CAP_PIN); | 498 | * separately, since r_old_dentry's d_parent may have |
499 | * changed between the dir mutex being dropped and | ||
500 | * this request being freed. | ||
501 | */ | ||
502 | ceph_put_cap_refs(ceph_inode(req->r_old_dentry_dir), | ||
503 | CEPH_CAP_PIN); | ||
501 | dput(req->r_old_dentry); | 504 | dput(req->r_old_dentry); |
505 | iput(req->r_old_dentry_dir); | ||
502 | } | 506 | } |
503 | kfree(req->r_path1); | 507 | kfree(req->r_path1); |
504 | kfree(req->r_path2); | 508 | kfree(req->r_path2); |
@@ -1931,9 +1935,8 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc, | |||
1931 | if (req->r_locked_dir) | 1935 | if (req->r_locked_dir) |
1932 | ceph_get_cap_refs(ceph_inode(req->r_locked_dir), CEPH_CAP_PIN); | 1936 | ceph_get_cap_refs(ceph_inode(req->r_locked_dir), CEPH_CAP_PIN); |
1933 | if (req->r_old_dentry) | 1937 | if (req->r_old_dentry) |
1934 | ceph_get_cap_refs( | 1938 | ceph_get_cap_refs(ceph_inode(req->r_old_dentry_dir), |
1935 | ceph_inode(req->r_old_dentry->d_parent->d_inode), | 1939 | CEPH_CAP_PIN); |
1936 | CEPH_CAP_PIN); | ||
1937 | 1940 | ||
1938 | /* issue */ | 1941 | /* issue */ |
1939 | mutex_lock(&mdsc->mutex); | 1942 | mutex_lock(&mdsc->mutex); |
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 8a40f0636ba9..4bb239921dbd 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h | |||
@@ -171,6 +171,7 @@ struct ceph_mds_request { | |||
171 | struct inode *r_inode; /* arg1 */ | 171 | struct inode *r_inode; /* arg1 */ |
172 | struct dentry *r_dentry; /* arg1 */ | 172 | struct dentry *r_dentry; /* arg1 */ |
173 | struct dentry *r_old_dentry; /* arg2: rename from or link from */ | 173 | struct dentry *r_old_dentry; /* arg2: rename from or link from */ |
174 | struct inode *r_old_dentry_dir; /* arg2: old dentry's parent dir */ | ||
174 | char *r_path1, *r_path2; | 175 | char *r_path1, *r_path2; |
175 | struct ceph_vino r_ino1, r_ino2; | 176 | struct ceph_vino r_ino1, r_ino2; |
176 | 177 | ||