Commit 66e55ff1 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull btrfs fixes from David Sterba:

 - fix quota root leak after quota disable failure

 - fix condition when checking if a zone can be added as free

 - allocate inode in NOFS context during logging or tree-log replay

 - handle raid-stripe-tree lookup correctly during scrub

* tag 'for-6.10-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: qgroup: fix quota root leak after quota disable failure
  btrfs: scrub: handle RST lookup error correctly
  btrfs: zoned: fix initial free space detection
  btrfs: use NOFS context when getting inodes during logging and log replay
parents fd19d4a4 a7e4c6a3
...@@ -2697,7 +2697,7 @@ static int __btrfs_add_free_space_zoned(struct btrfs_block_group *block_group, ...@@ -2697,7 +2697,7 @@ static int __btrfs_add_free_space_zoned(struct btrfs_block_group *block_group,
u64 offset = bytenr - block_group->start; u64 offset = bytenr - block_group->start;
u64 to_free, to_unusable; u64 to_free, to_unusable;
int bg_reclaim_threshold = 0; int bg_reclaim_threshold = 0;
bool initial = (size == block_group->length); bool initial = ((size == block_group->length) && (block_group->alloc_offset == 0));
u64 reclaimable_unusable; u64 reclaimable_unusable;
WARN_ON(!initial && offset + size > block_group->zone_capacity); WARN_ON(!initial && offset + size > block_group->zone_capacity);
......
...@@ -1351,7 +1351,7 @@ static int flush_reservations(struct btrfs_fs_info *fs_info) ...@@ -1351,7 +1351,7 @@ static int flush_reservations(struct btrfs_fs_info *fs_info)
int btrfs_quota_disable(struct btrfs_fs_info *fs_info) int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
{ {
struct btrfs_root *quota_root; struct btrfs_root *quota_root = NULL;
struct btrfs_trans_handle *trans = NULL; struct btrfs_trans_handle *trans = NULL;
int ret = 0; int ret = 0;
...@@ -1449,9 +1449,9 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info) ...@@ -1449,9 +1449,9 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
btrfs_free_tree_block(trans, btrfs_root_id(quota_root), btrfs_free_tree_block(trans, btrfs_root_id(quota_root),
quota_root->node, 0, 1); quota_root->node, 0, 1);
btrfs_put_root(quota_root);
out: out:
btrfs_put_root(quota_root);
mutex_unlock(&fs_info->qgroup_ioctl_lock); mutex_unlock(&fs_info->qgroup_ioctl_lock);
if (ret && trans) if (ret && trans)
btrfs_end_transaction(trans); btrfs_end_transaction(trans);
......
...@@ -1688,20 +1688,24 @@ static void scrub_submit_extent_sector_read(struct scrub_ctx *sctx, ...@@ -1688,20 +1688,24 @@ static void scrub_submit_extent_sector_read(struct scrub_ctx *sctx,
(i << fs_info->sectorsize_bits); (i << fs_info->sectorsize_bits);
int err; int err;
bbio = btrfs_bio_alloc(stripe->nr_sectors, REQ_OP_READ,
fs_info, scrub_read_endio, stripe);
bbio->bio.bi_iter.bi_sector = logical >> SECTOR_SHIFT;
io_stripe.is_scrub = true; io_stripe.is_scrub = true;
stripe_len = (nr_sectors - i) << fs_info->sectorsize_bits;
/*
* For RST cases, we need to manually split the bbio to
* follow the RST boundary.
*/
err = btrfs_map_block(fs_info, BTRFS_MAP_READ, logical, err = btrfs_map_block(fs_info, BTRFS_MAP_READ, logical,
&stripe_len, &bioc, &io_stripe, &stripe_len, &bioc, &io_stripe, &mirror);
&mirror);
btrfs_put_bioc(bioc); btrfs_put_bioc(bioc);
if (err) { if (err < 0) {
btrfs_bio_end_io(bbio, set_bit(i, &stripe->io_error_bitmap);
errno_to_blk_status(err)); set_bit(i, &stripe->error_bitmap);
return; continue;
} }
bbio = btrfs_bio_alloc(stripe->nr_sectors, REQ_OP_READ,
fs_info, scrub_read_endio, stripe);
bbio->bio.bi_iter.bi_sector = logical >> SECTOR_SHIFT;
} }
__bio_add_page(&bbio->bio, page, fs_info->sectorsize, pgoff); __bio_add_page(&bbio->bio, page, fs_info->sectorsize, pgoff);
......
...@@ -138,6 +138,25 @@ static void wait_log_commit(struct btrfs_root *root, int transid); ...@@ -138,6 +138,25 @@ static void wait_log_commit(struct btrfs_root *root, int transid);
* and once to do all the other items. * and once to do all the other items.
*/ */
static struct inode *btrfs_iget_logging(u64 objectid, struct btrfs_root *root)
{
unsigned int nofs_flag;
struct inode *inode;
/*
* We're holding a transaction handle whether we are logging or
* replaying a log tree, so we must make sure NOFS semantics apply
* because btrfs_alloc_inode() may be triggered and it uses GFP_KERNEL
* to allocate an inode, which can recurse back into the filesystem and
* attempt a transaction commit, resulting in a deadlock.
*/
nofs_flag = memalloc_nofs_save();
inode = btrfs_iget(root->fs_info->sb, objectid, root);
memalloc_nofs_restore(nofs_flag);
return inode;
}
/* /*
* start a sub transaction and setup the log tree * start a sub transaction and setup the log tree
* this increments the log tree writer count to make the people * this increments the log tree writer count to make the people
...@@ -600,7 +619,7 @@ static noinline struct inode *read_one_inode(struct btrfs_root *root, ...@@ -600,7 +619,7 @@ static noinline struct inode *read_one_inode(struct btrfs_root *root,
{ {
struct inode *inode; struct inode *inode;
inode = btrfs_iget(root->fs_info->sb, objectid, root); inode = btrfs_iget_logging(objectid, root);
if (IS_ERR(inode)) if (IS_ERR(inode))
inode = NULL; inode = NULL;
return inode; return inode;
...@@ -5438,7 +5457,6 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans, ...@@ -5438,7 +5457,6 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans,
struct btrfs_log_ctx *ctx) struct btrfs_log_ctx *ctx)
{ {
struct btrfs_root *root = start_inode->root; struct btrfs_root *root = start_inode->root;
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_path *path; struct btrfs_path *path;
LIST_HEAD(dir_list); LIST_HEAD(dir_list);
struct btrfs_dir_list *dir_elem; struct btrfs_dir_list *dir_elem;
...@@ -5499,7 +5517,7 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans, ...@@ -5499,7 +5517,7 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans,
continue; continue;
btrfs_release_path(path); btrfs_release_path(path);
di_inode = btrfs_iget(fs_info->sb, di_key.objectid, root); di_inode = btrfs_iget_logging(di_key.objectid, root);
if (IS_ERR(di_inode)) { if (IS_ERR(di_inode)) {
ret = PTR_ERR(di_inode); ret = PTR_ERR(di_inode);
goto out; goto out;
...@@ -5559,7 +5577,7 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans, ...@@ -5559,7 +5577,7 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans,
btrfs_add_delayed_iput(curr_inode); btrfs_add_delayed_iput(curr_inode);
curr_inode = NULL; curr_inode = NULL;
vfs_inode = btrfs_iget(fs_info->sb, ino, root); vfs_inode = btrfs_iget_logging(ino, root);
if (IS_ERR(vfs_inode)) { if (IS_ERR(vfs_inode)) {
ret = PTR_ERR(vfs_inode); ret = PTR_ERR(vfs_inode);
break; break;
...@@ -5654,7 +5672,7 @@ static int add_conflicting_inode(struct btrfs_trans_handle *trans, ...@@ -5654,7 +5672,7 @@ static int add_conflicting_inode(struct btrfs_trans_handle *trans,
if (ctx->num_conflict_inodes >= MAX_CONFLICT_INODES) if (ctx->num_conflict_inodes >= MAX_CONFLICT_INODES)
return BTRFS_LOG_FORCE_COMMIT; return BTRFS_LOG_FORCE_COMMIT;
inode = btrfs_iget(root->fs_info->sb, ino, root); inode = btrfs_iget_logging(ino, root);
/* /*
* If the other inode that had a conflicting dir entry was deleted in * If the other inode that had a conflicting dir entry was deleted in
* the current transaction then we either: * the current transaction then we either:
...@@ -5755,7 +5773,6 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans, ...@@ -5755,7 +5773,6 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct btrfs_log_ctx *ctx) struct btrfs_log_ctx *ctx)
{ {
struct btrfs_fs_info *fs_info = root->fs_info;
int ret = 0; int ret = 0;
/* /*
...@@ -5786,7 +5803,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans, ...@@ -5786,7 +5803,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
list_del(&curr->list); list_del(&curr->list);
kfree(curr); kfree(curr);
inode = btrfs_iget(fs_info->sb, ino, root); inode = btrfs_iget_logging(ino, root);
/* /*
* If the other inode that had a conflicting dir entry was * If the other inode that had a conflicting dir entry was
* deleted in the current transaction, we need to log its parent * deleted in the current transaction, we need to log its parent
...@@ -5797,7 +5814,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans, ...@@ -5797,7 +5814,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
if (ret != -ENOENT) if (ret != -ENOENT)
break; break;
inode = btrfs_iget(fs_info->sb, parent, root); inode = btrfs_iget_logging(parent, root);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
ret = PTR_ERR(inode); ret = PTR_ERR(inode);
break; break;
...@@ -6319,7 +6336,6 @@ static int log_new_delayed_dentries(struct btrfs_trans_handle *trans, ...@@ -6319,7 +6336,6 @@ static int log_new_delayed_dentries(struct btrfs_trans_handle *trans,
struct btrfs_log_ctx *ctx) struct btrfs_log_ctx *ctx)
{ {
const bool orig_log_new_dentries = ctx->log_new_dentries; const bool orig_log_new_dentries = ctx->log_new_dentries;
struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_delayed_item *item; struct btrfs_delayed_item *item;
int ret = 0; int ret = 0;
...@@ -6345,7 +6361,7 @@ static int log_new_delayed_dentries(struct btrfs_trans_handle *trans, ...@@ -6345,7 +6361,7 @@ static int log_new_delayed_dentries(struct btrfs_trans_handle *trans,
if (key.type == BTRFS_ROOT_ITEM_KEY) if (key.type == BTRFS_ROOT_ITEM_KEY)
continue; continue;
di_inode = btrfs_iget(fs_info->sb, key.objectid, inode->root); di_inode = btrfs_iget_logging(key.objectid, inode->root);
if (IS_ERR(di_inode)) { if (IS_ERR(di_inode)) {
ret = PTR_ERR(di_inode); ret = PTR_ERR(di_inode);
break; break;
...@@ -6729,7 +6745,6 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans, ...@@ -6729,7 +6745,6 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans,
struct btrfs_inode *inode, struct btrfs_inode *inode,
struct btrfs_log_ctx *ctx) struct btrfs_log_ctx *ctx)
{ {
struct btrfs_fs_info *fs_info = trans->fs_info;
int ret; int ret;
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_key key; struct btrfs_key key;
...@@ -6794,8 +6809,7 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans, ...@@ -6794,8 +6809,7 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans,
cur_offset = item_size; cur_offset = item_size;
} }
dir_inode = btrfs_iget(fs_info->sb, inode_key.objectid, dir_inode = btrfs_iget_logging(inode_key.objectid, root);
root);
/* /*
* If the parent inode was deleted, return an error to * If the parent inode was deleted, return an error to
* fallback to a transaction commit. This is to prevent * fallback to a transaction commit. This is to prevent
...@@ -6857,7 +6871,6 @@ static int log_new_ancestors(struct btrfs_trans_handle *trans, ...@@ -6857,7 +6871,6 @@ static int log_new_ancestors(struct btrfs_trans_handle *trans,
btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]); btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]);
while (true) { while (true) {
struct btrfs_fs_info *fs_info = root->fs_info;
struct extent_buffer *leaf; struct extent_buffer *leaf;
int slot; int slot;
struct btrfs_key search_key; struct btrfs_key search_key;
...@@ -6872,7 +6885,7 @@ static int log_new_ancestors(struct btrfs_trans_handle *trans, ...@@ -6872,7 +6885,7 @@ static int log_new_ancestors(struct btrfs_trans_handle *trans,
search_key.objectid = found_key.offset; search_key.objectid = found_key.offset;
search_key.type = BTRFS_INODE_ITEM_KEY; search_key.type = BTRFS_INODE_ITEM_KEY;
search_key.offset = 0; search_key.offset = 0;
inode = btrfs_iget(fs_info->sb, ino, root); inode = btrfs_iget_logging(ino, root);
if (IS_ERR(inode)) if (IS_ERR(inode))
return PTR_ERR(inode); return PTR_ERR(inode);
......
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