From 25c9a4ab4d73d251886e6b317181cfc433e011f9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 13 Jun 2023 00:47:51 +0300 Subject: dm integrity: Use %*ph for printing hexdump of a small buffer The kernel already has a helper to print a hexdump of a small buffer via pointer extension. Use that instead of open coded variant. In long term it helps to kill pr_cont() or at least narrow down its use. Note, the format is slightly changed, i.e. the trailing space is always printed. Also the IV dump is limited by 64 bytes which seems fine. Signed-off-by: Andy Shevchenko Signed-off-by: Mike Snitzer --- drivers/md/dm-integrity.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) (limited to 'drivers/md/dm-integrity.c') diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index 31838b13ea54..5e5f1c029b75 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -342,24 +342,9 @@ static struct kmem_cache *journal_io_cache; #define JOURNAL_IO_MEMPOOL 32 #ifdef DEBUG_PRINT -#define DEBUG_print(x, ...) printk(KERN_DEBUG x, ##__VA_ARGS__) -static void __DEBUG_bytes(__u8 *bytes, size_t len, const char *msg, ...) -{ - va_list args; - - va_start(args, msg); - vprintk(msg, args); - va_end(args); - if (len) - pr_cont(":"); - while (len) { - pr_cont(" %02x", *bytes); - bytes++; - len--; - } - pr_cont("\n"); -} -#define DEBUG_bytes(bytes, len, msg, ...) __DEBUG_bytes(bytes, len, KERN_DEBUG msg, ##__VA_ARGS__) +#define DEBUG_print(x, ...) printk(KERN_DEBUG x, ##__VA_ARGS__) +#define DEBUG_bytes(bytes, len, msg, ...) printk(KERN_DEBUG msg "%s%*ph\n", ##__VA_ARGS__, \ + len ? ": " : "", len, bytes) #else #define DEBUG_print(x, ...) do { } while (0) #define DEBUG_bytes(bytes, len, msg, ...) do { } while (0) -- cgit From 6d50eb4725934fd22f5eeccb401000687c790fd0 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Mon, 26 Jun 2023 16:44:34 +0200 Subject: dm integrity: reduce vmalloc space footprint on 32-bit architectures It was reported that dm-integrity runs out of vmalloc space on 32-bit architectures. On x86, there is only 128MiB vmalloc space and dm-integrity consumes it quickly because it has a 64MiB journal and 8MiB recalculate buffer. Fix this by reducing the size of the journal to 4MiB and the size of the recalculate buffer to 1MiB, so that multiple dm-integrity devices can be created and activated on 32-bit architectures. Cc: stable@vger.kernel.org Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer --- drivers/md/dm-integrity.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/md/dm-integrity.c') diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index 5e5f1c029b75..0a910bb8db17 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -34,11 +34,11 @@ #define DEFAULT_BUFFER_SECTORS 128 #define DEFAULT_JOURNAL_WATERMARK 50 #define DEFAULT_SYNC_MSEC 10000 -#define DEFAULT_MAX_JOURNAL_SECTORS 131072 +#define DEFAULT_MAX_JOURNAL_SECTORS (IS_ENABLED(CONFIG_64BIT) ? 131072 : 8192) #define MIN_LOG2_INTERLEAVE_SECTORS 3 #define MAX_LOG2_INTERLEAVE_SECTORS 31 #define METADATA_WORKQUEUE_MAX_ACTIVE 16 -#define RECALC_SECTORS 32768 +#define RECALC_SECTORS (IS_ENABLED(CONFIG_64BIT) ? 32768 : 2048) #define RECALC_WRITE_SUPER 16 #define BITMAP_BLOCK_SIZE 4096 /* don't change it */ #define BITMAP_FLUSH_INTERVAL (10 * HZ) -- cgit From da8b4fc1f63a01a0eca9338ae338b804c437b51f Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Mon, 26 Jun 2023 16:46:00 +0200 Subject: dm integrity: only allocate recalculate buffer when needed dm-integrity preallocated 8MiB buffer for recalculating in the constructor and freed it in the destructor. This wastes memory when the user has many dm-integrity devices. Fix dm-integrity so that the buffer is only allocated when recalculation is in progress; allocate the buffer at the beginning of integrity_recalc() and free it at the end. Note that integrity_recalc() doesn't hold any locks when allocating the buffer, so it shouldn't cause low-memory deadlock. Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer --- drivers/md/dm-integrity.c | 52 +++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers/md/dm-integrity.c') diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index 0a910bb8db17..16d1aa263066 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -251,8 +251,6 @@ struct dm_integrity_c { struct workqueue_struct *recalc_wq; struct work_struct recalc_work; - u8 *recalc_buffer; - u8 *recalc_tags; struct bio_list flush_bio_list; @@ -2646,6 +2644,9 @@ static void recalc_write_super(struct dm_integrity_c *ic) static void integrity_recalc(struct work_struct *w) { struct dm_integrity_c *ic = container_of(w, struct dm_integrity_c, recalc_work); + size_t recalc_tags_size; + u8 *recalc_buffer = NULL; + u8 *recalc_tags = NULL; struct dm_integrity_range range; struct dm_io_request io_req; struct dm_io_region io_loc; @@ -2658,6 +2659,20 @@ static void integrity_recalc(struct work_struct *w) int r; unsigned int super_counter = 0; + recalc_buffer = __vmalloc(RECALC_SECTORS << SECTOR_SHIFT, GFP_NOIO); + if (!recalc_buffer) { + DMCRIT("out of memory for recalculate buffer - recalculation disabled"); + goto free_ret; + } + recalc_tags_size = (RECALC_SECTORS >> ic->sb->log2_sectors_per_block) * ic->tag_size; + if (crypto_shash_digestsize(ic->internal_hash) > ic->tag_size) + recalc_tags_size += crypto_shash_digestsize(ic->internal_hash) - ic->tag_size; + recalc_tags = kvmalloc(recalc_tags_size, GFP_NOIO); + if (!recalc_tags) { + DMCRIT("out of memory for recalculate buffer - recalculation disabled"); + goto free_ret; + } + DEBUG_print("start recalculation... (position %llx)\n", le64_to_cpu(ic->sb->recalc_sector)); spin_lock_irq(&ic->endio_wait.lock); @@ -2720,7 +2735,7 @@ next_chunk: io_req.bi_opf = REQ_OP_READ; io_req.mem.type = DM_IO_VMA; - io_req.mem.ptr.addr = ic->recalc_buffer; + io_req.mem.ptr.addr = recalc_buffer; io_req.notify.fn = NULL; io_req.client = ic->io; io_loc.bdev = ic->dev->bdev; @@ -2733,15 +2748,15 @@ next_chunk: goto err; } - t = ic->recalc_tags; + t = recalc_tags; for (i = 0; i < n_sectors; i += ic->sectors_per_block) { - integrity_sector_checksum(ic, logical_sector + i, ic->recalc_buffer + (i << SECTOR_SHIFT), t); + integrity_sector_checksum(ic, logical_sector + i, recalc_buffer + (i << SECTOR_SHIFT), t); t += ic->tag_size; } metadata_block = get_metadata_sector_and_offset(ic, area, offset, &metadata_offset); - r = dm_integrity_rw_tag(ic, ic->recalc_tags, &metadata_block, &metadata_offset, t - ic->recalc_tags, TAG_WRITE); + r = dm_integrity_rw_tag(ic, recalc_tags, &metadata_block, &metadata_offset, t - recalc_tags, TAG_WRITE); if (unlikely(r)) { dm_integrity_io_error(ic, "writing tags", r); goto err; @@ -2769,12 +2784,16 @@ advance_and_next: err: remove_range(ic, &range); - return; + goto free_ret; unlock_ret: spin_unlock_irq(&ic->endio_wait.lock); recalc_write_super(ic); + +free_ret: + vfree(recalc_buffer); + kvfree(recalc_tags); } static void bitmap_block_work(struct work_struct *w) @@ -4439,8 +4458,6 @@ try_smaller_buffer: } if (ic->internal_hash) { - size_t recalc_tags_size; - ic->recalc_wq = alloc_workqueue("dm-integrity-recalc", WQ_MEM_RECLAIM, 1); if (!ic->recalc_wq) { ti->error = "Cannot allocate workqueue"; @@ -4448,21 +4465,6 @@ try_smaller_buffer: goto bad; } INIT_WORK(&ic->recalc_work, integrity_recalc); - ic->recalc_buffer = vmalloc(RECALC_SECTORS << SECTOR_SHIFT); - if (!ic->recalc_buffer) { - ti->error = "Cannot allocate buffer for recalculating"; - r = -ENOMEM; - goto bad; - } - recalc_tags_size = (RECALC_SECTORS >> ic->sb->log2_sectors_per_block) * ic->tag_size; - if (crypto_shash_digestsize(ic->internal_hash) > ic->tag_size) - recalc_tags_size += crypto_shash_digestsize(ic->internal_hash) - ic->tag_size; - ic->recalc_tags = kvmalloc(recalc_tags_size, GFP_KERNEL); - if (!ic->recalc_tags) { - ti->error = "Cannot allocate tags for recalculating"; - r = -ENOMEM; - goto bad; - } } else { if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) { ti->error = "Recalculate can only be specified with internal_hash"; @@ -4606,8 +4608,6 @@ static void dm_integrity_dtr(struct dm_target *ti) destroy_workqueue(ic->writer_wq); if (ic->recalc_wq) destroy_workqueue(ic->recalc_wq); - vfree(ic->recalc_buffer); - kvfree(ic->recalc_tags); kvfree(ic->bbs); if (ic->bufio) dm_bufio_client_destroy(ic->bufio); -- cgit From 3be1622895af25101f7046ed0b2286bead2219d4 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Mon, 26 Jun 2023 16:46:57 +0200 Subject: dm integrity: scale down the recalculate buffer if memory allocation fails If memory allocation fails, try to reduce the size of the recalculate buffer and continue with that smaller buffer. Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer --- drivers/md/dm-integrity.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers/md/dm-integrity.c') diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index 16d1aa263066..5ca3fc62e8f3 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -2658,19 +2658,25 @@ static void integrity_recalc(struct work_struct *w) unsigned int i; int r; unsigned int super_counter = 0; + unsigned recalc_sectors = RECALC_SECTORS; - recalc_buffer = __vmalloc(RECALC_SECTORS << SECTOR_SHIFT, GFP_NOIO); +retry: + recalc_buffer = __vmalloc(recalc_sectors << SECTOR_SHIFT, GFP_NOIO); if (!recalc_buffer) { +oom: + recalc_sectors >>= 1; + if (recalc_sectors >= 1U << ic->sb->log2_sectors_per_block) + goto retry; DMCRIT("out of memory for recalculate buffer - recalculation disabled"); goto free_ret; } - recalc_tags_size = (RECALC_SECTORS >> ic->sb->log2_sectors_per_block) * ic->tag_size; + recalc_tags_size = (recalc_sectors >> ic->sb->log2_sectors_per_block) * ic->tag_size; if (crypto_shash_digestsize(ic->internal_hash) > ic->tag_size) recalc_tags_size += crypto_shash_digestsize(ic->internal_hash) - ic->tag_size; recalc_tags = kvmalloc(recalc_tags_size, GFP_NOIO); if (!recalc_tags) { - DMCRIT("out of memory for recalculate buffer - recalculation disabled"); - goto free_ret; + vfree(recalc_buffer); + goto oom; } DEBUG_print("start recalculation... (position %llx)\n", le64_to_cpu(ic->sb->recalc_sector)); @@ -2693,7 +2699,7 @@ next_chunk: } get_area_and_offset(ic, range.logical_sector, &area, &offset); - range.n_sectors = min((sector_t)RECALC_SECTORS, ic->provided_data_sectors - range.logical_sector); + range.n_sectors = min((sector_t)recalc_sectors, ic->provided_data_sectors - range.logical_sector); if (!ic->meta_dev) range.n_sectors = min(range.n_sectors, ((sector_t)1U << ic->sb->log2_interleave_sectors) - (unsigned int)offset); -- cgit