From: Qu Wenruo Date: Wed, 13 Aug 2025 07:06:57 +0000 (+0930) Subject: btrfs: add generic workspace manager initialization X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=6f9c3f48acffaffe7bb643b3bc04f8a99021179a;p=users%2Fhch%2Fmisc.git btrfs: add generic workspace manager initialization 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 Reviewed-by: David Sterba Signed-off-by: David Sterba --- diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index d019a00055fd..26c632f0a20c 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -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); }