Skip to content

Commit 796432e

Browse files
chuckleverbrauner
authored andcommitted
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 <[email protected]> Closes: https://lore.kernel.org/linux-fsdevel/[email protected]/ Fixes: 6faddda ("libfs: Add directory operations for stable offsets") Signed-off-by: Chuck Lever <[email protected]> Link: https://lore.kernel.org/r/170043792492.4628.15646203084646716134.stgit@bazille.1015granger.net Signed-off-by: Christian Brauner <[email protected]>
1 parent 9c04138 commit 796432e

File tree

1 file changed

+11
-3
lines changed

1 file changed

+11
-3
lines changed

fs/libfs.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,8 @@ static loff_t offset_dir_llseek(struct file *file, loff_t offset, int whence)
399399
return -EINVAL;
400400
}
401401

402+
/* In this case, ->private_data is protected by f_pos_lock */
403+
file->private_data = NULL;
402404
return vfs_setpos(file, offset, U32_MAX);
403405
}
404406

@@ -428,7 +430,7 @@ static bool offset_dir_emit(struct dir_context *ctx, struct dentry *dentry)
428430
inode->i_ino, fs_umode_to_dtype(inode->i_mode));
429431
}
430432

431-
static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
433+
static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
432434
{
433435
struct offset_ctx *so_ctx = inode->i_op->get_offset_ctx(inode);
434436
XA_STATE(xas, &so_ctx->xa, ctx->pos);
@@ -437,7 +439,7 @@ static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
437439
while (true) {
438440
dentry = offset_find_next(&xas);
439441
if (!dentry)
440-
break;
442+
return ERR_PTR(-ENOENT);
441443

442444
if (!offset_dir_emit(ctx, dentry)) {
443445
dput(dentry);
@@ -447,6 +449,7 @@ static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
447449
dput(dentry);
448450
ctx->pos = xas.xa_index + 1;
449451
}
452+
return NULL;
450453
}
451454

452455
/**
@@ -479,7 +482,12 @@ static int offset_readdir(struct file *file, struct dir_context *ctx)
479482
if (!dir_emit_dots(file, ctx))
480483
return 0;
481484

482-
offset_iterate_dir(d_inode(dir), ctx);
485+
/* In this case, ->private_data is protected by f_pos_lock */
486+
if (ctx->pos == 2)
487+
file->private_data = NULL;
488+
else if (file->private_data == ERR_PTR(-ENOENT))
489+
return 0;
490+
file->private_data = offset_iterate_dir(d_inode(dir), ctx);
483491
return 0;
484492
}
485493

0 commit comments

Comments
 (0)