for-5.11-rc3-tag
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAl/8jD4ACgkQxWXV+ddt WDteWQ//QcpD6STpLwAC+g6zJyJln7Au9lfQvawugvOJssbtdPkJQP3ZiK+Izwi/ /xagu6XMazJM+47acNJKDNntOqVkp+O6CxEbLU+rL/D288L3HEGxayZ2LL90wm6J tbIebOE+BSVZ/5oe0jVdqZXwYvUtTiJ7PoFgrZPXJCnddSitZRD3tC4Wmi/Yo5+0 +7CW6PT3/s7KARwYXpgpMM5vi8qO2nfHfTUdRlSh59g7zC/TH7HiitL6roHzlX1k g/aaKYLVcg62OPpw7ZXwde/qH8n1TR+H5WX6vBInqd/9jYcNkVGqijCgBeL1TJkN Vx/b69ccODK2GNzuuYoo3k3XvSwZWsOTZp+k4y3EZ1cMONMo1snu/xglYsvSZvUL lNCQlA9hIZNskRwEvkEea68/bQdiOl6xezgR9tajMlmz7oCsV/Cz/MJ+RfqaxdH3 bV6eTTex67lQfzAda+gN+zjBrFzQdmK700gKimdzF1XfcYmmCIdZVX8Gm/N6ldQN LNRe8zYRaqrmRk9PQ355RqYDZmft/wLiUV6V0j74oV65WpPe2R4pULWdmPAGm6Oj UWM+ZR3u9m8asg7ghKYgct2pxCS3+gLbDNXNcOSxYxthEEZB2JqkAMjtjCfwJilN PXfuXaBKRmRck+AcYfbBrfJOljQ+zAJdTK/Rid40TwwpFCe/jjY= =G3R4 -----END PGP SIGNATURE----- Merge tag 'for-5.11-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux Pull btrfs fixes from David Sterba: "More material for stable trees. - tree-checker: check item end overflow - fix false warning during relocation regarding extent type - fix inode flushing logic, caused notable performance regression (since 5.10) - debugging fixups: - print correct offset for reloc tree key - pass reliable fs_info pointer to error reporting helper" * tag 'for-5.11-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: shrink delalloc pages instead of full inodes btrfs: reloc: fix wrong file extent type check to avoid false ENOENT btrfs: tree-checker: check if chunk item end overflows btrfs: prevent NULL pointer dereference in extent_io_tree_panic btrfs: print the actual offset in btrfs_root_name
This commit is contained in:
commit
6e68b9961f
|
@ -1457,7 +1457,7 @@ void btrfs_check_leaked_roots(struct btrfs_fs_info *fs_info)
|
|||
root = list_first_entry(&fs_info->allocated_roots,
|
||||
struct btrfs_root, leak_list);
|
||||
btrfs_err(fs_info, "leaked root %s refcount %d",
|
||||
btrfs_root_name(root->root_key.objectid, buf),
|
||||
btrfs_root_name(&root->root_key, buf),
|
||||
refcount_read(&root->refs));
|
||||
while (refcount_read(&root->refs) > 1)
|
||||
btrfs_put_root(root);
|
||||
|
|
|
@ -676,9 +676,7 @@ alloc_extent_state_atomic(struct extent_state *prealloc)
|
|||
|
||||
static void extent_io_tree_panic(struct extent_io_tree *tree, int err)
|
||||
{
|
||||
struct inode *inode = tree->private_data;
|
||||
|
||||
btrfs_panic(btrfs_sb(inode->i_sb), err,
|
||||
btrfs_panic(tree->fs_info, err,
|
||||
"locking error: extent tree was modified by another thread while locked");
|
||||
}
|
||||
|
||||
|
|
|
@ -9390,7 +9390,8 @@ static struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode
|
|||
* some fairly slow code that needs optimization. This walks the list
|
||||
* of all the inodes with pending delalloc and forces them to disk.
|
||||
*/
|
||||
static int start_delalloc_inodes(struct btrfs_root *root, u64 *nr, bool snapshot,
|
||||
static int start_delalloc_inodes(struct btrfs_root *root,
|
||||
struct writeback_control *wbc, bool snapshot,
|
||||
bool in_reclaim_context)
|
||||
{
|
||||
struct btrfs_inode *binode;
|
||||
|
@ -9399,6 +9400,7 @@ static int start_delalloc_inodes(struct btrfs_root *root, u64 *nr, bool snapshot
|
|||
struct list_head works;
|
||||
struct list_head splice;
|
||||
int ret = 0;
|
||||
bool full_flush = wbc->nr_to_write == LONG_MAX;
|
||||
|
||||
INIT_LIST_HEAD(&works);
|
||||
INIT_LIST_HEAD(&splice);
|
||||
|
@ -9427,18 +9429,24 @@ static int start_delalloc_inodes(struct btrfs_root *root, u64 *nr, bool snapshot
|
|||
if (snapshot)
|
||||
set_bit(BTRFS_INODE_SNAPSHOT_FLUSH,
|
||||
&binode->runtime_flags);
|
||||
work = btrfs_alloc_delalloc_work(inode);
|
||||
if (!work) {
|
||||
iput(inode);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
list_add_tail(&work->list, &works);
|
||||
btrfs_queue_work(root->fs_info->flush_workers,
|
||||
&work->work);
|
||||
if (*nr != U64_MAX) {
|
||||
(*nr)--;
|
||||
if (*nr == 0)
|
||||
if (full_flush) {
|
||||
work = btrfs_alloc_delalloc_work(inode);
|
||||
if (!work) {
|
||||
iput(inode);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
list_add_tail(&work->list, &works);
|
||||
btrfs_queue_work(root->fs_info->flush_workers,
|
||||
&work->work);
|
||||
} else {
|
||||
ret = sync_inode(inode, wbc);
|
||||
if (!ret &&
|
||||
test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
|
||||
&BTRFS_I(inode)->runtime_flags))
|
||||
ret = sync_inode(inode, wbc);
|
||||
btrfs_add_delayed_iput(inode);
|
||||
if (ret || wbc->nr_to_write <= 0)
|
||||
goto out;
|
||||
}
|
||||
cond_resched();
|
||||
|
@ -9464,18 +9472,29 @@ out:
|
|||
|
||||
int btrfs_start_delalloc_snapshot(struct btrfs_root *root)
|
||||
{
|
||||
struct writeback_control wbc = {
|
||||
.nr_to_write = LONG_MAX,
|
||||
.sync_mode = WB_SYNC_NONE,
|
||||
.range_start = 0,
|
||||
.range_end = LLONG_MAX,
|
||||
};
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
u64 nr = U64_MAX;
|
||||
|
||||
if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state))
|
||||
return -EROFS;
|
||||
|
||||
return start_delalloc_inodes(root, &nr, true, false);
|
||||
return start_delalloc_inodes(root, &wbc, true, false);
|
||||
}
|
||||
|
||||
int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, u64 nr,
|
||||
bool in_reclaim_context)
|
||||
{
|
||||
struct writeback_control wbc = {
|
||||
.nr_to_write = (nr == U64_MAX) ? LONG_MAX : (unsigned long)nr,
|
||||
.sync_mode = WB_SYNC_NONE,
|
||||
.range_start = 0,
|
||||
.range_end = LLONG_MAX,
|
||||
};
|
||||
struct btrfs_root *root;
|
||||
struct list_head splice;
|
||||
int ret;
|
||||
|
@ -9489,6 +9508,13 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, u64 nr,
|
|||
spin_lock(&fs_info->delalloc_root_lock);
|
||||
list_splice_init(&fs_info->delalloc_roots, &splice);
|
||||
while (!list_empty(&splice) && nr) {
|
||||
/*
|
||||
* Reset nr_to_write here so we know that we're doing a full
|
||||
* flush.
|
||||
*/
|
||||
if (nr == U64_MAX)
|
||||
wbc.nr_to_write = LONG_MAX;
|
||||
|
||||
root = list_first_entry(&splice, struct btrfs_root,
|
||||
delalloc_root);
|
||||
root = btrfs_grab_root(root);
|
||||
|
@ -9497,9 +9523,9 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, u64 nr,
|
|||
&fs_info->delalloc_roots);
|
||||
spin_unlock(&fs_info->delalloc_root_lock);
|
||||
|
||||
ret = start_delalloc_inodes(root, &nr, false, in_reclaim_context);
|
||||
ret = start_delalloc_inodes(root, &wbc, false, in_reclaim_context);
|
||||
btrfs_put_root(root);
|
||||
if (ret < 0)
|
||||
if (ret < 0 || wbc.nr_to_write <= 0)
|
||||
goto out;
|
||||
spin_lock(&fs_info->delalloc_root_lock);
|
||||
}
|
||||
|
|
|
@ -26,22 +26,22 @@ static const struct root_name_map root_map[] = {
|
|||
{ BTRFS_DATA_RELOC_TREE_OBJECTID, "DATA_RELOC_TREE" },
|
||||
};
|
||||
|
||||
const char *btrfs_root_name(u64 objectid, char *buf)
|
||||
const char *btrfs_root_name(const struct btrfs_key *key, char *buf)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (objectid == BTRFS_TREE_RELOC_OBJECTID) {
|
||||
if (key->objectid == BTRFS_TREE_RELOC_OBJECTID) {
|
||||
snprintf(buf, BTRFS_ROOT_NAME_BUF_LEN,
|
||||
"TREE_RELOC offset=%llu", objectid);
|
||||
"TREE_RELOC offset=%llu", key->offset);
|
||||
return buf;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(root_map); i++) {
|
||||
if (root_map[i].id == objectid)
|
||||
if (root_map[i].id == key->objectid)
|
||||
return root_map[i].name;
|
||||
}
|
||||
|
||||
snprintf(buf, BTRFS_ROOT_NAME_BUF_LEN, "%llu", objectid);
|
||||
snprintf(buf, BTRFS_ROOT_NAME_BUF_LEN, "%llu", key->objectid);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
|
||||
void btrfs_print_leaf(struct extent_buffer *l);
|
||||
void btrfs_print_tree(struct extent_buffer *c, bool follow);
|
||||
const char *btrfs_root_name(u64 objectid, char *buf);
|
||||
const char *btrfs_root_name(const struct btrfs_key *key, char *buf);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2975,11 +2975,16 @@ static int delete_v1_space_cache(struct extent_buffer *leaf,
|
|||
return 0;
|
||||
|
||||
for (i = 0; i < btrfs_header_nritems(leaf); i++) {
|
||||
u8 type;
|
||||
|
||||
btrfs_item_key_to_cpu(leaf, &key, i);
|
||||
if (key.type != BTRFS_EXTENT_DATA_KEY)
|
||||
continue;
|
||||
ei = btrfs_item_ptr(leaf, i, struct btrfs_file_extent_item);
|
||||
if (btrfs_file_extent_type(leaf, ei) == BTRFS_FILE_EXTENT_REG &&
|
||||
type = btrfs_file_extent_type(leaf, ei);
|
||||
|
||||
if ((type == BTRFS_FILE_EXTENT_REG ||
|
||||
type == BTRFS_FILE_EXTENT_PREALLOC) &&
|
||||
btrfs_file_extent_disk_bytenr(leaf, ei) == data_bytenr) {
|
||||
found = true;
|
||||
space_cache_ino = key.objectid;
|
||||
|
|
|
@ -532,7 +532,9 @@ static void shrink_delalloc(struct btrfs_fs_info *fs_info,
|
|||
|
||||
loops = 0;
|
||||
while ((delalloc_bytes || dio_bytes) && loops < 3) {
|
||||
btrfs_start_delalloc_roots(fs_info, items, true);
|
||||
u64 nr_pages = min(delalloc_bytes, to_reclaim) >> PAGE_SHIFT;
|
||||
|
||||
btrfs_start_delalloc_roots(fs_info, nr_pages, true);
|
||||
|
||||
loops++;
|
||||
if (wait_ordered && !trans) {
|
||||
|
|
|
@ -760,6 +760,7 @@ int btrfs_check_chunk_valid(struct extent_buffer *leaf,
|
|||
{
|
||||
struct btrfs_fs_info *fs_info = leaf->fs_info;
|
||||
u64 length;
|
||||
u64 chunk_end;
|
||||
u64 stripe_len;
|
||||
u16 num_stripes;
|
||||
u16 sub_stripes;
|
||||
|
@ -814,6 +815,12 @@ int btrfs_check_chunk_valid(struct extent_buffer *leaf,
|
|||
"invalid chunk length, have %llu", length);
|
||||
return -EUCLEAN;
|
||||
}
|
||||
if (unlikely(check_add_overflow(logical, length, &chunk_end))) {
|
||||
chunk_err(leaf, chunk, logical,
|
||||
"invalid chunk logical start and length, have logical start %llu length %llu",
|
||||
logical, length);
|
||||
return -EUCLEAN;
|
||||
}
|
||||
if (unlikely(!is_power_of_2(stripe_len) || stripe_len != BTRFS_STRIPE_LEN)) {
|
||||
chunk_err(leaf, chunk, logical,
|
||||
"invalid chunk stripe length: %llu",
|
||||
|
|
Loading…
Reference in New Issue