]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
btrfs: add workspace manager initialization for zstd
authorQu Wenruo <wqu@suse.com>
Wed, 13 Aug 2025 05:35:20 +0000 (15:05 +0930)
committerDavid Sterba <dsterba@suse.com>
Tue, 23 Sep 2025 06:49:15 +0000 (08:49 +0200)
This involves:

- Add zstd_alloc_workspace_manager() and zstd_free_workspace_manager()
  Those two functions will accept an fs_info pointer, and alloc/free
  fs_info->compr_wsm[BTRFS_COMPRESS_ZSTD] pointer.

- Add btrfs_alloc_compress_wsm() and btrfs_free_compress_wsm()
  Those are helpers allocating the workspace managers for all
  algorithms.
  For now only zstd is supported, and the timing is a little unusual,
  the btrfs_alloc_compress_wsm() should only be called after the
  sectorsize being initialized.

  Meanwhile btrfs_free_fs_info_compress() is called in
  btrfs_free_fs_info().

- Move the definition of btrfs_compression_type to "fs.h"
  The reason is that "compression.h" has already included "fs.h", thus
  we can not just include "compression.h" to get the definition of
  BTRFS_NR_COMPRESS_TYPES to define fs_info::compr_wsm[].

For now the per-fs zstd workspace manager won't really have any effect,
and all compression is still going through the global workspace manager.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/compression.c
fs/btrfs/compression.h
fs/btrfs/disk-io.c
fs/btrfs/fs.h
fs/btrfs/zstd.c

index d8ba6d0d4e837416cdf51cd8807de58204655b63..d019a00055fd405b15da7ea8d1ddcc83f7b8a701 100644 (file)
@@ -1097,6 +1097,24 @@ int btrfs_decompress(int type, const u8 *data_in, struct folio *dest_folio,
        return ret;
 }
 
