]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
btrfs: allow compression even if the range is not page aligned
authorQu Wenruo <wqu@suse.com>
Fri, 6 Sep 2024 02:52:56 +0000 (12:22 +0930)
committerDavid Sterba <dsterba@suse.com>
Mon, 11 Nov 2024 13:34:13 +0000 (14:34 +0100)
Previously for btrfs with sector size smaller than page size (subpage),
we only allow compression if the range is fully page aligned.

This is to work around the asynchronous submission of compressed range,
which delayed the page unlock and writeback into a workqueue,
furthermore asynchronous submission can lock multiple sector range
across page boundary.

Such asynchronous submission makes it very hard to co-operate with other
regular writes.

With the recent changes to the subpage folio unlock path, now
asynchronous submission of compressed pages can co-operate with regular
submission, so enable sector perfect compression if it's an experimental
build.

The ETA for moving this feature out of experimental is 6.15, and I hope
all remaining corner cases can be exposed before that.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/inode.c

index 686d39309410fa0f768ace0a8a1abf4d6393dede..355d83dd43c137c6e5941386d271ccf6f4dcd4bb 100644 (file)
@@ -832,32 +832,16 @@ static inline int inode_need_compress(struct btrfs_inode *inode, u64 start,
                return 0;
        }
        /*
-        * Special check for subpage.
+        * Only enable sector perfect compression for experimental builds.
         *
-        * We lock the full page then run each delalloc range in the page, thus
-        * for the following case, we will hit some subpage specific corner case:
+        * This is a big feature change for subpage cases, and can hit
+        * different corner cases, so only limit this feature for
+        * experimental build for now.
         *
-        * 0            32K             64K
-        * |    |///////|       |///////|
-        *              \- A            \- B
-        *
-        * In above case, both range A and range B will try to unlock the full
-        * page [0, 64K), causing the one finished later will have page
-        * unlocked already, triggering various page lock requirement BUG_ON()s.
-        *
-        * So here we add an artificial limit that subpage compression can only
-        * if the range is fully page aligned.
-        *
-        * In theory we only need to ensure the first page is fully covered, but
-        * the tailing partial page will be locked until the full compression
-        * finishes, delaying the write of other range.
-        *
-        * TODO: Make btrfs_run_delalloc_range() to lock all delalloc range
-        * first to prevent any submitted async extent to unlock the full page.
-        * By this, we can ensure for subpage case that only the last async_cow
-        * will unlock the full page.
+        * ETA for moving this out of experimental builds is 6.15.
         */
-       if (fs_info->sectorsize < PAGE_SIZE) {
+       if (fs_info->sectorsize < PAGE_SIZE &&
+           !IS_ENABLED(CONFIG_BTRFS_EXPERIMENTAL)) {
                if (!PAGE_ALIGNED(start) ||
                    !PAGE_ALIGNED(end + 1))
                        return 0;
@@ -1002,17 +986,6 @@ again:
           (start > 0 || end + 1 < inode->disk_i_size))
                goto cleanup_and_bail_uncompressed;
 
-       /*
-        * For subpage case, we require full page alignment for the sector
-        * aligned range.
-        * Thus we must also check against @actual_end, not just @end.
-        */
-       if (blocksize < PAGE_SIZE) {
-               if (!PAGE_ALIGNED(start) ||
-                   !PAGE_ALIGNED(round_up(actual_end, blocksize)))
-                       goto cleanup_and_bail_uncompressed;
-       }
-
        total_compressed = min_t(unsigned long, total_compressed,
                        BTRFS_MAX_UNCOMPRESSED);
        total_in = 0;