diff options
author | Sage Weil <sage@newdream.net> | 2011-11-03 12:23:36 -0400 |
---|---|---|
committer | Sage Weil <sage@newdream.net> | 2011-11-06 00:10:10 -0400 |
commit | c6ffe10015f4e6fba8a915318b319c43aed1836f (patch) | |
tree | dd39730aeb6d00713ca27a1bf34b116d31479151 /fs/ceph | |
parent | b58dc4100b9190f2cb437f1f67ffcb9f9acc4923 (diff) |
ceph: use new D_COMPLETE dentry flag
We used to use a flag on the directory inode to track whether the dcache
contents for a directory were a complete cached copy. Switch to a dentry
flag CEPH_D_COMPLETE that is safely updated by ->d_prune().
Signed-off-by: Sage Weil <sage@newdream.net>
Diffstat (limited to 'fs/ceph')
-rw-r--r-- | fs/ceph/caps.c | 8 | ||||
-rw-r--r-- | fs/ceph/dir.c | 59 | ||||
-rw-r--r-- | fs/ceph/inode.c | 8 | ||||
-rw-r--r-- | fs/ceph/mds_client.c | 6 | ||||
-rw-r--r-- | fs/ceph/super.h | 10 |
5 files changed, 68 insertions, 23 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 15b21e35078a..0f327c6c9679 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
@@ -487,17 +487,15 @@ static void __check_cap_issue(struct ceph_inode_info *ci, struct ceph_cap *cap, | |||
487 | ci->i_rdcache_gen++; | 487 | ci->i_rdcache_gen++; |
488 | 488 | ||
489 | /* | 489 | /* |
490 | * if we are newly issued FILE_SHARED, clear I_COMPLETE; we | 490 | * if we are newly issued FILE_SHARED, clear D_COMPLETE; we |
491 | * don't know what happened to this directory while we didn't | 491 | * don't know what happened to this directory while we didn't |
492 | * have the cap. | 492 | * have the cap. |
493 | */ | 493 | */ |
494 | if ((issued & CEPH_CAP_FILE_SHARED) && | 494 | if ((issued & CEPH_CAP_FILE_SHARED) && |
495 | (had & CEPH_CAP_FILE_SHARED) == 0) { | 495 | (had & CEPH_CAP_FILE_SHARED) == 0) { |
496 | ci->i_shared_gen++; | 496 | ci->i_shared_gen++; |
497 | if (S_ISDIR(ci->vfs_inode.i_mode)) { | 497 | if (S_ISDIR(ci->vfs_inode.i_mode)) |
498 | dout(" marking %p NOT complete\n", &ci->vfs_inode); | 498 | ceph_dir_clear_complete(&ci->vfs_inode); |
499 | ci->i_ceph_flags &= ~CEPH_I_COMPLETE; | ||
500 | } | ||
501 | } | 499 | } |
502 | } | 500 | } |
503 | 501 | ||
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 97fb155b3242..2abd0dfad7f8 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -108,7 +108,7 @@ static unsigned fpos_off(loff_t p) | |||
108 | * falling back to a "normal" sync readdir if any dentries in the dir | 108 | * falling back to a "normal" sync readdir if any dentries in the dir |
109 | * are dropped. | 109 | * are dropped. |
110 | * | 110 | * |
111 | * I_COMPLETE tells indicates we have all dentries in the dir. It is | 111 | * D_COMPLETE tells indicates we have all dentries in the dir. It is |
112 | * defined IFF we hold CEPH_CAP_FILE_SHARED (which will be revoked by | 112 | * defined IFF we hold CEPH_CAP_FILE_SHARED (which will be revoked by |
113 | * the MDS if/when the directory is modified). | 113 | * the MDS if/when the directory is modified). |
114 | */ | 114 | */ |
@@ -199,8 +199,8 @@ more: | |||
199 | filp->f_pos++; | 199 | filp->f_pos++; |
200 | 200 | ||
201 | /* make sure a dentry wasn't dropped while we didn't have parent lock */ | 201 | /* make sure a dentry wasn't dropped while we didn't have parent lock */ |
202 | if (!ceph_i_test(dir, CEPH_I_COMPLETE)) { | 202 | if (!ceph_dir_test_complete(dir)) { |
203 | dout(" lost I_COMPLETE on %p; falling back to mds\n", dir); | 203 | dout(" lost D_COMPLETE on %p; falling back to mds\n", dir); |
204 | err = -EAGAIN; | 204 | err = -EAGAIN; |
205 | goto out; | 205 | goto out; |
206 | } | 206 | } |
@@ -285,7 +285,7 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
285 | if ((filp->f_pos == 2 || fi->dentry) && | 285 | if ((filp->f_pos == 2 || fi->dentry) && |
286 | !ceph_test_mount_opt(fsc, NOASYNCREADDIR) && | 286 | !ceph_test_mount_opt(fsc, NOASYNCREADDIR) && |
287 | ceph_snap(inode) != CEPH_SNAPDIR && | 287 | ceph_snap(inode) != CEPH_SNAPDIR && |
288 | (ci->i_ceph_flags & CEPH_I_COMPLETE) && | 288 | ceph_dir_test_complete(inode) && |
289 | __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) { | 289 | __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) { |
290 | spin_unlock(&inode->i_lock); | 290 | spin_unlock(&inode->i_lock); |
291 | err = __dcache_readdir(filp, dirent, filldir); | 291 | err = __dcache_readdir(filp, dirent, filldir); |
@@ -351,7 +351,7 @@ more: | |||
351 | 351 | ||
352 | if (!req->r_did_prepopulate) { | 352 | if (!req->r_did_prepopulate) { |
353 | dout("readdir !did_prepopulate"); | 353 | dout("readdir !did_prepopulate"); |
354 | fi->dir_release_count--; /* preclude I_COMPLETE */ | 354 | fi->dir_release_count--; /* preclude D_COMPLETE */ |
355 | } | 355 | } |
356 | 356 | ||
357 | /* note next offset and last dentry name */ | 357 | /* note next offset and last dentry name */ |
@@ -430,8 +430,7 @@ more: | |||
430 | */ | 430 | */ |
431 | spin_lock(&inode->i_lock); | 431 | spin_lock(&inode->i_lock); |
432 | if (ci->i_release_count == fi->dir_release_count) { | 432 | if (ci->i_release_count == fi->dir_release_count) { |
433 | dout(" marking %p complete\n", inode); | 433 | ceph_dir_set_complete(inode); |
434 | /* ci->i_ceph_flags |= CEPH_I_COMPLETE; */ | ||
435 | ci->i_max_offset = filp->f_pos; | 434 | ci->i_max_offset = filp->f_pos; |
436 | } | 435 | } |
437 | spin_unlock(&inode->i_lock); | 436 | spin_unlock(&inode->i_lock); |
@@ -614,7 +613,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, | |||
614 | fsc->mount_options->snapdir_name, | 613 | fsc->mount_options->snapdir_name, |
615 | dentry->d_name.len) && | 614 | dentry->d_name.len) && |
616 | !is_root_ceph_dentry(dir, dentry) && | 615 | !is_root_ceph_dentry(dir, dentry) && |
617 | (ci->i_ceph_flags & CEPH_I_COMPLETE) && | 616 | ceph_dir_test_complete(dir) && |
618 | (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) { | 617 | (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) { |
619 | spin_unlock(&dir->i_lock); | 618 | spin_unlock(&dir->i_lock); |
620 | dout(" dir %p complete, -ENOENT\n", dir); | 619 | dout(" dir %p complete, -ENOENT\n", dir); |
@@ -934,7 +933,7 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
934 | */ | 933 | */ |
935 | 934 | ||
936 | /* d_move screws up d_subdirs order */ | 935 | /* d_move screws up d_subdirs order */ |
937 | ceph_i_clear(new_dir, CEPH_I_COMPLETE); | 936 | ceph_dir_clear_complete(new_dir); |
938 | 937 | ||
939 | d_move(old_dentry, new_dentry); | 938 | d_move(old_dentry, new_dentry); |
940 | 939 | ||
@@ -1093,6 +1092,48 @@ static int ceph_snapdir_d_revalidate(struct dentry *dentry, | |||
1093 | } | 1092 | } |
1094 | 1093 | ||
1095 | /* | 1094 | /* |
1095 | * Set/clear/test dir complete flag on the dir's dentry. | ||
1096 | */ | ||
1097 | static struct dentry * __d_find_any_alias(struct inode *inode) | ||
1098 | { | ||
1099 | struct dentry *alias; | ||
1100 | |||
1101 | if (list_empty(&inode->i_dentry)) | ||
1102 | return NULL; | ||
1103 | alias = list_first_entry(&inode->i_dentry, struct dentry, d_alias); | ||
1104 | return alias; | ||
1105 | } | ||
1106 | |||
1107 | void ceph_dir_set_complete(struct inode *inode) | ||
1108 | { | ||
1109 | struct dentry *dentry = __d_find_any_alias(inode); | ||
1110 | |||
1111 | if (dentry && ceph_dentry(dentry)) { | ||
1112 | dout(" marking %p (%p) complete\n", inode, dentry); | ||
1113 | set_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags); | ||
1114 | } | ||
1115 | } | ||
1116 | |||
1117 | void ceph_dir_clear_complete(struct inode *inode) | ||
1118 | { | ||
1119 | struct dentry *dentry = __d_find_any_alias(inode); | ||
1120 | |||
1121 | if (dentry && ceph_dentry(dentry)) { | ||
1122 | dout(" marking %p (%p) NOT complete\n", inode, dentry); | ||
1123 | clear_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags); | ||
1124 | } | ||
1125 | } | ||
1126 | |||
1127 | bool ceph_dir_test_complete(struct inode *inode) | ||
1128 | { | ||
1129 | struct dentry *dentry = __d_find_any_alias(inode); | ||
1130 | |||
1131 | if (dentry && ceph_dentry(dentry)) | ||
1132 | return test_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags); | ||
1133 | return false; | ||
1134 | } | ||
1135 | |||
1136 | /* | ||
1096 | * When the VFS prunes a dentry from the cache, we need to clear the | 1137 | * When the VFS prunes a dentry from the cache, we need to clear the |
1097 | * complete flag on the parent directory. | 1138 | * complete flag on the parent directory. |
1098 | * | 1139 | * |
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 1616a0d37cbd..e392bfce84a3 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
@@ -771,9 +771,9 @@ no_change: | |||
771 | ceph_snap(inode) == CEPH_NOSNAP && | 771 | ceph_snap(inode) == CEPH_NOSNAP && |
772 | (le32_to_cpu(info->cap.caps) & CEPH_CAP_FILE_SHARED) && | 772 | (le32_to_cpu(info->cap.caps) & CEPH_CAP_FILE_SHARED) && |
773 | (issued & CEPH_CAP_FILE_EXCL) == 0 && | 773 | (issued & CEPH_CAP_FILE_EXCL) == 0 && |
774 | (ci->i_ceph_flags & CEPH_I_COMPLETE) == 0) { | 774 | !ceph_dir_test_complete(inode)) { |
775 | dout(" marking %p complete (empty)\n", inode); | 775 | dout(" marking %p complete (empty)\n", inode); |
776 | /* ci->i_ceph_flags |= CEPH_I_COMPLETE; */ | 776 | ceph_dir_set_complete(inode); |
777 | ci->i_max_offset = 2; | 777 | ci->i_max_offset = 2; |
778 | } | 778 | } |
779 | 779 | ||
@@ -856,7 +856,7 @@ static void ceph_set_dentry_offset(struct dentry *dn) | |||
856 | di = ceph_dentry(dn); | 856 | di = ceph_dentry(dn); |
857 | 857 | ||
858 | spin_lock(&inode->i_lock); | 858 | spin_lock(&inode->i_lock); |
859 | if ((ceph_inode(inode)->i_ceph_flags & CEPH_I_COMPLETE) == 0) { | 859 | if (!ceph_dir_test_complete(inode)) { |
860 | spin_unlock(&inode->i_lock); | 860 | spin_unlock(&inode->i_lock); |
861 | return; | 861 | return; |
862 | } | 862 | } |
@@ -1056,7 +1056,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
1056 | * d_move() puts the renamed dentry at the end of | 1056 | * d_move() puts the renamed dentry at the end of |
1057 | * d_subdirs. We need to assign it an appropriate | 1057 | * d_subdirs. We need to assign it an appropriate |
1058 | * directory offset so we can behave when holding | 1058 | * directory offset so we can behave when holding |
1059 | * I_COMPLETE. | 1059 | * D_COMPLETE. |
1060 | */ | 1060 | */ |
1061 | ceph_set_dentry_offset(req->r_old_dentry); | 1061 | ceph_set_dentry_offset(req->r_old_dentry); |
1062 | dout("dn %p gets new offset %lld\n", req->r_old_dentry, | 1062 | dout("dn %p gets new offset %lld\n", req->r_old_dentry, |
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 1d72f15fe9f4..b4c3efa163c2 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
@@ -2002,7 +2002,7 @@ out: | |||
2002 | } | 2002 | } |
2003 | 2003 | ||
2004 | /* | 2004 | /* |
2005 | * Invalidate dir I_COMPLETE, dentry lease state on an aborted MDS | 2005 | * Invalidate dir D_COMPLETE, dentry lease state on an aborted MDS |
2006 | * namespace request. | 2006 | * namespace request. |
2007 | */ | 2007 | */ |
2008 | void ceph_invalidate_dir_request(struct ceph_mds_request *req) | 2008 | void ceph_invalidate_dir_request(struct ceph_mds_request *req) |
@@ -2010,9 +2010,9 @@ void ceph_invalidate_dir_request(struct ceph_mds_request *req) | |||
2010 | struct inode *inode = req->r_locked_dir; | 2010 | struct inode *inode = req->r_locked_dir; |
2011 | struct ceph_inode_info *ci = ceph_inode(inode); | 2011 | struct ceph_inode_info *ci = ceph_inode(inode); |
2012 | 2012 | ||
2013 | dout("invalidate_dir_request %p (I_COMPLETE, lease(s))\n", inode); | 2013 | dout("invalidate_dir_request %p (D_COMPLETE, lease(s))\n", inode); |
2014 | spin_lock(&inode->i_lock); | 2014 | spin_lock(&inode->i_lock); |
2015 | ci->i_ceph_flags &= ~CEPH_I_COMPLETE; | 2015 | ceph_dir_clear_complete(inode); |
2016 | ci->i_release_count++; | 2016 | ci->i_release_count++; |
2017 | spin_unlock(&inode->i_lock); | 2017 | spin_unlock(&inode->i_lock); |
2018 | 2018 | ||
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 98e60693c9a1..01bf189e08a9 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
@@ -264,7 +264,7 @@ struct ceph_inode_info { | |||
264 | struct timespec i_rctime; | 264 | struct timespec i_rctime; |
265 | u64 i_rbytes, i_rfiles, i_rsubdirs; | 265 | u64 i_rbytes, i_rfiles, i_rsubdirs; |
266 | u64 i_files, i_subdirs; | 266 | u64 i_files, i_subdirs; |
267 | u64 i_max_offset; /* largest readdir offset, set with I_COMPLETE */ | 267 | u64 i_max_offset; /* largest readdir offset, set with D_COMPLETE */ |
268 | 268 | ||
269 | struct rb_root i_fragtree; | 269 | struct rb_root i_fragtree; |
270 | struct mutex i_fragtree_mutex; | 270 | struct mutex i_fragtree_mutex; |
@@ -429,7 +429,6 @@ static inline struct inode *ceph_find_inode(struct super_block *sb, | |||
429 | /* | 429 | /* |
430 | * Ceph inode. | 430 | * Ceph inode. |
431 | */ | 431 | */ |
432 | #define CEPH_I_COMPLETE 1 /* we have complete directory cached */ | ||
433 | #define CEPH_I_NODELAY 4 /* do not delay cap release */ | 432 | #define CEPH_I_NODELAY 4 /* do not delay cap release */ |
434 | #define CEPH_I_FLUSH 8 /* do not delay flush of dirty metadata */ | 433 | #define CEPH_I_FLUSH 8 /* do not delay flush of dirty metadata */ |
435 | #define CEPH_I_NOFLUSH 16 /* do not flush dirty caps */ | 434 | #define CEPH_I_NOFLUSH 16 /* do not flush dirty caps */ |
@@ -487,6 +486,13 @@ static inline loff_t ceph_make_fpos(unsigned frag, unsigned off) | |||
487 | } | 486 | } |
488 | 487 | ||
489 | /* | 488 | /* |
489 | * set/clear directory D_COMPLETE flag | ||
490 | */ | ||
491 | void ceph_dir_set_complete(struct inode *inode); | ||
492 | void ceph_dir_clear_complete(struct inode *inode); | ||
493 | bool ceph_dir_test_complete(struct inode *inode); | ||
494 | |||
495 | /* | ||
490 | * caps helpers | 496 | * caps helpers |
491 | */ | 497 | */ |
492 | static inline bool __ceph_is_any_real_caps(struct ceph_inode_info *ci) | 498 | static inline bool __ceph_is_any_real_caps(struct ceph_inode_info *ci) |