Skip to content

Commit e4fd493

Browse files
Josef Bacikkdave
authored andcommitted
Btrfs: fix stale entries in readdir
In fixing the readdir+pagefault deadlock I accidentally introduced a stale entry regression in readdir. If we get close to full for the temporary buffer, and then skip a few delayed deletions, and then try to add another entry that won't fit, we will emit the entries we found and retry. Unfortunately we delete entries from our del_list as we find them, assuming we won't need them. However our pos will be with whatever our last entry was, which could be before the delayed deletions we skipped, so the next search will add the deleted entries back into our readdir buffer. So instead don't delete entries we find in our del_list so we can make sure we always find our delayed deletions. This is a slight perf hit for readdir with lots of pending deletions, but hopefully this isn't a common occurrence. If it is we can revist this and optimize it. cc: stable@vger.kernel.org Fixes: 23b5ec7 ("btrfs: fix readdir deadlock with pagefault") Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent ec35e48 commit e4fd493

File tree

1 file changed

+8
-18
lines changed

1 file changed

+8
-18
lines changed

fs/btrfs/delayed-inode.c

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,28 +1633,18 @@ void btrfs_readdir_put_delayed_items(struct inode *inode,
16331633
int btrfs_should_delete_dir_index(struct list_head *del_list,
16341634
u64 index)
16351635
{
1636-
struct btrfs_delayed_item *curr, *next;
1637-
int ret;
1638-
1639-
if (list_empty(del_list))
1640-
return 0;
1636+
struct btrfs_delayed_item *curr;
1637+
int ret = 0;
16411638

1642-
list_for_each_entry_safe(curr, next, del_list, readdir_list) {
1639+
list_for_each_entry(curr, del_list, readdir_list) {
16431640
if (curr->key.offset > index)
16441641
break;
1645-
1646-
list_del(&curr->readdir_list);
1647-
ret = (curr->key.offset == index);
1648-
1649-
if (refcount_dec_and_test(&curr->refs))
1650-
kfree(curr);
1651-
1652-
if (ret)
1653-
return 1;
1654-
else
1655-
continue;
1642+
if (curr->key.offset == index) {
1643+
ret = 1;
1644+
break;
1645+
}
16561646
}
1657-
return 0;
1647+
return ret;
16581648
}
16591649

16601650
/*

0 commit comments

Comments
 (0)