Repository navigation
Conversation
kdave
force-pushed
the
misc-next
branch
8 times, most recently
from
April 27, 2026 14:35
a464848 to
8f84140
Compare
kdave
force-pushed
the
misc-next
branch
2 times, most recently
from
April 29, 2026 14:08
d93f97d to
7d5a51d
Compare
kdave
force-pushed
the
misc-next
branch
2 times, most recently
from
May 12, 2026 15:26
14fb724 to
d39211d
Compare
kdave
force-pushed
the
misc-next
branch
2 times, most recently
from
May 16, 2026 01:02
8c55fe0 to
2fddc74
Compare
kdave
force-pushed
the
misc-next
branch
10 times, most recently
from
May 29, 2026 00:01
014f22d to
6b43c97
Compare
kdave
force-pushed
the
misc-next
branch
4 times, most recently
from
June 8, 2026 13:54
7263914 to
5342ffb
Compare
Since commit 545e560 ("btrfs: disable v1 space cache") the mount options can no longer request the v1 space cache, but a filesystem with an active v1 cache and no free space tree still enables it from cache_generation, and remount does the same. Drop both, so SPACE_CACHE can never be set. btrfs_start_pre_rw_mount() then sees the on-disk cache as active but unwanted and cleans it up, as -o nospace_cache does today. That covers the read-only to read-write remount as well, so drop the toggle in btrfs_remount_cleanup(), which would otherwise start a transaction on remounts of a read-only filesystem with an old cache. When a remount that isn't read-only to read-write asks to change the free space tree, btrfs_reconfigure() warns and keeps the on-disk state, but the fixup that resets the options only ran for a filesystem with a free space tree or an active v1 cache. On one with neither, a requested FREE_SPACE_TREE stayed set and the next read-write remount created the tree. Clear it whenever the tree is not on disk, which also covers a v1 filesystem once its cache has been cleaned up. The cleanup is now unconditional, and the first read-write mount fails if it fails, as it did with -o nospace_cache. This also lets an old filesystem mount without options when the page size is larger than the sector size, which btrfs_check_features() rejected once SPACE_CACHE was set from the superblock. Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
Nothing sets SPACE_CACHE anymore, so the dirty block group writers never have a cache to write out or wait for. Remove cache_save_setup(), btrfs_setup_space_cache(), the io_list handling, the io_bgs list and BTRFS_TRANS_CACHE_ENOSPC, and the abort-time cleanup of in-flight cache IO. The -ENOENT retry in btrfs_write_dirty_block_groups() handled a free space endio worker creating a block group during the commit critical section, so drop it too. Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
Free space inodes are no longer written to, so nothing queues ordered extent completion on endio_freespace_worker. Remove it and always use endio_write_workers in btrfs_queue_ordered_fn(). Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
Nothing writes out a v1 space cache any more. Remove the writers and their io_ctl helpers, along with create_free_space_inode() and btrfs_prealloc_file_range_trans(), whose only user was the cache inode creation. The io_list and io_ctl block group fields were only used by the writers, so remove them too. btrfs_truncate_free_space_cache() only needed the block group to wait for and clear in-flight cache IO, so drop that parameter. Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
The v1 space cache writeout is gone, but the mutex is still needed. It keeps btrfs_remove_block_group() from deleting a block group item while btrfs_start_dirty_block_groups() is updating it outside the commit critical section. Rename it to reflect what it protects, and update the comments around the dirty block group writeout that still refer to the space cache. Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
The v1 space cache created its inode during the transaction commit, and btrfs_prealloc_file_range_trans() existed so that preallocation could reuse the open handle. It was the only caller passing a transaction, so __btrfs_prealloc_file_range() and insert_prealloc_file_extent() now always start their own. Fold the wrapper into btrfs_prealloc_file_range() and drop the parameter. Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
Nothing writes a v1 space cache any more, and since commit 545e560 ("btrfs: disable v1 space cache") the mount option can't be enabled to read one either. Remove load_free_space_cache(), its io_ctl helpers and struct btrfs_io_ctl. Drop the gfp constraint on the inode mapping as well, it only covered the cache's page cache allocations. Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
With neither the writer nor the loader left, nothing acts on disk_cache_state. Remove it, the need_clear handling when reading block groups, and the enum. While at it, drop the unused cache_generation field from struct btrfs_block_group. lookup_free_space_inode() converted old style space inodes by clearing disk_cache_state so the cache would be rewritten with the new inode flags. Without that it only sets flags on the in-memory inode, which every remaining caller truncates or deletes right after, so drop the conversion too. Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
Nothing sets BTRFS_MOUNT_SPACE_CACHE anymore, so every test of it is false. Remove the flag, the checks rejecting the v1 cache on zoned filesystems and for sector sizes other than the page size, and the deprecation warning. Show a read-only filesystem that still has an old cache as nospace_cache, since that's what's in effect. space_cache and space_cache=v1 keep falling back to no space cache with a warning. Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
…helper The only caller passes active = false. Turn it into btrfs_cleanup_free_space_cache_v1() and fold the block group loop into it. Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
cache_writeout_mutex and trimming_ranges let the v1 cache writer see ranges that were unlinked from the free space tree while being discarded. Nothing consumes the list anymore, and the tree itself is protected by tree_lock, so remove them. Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
Free space inodes no longer reserve data or delalloc space, as nothing writes to them. Remove the flush mode and the special cases that selected it. Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
Free space inodes never have ordered extents anymore. Drop the lockdep exceptions for them and btrfs_join_transaction_spacecache(), which was only used to finish their ordered extents during a commit. Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
Free space inodes are never written anymore, so drop the special cases for them in cow_file_range(), fallback_to_cow(), can_nocow_file_extent() and btrfs_finish_one_ordered(). Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
Free space inodes never have delalloc or outstanding extents any more, so they don't need to be kept off the root's delalloc inode list, out of the outstanding extents tracepoint, or exempt from the delalloc metadata release, which skipped the tree root since free space inodes are its only inodes with data. Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
Free space inode data was only read when loading the v1 cache, which is gone, so btrfs_get_extent() and btrfs_lookup_bio_sums() no longer need to search the commit root for them. Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
btrfs_join_transaction_spacecache() was the only user of TRANS_JOIN_NOLOCK and is gone, so remove the join type, its entries in the blocked types table, and the special cases in join_transaction() and start_transaction(). Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
The member btrfs_chunk_map::stripe_size sounds very similar to btrfs_chunk::stripe_len, but they have very different meanings. btrfs_chunk_map::stripe_size is in fact the device extent size for the chunk. E.g. a 2GiB RAID0 chunk with 2 stripes, btrfs_chunk_map::stripe_size will be 1GiB (2GiB / 2). But btrfs_chunk::stripe_len is the stripe length that striping profiles should follow, and the value is now fixed to 64KiB. E.g. for a 2GiB RAID0 chunk with 2 stripes, every write will be split into 64KiB stripes, and then distributed across the 2 devices. To avoid confusion, rename btrfs_chunk_map::stripe_size to dev_extent_size. And since we're here, also rename the helper btrfs_calc_stripe_length() to btrfs_calc_dev_extent_size(). Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
Rename the "stripe_size" used inside volumes.c by: - local variable in alloc_virtual_chunk() - alloc_chunk_ctl::stripe_size All rename to "dev_extent_size". - alloc_chunk_ctl::max_stripe_size Rename to "dev_extent_max" as there is already a "dev_extent_min". - decide_stripe_size*() functions Rename to decide_dev_extent_size*(). This further reduces the confusion between "stripe_size" and "stripe_len". Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
During read_one_chunk() we can hit an existing chunk map. There are several situations that this can happen: - System chunk maps This is the most common case, where the system chunks are added from super block during bootstrap. But in that case, the system chunks in the super block should match the one in the chunk tree, if not there is definitely something wrong. - Overlapping chunk maps This is rare, but potentially malicious. Crafted images or even some bitflips in the chunk tree can lead to this. In that case we should reject such cases. To detect and reject those cases: - Introduce a new helper, is_same_chunk_map() This checks most important members, so we can detect such problem without fully checking the stripes. If the helper returns false, then we output an error message and reject the mount. - Use the full chunk map range for btrfs_find_chunk_map() The current search range is [@logical, @logical], which is only one bytenr in length. If we have the following case, btrfs_find_chunk_map() returns NULL but we still have an overlapping chunk map: Logical |<--- New chunk map --->| |<--- Existing chunk map --->| Using the full range to do the search would return the existing chunk map and get the new one rejected. Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
Since commit 3eaf5f0 ("btrfs: extract inlined creation into a dedicated delalloc helper"), even for inlined compressed extents the cb range will be exact one block, aka [0, sector). And several attempts to bring back the old compression range [0, i_size] all failed with extra races against i_size. So I think the behavior will stay. With that said, we can further simplify the lzo compression path. Since the range is always aligned to block size, and lzo compression is already done block by block, there is no reason to handle sub-block sized range. We can safely remove the @sectorsize_mask, @sector_off and @in_len variables, and always use @sectorsize as input length for each compression iteration. Finally add two ASSERT()s to make sure the range passed into btrfs_compress_bio() is always block aligned. Reviewed-by: Daniel Vacek <neelx@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
In init_scrub_stripe() we are allocating a stripe's buffer with GFP_NOFS but we can use GFP_KERNEL instead since we are not holding a transaction handle or any locks that could cause a deadlock if GFP_KERNEL triggers a transaction commit. So switch to GFP_KERNEL. We are also doing GFP_KERNEL for the allocation of stripe->csums just a few lines below. Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
…s finishing When scrub finishes, it does a wakeup on the fs_info->scrub_pause_wait wait queue and then sets dev->scrub_sctx to NULL. On the other hand the scrub cancel code (btrfs_scrub_cancel_dev()) waits on that wait queue for dev->scrub_sctx to be NULL. So this means if btrfs_scrub_cancel_dev() is called right when scrub is finishing and sees the wakeup before the NULL is assigned to dev->scrub_sctx by btrfs_scrub_dev(), it hangs. Fix this by doing the wakeup in btrfs_scrub_dev() after setting dev->scrub_sctx to NULL. Fixes: a2de733 ("btrfs: scrub") Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
It's not used since commit 001e3fc ("btrfs: scrub: remove scrub_block and scrub_sector structures"), so remove it. Reviewed-by: Daniel Vacek <neelx@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
…s ioctl If the scrub progress ioctl is called when replace is about to finish, we have a race that can result in a use-after-free of the scrub context: 1) A scrub is finishing and is at btrfs_scrub_dev(); 2) A concurrent task called the scrub progress ioctl and is in btrfs_scrub_progress(), where it takes the device_list_mutex and grabs the device. Then it starts using the device's scrub context (for a memcpy operation); 3) While the scrub progress ioctl task is running, the scrub task sets the device's scrub_ctx to NULL (acquiring fs_info->scrub_lock) and then calls scrub_put_ctx() against the scrub context, dropping the last reference and freeing the memory - while the scrub progress ioctl task is still using it, resulting in a use-after-free. Fix this by changing btrfs_scrub_progress() to take fs_info->scrub_lock before using the scrub context. Reviewed-by: Qu Wenruo <wqu@suse.com> Reviewed-by: Daniel Vacek <neelx@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
The scrub progress ioctl is copying the scrub progress stats without acquiring the spinlock that protects it and a concurrent scrub can be updating the stats at the same time which can lead to load tearing issues. So take the spinlock when copying the progress stats. Reviewed-by: Qu Wenruo <wqu@suse.com> Reviewed-by: Daniel Vacek <neelx@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
Commit 6ded22c ("btrfs: reduce div64 calls by limiting the number of stripes of a chunk to u32") introduced a chunk size limit check, but it is using a wrong result in the comment: U32_MAX << BTRFS_STRIPE_LEN_SHIFT results 256T, not 256G. Instead of calculating the size limit, using an immediate number (SZ_256G). This has the following benefit: - Still large enough for future expansion Although the check is 1024 times more strict, I don't think we will allow 256G chunk anytime soon. And we have higher chance (10 more bits) to catch a bitflip in the high bits. - Much harder to diverge from the comment We don't need to calculate the number anymore. Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
When deleting a subvolume by ID, btrfs_ioctl_snap_destroy() first resolves the requested ID to a name, then looks up that name again under the parent directory lock. A concurrent rename can change which subvolume is associated with the name between these operations. Since the deletion path does not verify the ID of the resolved subvolume, it can delete a different subvolume while leaving the requested one intact. This was reproduced by repeatedly exchanging the names of two subvolumes using renameat2(RENAME_EXCHANGE) while deleting one of them by ID. The wrong subvolume was deleted in 9 out of 14 independent tests. Fix this by checking that the resolved subvolume ID matches the requested ID while holding the parent directory lock. Return -EAGAIN on a mismatch so that userspace can retry the operation instead of being told that the requested subvolume does not exist. Fixes: 949964c ("btrfs: add new BTRFS_IOC_SNAP_DESTROY_V2 ioctl") Cc: stable@vger.kernel.org Signed-off-by: guolingxing <guolingxing@tju.edu.cn> Signed-off-by: David Sterba <dsterba@suse.com>
btrfs_ioctl_defrag() checks MAY_WRITE against nop_mnt_idmap, so on an idmapped mount the owner comparison uses the caller's fsuid against the raw on-disk uid and the ioctl fails with -EPERM even for the file's owner. Pass the mount idmap down so defrag works on idmapped mounts. The check, added in 616d374 ("btrfs: allow defrag on a file opened read-only that has rw permissions"), is not a privilege gate. It only tests whether the file could have been opened for writing, and a user who owns the file on the idmapped mount can already open it O_RDWR, write() to it or fallocate() it. Defragmenting a regular file only rearranges the caller's own extents; there is nothing it can rewrite that the caller could not rewrite anyway. Whole-subvolume defrag on a directory keeps its capable(CAP_SYS_ADMIN) requirement, and the !capable() guard around this check is left as is. FIDEDUPERANGE already works this way for unprivileged callers: may_dedupe_file() in fs/remap_range.c compares the inode owner through file_mnt_idmap(file) and falls back to inode_permission() with the same idmap, and dedupe can rewrite one file's extents from another file's contents, which is a stronger operation than defrag. On regular mounts file_mnt_idmap() is nop_mnt_idmap and nothing changes. Reviewed-by: Seth Forshee <sforshee@kernel.org> Reviewed-by: Qu Wenruo <wqu@suse.com> Reviewed-by: Christian Brauner (Amutable) <brauner@kernel.org> Signed-off-by: Tao Cui <cuitao@kylinos.cn> Signed-off-by: David Sterba <dsterba@suse.com>
Any commits after this one are for testing and evaluation only. Signed-off-by: David Sterba <dsterba@suse.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.