+int btrfs_alloc_compress_wsm(struct btrfs_fs_info *fs_info)
+{
+       int ret;
+
+       ret = zstd_alloc_workspace_manager(fs_info);
+       if (ret < 0)
+               goto error;
+       return 0;
+error:
+       btrfs_free_compress_wsm(fs_info);
+       return ret;
+}
+
+void btrfs_free_compress_wsm(struct btrfs_fs_info *fs_info)
+{
+       zstd_free_workspace_manager(fs_info);
+}
+
 int __init btrfs_init_compress(void)
 {
        if (bioset_init(&btrfs_compressed_bioset, BIO_POOL_SIZE,
index f600555b758388dc9b21783727008a10546c77d5..70a3294bd14a8dc2fb249abf1f63c833d1393d09 100644 (file)
@@ -89,6 +89,9 @@ static inline u32 btrfs_calc_input_length(struct folio *folio, u64 range_end, u6
        return min(range_end, folio_end(folio)) - cur;
 }
 
+int btrfs_alloc_compress_wsm(struct btrfs_fs_info *fs_info);
+void btrfs_free_compress_wsm(struct btrfs_fs_info *fs_info);
+
 int __init btrfs_init_compress(void);
 void __cold btrfs_exit_compress(void);
 
@@ -112,16 +115,6 @@ int btrfs_compress_str2level(unsigned int type, const char *str, int *level_ret)
 struct folio *btrfs_alloc_compr_folio(void);
 void btrfs_free_compr_folio(struct folio *folio);
 
-enum btrfs_compression_type {
-       BTRFS_COMPRESS_NONE  = 0,
-       BTRFS_COMPRESS_ZLIB  = 1,
-       BTRFS_COMPRESS_LZO   = 2,
-       BTRFS_COMPRESS_ZSTD  = 3,
-       BTRFS_NR_COMPRESS_TYPES = 4,
-
-       BTRFS_DEFRAG_DONT_COMPRESS,
-};
-
 struct workspace_manager {
        struct list_head idle_ws;
        spinlock_t ws_lock;
@@ -188,6 +181,8 @@ int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb);
 int zstd_decompress(struct list_head *ws, const u8 *data_in,
                struct folio *dest_folio, unsigned long dest_pgoff, size_t srclen,
                size_t destlen);
+int zstd_alloc_workspace_manager(struct btrfs_fs_info *fs_info);
+void zstd_free_workspace_manager(struct btrfs_fs_info *fs_info);
 void zstd_init_workspace_manager(struct btrfs_fs_info *fs_info);
 void zstd_cleanup_workspace_manager(void);
 struct list_head *zstd_alloc_workspace(struct btrfs_fs_info *fs_info, int level);
index b8ea63e444c724245d859f857c4e696abf982a71..eb55ecf4bf25822f70bebfb326427746cae2ac22 100644 (file)
@@ -1248,6 +1248,7 @@ void btrfs_free_fs_info(struct btrfs_fs_info *fs_info)
 
        if (fs_info->fs_devices)
                btrfs_close_devices(fs_info->fs_devices);
+       btrfs_free_compress_wsm(fs_info);
        percpu_counter_destroy(&fs_info->stats_read_blocks);
        percpu_counter_destroy(&fs_info->dirty_metadata_bytes);
        percpu_counter_destroy(&fs_info->delalloc_bytes);
@@ -3407,6 +3408,9 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
         */
        fs_info->max_inline = min_t(u64, fs_info->max_inline, fs_info->sectorsize);
 
+       ret = btrfs_alloc_compress_wsm(fs_info);
+       if (ret)
+               goto fail_sb_buffer;
        ret = btrfs_init_workqueues(fs_info);
        if (ret)
                goto fail_sb_buffer;
index a84128e991a9d43a77c29c3b504891758a9356d9..2ccba95af0607683dec5872e9ab059cec1243c9a 100644 (file)
@@ -306,6 +306,16 @@ enum {
 #define BTRFS_WARNING_COMMIT_INTERVAL  (300)
 #define BTRFS_DEFAULT_MAX_INLINE       (2048)
 
+enum btrfs_compression_type {
+       BTRFS_COMPRESS_NONE  = 0,
+       BTRFS_COMPRESS_ZLIB  = 1,
+       BTRFS_COMPRESS_LZO   = 2,
+       BTRFS_COMPRESS_ZSTD  = 3,
+       BTRFS_NR_COMPRESS_TYPES = 4,
+
+       BTRFS_DEFRAG_DONT_COMPRESS,
+};
+
 struct btrfs_dev_replace {
        /* See #define above */
        u64 replace_state;
@@ -508,6 +518,9 @@ struct btrfs_fs_info {
        u64 last_trans_log_full_commit;
        unsigned long long mount_opt;
 
+       /* Compress related structures. */
+       void *compr_wsm[BTRFS_NR_COMPRESS_TYPES];
+
        int compress_type;
        int compress_level;
        u32 commit_interval;
index 24bf5cfaecec2a6f93963902fb6c5fe49b41179e..24898aee3ee00da6c9bfd2910ed0ef171267900a 100644 (file)
@@ -182,6 +182,36 @@ static void zstd_calc_ws_mem_sizes(void)
        }
 }
 
+int zstd_alloc_workspace_manager(struct btrfs_fs_info *fs_info)
+{
+       struct zstd_workspace_manager *zwsm;
+       struct list_head *ws;
+
+       ASSERT(fs_info->compr_wsm[BTRFS_COMPRESS_ZSTD] == NULL);
+       zwsm = kzalloc(sizeof(*zwsm), GFP_KERNEL);
+       if (!zwsm)
+               return -ENOMEM;
+       zstd_calc_ws_mem_sizes();
+       zwsm->ops = &btrfs_zstd_compress;
+       spin_lock_init(&zwsm->lock);
+       init_waitqueue_head(&zwsm->wait);
+       timer_setup(&zwsm->timer, zstd_reclaim_timer_fn, 0);
+
+       INIT_LIST_HEAD(&zwsm->lru_list);
+       for (int i = 0; i < ZSTD_BTRFS_MAX_LEVEL; i++)
+               INIT_LIST_HEAD(&zwsm->idle_ws[i]);
+       fs_info->compr_wsm[BTRFS_COMPRESS_ZSTD] = zwsm;
+
+       ws = zstd_alloc_workspace(fs_info, ZSTD_BTRFS_MAX_LEVEL);
+       if (IS_ERR(ws)) {
+               btrfs_warn(NULL, "cannot preallocate zstd compression workspace");
+       } else {
+               set_bit(ZSTD_BTRFS_MAX_LEVEL - 1, &zwsm->active_map);
+               list_add(ws, &zwsm->idle_ws[ZSTD_BTRFS_MAX_LEVEL - 1]);
+       }
+       return 0;
+}
+
 void zstd_init_workspace_manager(struct btrfs_fs_info *fs_info)
 {
        struct list_head *ws;
@@ -207,6 +237,29 @@ void zstd_init_workspace_manager(struct btrfs_fs_info *fs_info)
        }
 }
 
+void zstd_free_workspace_manager(struct btrfs_fs_info *fs_info)
+{
+       struct zstd_workspace_manager *zwsm = fs_info->compr_wsm[BTRFS_COMPRESS_ZSTD];
+       struct workspace *workspace;
+
+       if (!zwsm)
+               return;
+       fs_info->compr_wsm[BTRFS_COMPRESS_ZSTD] = NULL;
+       spin_lock_bh(&zwsm->lock);
+       for (int i = 0; i < ZSTD_BTRFS_MAX_LEVEL; i++) {
+               while (!list_empty(&zwsm->idle_ws[i])) {
+                       workspace = container_of(zwsm->idle_ws[i].next,
+                                                struct workspace, list);
+                       list_del(&workspace->list);
+                       list_del(&workspace->lru_list);
+                       zstd_free_workspace(&workspace->list);
+               }
+       }
+       spin_unlock_bh(&zwsm->lock);
+       timer_delete_sync(&zwsm->timer);
+       kfree(zwsm);
+}
+
 void zstd_cleanup_workspace_manager(void)
 {
        struct workspace *workspace;