diff options
Diffstat (limited to 'drivers/md/dm-bufio.c')
-rw-r--r-- | drivers/md/dm-bufio.c | 130 |
1 files changed, 75 insertions, 55 deletions
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index bb786c39545e..cf077f9b30c3 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009-2011 Red Hat, Inc. * @@ -89,18 +90,18 @@ struct dm_bufio_client { unsigned long n_buffers[LIST_SIZE]; struct block_device *bdev; - unsigned block_size; + unsigned int block_size; s8 sectors_per_block_bits; - void (*alloc_callback)(struct dm_buffer *); - void (*write_callback)(struct dm_buffer *); + void (*alloc_callback)(struct dm_buffer *buf); + void (*write_callback)(struct dm_buffer *buf); struct kmem_cache *slab_buffer; struct kmem_cache *slab_cache; struct dm_io_client *dm_io; struct list_head reserved_buffers; - unsigned need_reserved_buffers; + unsigned int need_reserved_buffers; - unsigned minimum_buffers; + unsigned int minimum_buffers; struct rb_root buffer_tree; wait_queue_head_t free_buffer_wait; @@ -145,17 +146,17 @@ struct dm_buffer { unsigned char list_mode; /* LIST_* */ blk_status_t read_error; blk_status_t write_error; - unsigned accessed; - unsigned hold_count; + unsigned int accessed; + unsigned int hold_count; unsigned long state; unsigned long last_accessed; - unsigned dirty_start; - unsigned dirty_end; - unsigned write_start; - unsigned write_end; + unsigned int dirty_start; + unsigned int dirty_end; + unsigned int write_start; + unsigned int write_end; struct dm_bufio_client *c; struct list_head write_list; - void (*end_io)(struct dm_buffer *, blk_status_t); + void (*end_io)(struct dm_buffer *buf, blk_status_t stat); #ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING #define MAX_STACK 10 unsigned int stack_len; @@ -215,12 +216,12 @@ static DEFINE_SPINLOCK(global_spinlock); static LIST_HEAD(global_queue); -static unsigned long global_num = 0; +static unsigned long global_num; /* * Buffers are freed after this timeout */ -static unsigned dm_bufio_max_age = DM_BUFIO_DEFAULT_AGE_SECS; +static unsigned int dm_bufio_max_age = DM_BUFIO_DEFAULT_AGE_SECS; static unsigned long dm_bufio_retain_bytes = DM_BUFIO_DEFAULT_RETAIN_BYTES; static unsigned long dm_bufio_peak_allocated; @@ -258,9 +259,11 @@ static void buffer_record_stack(struct dm_buffer *b) } #endif -/*---------------------------------------------------------------- +/* + *---------------------------------------------------------------- * A red/black tree acts as an index for all the buffers. - *--------------------------------------------------------------*/ + *---------------------------------------------------------------- + */ static struct dm_buffer *__find(struct dm_bufio_client *c, sector_t block) { struct rb_node *n = c->buffer_tree.rb_node; @@ -438,7 +441,7 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, * as if GFP_NOIO was specified. */ if (gfp_mask & __GFP_NORETRY) { - unsigned noio_flag = memalloc_noio_save(); + unsigned int noio_flag = memalloc_noio_save(); void *ptr = __vmalloc(c->block_size, gfp_mask); memalloc_noio_restore(noio_flag); @@ -561,7 +564,8 @@ static void __relink_lru(struct dm_buffer *b, int dirty) b->last_accessed = jiffies; } -/*---------------------------------------------------------------- +/* + *-------------------------------------------------------------------------- * Submit I/O on the buffer. * * Bio interface is faster but it has some problems: @@ -577,7 +581,8 @@ static void __relink_lru(struct dm_buffer *b, int dirty) * rejects the bio because it is too large, use dm-io layer to do the I/O. * The dm-io layer splits the I/O into multiple requests, avoiding the above * shortcomings. - *--------------------------------------------------------------*/ + *-------------------------------------------------------------------------- + */ /* * dm-io completion routine. It just calls b->bio.bi_end_io, pretending @@ -591,7 +596,7 @@ static void dmio_complete(unsigned long error, void *context) } static void use_dmio(struct dm_buffer *b, enum req_op op, sector_t sector, - unsigned n_sectors, unsigned offset) + unsigned int n_sectors, unsigned int offset) { int r; struct dm_io_request io_req = { @@ -623,17 +628,18 @@ static void bio_complete(struct bio *bio) { struct dm_buffer *b = bio->bi_private; blk_status_t status = bio->bi_status; + bio_uninit(bio); kfree(bio); b->end_io(b, status); } static void use_bio(struct dm_buffer *b, enum req_op op, sector_t sector, - unsigned n_sectors, unsigned offset) + unsigned int n_sectors, unsigned int offset) { struct bio *bio; char *ptr; - unsigned vec_size, len; + unsigned int vec_size, len; vec_size = b->c->block_size >> PAGE_SHIFT; if (unlikely(b->c->sectors_per_block_bits < PAGE_SHIFT - SECTOR_SHIFT)) @@ -654,7 +660,8 @@ dmio: len = n_sectors << SECTOR_SHIFT; do { - unsigned this_step = min((unsigned)(PAGE_SIZE - offset_in_page(ptr)), len); + unsigned int this_step = min((unsigned int)(PAGE_SIZE - offset_in_page(ptr)), len); + if (!bio_add_page(bio, virt_to_page(ptr), this_step, offset_in_page(ptr))) { bio_put(bio); @@ -684,9 +691,9 @@ static inline sector_t block_to_sector(struct dm_bufio_client *c, sector_t block static void submit_io(struct dm_buffer *b, enum req_op op, void (*end_io)(struct dm_buffer *, blk_status_t)) { - unsigned n_sectors; + unsigned int n_sectors; sector_t sector; - unsigned offset, end; + unsigned int offset, end; b->end_io = end_io; @@ -716,9 +723,11 @@ static void submit_io(struct dm_buffer *b, enum req_op op, use_dmio(b, op, sector, n_sectors, offset); } -/*---------------------------------------------------------------- +/* + *-------------------------------------------------------------- * Writing dirty buffers - *--------------------------------------------------------------*/ + *-------------------------------------------------------------- + */ /* * The endio routine for write. @@ -775,6 +784,7 @@ static void __write_dirty_buffer(struct dm_buffer *b, static void __flush_write_list(struct list_head *write_list) { struct blk_plug plug; + blk_start_plug(&plug); while (!list_empty(write_list)) { struct dm_buffer *b = @@ -998,9 +1008,11 @@ static void __check_watermark(struct dm_bufio_client *c, __write_dirty_buffers_async(c, 1, write_list); } -/*---------------------------------------------------------------- +/* + *-------------------------------------------------------------- * Getting a buffer - *--------------------------------------------------------------*/ + *-------------------------------------------------------------- + */ static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block, enum new_flag nf, int *need_submit, @@ -1156,7 +1168,7 @@ void *dm_bufio_new(struct dm_bufio_client *c, sector_t block, EXPORT_SYMBOL_GPL(dm_bufio_new); void dm_bufio_prefetch(struct dm_bufio_client *c, - sector_t block, unsigned n_blocks) + sector_t block, unsigned int n_blocks) { struct blk_plug plug; @@ -1170,6 +1182,7 @@ void dm_bufio_prefetch(struct dm_bufio_client *c, for (; n_blocks--; block++) { int need_submit; struct dm_buffer *b; + b = __bufio_new(c, block, NF_PREFETCH, &need_submit, &write_list); if (unlikely(!list_empty(&write_list))) { @@ -1232,7 +1245,7 @@ void dm_bufio_release(struct dm_buffer *b) EXPORT_SYMBOL_GPL(dm_bufio_release); void dm_bufio_mark_partial_buffer_dirty(struct dm_buffer *b, - unsigned start, unsigned end) + unsigned int start, unsigned int end) { struct dm_bufio_client *c = b->c; @@ -1454,6 +1467,7 @@ retry: __link_buffer(b, new_block, LIST_DIRTY); } else { sector_t old_block; + wait_on_bit_lock_io(&b->state, B_WRITING, TASK_UNINTERRUPTIBLE); /* @@ -1529,13 +1543,13 @@ void dm_bufio_forget_buffers(struct dm_bufio_client *c, sector_t block, sector_t } EXPORT_SYMBOL_GPL(dm_bufio_forget_buffers); -void dm_bufio_set_minimum_buffers(struct dm_bufio_client *c, unsigned n) +void dm_bufio_set_minimum_buffers(struct dm_bufio_client *c, unsigned int n) { c->minimum_buffers = n; } EXPORT_SYMBOL_GPL(dm_bufio_set_minimum_buffers); -unsigned dm_bufio_get_block_size(struct dm_bufio_client *c) +unsigned int dm_bufio_get_block_size(struct dm_bufio_client *c) { return c->block_size; } @@ -1544,6 +1558,7 @@ EXPORT_SYMBOL_GPL(dm_bufio_get_block_size); sector_t dm_bufio_get_device_size(struct dm_bufio_client *c) { sector_t s = bdev_nr_sectors(c->bdev); + if (s >= c->start) s -= c->start; else @@ -1659,10 +1674,12 @@ static bool __try_evict_buffer(struct dm_buffer *b, gfp_t gfp) static unsigned long get_retain_buffers(struct dm_bufio_client *c) { unsigned long retain_bytes = READ_ONCE(dm_bufio_retain_bytes); + if (likely(c->sectors_per_block_bits >= 0)) retain_bytes >>= c->sectors_per_block_bits + SECTOR_SHIFT; else retain_bytes /= c->block_size; + return retain_bytes; } @@ -1734,15 +1751,15 @@ static unsigned long dm_bufio_shrink_count(struct shrinker *shrink, struct shrin /* * 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, +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; - unsigned i; + unsigned int i; char slab_name[27]; if (!block_size || block_size & ((1 << SECTOR_SHIFT) - 1)) { @@ -1796,8 +1813,9 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign if (block_size <= KMALLOC_MAX_SIZE && (block_size < PAGE_SIZE || !is_power_of_2(block_size))) { - unsigned align = min(1U << __ffs(block_size), (unsigned)PAGE_SIZE); - snprintf(slab_name, sizeof slab_name, "dm_bufio_cache-%u", block_size); + unsigned int align = min(1U << __ffs(block_size), (unsigned int)PAGE_SIZE); + + snprintf(slab_name, sizeof(slab_name), "dm_bufio_cache-%u", block_size); c->slab_cache = kmem_cache_create(slab_name, block_size, align, SLAB_RECLAIM_ACCOUNT, NULL); if (!c->slab_cache) { @@ -1806,9 +1824,9 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign } } if (aux_size) - snprintf(slab_name, sizeof slab_name, "dm_bufio_buffer-%u", aux_size); + snprintf(slab_name, sizeof(slab_name), "dm_bufio_buffer-%u", aux_size); else - snprintf(slab_name, sizeof slab_name, "dm_bufio_buffer"); + snprintf(slab_name, sizeof(slab_name), "dm_bufio_buffer"); c->slab_buffer = kmem_cache_create(slab_name, sizeof(struct dm_buffer) + aux_size, 0, SLAB_RECLAIM_ACCOUNT, NULL); if (!c->slab_buffer) { @@ -1833,7 +1851,7 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign c->shrinker.scan_objects = dm_bufio_shrink_scan; c->shrinker.seeks = 1; c->shrinker.batch = 0; - r = register_shrinker(&c->shrinker, "md-%s:(%u:%u)", slab_name, + r = register_shrinker(&c->shrinker, "dm-bufio:(%u:%u)", MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev)); if (r) goto bad; @@ -1872,7 +1890,7 @@ EXPORT_SYMBOL_GPL(dm_bufio_client_create); */ void dm_bufio_client_destroy(struct dm_bufio_client *c) { - unsigned i; + unsigned int i; drop_buffers(c); @@ -1920,9 +1938,9 @@ void dm_bufio_set_sector_offset(struct dm_bufio_client *c, sector_t start) } EXPORT_SYMBOL_GPL(dm_bufio_set_sector_offset); -static unsigned get_max_age_hz(void) +static unsigned int get_max_age_hz(void) { - unsigned max_age = READ_ONCE(dm_bufio_max_age); + unsigned int max_age = READ_ONCE(dm_bufio_max_age); if (max_age > UINT_MAX / HZ) max_age = UINT_MAX / HZ; @@ -1973,7 +1991,7 @@ static void do_global_cleanup(struct work_struct *w) struct dm_bufio_client *locked_client = NULL; struct dm_bufio_client *current_client; struct dm_buffer *b; - unsigned spinlock_hold_count; + unsigned int spinlock_hold_count; unsigned long threshold = dm_bufio_cache_size - dm_bufio_cache_size / DM_BUFIO_LOW_WATERMARK_RATIO; unsigned long loops = global_num * 2; @@ -2059,9 +2077,11 @@ static void work_fn(struct work_struct *w) DM_BUFIO_WORK_TIMER_SECS * HZ); } -/*---------------------------------------------------------------- +/* + *-------------------------------------------------------------- * Module setup - *--------------------------------------------------------------*/ + *-------------------------------------------------------------- + */ /* * This is called only once for the whole dm_bufio module. @@ -2145,28 +2165,28 @@ static void __exit dm_bufio_exit(void) module_init(dm_bufio_init) module_exit(dm_bufio_exit) -module_param_named(max_cache_size_bytes, dm_bufio_cache_size, ulong, S_IRUGO | S_IWUSR); +module_param_named(max_cache_size_bytes, dm_bufio_cache_size, ulong, 0644); MODULE_PARM_DESC(max_cache_size_bytes, "Size of metadata cache"); -module_param_named(max_age_seconds, dm_bufio_max_age, uint, S_IRUGO | S_IWUSR); +module_param_named(max_age_seconds, dm_bufio_max_age, uint, 0644); MODULE_PARM_DESC(max_age_seconds, "Max age of a buffer in seconds"); -module_param_named(retain_bytes, dm_bufio_retain_bytes, ulong, S_IRUGO | S_IWUSR); +module_param_named(retain_bytes, dm_bufio_retain_bytes, ulong, 0644); MODULE_PARM_DESC(retain_bytes, "Try to keep at least this many bytes cached in memory"); -module_param_named(peak_allocated_bytes, dm_bufio_peak_allocated, ulong, S_IRUGO | S_IWUSR); +module_param_named(peak_allocated_bytes, dm_bufio_peak_allocated, ulong, 0644); MODULE_PARM_DESC(peak_allocated_bytes, "Tracks the maximum allocated memory"); -module_param_named(allocated_kmem_cache_bytes, dm_bufio_allocated_kmem_cache, ulong, S_IRUGO); +module_param_named(allocated_kmem_cache_bytes, dm_bufio_allocated_kmem_cache, ulong, 0444); MODULE_PARM_DESC(allocated_kmem_cache_bytes, "Memory allocated with kmem_cache_alloc"); -module_param_named(allocated_get_free_pages_bytes, dm_bufio_allocated_get_free_pages, ulong, S_IRUGO); +module_param_named(allocated_get_free_pages_bytes, dm_bufio_allocated_get_free_pages, ulong, 0444); MODULE_PARM_DESC(allocated_get_free_pages_bytes, "Memory allocated with get_free_pages"); -module_param_named(allocated_vmalloc_bytes, dm_bufio_allocated_vmalloc, ulong, S_IRUGO); +module_param_named(allocated_vmalloc_bytes, dm_bufio_allocated_vmalloc, ulong, 0444); MODULE_PARM_DESC(allocated_vmalloc_bytes, "Memory allocated with vmalloc"); -module_param_named(current_allocated_bytes, dm_bufio_current_allocated, ulong, S_IRUGO); +module_param_named(current_allocated_bytes, dm_bufio_current_allocated, ulong, 0444); MODULE_PARM_DESC(current_allocated_bytes, "Memory currently used by the cache"); MODULE_AUTHOR("Mikulas Patocka <dm-devel@redhat.com>"); |