Commit e2f0c565 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-5.10-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux

Pull btrfs fixes from David Sterba:
 "A handful of minor fixes and updates:

   - handle missing device replace item on mount (syzbot report)

   - fix space reservation calculation when finishing relocation

   - fix memory leak on error path in ref-verify (debugging feature)

   - fix potential overflow during defrag on 32bit arches

   - minor code update to silence smatch warning

   - minor error message updates"

* tag 'for-5.10-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: ref-verify: fix memory leak in btrfs_ref_tree_mod
  btrfs: dev-replace: fail mount if we don't have replace item with target device
  btrfs: scrub: update message regarding read-only status
  btrfs: clean up NULL checks in qgroup_unreserve_range()
  btrfs: fix min reserved size calculation in merge_reloc_root
  btrfs: print the block rsv type when we fail our reservation
  btrfs: fix potential overflow in cluster_pages_for_defrag on 32bit arch
parents 52d1998d 468600c6
...@@ -511,7 +511,8 @@ struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans, ...@@ -511,7 +511,8 @@ struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans,
/*DEFAULT_RATELIMIT_BURST*/ 1); /*DEFAULT_RATELIMIT_BURST*/ 1);
if (__ratelimit(&_rs)) if (__ratelimit(&_rs))
WARN(1, KERN_DEBUG WARN(1, KERN_DEBUG
"BTRFS: block rsv returned %d\n", ret); "BTRFS: block rsv %d returned %d\n",
block_rsv->type, ret);
} }
try_reserve: try_reserve:
ret = btrfs_reserve_metadata_bytes(root, block_rsv, blocksize, ret = btrfs_reserve_metadata_bytes(root, block_rsv, blocksize,
......
...@@ -91,6 +91,17 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info) ...@@ -91,6 +91,17 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info)
ret = btrfs_search_slot(NULL, dev_root, &key, path, 0, 0); ret = btrfs_search_slot(NULL, dev_root, &key, path, 0, 0);
if (ret) { if (ret) {
no_valid_dev_replace_entry_found: no_valid_dev_replace_entry_found:
/*
* We don't have a replace item or it's corrupted. If there is
* a replace target, fail the mount.
*/
if (btrfs_find_device(fs_info->fs_devices,
BTRFS_DEV_REPLACE_DEVID, NULL, NULL, false)) {
btrfs_err(fs_info,
"found replace target device without a valid replace item");
ret = -EUCLEAN;
goto out;
}
ret = 0; ret = 0;
dev_replace->replace_state = dev_replace->replace_state =
BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED; BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED;
...@@ -143,8 +154,19 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info) ...@@ -143,8 +154,19 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info)
case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
/*
* We don't have an active replace item but if there is a
* replace target, fail the mount.
*/
if (btrfs_find_device(fs_info->fs_devices,
BTRFS_DEV_REPLACE_DEVID, NULL, NULL, false)) {
btrfs_err(fs_info,
"replace devid present without an active replace item");
ret = -EUCLEAN;
} else {
dev_replace->srcdev = NULL; dev_replace->srcdev = NULL;
dev_replace->tgtdev = NULL; dev_replace->tgtdev = NULL;
}
break; break;
case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
......
...@@ -1274,6 +1274,7 @@ static int cluster_pages_for_defrag(struct inode *inode, ...@@ -1274,6 +1274,7 @@ static int cluster_pages_for_defrag(struct inode *inode,
u64 page_start; u64 page_start;
u64 page_end; u64 page_end;
u64 page_cnt; u64 page_cnt;
u64 start = (u64)start_index << PAGE_SHIFT;
int ret; int ret;
int i; int i;
int i_done; int i_done;
...@@ -1290,8 +1291,7 @@ static int cluster_pages_for_defrag(struct inode *inode, ...@@ -1290,8 +1291,7 @@ static int cluster_pages_for_defrag(struct inode *inode,
page_cnt = min_t(u64, (u64)num_pages, (u64)file_end - start_index + 1); page_cnt = min_t(u64, (u64)num_pages, (u64)file_end - start_index + 1);
ret = btrfs_delalloc_reserve_space(BTRFS_I(inode), &data_reserved, ret = btrfs_delalloc_reserve_space(BTRFS_I(inode), &data_reserved,
start_index << PAGE_SHIFT, start, page_cnt << PAGE_SHIFT);
page_cnt << PAGE_SHIFT);
if (ret) if (ret)
return ret; return ret;
i_done = 0; i_done = 0;
...@@ -1380,8 +1380,7 @@ static int cluster_pages_for_defrag(struct inode *inode, ...@@ -1380,8 +1380,7 @@ static int cluster_pages_for_defrag(struct inode *inode,
btrfs_mod_outstanding_extents(BTRFS_I(inode), 1); btrfs_mod_outstanding_extents(BTRFS_I(inode), 1);
spin_unlock(&BTRFS_I(inode)->lock); spin_unlock(&BTRFS_I(inode)->lock);
btrfs_delalloc_release_space(BTRFS_I(inode), data_reserved, btrfs_delalloc_release_space(BTRFS_I(inode), data_reserved,
start_index << PAGE_SHIFT, start, (page_cnt - i_done) << PAGE_SHIFT, true);
(page_cnt - i_done) << PAGE_SHIFT, true);
} }
...@@ -1408,8 +1407,7 @@ static int cluster_pages_for_defrag(struct inode *inode, ...@@ -1408,8 +1407,7 @@ static int cluster_pages_for_defrag(struct inode *inode,
put_page(pages[i]); put_page(pages[i]);
} }
btrfs_delalloc_release_space(BTRFS_I(inode), data_reserved, btrfs_delalloc_release_space(BTRFS_I(inode), data_reserved,
start_index << PAGE_SHIFT, start, page_cnt << PAGE_SHIFT, true);
page_cnt << PAGE_SHIFT, true);
btrfs_delalloc_release_extents(BTRFS_I(inode), page_cnt << PAGE_SHIFT); btrfs_delalloc_release_extents(BTRFS_I(inode), page_cnt << PAGE_SHIFT);
extent_changeset_free(data_reserved); extent_changeset_free(data_reserved);
return ret; return ret;
......
...@@ -3435,24 +3435,20 @@ static int qgroup_unreserve_range(struct btrfs_inode *inode, ...@@ -3435,24 +3435,20 @@ static int qgroup_unreserve_range(struct btrfs_inode *inode,
{ {
struct rb_node *node; struct rb_node *node;
struct rb_node *next; struct rb_node *next;
struct ulist_node *entry = NULL; struct ulist_node *entry;
int ret = 0; int ret = 0;
node = reserved->range_changed.root.rb_node; node = reserved->range_changed.root.rb_node;
if (!node)
return 0;
while (node) { while (node) {
entry = rb_entry(node, struct ulist_node, rb_node); entry = rb_entry(node, struct ulist_node, rb_node);
if (entry->val < start) if (entry->val < start)
node = node->rb_right; node = node->rb_right;
else if (entry)
node = node->rb_left;
else else
break; node = node->rb_left;
} }
/* Empty changeset */
if (!entry)
return 0;
if (entry->val > start && rb_prev(&entry->rb_node)) if (entry->val > start && rb_prev(&entry->rb_node))
entry = rb_entry(rb_prev(&entry->rb_node), struct ulist_node, entry = rb_entry(rb_prev(&entry->rb_node), struct ulist_node,
rb_node); rb_node);
......
...@@ -860,6 +860,7 @@ int btrfs_ref_tree_mod(struct btrfs_fs_info *fs_info, ...@@ -860,6 +860,7 @@ int btrfs_ref_tree_mod(struct btrfs_fs_info *fs_info,
"dropping a ref for a root that doesn't have a ref on the block"); "dropping a ref for a root that doesn't have a ref on the block");
dump_block_entry(fs_info, be); dump_block_entry(fs_info, be);
dump_ref_action(fs_info, ra); dump_ref_action(fs_info, ra);
kfree(ref);
kfree(ra); kfree(ra);
goto out_unlock; goto out_unlock;
} }
......
...@@ -1648,6 +1648,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc, ...@@ -1648,6 +1648,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
struct btrfs_root_item *root_item; struct btrfs_root_item *root_item;
struct btrfs_path *path; struct btrfs_path *path;
struct extent_buffer *leaf; struct extent_buffer *leaf;
int reserve_level;
int level; int level;
int max_level; int max_level;
int replaced = 0; int replaced = 0;
...@@ -1696,7 +1697,8 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc, ...@@ -1696,7 +1697,8 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
* Thus the needed metadata size is at most root_level * nodesize, * Thus the needed metadata size is at most root_level * nodesize,
* and * 2 since we have two trees to COW. * and * 2 since we have two trees to COW.
*/ */
min_reserved = fs_info->nodesize * btrfs_root_level(root_item) * 2; reserve_level = max_t(int, 1, btrfs_root_level(root_item));
min_reserved = fs_info->nodesize * reserve_level * 2;
memset(&next_key, 0, sizeof(next_key)); memset(&next_key, 0, sizeof(next_key));
while (1) { while (1) {
......
...@@ -3866,8 +3866,9 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, ...@@ -3866,8 +3866,9 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
if (!is_dev_replace && !readonly && if (!is_dev_replace && !readonly &&
!test_bit(BTRFS_DEV_STATE_WRITEABLE, &dev->dev_state)) { !test_bit(BTRFS_DEV_STATE_WRITEABLE, &dev->dev_state)) {
mutex_unlock(&fs_info->fs_devices->device_list_mutex); mutex_unlock(&fs_info->fs_devices->device_list_mutex);
btrfs_err_in_rcu(fs_info, "scrub: device %s is not writable", btrfs_err_in_rcu(fs_info,
rcu_str_deref(dev->name)); "scrub on devid %llu: filesystem on %s is not writable",
devid, rcu_str_deref(dev->name));
ret = -EROFS; ret = -EROFS;
goto out; goto out;
} }
......
...@@ -1056,22 +1056,13 @@ static void __btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices, ...@@ -1056,22 +1056,13 @@ static void __btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices,
continue; continue;
} }
if (device->devid == BTRFS_DEV_REPLACE_DEVID) {
/* /*
* In the first step, keep the device which has * We have already validated the presence of BTRFS_DEV_REPLACE_DEVID,
* the correct fsid and the devid that is used * in btrfs_init_dev_replace() so just continue.
* for the dev_replace procedure. */
* In the second step, the dev_replace state is if (device->devid == BTRFS_DEV_REPLACE_DEVID)
* read from the device tree and it is known
* whether the procedure is really active or
* not, which means whether this device is
* used or whether it should be removed.
*/
if (step == 0 || test_bit(BTRFS_DEV_STATE_REPLACE_TGT,
&device->dev_state)) {
continue; continue;
}
}
if (device->bdev) { if (device->bdev) {
blkdev_put(device->bdev, device->mode); blkdev_put(device->bdev, device->mode);
device->bdev = NULL; device->bdev = NULL;
...@@ -1080,9 +1071,6 @@ static void __btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices, ...@@ -1080,9 +1071,6 @@ static void __btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices,
if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) { if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
list_del_init(&device->dev_alloc_list); list_del_init(&device->dev_alloc_list);
clear_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state); clear_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
if (!test_bit(BTRFS_DEV_STATE_REPLACE_TGT,
&device->dev_state))
fs_devices->rw_devices--;
} }
list_del_init(&device->dev_list); list_del_init(&device->dev_list);
fs_devices->num_devices--; fs_devices->num_devices--;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment