mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-16 21:35:07 +00:00
libfs: getdents() should return 0 after reaching EOD
The new directory offset helpers don't conform with the convention of getdents() returning no more entries once a directory file descriptor has reached the current end-of-directory. To address this, copy the logic from dcache_readdir() to mark the open directory file descriptor once EOD has been reached. Seeking resets the mark. Reported-by: Tavian Barnes <tavianator@tavianator.com> Closes: https://lore.kernel.org/linux-fsdevel/20231113180616.2831430-1-tavianator@tavianator.com/ Fixes: 6faddda69f62 ("libfs: Add directory operations for stable offsets") Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Link: https://lore.kernel.org/r/170043792492.4628.15646203084646716134.stgit@bazille.1015granger.net Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
parent
9c04138414
commit
796432efab
14
fs/libfs.c
14
fs/libfs.c
@ -399,6 +399,8 @@ static loff_t offset_dir_llseek(struct file *file, loff_t offset, int whence)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* In this case, ->private_data is protected by f_pos_lock */
|
||||
file->private_data = NULL;
|
||||
return vfs_setpos(file, offset, U32_MAX);
|
||||
}
|
||||
|
||||
@ -428,7 +430,7 @@ static bool offset_dir_emit(struct dir_context *ctx, struct dentry *dentry)
|
||||
inode->i_ino, fs_umode_to_dtype(inode->i_mode));
|
||||
}
|
||||
|
||||
static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
|
||||
static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
|
||||
{
|
||||
struct offset_ctx *so_ctx = inode->i_op->get_offset_ctx(inode);
|
||||
XA_STATE(xas, &so_ctx->xa, ctx->pos);
|
||||
@ -437,7 +439,7 @@ static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
|
||||
while (true) {
|
||||
dentry = offset_find_next(&xas);
|
||||
if (!dentry)
|
||||
break;
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
if (!offset_dir_emit(ctx, dentry)) {
|
||||
dput(dentry);
|
||||
@ -447,6 +449,7 @@ static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
|
||||
dput(dentry);
|
||||
ctx->pos = xas.xa_index + 1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -479,7 +482,12 @@ static int offset_readdir(struct file *file, struct dir_context *ctx)
|
||||
if (!dir_emit_dots(file, ctx))
|
||||
return 0;
|
||||
|
||||
offset_iterate_dir(d_inode(dir), ctx);
|
||||
/* In this case, ->private_data is protected by f_pos_lock */
|
||||
if (ctx->pos == 2)
|
||||
file->private_data = NULL;
|
||||
else if (file->private_data == ERR_PTR(-ENOENT))
|
||||
return 0;
|
||||
file->private_data = offset_iterate_dir(d_inode(dir), ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user