Split main logic excepts shrinker register/unregister out of dm_bufio_client creation/destroy, the extracted code is wrapped into new helpers __do_init and __do_destroy. This commit is prepare to support dm_bufio_client resetting. Signed-off-by: Zhihao Cheng <chengzhihao1@xxxxxxxxxx> --- drivers/md/dm-bufio.c | 144 +++++++++++++++++++++++++++------------ include/linux/dm-bufio.h | 4 +- 2 files changed, 101 insertions(+), 47 deletions(-) diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index bb786c39545e..5859d69d6944 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -1731,31 +1731,17 @@ static unsigned long dm_bufio_shrink_count(struct shrinker *shrink, struct shrin return count; } -/* - * Create the buffering interface - */ -struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsigned block_size, - unsigned reserved_buffers, unsigned aux_size, - void (*alloc_callback)(struct dm_buffer *), - void (*write_callback)(struct dm_buffer *), - unsigned int flags) -{ - int r; - struct dm_bufio_client *c; - unsigned i; +static int __do_init(struct dm_bufio_client *c, struct block_device *bdev, + unsigned int block_size, unsigned int reserved_buffers, + unsigned int aux_size, + void (*alloc_callback)(struct dm_buffer *), + void (*write_callback)(struct dm_buffer *), + unsigned int flags) +{ + int r = 0; + unsigned int i; char slab_name[27]; - if (!block_size || block_size & ((1 << SECTOR_SHIFT) - 1)) { - DMERR("%s: block size not specified or is not multiple of 512b", __func__); - r = -EINVAL; - goto bad_client; - } - - c = kzalloc(sizeof(*c), GFP_KERNEL); - if (!c) { - r = -ENOMEM; - goto bad_client; - } c->buffer_tree = RB_ROOT; c->bdev = bdev; @@ -1829,6 +1815,63 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign INIT_WORK(&c->shrink_work, shrink_work); atomic_long_set(&c->need_shrink, 0); + return 0; + +bad: + while (!list_empty(&c->reserved_buffers)) { + struct dm_buffer *b = list_entry(c->reserved_buffers.next, + struct dm_buffer, lru_list); + list_del(&b->lru_list); + free_buffer(b); + } + kmem_cache_destroy(c->slab_cache); + c->slab_cache = NULL; + kmem_cache_destroy(c->slab_buffer); + c->slab_buffer = NULL; + dm_io_client_destroy(c->dm_io); +bad_dm_io: + c->dm_io = NULL; + mutex_destroy(&c->lock); + c->need_reserved_buffers = 0; + if (c->no_sleep) { + static_branch_dec(&no_sleep_enabled); + c->no_sleep = false; + } + return r; +} + +/* + * Create the buffering interface + */ +struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, + unsigned int block_size, + unsigned int reserved_buffers, + unsigned int aux_size, + void (*alloc_callback)(struct dm_buffer *), + void (*write_callback)(struct dm_buffer *), + unsigned int flags) +{ + int r; + struct dm_bufio_client *c; + char slab_name[27]; + + if (!block_size || block_size & ((1 << SECTOR_SHIFT) - 1)) { + DMERR("%s: block size not specified or is not multiple of 512b", __func__); + r = -EINVAL; + goto bad_client; + } + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) { + r = -ENOMEM; + goto bad_client; + } + + r = __do_init(c, bdev, block_size, reserved_buffers, aux_size, + alloc_callback, write_callback, flags); + if (r) + goto bad_do_init; + c->shrinker.count_objects = dm_bufio_shrink_count; c->shrinker.scan_objects = dm_bufio_shrink_scan; c->shrinker.seeks = 1; @@ -1856,36 +1899,19 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign kmem_cache_destroy(c->slab_cache); kmem_cache_destroy(c->slab_buffer); dm_io_client_destroy(c->dm_io); -bad_dm_io: mutex_destroy(&c->lock); if (c->no_sleep) static_branch_dec(&no_sleep_enabled); +bad_do_init: kfree(c); bad_client: return ERR_PTR(r); } EXPORT_SYMBOL_GPL(dm_bufio_client_create); -/* - * Free the buffering interface. - * It is required that there are no references on any buffers. - */ -void dm_bufio_client_destroy(struct dm_bufio_client *c) +static void __do_destroy(struct dm_bufio_client *c) { - unsigned i; - - drop_buffers(c); - - unregister_shrinker(&c->shrinker); - flush_work(&c->shrink_work); - - mutex_lock(&dm_bufio_clients_lock); - - list_del(&c->client_list); - dm_bufio_client_count--; - __cache_size_refresh(); - - mutex_unlock(&dm_bufio_clients_lock); + unsigned int i; BUG_ON(!RB_EMPTY_ROOT(&c->buffer_tree)); BUG_ON(c->need_reserved_buffers); @@ -1905,11 +1931,39 @@ void dm_bufio_client_destroy(struct dm_bufio_client *c) BUG_ON(c->n_buffers[i]); kmem_cache_destroy(c->slab_cache); + c->slab_cache = NULL; kmem_cache_destroy(c->slab_buffer); - dm_io_client_destroy(c->dm_io); + c->slab_buffer = NULL; + if (c->dm_io) { + dm_io_client_destroy(c->dm_io); + c->dm_io = NULL; + } mutex_destroy(&c->lock); - if (c->no_sleep) + if (c->no_sleep) { static_branch_dec(&no_sleep_enabled); + c->no_sleep = false; + } +} + +/* + * Free the buffering interface. + * It is required that there are no references on any buffers. + */ +void dm_bufio_client_destroy(struct dm_bufio_client *c) +{ + drop_buffers(c); + + unregister_shrinker(&c->shrinker); + flush_work(&c->shrink_work); + + mutex_lock(&dm_bufio_clients_lock); + list_del(&c->client_list); + dm_bufio_client_count--; + __cache_size_refresh(); + mutex_unlock(&dm_bufio_clients_lock); + + __do_destroy(c); + kfree(c); } EXPORT_SYMBOL_GPL(dm_bufio_client_destroy); diff --git a/include/linux/dm-bufio.h b/include/linux/dm-bufio.h index 15d9e15ca830..ee4f19c170ab 100644 --- a/include/linux/dm-bufio.h +++ b/include/linux/dm-bufio.h @@ -26,8 +26,8 @@ struct dm_buffer; * Create a buffered IO cache on a given device */ struct dm_bufio_client * -dm_bufio_client_create(struct block_device *bdev, unsigned block_size, - unsigned reserved_buffers, unsigned aux_size, +dm_bufio_client_create(struct block_device *bdev, unsigned int block_size, + unsigned int reserved_buffers, unsigned int aux_size, void (*alloc_callback)(struct dm_buffer *), void (*write_callback)(struct dm_buffer *), unsigned int flags); -- 2.31.1