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 | /* |
