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

- Add (alloc|free)_workspace_manager helpers.
  These are the helper to alloc/free workspace_manager structure.

  The allocator will allocate a workspace_manager structure, initialize
  it, and pre-allocate one workspace for it.

  The freer will do the cleanup and set the manager pointer to NULL.

- Call alloc_workspace_manager() inside btrfs_alloc_compress_wsm()
- Call alloc_workspace_manager() inside btrfs_free_compress_wsm()
  For none, zlib and lzo compression algorithms.

For now the generic per-fs workspace managers 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

index d019a00055fd405b15da7ea8d1ddcc83f7b8a701..26c632f0a20cc55875fd25e388b80462e7ed9628 100644 (file)
@@ -773,6 +773,40 @@ static void free_workspace(int type, struct list_head *ws)
        }
 }
 
+static int alloc_workspace_manager(struct btrfs_fs_info *fs_info,
+                                  enum btrfs_compression_type type)
+{
+       struct workspace_manager *gwsm;
+       struct list_head *workspace;
+
+       ASSERT(fs_info->compr_wsm[type] == NULL);
+       gwsm = kzalloc(sizeof(*gwsm), GFP_KERNEL);
+       if (!gwsm)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&gwsm->idle_ws);
+       spin_lock_init(&gwsm->ws_lock);
+       atomic_set(&gwsm->total_ws, 0);
+       init_waitqueue_head(&gwsm->ws_wait);
+       fs_info->compr_wsm[type] = gwsm;
+
+       /*
+        * Preallocate one workspace for each compression type so we can
+        * guarantee forward progress in the worst case
+        */
+       workspace = alloc_workspace(fs_info, type, 0);
+       if (IS_ERR(workspace)) {
+               btrfs_warn(fs_info,
+       "cannot preallocate compression workspace for %s, will try later",
+                          btrfs_compress_type2str(type));
+       } else {
+               atomic_set(&gwsm->total_ws, 1);
+               gwsm->free_ws = 1;
+               list_add(workspace, &gwsm->idle_ws);
+       }
+       return 0;
+}
+
 static void btrfs_init_workspace_manager(struct btrfs_fs_info *fs_info, int type)
 {
        struct workspace_manager *wsm;
@@ -799,6 +833,26 @@ static void btrfs_init_workspace_manager(struct btrfs_fs_info *fs_info, int type
        }
 }
 
+static void free_workspace_manager(struct btrfs_fs_info *fs_info,
+                                  enum btrfs_compression_type type)
+{
+       struct list_head *ws;
+       struct workspace_manager *gwsm = fs_info->compr_wsm[type];
+
+       /* ZSTD uses its own workspace manager, should enter here. */
+       ASSERT(type != BTRFS_COMPRESS_ZSTD && type < BTRFS_NR_COMPRESS_TYPES);
+       if (!gwsm)
+               return;
+       fs_info->compr_wsm[type] = NULL;
+       while (!list_empty(&gwsm->idle_ws)) {
+               ws = gwsm->idle_ws.next;
+               list_del(ws);
+               free_workspace(type, ws);
+               atomic_dec(&gwsm->total_ws);
+       }
+       kfree(gwsm);
+}
+
 static void btrfs_cleanup_workspace_manager(int type)
 {
        struct workspace_manager *wsman;
@@ -1101,6 +1155,15 @@ int btrfs_alloc_compress_wsm(struct btrfs_fs_info *fs_info)
 {
        int ret;
 
+       ret = alloc_workspace_manager(fs_info, BTRFS_COMPRESS_NONE);
+       if (ret < 0)
+               goto error;
+       ret = alloc_workspace_manager(fs_info, BTRFS_COMPRESS_ZLIB);
+       if (ret < 0)
+               goto error;
+       ret = alloc_workspace_manager(fs_info, BTRFS_COMPRESS_LZO);
+       if (ret < 0)
+               goto error;
        ret = zstd_alloc_workspace_manager(fs_info);
        if (ret < 0)
                goto error;
@@ -1112,6 +1175,9 @@ error:
 
 void btrfs_free_compress_wsm(struct btrfs_fs_info *fs_info)
 {
+       free_workspace_manager(fs_info, BTRFS_COMPRESS_NONE);
+       free_workspace_manager(fs_info, BTRFS_COMPRESS_ZLIB);
+       free_workspace_manager(fs_info, BTRFS_COMPRESS_LZO);
        zstd_free_workspace_manager(fs_info);
 }