Commit 92ee5530 authored by Dennis Zhou's avatar Dennis Zhou Committed by David Sterba
Browse files

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: default avatarJosef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarDennis Zhou <dennis@kernel.org>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 929f4baf
Loading
Loading
Loading
Loading
+56 −45
Original line number Diff line number Diff line
@@ -730,6 +730,28 @@ struct heuristic_ws {
	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)
{
	struct heuristic_ws *workspace;
@@ -770,24 +792,14 @@ fail:
}

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,
	.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[] = {
	/* The heuristic is represented as compression type 0 */
	&btrfs_heuristic_compress,
@@ -796,34 +808,34 @@ static const struct btrfs_compress_op * const btrfs_compress_op[] = {
	&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;

	wsman->ops = btrfs_compress_op[type];
	wsm->ops = ops;

	INIT_LIST_HEAD(&wsman->idle_ws);
	spin_lock_init(&wsman->ws_lock);
	atomic_set(&wsman->total_ws, 0);
	init_waitqueue_head(&wsman->ws_wait);
	INIT_LIST_HEAD(&wsm->idle_ws);
	spin_lock_init(&wsm->ws_lock);
	atomic_set(&wsm->total_ws, 0);
	init_waitqueue_head(&wsm->ws_wait);

	/*
	 * Preallocate one workspace for each compression type so we can
	 * guarantee forward progress in the worst case
	 */
	workspace = wsman->ops->alloc_workspace();
	workspace = wsm->ops->alloc_workspace();
	if (IS_ERR(workspace)) {
		pr_warn(
	"BTRFS: cannot preallocate compression workspace, will try later\n");
	} else {
		atomic_set(&wsman->total_ws, 1);
		wsman->free_ws = 1;
		list_add(workspace, &wsman->idle_ws);
		atomic_set(&wsm->total_ws, 1);
		wsm->free_ws = 1;
		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;

@@ -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
 * 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;
	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;
	int *free_ws;

	idle_ws	 = &wsman->idle_ws;
	ws_lock	 = &wsman->ws_lock;
	total_ws = &wsman->total_ws;
	ws_wait	 = &wsman->ws_wait;
	free_ws	 = &wsman->free_ws;
	idle_ws	 = &wsm->idle_ws;
	ws_lock	 = &wsm->ws_lock;
	total_ws = &wsm->total_ws;
	ws_wait	 = &wsm->ws_wait;
	free_ws	 = &wsm->free_ws;

again:
	spin_lock(ws_lock);
@@ -887,7 +899,7 @@ again:
	 * context of btrfs_compress_bio/btrfs_compress_pages
	 */
	nofs_flag = memalloc_nofs_save();
	workspace = wsman->ops->alloc_workspace();
	workspace = wsm->ops->alloc_workspace();
	memalloc_nofs_restore(nofs_flag);

	if (IS_ERR(workspace)) {
@@ -920,15 +932,14 @@ again:

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
 * idle ones sitting around
 */
static void btrfs_put_workspace(struct workspace_manager *wsman,
				struct list_head *ws)
void btrfs_put_workspace(struct workspace_manager *wsm, struct list_head *ws)
{
	struct list_head *idle_ws;
	spinlock_t *ws_lock;
@@ -936,11 +947,11 @@ static void btrfs_put_workspace(struct workspace_manager *wsman,
	wait_queue_head_t *ws_wait;
	int *free_ws;

	idle_ws	 = &wsman->idle_ws;
	ws_lock	 = &wsman->ws_lock;
	total_ws = &wsman->total_ws;
	ws_wait	 = &wsman->ws_wait;
	free_ws	 = &wsman->free_ws;
	idle_ws	 = &wsm->idle_ws;
	ws_lock	 = &wsm->ws_lock;
	total_ws = &wsm->total_ws;
	ws_wait	 = &wsm->ws_wait;
	free_ws	 = &wsm->free_ws;

	spin_lock(ws_lock);
	if (*free_ws <= num_online_cpus()) {
@@ -951,7 +962,7 @@ static void btrfs_put_workspace(struct workspace_manager *wsman,
	}
	spin_unlock(ws_lock);

	wsman->ops->free_workspace(ws);
	wsm->ops->free_workspace(ws);
	atomic_dec(total_ws);
wake:
	cond_wake_up(ws_wait);
@@ -959,7 +970,7 @@ wake:

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;

	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)
@@ -1067,7 +1078,7 @@ void __cold btrfs_exit_compress(void)
	int i;

	for (i = 0; i < BTRFS_NR_WORKSPACE_MANAGERS; i++)
		btrfs_cleanup_workspace_manager(&wsm[i]);
		btrfs_compress_op[i]->cleanup_workspace_manager();
}

/*
+26 −0
Original line number Diff line number Diff line
@@ -107,7 +107,33 @@ enum btrfs_compression_type {
	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 {
	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);

	void (*free_workspace)(struct list_head *workspace);
+26 −0
Original line number Diff line number Diff line
@@ -61,6 +61,28 @@ struct workspace {
	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)
{
	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 = {
	.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,
	.free_workspace		= lzo_free_workspace,
	.compress_pages		= lzo_compress_pages,
+26 −0
Original line number Diff line number Diff line
@@ -27,6 +27,28 @@ struct workspace {
	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)
{
	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 = {
	.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,
	.free_workspace		= zlib_free_workspace,
	.compress_pages		= zlib_compress_pages,
+26 −0
Original line number Diff line number Diff line
@@ -41,6 +41,28 @@ struct workspace {
	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)
{
	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 = {
	.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,
	.free_workspace = zstd_free_workspace,
	.compress_pages = zstd_compress_pages,