ceph: introduce a new inode flag indicating if cached dentries are ordered
After creating/deleting/renaming file, offsets of sibling dentries may change. So we can not use cached dentries to satisfy readdir. But we can still use the cached dentries to conclude -ENOENT for lookup. This patch introduces a new inode flag indicating if child dentries are ordered. The flag is set at the same time marking a directory complete. After creating/deleting/renaming file, we clear the flag on directory inode. This prevents ceph_readdir() from using cached dentries to satisfy readdir syscall. Signed-off-by: Yan, Zheng <zyan@redhat.com>
This commit is contained in:
@@ -183,7 +183,7 @@ more:
|
||||
spin_unlock(&parent->d_lock);
|
||||
|
||||
/* make sure a dentry wasn't dropped while we didn't have parent lock */
|
||||
if (!ceph_dir_is_complete(dir)) {
|
||||
if (!ceph_dir_is_complete_ordered(dir)) {
|
||||
dout(" lost dir complete on %p; falling back to mds\n", dir);
|
||||
dput(dentry);
|
||||
err = -EAGAIN;
|
||||
@@ -261,10 +261,6 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
|
||||
|
||||
/* always start with . and .. */
|
||||
if (ctx->pos == 0) {
|
||||
/* note dir version at start of readdir so we can tell
|
||||
* if any dentries get dropped */
|
||||
fi->dir_release_count = atomic_read(&ci->i_release_count);
|
||||
|
||||
dout("readdir off 0 -> '.'\n");
|
||||
if (!dir_emit(ctx, ".", 1,
|
||||
ceph_translate_ino(inode->i_sb, inode->i_ino),
|
||||
@@ -289,7 +285,7 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
|
||||
if ((ctx->pos == 2 || fi->dentry) &&
|
||||
!ceph_test_mount_opt(fsc, NOASYNCREADDIR) &&
|
||||
ceph_snap(inode) != CEPH_SNAPDIR &&
|
||||
__ceph_dir_is_complete(ci) &&
|
||||
__ceph_dir_is_complete_ordered(ci) &&
|
||||
__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) {
|
||||
u32 shared_gen = ci->i_shared_gen;
|
||||
spin_unlock(&ci->i_ceph_lock);
|
||||
@@ -312,6 +308,13 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
|
||||
|
||||
/* proceed with a normal readdir */
|
||||
|
||||
if (ctx->pos == 2) {
|
||||
/* note dir version at start of readdir so we can tell
|
||||
* if any dentries get dropped */
|
||||
fi->dir_release_count = atomic_read(&ci->i_release_count);
|
||||
fi->dir_ordered_count = ci->i_ordered_count;
|
||||
}
|
||||
|
||||
more:
|
||||
/* do we have the correct frag content buffered? */
|
||||
if (fi->frag != frag || fi->last_readdir == NULL) {
|
||||
@@ -446,8 +449,12 @@ more:
|
||||
*/
|
||||
spin_lock(&ci->i_ceph_lock);
|
||||
if (atomic_read(&ci->i_release_count) == fi->dir_release_count) {
|
||||
dout(" marking %p complete\n", inode);
|
||||
__ceph_dir_set_complete(ci, fi->dir_release_count);
|
||||
if (ci->i_ordered_count == fi->dir_ordered_count)
|
||||
dout(" marking %p complete and ordered\n", inode);
|
||||
else
|
||||
dout(" marking %p complete\n", inode);
|
||||
__ceph_dir_set_complete(ci, fi->dir_release_count,
|
||||
fi->dir_ordered_count);
|
||||
}
|
||||
spin_unlock(&ci->i_ceph_lock);
|
||||
|
||||
|
Reference in New Issue
Block a user