btrfs: move to function pointers for get/put workspaces

The previous patch added generic helpers for get_workspace() and
put_workspace(). Now, we can migrate ownership of the workspace_manager
to be in the compression type code as the compression code itself
doesn't care beyond being able to get a workspace. The init/cleanup and
get/put methods are abstracted so each compression algorithm can decide
how they want to manage their workspaces.

Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Dennis Zhou <dennis@kernel.org>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Dennis Zhou 2019-02-04 15:20:03 -05:00 committed by David Sterba
parent 929f4baf93
commit 92ee553036
5 changed files with 160 additions and 45 deletions

View File

@ -730,6 +730,28 @@ struct heuristic_ws {
struct list_head list; struct list_head list;
}; };
static struct workspace_manager heuristic_wsm;
static void heuristic_init_workspace_manager(void)
{
btrfs_init_workspace_manager(&heuristic_wsm, &btrfs_heuristic_compress);
}
static void heuristic_cleanup_workspace_manager(void)
{
btrfs_cleanup_workspace_manager(&heuristic_wsm);
}
static struct list_head *heuristic_get_workspace(void)
{
return btrfs_get_workspace(&heuristic_wsm);
}
static void heuristic_put_workspace(struct list_head *ws)
{
btrfs_put_workspace(&heuristic_wsm, ws);
}
static void free_heuristic_ws(struct list_head *ws) static void free_heuristic_ws(struct list_head *ws)
{ {
struct heuristic_ws *workspace; struct heuristic_ws *workspace;
@ -770,24 +792,14 @@ fail:
} }
const struct btrfs_compress_op btrfs_heuristic_compress = { const struct btrfs_compress_op btrfs_heuristic_compress = {
.init_workspace_manager = heuristic_init_workspace_manager,
.cleanup_workspace_manager = heuristic_cleanup_workspace_manager,
.get_workspace = heuristic_get_workspace,
.put_workspace = heuristic_put_workspace,
.alloc_workspace = alloc_heuristic_ws, .alloc_workspace = alloc_heuristic_ws,
.free_workspace = free_heuristic_ws, .free_workspace = free_heuristic_ws,
}; };
struct workspace_manager {
const struct btrfs_compress_op *ops;
struct list_head idle_ws;
spinlock_t ws_lock;
/* Number of free workspaces */
int free_ws;
/* Total number of allocated workspaces */
atomic_t total_ws;
/* Waiters for a free workspace */
wait_queue_head_t ws_wait;
};
static struct workspace_manager wsm[BTRFS_NR_WORKSPACE_MANAGERS];
static const struct btrfs_compress_op * const btrfs_compress_op[] = { static const struct btrfs_compress_op * const btrfs_compress_op[] = {
/* The heuristic is represented as compression type 0 */ /* The heuristic is represented as compression type 0 */
&btrfs_heuristic_compress, &btrfs_heuristic_compress,
@ -796,34 +808,34 @@ static const struct btrfs_compress_op * const btrfs_compress_op[] = {
&btrfs_zstd_compress, &btrfs_zstd_compress,
}; };
static void btrfs_init_workspace_manager(int type) void btrfs_init_workspace_manager(struct workspace_manager *wsm,
const struct btrfs_compress_op *ops)
{ {
struct workspace_manager *wsman = &wsm[type];
struct list_head *workspace; struct list_head *workspace;
wsman->ops = btrfs_compress_op[type]; wsm->ops = ops;
INIT_LIST_HEAD(&wsman->idle_ws); INIT_LIST_HEAD(&wsm->idle_ws);
spin_lock_init(&wsman->ws_lock); spin_lock_init(&wsm->ws_lock);
atomic_set(&wsman->total_ws, 0); atomic_set(&wsm->total_ws, 0);
init_waitqueue_head(&wsman->ws_wait); init_waitqueue_head(&wsm->ws_wait);
/* /*
* Preallocate one workspace for each compression type so we can * Preallocate one workspace for each compression type so we can
* guarantee forward progress in the worst case * guarantee forward progress in the worst case
*/ */
workspace = wsman->ops->alloc_workspace(); workspace = wsm->ops->alloc_workspace();
if (IS_ERR(workspace)) { if (IS_ERR(workspace)) {
pr_warn( pr_warn(
"BTRFS: cannot preallocate compression workspace, will try later\n"); "BTRFS: cannot preallocate compression workspace, will try later\n");
} else { } else {
atomic_set(&wsman->total_ws, 1); atomic_set(&wsm->total_ws, 1);
wsman->free_ws = 1; wsm->free_ws = 1;
list_add(workspace, &wsman->idle_ws); list_add(workspace, &wsm->idle_ws);
} }
} }
static void btrfs_cleanup_workspace_manager(struct workspace_manager *wsman) void btrfs_cleanup_workspace_manager(struct workspace_manager *wsman)
{ {
struct list_head *ws; struct list_head *ws;
@ -841,7 +853,7 @@ static void btrfs_cleanup_workspace_manager(struct workspace_manager *wsman)
* Preallocation makes a forward progress guarantees and we do not return * Preallocation makes a forward progress guarantees and we do not return
* errors. * errors.
*/ */
static struct list_head *btrfs_get_workspace(struct workspace_manager *wsman) struct list_head *btrfs_get_workspace(struct workspace_manager *wsm)
{ {
struct list_head *workspace; struct list_head *workspace;
int cpus = num_online_cpus(); int cpus = num_online_cpus();
@ -852,11 +864,11 @@ static struct list_head *btrfs_get_workspace(struct workspace_manager *wsman)
wait_queue_head_t *ws_wait; wait_queue_head_t *ws_wait;
int *free_ws; int *free_ws;
idle_ws = &wsman->idle_ws; idle_ws = &wsm->idle_ws;
ws_lock = &wsman->ws_lock; ws_lock = &wsm->ws_lock;
total_ws = &wsman->total_ws; total_ws = &wsm->total_ws;
ws_wait = &wsman->ws_wait; ws_wait = &wsm->ws_wait;
free_ws = &wsman->free_ws; free_ws = &wsm->free_ws;
again: again:
spin_lock(ws_lock); spin_lock(ws_lock);
@ -887,7 +899,7 @@ again:
* context of btrfs_compress_bio/btrfs_compress_pages * context of btrfs_compress_bio/btrfs_compress_pages
*/ */
nofs_flag = memalloc_nofs_save(); nofs_flag = memalloc_nofs_save();
workspace = wsman->ops->alloc_workspace(); workspace = wsm->ops->alloc_workspace();
memalloc_nofs_restore(nofs_flag); memalloc_nofs_restore(nofs_flag);
if (IS_ERR(workspace)) { if (IS_ERR(workspace)) {
@ -920,15 +932,14 @@ again:
static struct list_head *get_workspace(int type) static struct list_head *get_workspace(int type)
{ {
return btrfs_get_workspace(&wsm[type]); return btrfs_compress_op[type]->get_workspace();
} }
/* /*
* put a workspace struct back on the list or free it if we have enough * put a workspace struct back on the list or free it if we have enough
* idle ones sitting around * idle ones sitting around
*/ */
static void btrfs_put_workspace(struct workspace_manager *wsman, void btrfs_put_workspace(struct workspace_manager *wsm, struct list_head *ws)
struct list_head *ws)
{ {
struct list_head *idle_ws; struct list_head *idle_ws;
spinlock_t *ws_lock; spinlock_t *ws_lock;
@ -936,11 +947,11 @@ static void btrfs_put_workspace(struct workspace_manager *wsman,
wait_queue_head_t *ws_wait; wait_queue_head_t *ws_wait;
int *free_ws; int *free_ws;
idle_ws = &wsman->idle_ws; idle_ws = &wsm->idle_ws;
ws_lock = &wsman->ws_lock; ws_lock = &wsm->ws_lock;
total_ws = &wsman->total_ws; total_ws = &wsm->total_ws;
ws_wait = &wsman->ws_wait; ws_wait = &wsm->ws_wait;
free_ws = &wsman->free_ws; free_ws = &wsm->free_ws;
spin_lock(ws_lock); spin_lock(ws_lock);
if (*free_ws <= num_online_cpus()) { if (*free_ws <= num_online_cpus()) {
@ -951,7 +962,7 @@ static void btrfs_put_workspace(struct workspace_manager *wsman,
} }
spin_unlock(ws_lock); spin_unlock(ws_lock);
wsman->ops->free_workspace(ws); wsm->ops->free_workspace(ws);
atomic_dec(total_ws); atomic_dec(total_ws);
wake: wake:
cond_wake_up(ws_wait); cond_wake_up(ws_wait);
@ -959,7 +970,7 @@ wake:
static void put_workspace(int type, struct list_head *ws) static void put_workspace(int type, struct list_head *ws)
{ {
return btrfs_put_workspace(&wsm[type], ws); return btrfs_compress_op[type]->put_workspace(ws);
} }
/* /*
@ -1059,7 +1070,7 @@ void __init btrfs_init_compress(void)
int i; int i;
for (i = 0; i < BTRFS_NR_WORKSPACE_MANAGERS; i++) for (i = 0; i < BTRFS_NR_WORKSPACE_MANAGERS; i++)
btrfs_init_workspace_manager(i); btrfs_compress_op[i]->init_workspace_manager();
} }
void __cold btrfs_exit_compress(void) void __cold btrfs_exit_compress(void)
@ -1067,7 +1078,7 @@ void __cold btrfs_exit_compress(void)
int i; int i;
for (i = 0; i < BTRFS_NR_WORKSPACE_MANAGERS; i++) for (i = 0; i < BTRFS_NR_WORKSPACE_MANAGERS; i++)
btrfs_cleanup_workspace_manager(&wsm[i]); btrfs_compress_op[i]->cleanup_workspace_manager();
} }
/* /*

View File

@ -107,7 +107,33 @@ enum btrfs_compression_type {
BTRFS_COMPRESS_TYPES = 3, BTRFS_COMPRESS_TYPES = 3,
}; };
struct workspace_manager {
const struct btrfs_compress_op *ops;
struct list_head idle_ws;
spinlock_t ws_lock;
/* Number of free workspaces */
int free_ws;
/* Total number of allocated workspaces */
atomic_t total_ws;
/* Waiters for a free workspace */
wait_queue_head_t ws_wait;
};
void btrfs_init_workspace_manager(struct workspace_manager *wsm,
const struct btrfs_compress_op *ops);
struct list_head *btrfs_get_workspace(struct workspace_manager *wsm);
void btrfs_put_workspace(struct workspace_manager *wsm, struct list_head *ws);
void btrfs_cleanup_workspace_manager(struct workspace_manager *wsm);
struct btrfs_compress_op { struct btrfs_compress_op {
void (*init_workspace_manager)(void);
void (*cleanup_workspace_manager)(void);
struct list_head *(*get_workspace)(void);
void (*put_workspace)(struct list_head *ws);
struct list_head *(*alloc_workspace)(void); struct list_head *(*alloc_workspace)(void);
void (*free_workspace)(struct list_head *workspace); void (*free_workspace)(struct list_head *workspace);

View File

@ -61,6 +61,28 @@ struct workspace {
struct list_head list; struct list_head list;
}; };
static struct workspace_manager wsm;
static void lzo_init_workspace_manager(void)
{
btrfs_init_workspace_manager(&wsm, &btrfs_lzo_compress);
}
static void lzo_cleanup_workspace_manager(void)
{
btrfs_cleanup_workspace_manager(&wsm);
}
static struct list_head *lzo_get_workspace(void)
{
return btrfs_get_workspace(&wsm);
}
static void lzo_put_workspace(struct list_head *ws)
{
btrfs_put_workspace(&wsm, ws);
}
static void lzo_free_workspace(struct list_head *ws) static void lzo_free_workspace(struct list_head *ws)
{ {
struct workspace *workspace = list_entry(ws, struct workspace, list); struct workspace *workspace = list_entry(ws, struct workspace, list);
@ -490,6 +512,10 @@ static void lzo_set_level(struct list_head *ws, unsigned int type)
} }
const struct btrfs_compress_op btrfs_lzo_compress = { const struct btrfs_compress_op btrfs_lzo_compress = {
.init_workspace_manager = lzo_init_workspace_manager,
.cleanup_workspace_manager = lzo_cleanup_workspace_manager,
.get_workspace = lzo_get_workspace,
.put_workspace = lzo_put_workspace,
.alloc_workspace = lzo_alloc_workspace, .alloc_workspace = lzo_alloc_workspace,
.free_workspace = lzo_free_workspace, .free_workspace = lzo_free_workspace,
.compress_pages = lzo_compress_pages, .compress_pages = lzo_compress_pages,

View File

@ -27,6 +27,28 @@ struct workspace {
int level; int level;
}; };
static struct workspace_manager wsm;
static void zlib_init_workspace_manager(void)
{
btrfs_init_workspace_manager(&wsm, &btrfs_zlib_compress);
}
static void zlib_cleanup_workspace_manager(void)
{
btrfs_cleanup_workspace_manager(&wsm);
}
static struct list_head *zlib_get_workspace(void)
{
return btrfs_get_workspace(&wsm);
}
static void zlib_put_workspace(struct list_head *ws)
{
btrfs_put_workspace(&wsm, ws);
}
static void zlib_free_workspace(struct list_head *ws) static void zlib_free_workspace(struct list_head *ws)
{ {
struct workspace *workspace = list_entry(ws, struct workspace, list); struct workspace *workspace = list_entry(ws, struct workspace, list);
@ -402,6 +424,10 @@ static void zlib_set_level(struct list_head *ws, unsigned int type)
} }
const struct btrfs_compress_op btrfs_zlib_compress = { const struct btrfs_compress_op btrfs_zlib_compress = {
.init_workspace_manager = zlib_init_workspace_manager,
.cleanup_workspace_manager = zlib_cleanup_workspace_manager,
.get_workspace = zlib_get_workspace,
.put_workspace = zlib_put_workspace,
.alloc_workspace = zlib_alloc_workspace, .alloc_workspace = zlib_alloc_workspace,
.free_workspace = zlib_free_workspace, .free_workspace = zlib_free_workspace,
.compress_pages = zlib_compress_pages, .compress_pages = zlib_compress_pages,

View File

@ -41,6 +41,28 @@ struct workspace {
ZSTD_outBuffer out_buf; ZSTD_outBuffer out_buf;
}; };
static struct workspace_manager wsm;
static void zstd_init_workspace_manager(void)
{
btrfs_init_workspace_manager(&wsm, &btrfs_zstd_compress);
}
static void zstd_cleanup_workspace_manager(void)
{
btrfs_cleanup_workspace_manager(&wsm);
}
static struct list_head *zstd_get_workspace(void)
{
return btrfs_get_workspace(&wsm);
}
static void zstd_put_workspace(struct list_head *ws)
{
btrfs_put_workspace(&wsm, ws);
}
static void zstd_free_workspace(struct list_head *ws) static void zstd_free_workspace(struct list_head *ws)
{ {
struct workspace *workspace = list_entry(ws, struct workspace, list); struct workspace *workspace = list_entry(ws, struct workspace, list);
@ -424,6 +446,10 @@ static void zstd_set_level(struct list_head *ws, unsigned int type)
} }
const struct btrfs_compress_op btrfs_zstd_compress = { const struct btrfs_compress_op btrfs_zstd_compress = {
.init_workspace_manager = zstd_init_workspace_manager,
.cleanup_workspace_manager = zstd_cleanup_workspace_manager,
.get_workspace = zstd_get_workspace,
.put_workspace = zstd_put_workspace,
.alloc_workspace = zstd_alloc_workspace, .alloc_workspace = zstd_alloc_workspace,
.free_workspace = zstd_free_workspace, .free_workspace = zstd_free_workspace,
.compress_pages = zstd_compress_pages, .compress_pages = zstd_compress_pages,