Skip to content

Commit d2fbb2b

Browse files
jeffmahoneykdave
authored andcommitted
btrfs: increment ctx->pos for every emitted or skipped dirent in readdir
If we process the last item in the leaf and hit an I/O error while reading the next leaf, we return -EIO without having adjusted the position. Since we have emitted dirents, getdents() will return the byte count to the user instead of the error. Subsequent callers will emit the last successful dirent again, and return -EIO again, with the same result. Callers loop forever. Instead, if we always increment ctx->pos after emitting or skipping the dirent, we'll be sure that we won't hit the same one again. When we go to process the next leaf, we won't have emitted any dirents and the -EIO will be returned to the user properly. We also don't need to track if we've emitted a dirent already or if we've changed the position yet. Signed-off-by: Jeff Mahoney <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent c2951f3 commit d2fbb2b

File tree

3 files changed

+4
-23
lines changed

3 files changed

+4
-23
lines changed

fs/btrfs/delayed-inode.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,7 +1686,7 @@ int btrfs_should_delete_dir_index(struct list_head *del_list,
16861686
*
16871687
*/
16881688
int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
1689-
struct list_head *ins_list, bool *emitted)
1689+
struct list_head *ins_list)
16901690
{
16911691
struct btrfs_dir_item *di;
16921692
struct btrfs_delayed_item *curr, *next;
@@ -1730,7 +1730,6 @@ int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
17301730

17311731
if (over)
17321732
return 1;
1733-
*emitted = true;
17341733
}
17351734
return 0;
17361735
}

fs/btrfs/delayed-inode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ void btrfs_readdir_put_delayed_items(struct inode *inode,
146146
int btrfs_should_delete_dir_index(struct list_head *del_list,
147147
u64 index);
148148
int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
149-
struct list_head *ins_list, bool *emitted);
149+
struct list_head *ins_list);
150150

151151
/* for init */
152152
int __init btrfs_delayed_inode_init(void);

fs/btrfs/inode.c

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5807,8 +5807,6 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
58075807
char tmp_name[32];
58085808
char *name_ptr;
58095809
int name_len;
5810-
int is_curr = 0; /* ctx->pos points to the current index? */
5811-
bool emitted;
58125810
bool put = false;
58135811
struct btrfs_key location;
58145812

@@ -5833,7 +5831,6 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
58335831
if (ret < 0)
58345832
goto err;
58355833

5836-
emitted = false;
58375834
while (1) {
58385835
leaf = path->nodes[0];
58395836
slot = path->slots[0];
@@ -5859,7 +5856,6 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
58595856
goto next;
58605857

58615858
ctx->pos = found_key.offset;
5862-
is_curr = 1;
58635859

58645860
di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
58655861
if (verify_dir_item(root, leaf, di))
@@ -5887,31 +5883,17 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
58875883
if (name_ptr != tmp_name)
58885884
kfree(name_ptr);
58895885

5890-
emitted = true;
58915886
if (over)
58925887
goto nopos;
5888+
ctx->pos++;
58935889
next:
58945890
path->slots[0]++;
58955891
}
58965892

5897-
if (is_curr)
5898-
ctx->pos++;
5899-
ret = btrfs_readdir_delayed_dir_index(ctx, &ins_list, &emitted);
5893+
ret = btrfs_readdir_delayed_dir_index(ctx, &ins_list);
59005894
if (ret)
59015895
goto nopos;
59025896

5903-
/*
5904-
* If we haven't emitted any dir entry, we must not touch ctx->pos as
5905-
* it was was set to the termination value in previous call. We assume
5906-
* that "." and ".." were emitted if we reach this point and set the
5907-
* termination value as well for an empty directory.
5908-
*/
5909-
if (ctx->pos > 2 && !emitted)
5910-
goto nopos;
5911-
5912-
/* Reached end of directory/root. Bump pos past the last item. */
5913-
ctx->pos++;
5914-
59155897
/*
59165898
* Stop new entries from being returned after we return the last
59175899
* entry.

0 commit comments

Comments
 (0)