From 004641bd06405611f5636a0f923c2b4da3e3ef07 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 3 Oct 2024 21:33:19 +0100 Subject: [PATCH 01/16] btrfs: remove unused btrfs_free_squota_rsv() btrfs_free_squota_rsv() was added in commit e85a0adacf17 ("btrfs: ensure releasing squota reserve on head refs") but has remained unused since then. Remove it as we don't seem to need it and was probably a leftover. Reviewed-by: Qu Wenruo Signed-off-by: Dr. David Alan Gilbert Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 11 ----------- fs/btrfs/qgroup.h | 1 - 2 files changed, 12 deletions(-) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 4276c4607c56..5a42fefd3d11 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -4893,17 +4893,6 @@ void btrfs_qgroup_destroy_extent_records(struct btrfs_transaction *trans) xa_destroy(&trans->delayed_refs.dirty_extents); } -void btrfs_free_squota_rsv(struct btrfs_fs_info *fs_info, u64 root, u64 rsv_bytes) -{ - if (btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_SIMPLE) - return; - - if (!is_fstree(root)) - return; - - btrfs_qgroup_free_refroot(fs_info, root, rsv_bytes, BTRFS_QGROUP_RSV_DATA); -} - int btrfs_record_squota_delta(struct btrfs_fs_info *fs_info, const struct btrfs_squota_delta *delta) { diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index c36019abc82f..afb184c4d744 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -449,7 +449,6 @@ int btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *eb); void btrfs_qgroup_destroy_extent_records(struct btrfs_transaction *trans); bool btrfs_check_quota_leak(const struct btrfs_fs_info *fs_info); -void btrfs_free_squota_rsv(struct btrfs_fs_info *fs_info, u64 root, u64 rsv_bytes); int btrfs_record_squota_delta(struct btrfs_fs_info *fs_info, const struct btrfs_squota_delta *delta); -- 2.51.0 From 441ffe8a98302f96e497272df1ff6aacd8842d6c Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 3 Oct 2024 15:27:26 +0100 Subject: [PATCH 02/16] btrfs: remove unused btrfs_is_parity_mirror() btrfs_is_parity_mirror() has been unused since commit 4886ff7b50f6 ("btrfs: introduce a new helper to submit write bio for repair"). Remove it as the code was refactored and we don't need the helper anymore. Reviewed-by: Qu Wenruo Signed-off-by: Dr. David Alan Gilbert Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 18 ------------------ fs/btrfs/volumes.h | 2 -- 2 files changed, 20 deletions(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index edb2dd6bb4f4..f5bfb4c8adb2 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5963,24 +5963,6 @@ unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info, return len; } -int btrfs_is_parity_mirror(struct btrfs_fs_info *fs_info, u64 logical, u64 len) -{ - struct btrfs_chunk_map *map; - int ret = 0; - - if (!btrfs_fs_incompat(fs_info, RAID56)) - return 0; - - map = btrfs_get_chunk_map(fs_info, logical, len); - - if (!WARN_ON(IS_ERR(map))) { - if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) - ret = 1; - btrfs_free_chunk_map(map); - } - return ret; -} - static int find_live_mirror(struct btrfs_fs_info *fs_info, struct btrfs_chunk_map *map, int first, int dev_replace_is_ongoing) diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 3ebb3c2732b0..3a416b1bc24c 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -741,8 +741,6 @@ int btrfs_run_dev_stats(struct btrfs_trans_handle *trans); void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_device *srcdev); void btrfs_rm_dev_replace_free_srcdev(struct btrfs_device *srcdev); void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev); -int btrfs_is_parity_mirror(struct btrfs_fs_info *fs_info, - u64 logical, u64 len); unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info, u64 logical); u64 btrfs_calc_stripe_length(const struct btrfs_chunk_map *map); -- 2.51.0 From b628c139519ae0e5453e5327161a41bae966201d Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 3 Oct 2024 15:27:27 +0100 Subject: [PATCH 03/16] btrfs: remove unused btrfs_try_tree_write_lock() btrfs_try_tree_write_lock() has been unused since commit 50b21d7a066f ("btrfs: submit a writeback bio per extent_buffer"). Remove it as we don't need it anymore. Reviewed-by: Christoph Hellwig Reviewed-by: Qu Wenruo Signed-off-by: Dr. David Alan Gilbert Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/locking.c | 15 --------------- fs/btrfs/locking.h | 1 - include/trace/events/btrfs.h | 1 - 3 files changed, 17 deletions(-) diff --git a/fs/btrfs/locking.c b/fs/btrfs/locking.c index 6a0b7abb5bd9..9a7a7b723305 100644 --- a/fs/btrfs/locking.c +++ b/fs/btrfs/locking.c @@ -161,21 +161,6 @@ int btrfs_try_tree_read_lock(struct extent_buffer *eb) return 0; } -/* - * Try-lock for write. - * - * Return 1 if the rwlock has been taken, 0 otherwise - */ -int btrfs_try_tree_write_lock(struct extent_buffer *eb) -{ - if (down_write_trylock(&eb->lock)) { - btrfs_set_eb_lock_owner(eb, current->pid); - trace_btrfs_try_tree_write_lock(eb); - return 1; - } - return 0; -} - /* * Release read lock. */ diff --git a/fs/btrfs/locking.h b/fs/btrfs/locking.h index 3c15c75e0582..46c8be2afab1 100644 --- a/fs/btrfs/locking.h +++ b/fs/btrfs/locking.h @@ -180,7 +180,6 @@ static inline void btrfs_tree_read_lock(struct extent_buffer *eb) void btrfs_tree_read_unlock(struct extent_buffer *eb); int btrfs_try_tree_read_lock(struct extent_buffer *eb); -int btrfs_try_tree_write_lock(struct extent_buffer *eb); struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root); struct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root); struct extent_buffer *btrfs_try_read_lock_root_node(struct btrfs_root *root); diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h index 8d2ff32fb3b0..bd515415ea8b 100644 --- a/include/trace/events/btrfs.h +++ b/include/trace/events/btrfs.h @@ -2344,7 +2344,6 @@ DEFINE_BTRFS_LOCK_EVENT(btrfs_tree_read_unlock_blocking); DEFINE_BTRFS_LOCK_EVENT(btrfs_set_lock_blocking_read); DEFINE_BTRFS_LOCK_EVENT(btrfs_set_lock_blocking_write); DEFINE_BTRFS_LOCK_EVENT(btrfs_try_tree_read_lock); -DEFINE_BTRFS_LOCK_EVENT(btrfs_try_tree_write_lock); DEFINE_BTRFS_LOCK_EVENT(btrfs_tree_read_lock_atomic); DECLARE_EVENT_CLASS(btrfs__space_info_update, -- 2.51.0 From 00c5135dceaf57b212a808444d719d321444c819 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Wed, 2 Oct 2024 08:47:48 +0930 Subject: [PATCH 04/16] btrfs: remove the dirty_page local variable Inside btrfs_buffered_write(), we have a local variable @dirty_pages, recording the number of pages we dirtied in the current iteration. However we do not really need that variable, since it can be calculated from @pos and @copied. In fact there is already a problem inside the short copy path, where we use @dirty_pages to calculate the range we need to release. But that usage assumes sectorsize == PAGE_SIZE, which is no longer true. Instead of keeping @dirty_pages and cause incorrect usage, just calculate the number of dirtied pages inside btrfs_dirty_pages(). Reviewed-by: Josef Bacik Reviewed-by: Johannes Thumshirn Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/file.c | 19 +++++++------------ fs/btrfs/file.h | 2 +- fs/btrfs/free-space-cache.c | 3 +-- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 4fb521d91b06..9555a3485670 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -124,12 +124,14 @@ static void btrfs_drop_pages(struct btrfs_fs_info *fs_info, * - Update inode size for past EOF write */ int btrfs_dirty_pages(struct btrfs_inode *inode, struct page **pages, - size_t num_pages, loff_t pos, size_t write_bytes, + loff_t pos, size_t write_bytes, struct extent_state **cached, bool noreserve) { struct btrfs_fs_info *fs_info = inode->root->fs_info; int ret = 0; int i; + const int num_pages = (round_up(pos + write_bytes, PAGE_SIZE) - + round_down(pos, PAGE_SIZE)) >> PAGE_SHIFT; u64 num_bytes; u64 start_pos; u64 end_of_last_block; @@ -1242,7 +1244,6 @@ ssize_t btrfs_buffered_write(struct kiocb *iocb, struct iov_iter *i) offset); size_t num_pages; size_t reserve_bytes; - size_t dirty_pages; size_t copied; size_t dirty_sectors; size_t num_sectors; @@ -1361,11 +1362,8 @@ again: if (copied == 0) { force_page_uptodate = true; dirty_sectors = 0; - dirty_pages = 0; } else { force_page_uptodate = false; - dirty_pages = DIV_ROUND_UP(copied + offset, - PAGE_SIZE); } if (num_sectors > dirty_sectors) { @@ -1375,13 +1373,10 @@ again: btrfs_delalloc_release_metadata(BTRFS_I(inode), release_bytes, true); } else { - u64 __pos; - - __pos = round_down(pos, - fs_info->sectorsize) + - (dirty_pages << PAGE_SHIFT); + u64 release_start = round_up(pos + copied, + fs_info->sectorsize); btrfs_delalloc_release_space(BTRFS_I(inode), - data_reserved, __pos, + data_reserved, release_start, release_bytes, true); } } @@ -1390,7 +1385,7 @@ again: fs_info->sectorsize); ret = btrfs_dirty_pages(BTRFS_I(inode), pages, - dirty_pages, pos, copied, + pos, copied, &cached_state, only_release_metadata); /* diff --git a/fs/btrfs/file.h b/fs/btrfs/file.h index 912254e653cf..c23d0bf42598 100644 --- a/fs/btrfs/file.h +++ b/fs/btrfs/file.h @@ -35,7 +35,7 @@ ssize_t btrfs_do_write_iter(struct kiocb *iocb, struct iov_iter *from, const struct btrfs_ioctl_encoded_io_args *encoded); int btrfs_release_file(struct inode *inode, struct file *file); int btrfs_dirty_pages(struct btrfs_inode *inode, struct page **pages, - size_t num_pages, loff_t pos, size_t write_bytes, + loff_t pos, size_t write_bytes, struct extent_state **cached, bool noreserve); int btrfs_fdatawrite_range(struct btrfs_inode *inode, loff_t start, loff_t end); int btrfs_check_nocow_lock(struct btrfs_inode *inode, loff_t pos, diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index f4bcb2530660..0d2db205b9f6 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -1457,8 +1457,7 @@ static int __btrfs_write_out_cache(struct inode *inode, io_ctl_zero_remaining_pages(io_ctl); /* Everything is written out, now we dirty the pages in the file. */ - ret = btrfs_dirty_pages(BTRFS_I(inode), io_ctl->pages, - io_ctl->num_pages, 0, i_size_read(inode), + ret = btrfs_dirty_pages(BTRFS_I(inode), io_ctl->pages, 0, i_size_read(inode), &cached_state, false); if (ret) goto out_nospc; -- 2.51.0 From 7f91c6a78a0e0125e69f6aef05914aeb2d91a2eb Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Wed, 2 Oct 2024 08:47:49 +0930 Subject: [PATCH 05/16] btrfs: simplify the page uptodate preparation for prepare_pages() Currently inside prepare_pages(), we handle the leading and tailing page differently, and skip the middle pages (if any). This is to avoid reading pages which are fully covered by the dirty range. Refactor the code by moving all checks (alignment check, range check, force read check) into prepare_uptodate_page(). So that prepare_pages() only needs to iterate all the pages unconditionally. And since we're here, also update prepare_uptodate_page() to use folio API other than the old page API. Reviewed-by: Johannes Thumshirn Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/file.c | 64 +++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 9555a3485670..160d77f8eb6f 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -858,36 +858,42 @@ out: */ static int prepare_uptodate_page(struct inode *inode, struct page *page, u64 pos, - bool force_uptodate) + u64 len, bool force_uptodate) { struct folio *folio = page_folio(page); + u64 clamp_start = max_t(u64, pos, folio_pos(folio)); + u64 clamp_end = min_t(u64, pos + len, folio_pos(folio) + folio_size(folio)); int ret = 0; - if (((pos & (PAGE_SIZE - 1)) || force_uptodate) && - !PageUptodate(page)) { - ret = btrfs_read_folio(NULL, folio); - if (ret) - return ret; - lock_page(page); - if (!PageUptodate(page)) { - unlock_page(page); - return -EIO; - } + if (folio_test_uptodate(folio)) + return 0; - /* - * Since btrfs_read_folio() will unlock the folio before it - * returns, there is a window where btrfs_release_folio() can be - * called to release the page. Here we check both inode - * mapping and PagePrivate() to make sure the page was not - * released. - * - * The private flag check is essential for subpage as we need - * to store extra bitmap using folio private. - */ - if (page->mapping != inode->i_mapping || !folio_test_private(folio)) { - unlock_page(page); - return -EAGAIN; - } + if (!force_uptodate && + IS_ALIGNED(clamp_start, PAGE_SIZE) && + IS_ALIGNED(clamp_end, PAGE_SIZE)) + return 0; + + ret = btrfs_read_folio(NULL, folio); + if (ret) + return ret; + folio_lock(folio); + if (!folio_test_uptodate(folio)) { + folio_unlock(folio); + return -EIO; + } + + /* + * Since btrfs_read_folio() will unlock the folio before it returns, + * there is a window where btrfs_release_folio() can be called to + * release the page. Here we check both inode mapping and page + * private to make sure the page was not released. + * + * The private flag check is essential for subpage as we need to store + * extra bitmap using folio private. + */ + if (page->mapping != inode->i_mapping || !folio_test_private(folio)) { + folio_unlock(folio); + return -EAGAIN; } return 0; } @@ -949,12 +955,8 @@ again: goto fail; } - if (i == 0) - ret = prepare_uptodate_page(inode, pages[i], pos, - force_uptodate); - if (!ret && i == num_pages - 1) - ret = prepare_uptodate_page(inode, pages[i], - pos + write_bytes, false); + ret = prepare_uptodate_page(inode, pages[i], pos, write_bytes, + force_uptodate); if (ret) { put_page(pages[i]); if (!nowait && ret == -EAGAIN) { -- 2.51.0 From 61b4d75e3c5c10d523d95e19728dd5a6e2fd58f9 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Fri, 4 Oct 2024 15:19:01 +0200 Subject: [PATCH 06/16] btrfs: handle empty list of NOCOW ordered extents with checksum list Currently we BUG_ON() in btrfs_finish_one_ordered() if we are finishing an ordered extent that is flagged as NOCOW, but it's checksum list is not empty. This is clearly a logic error which we can recover from by aborting the transaction. For developer builds which enable CONFIG_BTRFS_ASSERT, also ASSERT() that the list is empty. Suggested-by: Filipe Manana Reviewed-by: Qu Wenruo Reviewed-by: Filipe Manana Signed-off-by: Johannes Thumshirn Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5d8da882d487..8da5e47db751 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3088,7 +3088,12 @@ int btrfs_finish_one_ordered(struct btrfs_ordered_extent *ordered_extent) if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) { /* Logic error */ - BUG_ON(!list_empty(&ordered_extent->list)); + ASSERT(list_empty(&ordered_extent->list)); + if (!list_empty(&ordered_extent->list)) { + ret = -EINVAL; + btrfs_abort_transaction(trans, ret); + goto out; + } btrfs_inode_safe_disk_i_size_write(inode, 0); ret = btrfs_update_inode_fallback(trans, inode); -- 2.51.0 From 5e72aabc1fffe9d713276974b0533d10354d0a13 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Mon, 7 Oct 2024 13:52:47 +0200 Subject: [PATCH 07/16] btrfs: return ENODATA in case RST lookup fails In case a lookup in the RAID stripe-tree fails, return ENODATA instead of ENOENT to better distinguish stripe-tree lookups from other code paths where we return ENOENT. Suggested-by: Josef Bacik Reviewed-by: Josef Bacik Signed-off-by: Johannes Thumshirn Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/raid-stripe-tree.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c index b7787a8e4af2..41970bbdb05f 100644 --- a/fs/btrfs/raid-stripe-tree.c +++ b/fs/btrfs/raid-stripe-tree.c @@ -234,7 +234,7 @@ int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info, found_end = found_logical + found_length; if (found_logical > end) { - ret = -ENOENT; + ret = -ENODATA; goto out; } @@ -280,10 +280,10 @@ int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info, } /* If we're here, we haven't found the requested devid in the stripe. */ - ret = -ENOENT; + ret = -ENODATA; out: if (ret > 0) - ret = -ENOENT; + ret = -ENODATA; if (ret && ret != -EIO && !stripe->rst_search_commit_root) { btrfs_debug(fs_info, "cannot find raid-stripe for logical [%llu, %llu] devid %llu, profile %s", -- 2.51.0 From 9fde8a67b9786f31cbc77c23b0e468d259ce82d1 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Mon, 7 Oct 2024 13:52:48 +0200 Subject: [PATCH 08/16] btrfs: scrub: skip initial RST lookup errors Performing the initial extent sector read on a RAID stripe-tree backed filesystem with pre-allocated extents will cause the RAID stripe-tree lookup code to return ENODATA, as pre-allocated extents do not have any on-disk bytes and thus no RAID stripe-tree entries. But the current scrub read code marks these extents as errors, because the lookup fails. If btrfs_map_block() returns -ENODATA, it means that the call to btrfs_get_raid_extent_offset() returned -ENODATA, because there is no entry for the corresponding range in the RAID stripe-tree. But as this range is in the extent tree it means we've hit a pre-allocated extent. In this case, don't mark the sector in the stripe's error bitmaps as faulty and carry on to the next. Reviewed-by: Josef Bacik Signed-off-by: Johannes Thumshirn Signed-off-by: David Sterba --- fs/btrfs/scrub.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index e141132b5c8d..52e09f307462 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1704,8 +1704,18 @@ static void scrub_submit_extent_sector_read(struct scrub_ctx *sctx, &stripe_len, &bioc, &io_stripe, &mirror); btrfs_put_bioc(bioc); if (err < 0) { - set_bit(i, &stripe->io_error_bitmap); - set_bit(i, &stripe->error_bitmap); + if (err != -ENODATA) { + /* + * Earlier btrfs_get_raid_extent_offset() + * returned -ENODATA, which means there's + * no entry for the corresponding range + * in the stripe tree. But if it's in + * the extent tree, then it's a preallocated + * extent and not an error. + */ + set_bit(i, &stripe->io_error_bitmap); + set_bit(i, &stripe->error_bitmap); + } continue; } -- 2.51.0 From dd4028315e5dfdfe9ecde68db90681313822f906 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Mon, 7 Oct 2024 15:55:43 +0100 Subject: [PATCH 09/16] btrfs: qgroup: run delayed iputs after ordered extent completion When trying to flush qgroups in order to release space we run delayed iputs in order to release space from recently deleted files (their link counted reached zero), and then we start delalloc and wait for any existing ordered extents to complete. However there's a time window here where we end up not doing the final iput on a deleted file which could release necessary space: 1) An unlink operation starts; 2) During the unlink, or right before it completes, delalloc is flushed and an ordered extent is created; 3) When the ordered extent is created, the inode's ref count is incremented (with igrab() at alloc_ordered_extent()); 4) When the unlink finishes it doesn't drop the last reference on the inode and so it doesn't trigger inode eviction to delete all of the inode's items in its root and drop all references on its data extents; 5) Another task enters try_flush_qgroup() to try to release space, it runs all delayed iputs, but there's no delayed iput yet for that deleted file because the ordered extent hasn't completed yet; 6) Then at try_flush_qgroup() we wait for the ordered extent to complete and that results in adding a delayed iput at btrfs_put_ordered_extent() when called from btrfs_finish_one_ordered(); 7) Adding the delayed iput results in waking the cleaner kthread if it's not running already. However it may take some time for it to be scheduled, or it may be running but busy running auto defrag, dropping deleted snapshots or doing other work, so by the time we return from try_flush_qgroup() the space for deleted file isn't released. Improve on this by running delayed iputs only after flushing delalloc and waiting for ordered extent completion. Reviewed-by: Qu Wenruo Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 5a42fefd3d11..3ba650c06bfe 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -4195,13 +4195,20 @@ static int try_flush_qgroup(struct btrfs_root *root) return 0; } - btrfs_run_delayed_iputs(root->fs_info); - btrfs_wait_on_delayed_iputs(root->fs_info); ret = btrfs_start_delalloc_snapshot(root, true); if (ret < 0) goto out; btrfs_wait_ordered_extents(root, U64_MAX, NULL); + /* + * After waiting for ordered extents run delayed iputs in order to free + * space from unlinked files before committing the current transaction, + * as ordered extents may have been holding the last reference of an + * inode and they add a delayed iput when they complete. + */ + btrfs_run_delayed_iputs(root->fs_info); + btrfs_wait_on_delayed_iputs(root->fs_info); + ret = btrfs_commit_current_transaction(root); out: clear_bit(BTRFS_ROOT_QGROUP_FLUSHING, &root->state); -- 2.51.0 From 0fcaf926ad7650f3f4badaca355e59ebc2773045 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Sun, 6 Oct 2024 10:36:20 +1030 Subject: [PATCH 10/16] btrfs: remove btrfs_set_range_writeback() The function btrfs_set_range_writeback() was originally a callback for metadata and data, to mark a range with writeback flag. Then it was converted into a common function call for both metadata and data. From the very beginning, the function had been only called on a full page, later converted to handle range inside a page. But it never needed to handle multiple pages, and since commit 8189197425e7 ("btrfs: refactor __extent_writepage_io() to do sector-by-sector submission") the function was only called on a sector-by-sector basis. This makes the function unnecessary, and can be converted to a simple btrfs_folio_set_writeback() call instead. Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/btrfs_inode.h | 1 - fs/btrfs/extent_io.c | 2 +- fs/btrfs/inode.c | 22 ---------------------- 3 files changed, 1 insertion(+), 24 deletions(-) diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index e152fde888fc..c514bab532fa 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -577,7 +577,6 @@ void btrfs_merge_delalloc_extent(struct btrfs_inode *inode, struct extent_state struct extent_state *other); void btrfs_split_delalloc_extent(struct btrfs_inode *inode, struct extent_state *orig, u64 split); -void btrfs_set_range_writeback(struct btrfs_inode *inode, u64 start, u64 end); void btrfs_evict_inode(struct inode *inode); struct inode *btrfs_alloc_inode(struct super_block *sb); void btrfs_destroy_inode(struct inode *inode); diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 6aa39e0be2e8..bfa745258e9b 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1360,7 +1360,7 @@ static int submit_one_sector(struct btrfs_inode *inode, * a folio for a range already written to disk. */ btrfs_folio_clear_dirty(fs_info, folio, filepos, sectorsize); - btrfs_set_range_writeback(inode, filepos, filepos + sectorsize - 1); + btrfs_folio_set_writeback(fs_info, folio, filepos, sectorsize); /* * Above call should set the whole folio with writeback flag, even * just for a single subpage sector. diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 8da5e47db751..3404e7043dac 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -8941,28 +8941,6 @@ out_inode: return finish_open_simple(file, ret); } -void btrfs_set_range_writeback(struct btrfs_inode *inode, u64 start, u64 end) -{ - struct btrfs_fs_info *fs_info = inode->root->fs_info; - unsigned long index = start >> PAGE_SHIFT; - unsigned long end_index = end >> PAGE_SHIFT; - struct folio *folio; - u32 len; - - ASSERT(end + 1 - start <= U32_MAX); - len = end + 1 - start; - while (index <= end_index) { - folio = __filemap_get_folio(inode->vfs_inode.i_mapping, index, 0, 0); - ASSERT(!IS_ERR(folio)); /* folios should be in the extent_io_tree */ - - /* This is for data, which doesn't yet support larger folio. */ - ASSERT(folio_order(folio) == 0); - btrfs_folio_set_writeback(fs_info, folio, start, len); - folio_put(folio); - index++; - } -} - int btrfs_encoded_io_compression_from_extent(struct btrfs_fs_info *fs_info, int compress_type) { -- 2.51.0 From 2fac7e163d24f77476399c5e646edcf86db57d0c Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 9 Oct 2024 16:30:50 +0200 Subject: [PATCH 11/16] btrfs: zstd: assert the timer pointer in callback Make sure we got the right timer struct for the zstd workspace reclaim work. Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/zstd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/btrfs/zstd.c b/fs/btrfs/zstd.c index 15f8a83165a3..5232b56d5892 100644 --- a/fs/btrfs/zstd.c +++ b/fs/btrfs/zstd.c @@ -111,6 +111,8 @@ static void zstd_reclaim_timer_fn(struct timer_list *timer) unsigned long reclaim_threshold = jiffies - ZSTD_BTRFS_RECLAIM_JIFFIES; struct list_head *pos, *next; + ASSERT(timer == &wsm.timer); + spin_lock(&wsm.lock); if (list_empty(&wsm.lru_list)) { -- 2.51.0 From 25a1399a6d9840faa9b595f79875d26ec5ddc7b6 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 9 Oct 2024 16:30:53 +0200 Subject: [PATCH 12/16] btrfs: drop unused parameter path from btrfs_tree_mod_log_rewind() The path parameter was used for our own locking, that got converted to rwsem eventually. Last usage in ac5887c8e013d6 ("btrfs: locking: remove all the blocking helpers"). Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/ctree.c | 2 +- fs/btrfs/tree-mod-log.c | 1 - fs/btrfs/tree-mod-log.h | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 0cc919d15b14..b11ec86102e3 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -2334,7 +2334,7 @@ again: level = btrfs_header_level(b); btrfs_tree_read_lock(b); - b = btrfs_tree_mod_log_rewind(fs_info, p, b, time_seq); + b = btrfs_tree_mod_log_rewind(fs_info, b, time_seq); if (!b) { ret = -ENOMEM; goto done; diff --git a/fs/btrfs/tree-mod-log.c b/fs/btrfs/tree-mod-log.c index b382a4c443d4..1ac2678fc4ca 100644 --- a/fs/btrfs/tree-mod-log.c +++ b/fs/btrfs/tree-mod-log.c @@ -909,7 +909,6 @@ static void tree_mod_log_rewind(struct btrfs_fs_info *fs_info, * is freed (its refcount is decremented). */ struct extent_buffer *btrfs_tree_mod_log_rewind(struct btrfs_fs_info *fs_info, - struct btrfs_path *path, struct extent_buffer *eb, u64 time_seq) { diff --git a/fs/btrfs/tree-mod-log.h b/fs/btrfs/tree-mod-log.h index 6308c577a4a4..1c12566040db 100644 --- a/fs/btrfs/tree-mod-log.h +++ b/fs/btrfs/tree-mod-log.h @@ -41,7 +41,6 @@ int btrfs_tree_mod_log_insert_key(const struct extent_buffer *eb, int slot, enum btrfs_mod_log_op op); int btrfs_tree_mod_log_free_eb(struct extent_buffer *eb); struct extent_buffer *btrfs_tree_mod_log_rewind(struct btrfs_fs_info *fs_info, - struct btrfs_path *path, struct extent_buffer *eb, u64 time_seq); struct extent_buffer *btrfs_get_old_root(struct btrfs_root *root, u64 time_seq); -- 2.51.0 From 2d5903dd5b5bb74d0a662622cc2a03aa5bd85703 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 9 Oct 2024 16:30:59 +0200 Subject: [PATCH 13/16] btrfs: drop unused parameter ctx from batch_delete_dir_index_items() The ctx parameter is not used, we can drop it. Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/tree-log.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 9637c7cdc0cf..c8d6587688b3 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -6204,7 +6204,6 @@ static int log_delayed_deletions_full(struct btrfs_trans_handle *trans, static int batch_delete_dir_index_items(struct btrfs_trans_handle *trans, struct btrfs_inode *inode, struct btrfs_path *path, - struct btrfs_log_ctx *ctx, const struct list_head *delayed_del_list, const struct btrfs_delayed_item *first, const struct btrfs_delayed_item **last_ret) @@ -6265,7 +6264,7 @@ static int log_delayed_deletions_incremental(struct btrfs_trans_handle *trans, if (ret < 0) { return ret; } else if (ret == 0) { - ret = batch_delete_dir_index_items(trans, inode, path, ctx, + ret = batch_delete_dir_index_items(trans, inode, path, delayed_del_list, curr, &last); if (ret) -- 2.51.0 From a6563fa06ab6d4a56908c0d3745825f04e43b88e Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 9 Oct 2024 16:31:02 +0200 Subject: [PATCH 14/16] btrfs: drop unused parameter fs_info from wait_reserve_ticket() The parameter is not used, we can also reach it from the space info if needed in the future. Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/space-info.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c index ee23fae73f47..3c7ccb3935cf 100644 --- a/fs/btrfs/space-info.c +++ b/fs/btrfs/space-info.c @@ -1488,8 +1488,7 @@ static void priority_reclaim_data_space(struct btrfs_fs_info *fs_info, spin_unlock(&space_info->lock); } -static void wait_reserve_ticket(struct btrfs_fs_info *fs_info, - struct btrfs_space_info *space_info, +static void wait_reserve_ticket(struct btrfs_space_info *space_info, struct reserve_ticket *ticket) { @@ -1547,7 +1546,7 @@ static int handle_reserve_ticket(struct btrfs_fs_info *fs_info, case BTRFS_RESERVE_FLUSH_DATA: case BTRFS_RESERVE_FLUSH_ALL: case BTRFS_RESERVE_FLUSH_ALL_STEAL: - wait_reserve_ticket(fs_info, space_info, ticket); + wait_reserve_ticket(space_info, ticket); break; case BTRFS_RESERVE_FLUSH_LIMIT: priority_reclaim_metadata_space(fs_info, space_info, ticket, -- 2.51.0 From 343a63594bb6a49d094860705817aad6663b1f8f Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 9 Oct 2024 16:31:04 +0200 Subject: [PATCH 15/16] btrfs: drop unused parameter fs_info from do_reclaim_sweep() The parameter is unused and we can get it from space info if needed. Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/space-info.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c index 3c7ccb3935cf..255e85f78313 100644 --- a/fs/btrfs/space-info.c +++ b/fs/btrfs/space-info.c @@ -1983,8 +1983,7 @@ static bool is_reclaim_urgent(struct btrfs_space_info *space_info) return unalloc < data_chunk_size; } -static void do_reclaim_sweep(const struct btrfs_fs_info *fs_info, - struct btrfs_space_info *space_info, int raid) +static void do_reclaim_sweep(struct btrfs_space_info *space_info, int raid) { struct btrfs_block_group *bg; int thresh_pct; @@ -2080,6 +2079,6 @@ void btrfs_reclaim_sweep(const struct btrfs_fs_info *fs_info) if (!btrfs_should_periodic_reclaim(space_info)) continue; for (raid = 0; raid < BTRFS_NR_RAID_TYPES; raid++) - do_reclaim_sweep(fs_info, space_info, raid); + do_reclaim_sweep(space_info, raid); } } -- 2.51.0 From a1e76e362f0467c872ff263d6d94276090aeb2ea Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 9 Oct 2024 16:31:06 +0200 Subject: [PATCH 16/16] btrfs: send: drop unused parameter num from iterate_inode_ref_t callbacks None of the ref iteration callbacks needs the num parameter (this is for the directory item iteration), so we can drop it. Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/send.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index b068469871f8..b8ffded33fef 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -980,7 +980,7 @@ static int get_inode_gen(struct btrfs_root *root, u64 ino, u64 *gen) return ret; } -typedef int (*iterate_inode_ref_t)(int num, u64 dir, int index, +typedef int (*iterate_inode_ref_t)(u64 dir, int index, struct fs_path *p, void *ctx); @@ -1007,7 +1007,6 @@ static int iterate_inode_ref(struct btrfs_root *root, struct btrfs_path *path, u32 name_len; char *start; int ret = 0; - int num = 0; int index; u64 dir; unsigned long name_off; @@ -1094,10 +1093,9 @@ static int iterate_inode_ref(struct btrfs_root *root, struct btrfs_path *path, } cur += elem_size + name_len; - ret = iterate(num, dir, index, p, ctx); + ret = iterate(dir, index, p, ctx); if (ret) goto out; - num++; } out: @@ -1227,7 +1225,7 @@ out: return ret; } -static int __copy_first_ref(int num, u64 dir, int index, +static int __copy_first_ref(u64 dir, int index, struct fs_path *p, void *ctx) { int ret; @@ -4708,7 +4706,7 @@ out: return ret; } -static int record_new_ref_if_needed(int num, u64 dir, int index, +static int record_new_ref_if_needed(u64 dir, int index, struct fs_path *name, void *ctx) { int ret = 0; @@ -4738,7 +4736,7 @@ out: return ret; } -static int record_deleted_ref_if_needed(int num, u64 dir, int index, +static int record_deleted_ref_if_needed(u64 dir, int index, struct fs_path *name, void *ctx) { int ret = 0; -- 2.51.0