diff options
author | Yan, Zheng <zheng.z.yan@intel.com> | 2013-02-18 03:38:14 -0500 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2013-05-02 00:14:33 -0400 |
commit | a8673d61ad77ddf2118599507bd40cc345e95368 (patch) | |
tree | 0b8688fee3c2f6c7c35db75d42edd806df689d1d /fs/ceph/dir.c | |
parent | 964266cce94cee7e4aca42994fcda206c111e917 (diff) |
ceph: use I_COMPLETE inode flag instead of D_COMPLETE flag
commit c6ffe10015 moved the flag that tracks if the dcache contents
for a directory are complete to dentry. The problem is there are
lots of places that use ceph_dir_{set,clear,test}_complete() while
holding i_ceph_lock. but ceph_dir_{set,clear,test}_complete() may
sleep because they call dput().
This patch basically reverts that commit. For ceph_d_prune(), it's
called with both the dentry to prune and the parent dentry are
locked. So it's safe to access the parent dentry's d_inode and
clear I_COMPLETE flag.
Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
Reviewed-by: Greg Farnum <greg@inktank.com>
Reviewed-by: Sage Weil <sage@inktank.com>
Diffstat (limited to 'fs/ceph/dir.c')
-rw-r--r-- | fs/ceph/dir.c | 62 |
1 files changed, 11 insertions, 51 deletions
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 6d797f46d772..0c369ac62c07 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -107,7 +107,7 @@ static unsigned fpos_off(loff_t p) | |||
107 | * falling back to a "normal" sync readdir if any dentries in the dir | 107 | * falling back to a "normal" sync readdir if any dentries in the dir |
108 | * are dropped. | 108 | * are dropped. |
109 | * | 109 | * |
110 | * D_COMPLETE tells indicates we have all dentries in the dir. It is | 110 | * I_COMPLETE tells indicates we have all dentries in the dir. It is |
111 | * defined IFF we hold CEPH_CAP_FILE_SHARED (which will be revoked by | 111 | * defined IFF we hold CEPH_CAP_FILE_SHARED (which will be revoked by |
112 | * the MDS if/when the directory is modified). | 112 | * the MDS if/when the directory is modified). |
113 | */ | 113 | */ |
@@ -198,8 +198,8 @@ more: | |||
198 | filp->f_pos++; | 198 | filp->f_pos++; |
199 | 199 | ||
200 | /* make sure a dentry wasn't dropped while we didn't have parent lock */ | 200 | /* make sure a dentry wasn't dropped while we didn't have parent lock */ |
201 | if (!ceph_dir_test_complete(dir)) { | 201 | if (!ceph_i_test(dir, CEPH_I_COMPLETE)) { |
202 | dout(" lost D_COMPLETE on %p; falling back to mds\n", dir); | 202 | dout(" lost I_COMPLETE on %p; falling back to mds\n", dir); |
203 | err = -EAGAIN; | 203 | err = -EAGAIN; |
204 | goto out; | 204 | goto out; |
205 | } | 205 | } |
@@ -284,7 +284,7 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
284 | if ((filp->f_pos == 2 || fi->dentry) && | 284 | if ((filp->f_pos == 2 || fi->dentry) && |
285 | !ceph_test_mount_opt(fsc, NOASYNCREADDIR) && | 285 | !ceph_test_mount_opt(fsc, NOASYNCREADDIR) && |
286 | ceph_snap(inode) != CEPH_SNAPDIR && | 286 | ceph_snap(inode) != CEPH_SNAPDIR && |
287 | ceph_dir_test_complete(inode) && | 287 | (ci->i_ceph_flags & CEPH_I_COMPLETE) && |
288 | __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) { | 288 | __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) { |
289 | spin_unlock(&ci->i_ceph_lock); | 289 | spin_unlock(&ci->i_ceph_lock); |
290 | err = __dcache_readdir(filp, dirent, filldir); | 290 | err = __dcache_readdir(filp, dirent, filldir); |
@@ -350,7 +350,7 @@ more: | |||
350 | 350 | ||
351 | if (!req->r_did_prepopulate) { | 351 | if (!req->r_did_prepopulate) { |
352 | dout("readdir !did_prepopulate"); | 352 | dout("readdir !did_prepopulate"); |
353 | fi->dir_release_count--; /* preclude D_COMPLETE */ | 353 | fi->dir_release_count--; /* preclude I_COMPLETE */ |
354 | } | 354 | } |
355 | 355 | ||
356 | /* note next offset and last dentry name */ | 356 | /* note next offset and last dentry name */ |
@@ -429,7 +429,8 @@ more: | |||
429 | */ | 429 | */ |
430 | spin_lock(&ci->i_ceph_lock); | 430 | spin_lock(&ci->i_ceph_lock); |
431 | if (ci->i_release_count == fi->dir_release_count) { | 431 | if (ci->i_release_count == fi->dir_release_count) { |
432 | ceph_dir_set_complete(inode); | 432 | dout(" marking %p complete\n", inode); |
433 | ci->i_ceph_flags |= CEPH_I_COMPLETE; | ||
433 | ci->i_max_offset = filp->f_pos; | 434 | ci->i_max_offset = filp->f_pos; |
434 | } | 435 | } |
435 | spin_unlock(&ci->i_ceph_lock); | 436 | spin_unlock(&ci->i_ceph_lock); |
@@ -604,7 +605,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, | |||
604 | fsc->mount_options->snapdir_name, | 605 | fsc->mount_options->snapdir_name, |
605 | dentry->d_name.len) && | 606 | dentry->d_name.len) && |
606 | !is_root_ceph_dentry(dir, dentry) && | 607 | !is_root_ceph_dentry(dir, dentry) && |
607 | ceph_dir_test_complete(dir) && | 608 | (ci->i_ceph_flags & CEPH_I_COMPLETE) && |
608 | (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) { | 609 | (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) { |
609 | spin_unlock(&ci->i_ceph_lock); | 610 | spin_unlock(&ci->i_ceph_lock); |
610 | dout(" dir %p complete, -ENOENT\n", dir); | 611 | dout(" dir %p complete, -ENOENT\n", dir); |
@@ -908,7 +909,7 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
908 | */ | 909 | */ |
909 | 910 | ||
910 | /* d_move screws up d_subdirs order */ | 911 | /* d_move screws up d_subdirs order */ |
911 | ceph_dir_clear_complete(new_dir); | 912 | ceph_i_clear(new_dir, CEPH_I_COMPLETE); |
912 | 913 | ||
913 | d_move(old_dentry, new_dentry); | 914 | d_move(old_dentry, new_dentry); |
914 | 915 | ||
@@ -1065,44 +1066,6 @@ static int ceph_snapdir_d_revalidate(struct dentry *dentry, | |||
1065 | } | 1066 | } |
1066 | 1067 | ||
1067 | /* | 1068 | /* |
1068 | * Set/clear/test dir complete flag on the dir's dentry. | ||
1069 | */ | ||
1070 | void ceph_dir_set_complete(struct inode *inode) | ||
1071 | { | ||
1072 | struct dentry *dentry = d_find_any_alias(inode); | ||
1073 | |||
1074 | if (dentry && ceph_dentry(dentry) && | ||
1075 | ceph_test_mount_opt(ceph_sb_to_client(dentry->d_sb), DCACHE)) { | ||
1076 | dout(" marking %p (%p) complete\n", inode, dentry); | ||
1077 | set_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags); | ||
1078 | } | ||
1079 | dput(dentry); | ||
1080 | } | ||
1081 | |||
1082 | void ceph_dir_clear_complete(struct inode *inode) | ||
1083 | { | ||
1084 | struct dentry *dentry = d_find_any_alias(inode); | ||
1085 | |||
1086 | if (dentry && ceph_dentry(dentry)) { | ||
1087 | dout(" marking %p (%p) complete\n", inode, dentry); | ||
1088 | set_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags); | ||
1089 | } | ||
1090 | dput(dentry); | ||
1091 | } | ||
1092 | |||
1093 | bool ceph_dir_test_complete(struct inode *inode) | ||
1094 | { | ||
1095 | struct dentry *dentry = d_find_any_alias(inode); | ||
1096 | |||
1097 | if (dentry && ceph_dentry(dentry)) { | ||
1098 | dout(" marking %p (%p) NOT complete\n", inode, dentry); | ||
1099 | clear_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags); | ||
1100 | } | ||
1101 | dput(dentry); | ||
1102 | return false; | ||
1103 | } | ||
1104 | |||
1105 | /* | ||
1106 | * When the VFS prunes a dentry from the cache, we need to clear the | 1069 | * When the VFS prunes a dentry from the cache, we need to clear the |
1107 | * complete flag on the parent directory. | 1070 | * complete flag on the parent directory. |
1108 | * | 1071 | * |
@@ -1110,15 +1073,13 @@ bool ceph_dir_test_complete(struct inode *inode) | |||
1110 | */ | 1073 | */ |
1111 | static void ceph_d_prune(struct dentry *dentry) | 1074 | static void ceph_d_prune(struct dentry *dentry) |
1112 | { | 1075 | { |
1113 | struct ceph_dentry_info *di; | ||
1114 | |||
1115 | dout("ceph_d_prune %p\n", dentry); | 1076 | dout("ceph_d_prune %p\n", dentry); |
1116 | 1077 | ||
1117 | /* do we have a valid parent? */ | 1078 | /* do we have a valid parent? */ |
1118 | if (IS_ROOT(dentry)) | 1079 | if (IS_ROOT(dentry)) |
1119 | return; | 1080 | return; |
1120 | 1081 | ||
1121 | /* if we are not hashed, we don't affect D_COMPLETE */ | 1082 | /* if we are not hashed, we don't affect I_COMPLETE */ |
1122 | if (d_unhashed(dentry)) | 1083 | if (d_unhashed(dentry)) |
1123 | return; | 1084 | return; |
1124 | 1085 | ||
@@ -1126,8 +1087,7 @@ static void ceph_d_prune(struct dentry *dentry) | |||
1126 | * we hold d_lock, so d_parent is stable, and d_fsdata is never | 1087 | * we hold d_lock, so d_parent is stable, and d_fsdata is never |
1127 | * cleared until d_release | 1088 | * cleared until d_release |
1128 | */ | 1089 | */ |
1129 | di = ceph_dentry(dentry->d_parent); | 1090 | ceph_i_clear(dentry->d_parent->d_inode, CEPH_I_COMPLETE); |
1130 | clear_bit(CEPH_D_COMPLETE, &di->flags); | ||
1131 | } | 1091 | } |
1132 | 1092 | ||
1133 | /* | 1093 | /* |