diff options
author | Sage Weil <sage@newdream.net> | 2011-07-26 14:30:43 -0400 |
---|---|---|
committer | Sage Weil <sage@newdream.net> | 2011-07-26 14:30:43 -0400 |
commit | bf1c6aca96c9d2f117dc7e590c2bc2304e7febe1 (patch) | |
tree | 1ecb6f35e572ba1e498390d1b09faf3c309bbaee | |
parent | 5f21c96dd5c615341963036ae8f5e4f5227a818d (diff) |
ceph: protect d_parent access in ceph_d_revalidate
Protect d_parent with d_lock. Carry a reference. Simplify the flow so
that there is a single exit point and cleanup.
Reviewed-by: Yehuda Sadeh <yehuda@hq.newdream.net>
Signed-off-by: Sage Weil <sage@newdream.net>
-rw-r--r-- | fs/ceph/dir.c | 32 |
1 files changed, 17 insertions, 15 deletions
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index ed296ec121d1..31d27f8f8261 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -1024,36 +1024,38 @@ static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry) | |||
1024 | */ | 1024 | */ |
1025 | static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd) | 1025 | static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd) |
1026 | { | 1026 | { |
1027 | int valid = 0; | ||
1027 | struct inode *dir; | 1028 | struct inode *dir; |
1028 | 1029 | ||
1029 | if (nd && nd->flags & LOOKUP_RCU) | 1030 | if (nd && nd->flags & LOOKUP_RCU) |
1030 | return -ECHILD; | 1031 | return -ECHILD; |
1031 | 1032 | ||
1032 | dir = dentry->d_parent->d_inode; | ||
1033 | |||
1034 | dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry, | 1033 | dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry, |
1035 | dentry->d_name.len, dentry->d_name.name, dentry->d_inode, | 1034 | dentry->d_name.len, dentry->d_name.name, dentry->d_inode, |
1036 | ceph_dentry(dentry)->offset); | 1035 | ceph_dentry(dentry)->offset); |
1037 | 1036 | ||
1037 | dir = ceph_get_dentry_parent_inode(dentry); | ||
1038 | |||
1038 | /* always trust cached snapped dentries, snapdir dentry */ | 1039 | /* always trust cached snapped dentries, snapdir dentry */ |
1039 | if (ceph_snap(dir) != CEPH_NOSNAP) { | 1040 | if (ceph_snap(dir) != CEPH_NOSNAP) { |
1040 | dout("d_revalidate %p '%.*s' inode %p is SNAPPED\n", dentry, | 1041 | dout("d_revalidate %p '%.*s' inode %p is SNAPPED\n", dentry, |
1041 | dentry->d_name.len, dentry->d_name.name, dentry->d_inode); | 1042 | dentry->d_name.len, dentry->d_name.name, dentry->d_inode); |
1042 | goto out_touch; | 1043 | valid = 1; |
1044 | } else if (dentry->d_inode && | ||
1045 | ceph_snap(dentry->d_inode) == CEPH_SNAPDIR) { | ||
1046 | valid = 1; | ||
1047 | } else if (dentry_lease_is_valid(dentry) || | ||
1048 | dir_lease_is_valid(dir, dentry)) { | ||
1049 | valid = 1; | ||
1043 | } | 1050 | } |
1044 | if (dentry->d_inode && ceph_snap(dentry->d_inode) == CEPH_SNAPDIR) | ||
1045 | goto out_touch; | ||
1046 | 1051 | ||
1047 | if (dentry_lease_is_valid(dentry) || | 1052 | dout("d_revalidate %p %s\n", dentry, valid ? "valid" : "invalid"); |
1048 | dir_lease_is_valid(dir, dentry)) | 1053 | if (valid) |
1049 | goto out_touch; | 1054 | ceph_dentry_lru_touch(dentry); |
1050 | 1055 | else | |
1051 | dout("d_revalidate %p invalid\n", dentry); | 1056 | d_drop(dentry); |
1052 | d_drop(dentry); | 1057 | iput(dir); |
1053 | return 0; | 1058 | return valid; |
1054 | out_touch: | ||
1055 | ceph_dentry_lru_touch(dentry); | ||
1056 | return 1; | ||
1057 | } | 1059 | } |
1058 | 1060 | ||
1059 | /* | 1061 | /* |