diff options
| -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) |
