Skip to content

Commit da8b4fc

Browse files
Mikulas PatockaMike Snitzer
authored andcommitted
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 <[email protected]> Signed-off-by: Mike Snitzer <[email protected]>
1 parent 6d50eb4 commit da8b4fc

File tree

1 file changed

+26
-26
lines changed

1 file changed

+26
-26
lines changed

drivers/md/dm-integrity.c

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,6 @@ struct dm_integrity_c {
251251

252252
struct workqueue_struct *recalc_wq;
253253
struct work_struct recalc_work;
254-
u8 *recalc_buffer;
255-
u8 *recalc_tags;
256254

257255
struct bio_list flush_bio_list;
258256

@@ -2646,6 +2644,9 @@ static void recalc_write_super(struct dm_integrity_c *ic)
26462644
static void integrity_recalc(struct work_struct *w)
26472645
{
26482646
struct dm_integrity_c *ic = container_of(w, struct dm_integrity_c, recalc_work);
2647+
size_t recalc_tags_size;
2648+
u8 *recalc_buffer = NULL;
2649+
u8 *recalc_tags = NULL;
26492650
struct dm_integrity_range range;
26502651
struct dm_io_request io_req;
26512652
struct dm_io_region io_loc;
@@ -2658,6 +2659,20 @@ static void integrity_recalc(struct work_struct *w)
26582659
int r;
26592660
unsigned int super_counter = 0;
26602661

2662+
recalc_buffer = __vmalloc(RECALC_SECTORS << SECTOR_SHIFT, GFP_NOIO);
2663+
if (!recalc_buffer) {
2664+
DMCRIT("out of memory for recalculate buffer - recalculation disabled");
2665+
goto free_ret;
2666+
}
2667+
recalc_tags_size = (RECALC_SECTORS >> ic->sb->log2_sectors_per_block) * ic->tag_size;
2668+
if (crypto_shash_digestsize(ic->internal_hash) > ic->tag_size)
2669+
recalc_tags_size += crypto_shash_digestsize(ic->internal_hash) - ic->tag_size;
2670+
recalc_tags = kvmalloc(recalc_tags_size, GFP_NOIO);
2671+
if (!recalc_tags) {
2672+
DMCRIT("out of memory for recalculate buffer - recalculation disabled");
2673+
goto free_ret;
2674+
}
2675+
26612676
DEBUG_print("start recalculation... (position %llx)\n", le64_to_cpu(ic->sb->recalc_sector));
26622677

26632678
spin_lock_irq(&ic->endio_wait.lock);
@@ -2720,7 +2735,7 @@ static void integrity_recalc(struct work_struct *w)
27202735

27212736
io_req.bi_opf = REQ_OP_READ;
27222737
io_req.mem.type = DM_IO_VMA;
2723-
io_req.mem.ptr.addr = ic->recalc_buffer;
2738+
io_req.mem.ptr.addr = recalc_buffer;
27242739
io_req.notify.fn = NULL;
27252740
io_req.client = ic->io;
27262741
io_loc.bdev = ic->dev->bdev;
@@ -2733,15 +2748,15 @@ static void integrity_recalc(struct work_struct *w)
27332748
goto err;
27342749
}
27352750

2736-
t = ic->recalc_tags;
2751+
t = recalc_tags;
27372752
for (i = 0; i < n_sectors; i += ic->sectors_per_block) {
2738-
integrity_sector_checksum(ic, logical_sector + i, ic->recalc_buffer + (i << SECTOR_SHIFT), t);
2753+
integrity_sector_checksum(ic, logical_sector + i, recalc_buffer + (i << SECTOR_SHIFT), t);
27392754
t += ic->tag_size;
27402755
}
27412756

27422757
metadata_block = get_metadata_sector_and_offset(ic, area, offset, &metadata_offset);
27432758

2744-
r = dm_integrity_rw_tag(ic, ic->recalc_tags, &metadata_block, &metadata_offset, t - ic->recalc_tags, TAG_WRITE);
2759+
r = dm_integrity_rw_tag(ic, recalc_tags, &metadata_block, &metadata_offset, t - recalc_tags, TAG_WRITE);
27452760
if (unlikely(r)) {
27462761
dm_integrity_io_error(ic, "writing tags", r);
27472762
goto err;
@@ -2769,12 +2784,16 @@ static void integrity_recalc(struct work_struct *w)
27692784

27702785
err:
27712786
remove_range(ic, &range);
2772-
return;
2787+
goto free_ret;
27732788

27742789
unlock_ret:
27752790
spin_unlock_irq(&ic->endio_wait.lock);
27762791

27772792
recalc_write_super(ic);
2793+
2794+
free_ret:
2795+
vfree(recalc_buffer);
2796+
kvfree(recalc_tags);
27782797
}
27792798

27802799
static void bitmap_block_work(struct work_struct *w)
@@ -4439,30 +4458,13 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv
44394458
}
44404459

44414460
if (ic->internal_hash) {
4442-
size_t recalc_tags_size;
4443-
44444461
ic->recalc_wq = alloc_workqueue("dm-integrity-recalc", WQ_MEM_RECLAIM, 1);
44454462
if (!ic->recalc_wq) {
44464463
ti->error = "Cannot allocate workqueue";
44474464
r = -ENOMEM;
44484465
goto bad;
44494466
}
44504467
INIT_WORK(&ic->recalc_work, integrity_recalc);
4451-
ic->recalc_buffer = vmalloc(RECALC_SECTORS << SECTOR_SHIFT);
4452-
if (!ic->recalc_buffer) {
4453-
ti->error = "Cannot allocate buffer for recalculating";
4454-
r = -ENOMEM;
4455-
goto bad;
4456-
}
4457-
recalc_tags_size = (RECALC_SECTORS >> ic->sb->log2_sectors_per_block) * ic->tag_size;
4458-
if (crypto_shash_digestsize(ic->internal_hash) > ic->tag_size)
4459-
recalc_tags_size += crypto_shash_digestsize(ic->internal_hash) - ic->tag_size;
4460-
ic->recalc_tags = kvmalloc(recalc_tags_size, GFP_KERNEL);
4461-
if (!ic->recalc_tags) {
4462-
ti->error = "Cannot allocate tags for recalculating";
4463-
r = -ENOMEM;
4464-
goto bad;
4465-
}
44664468
} else {
44674469
if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) {
44684470
ti->error = "Recalculate can only be specified with internal_hash";
@@ -4606,8 +4608,6 @@ static void dm_integrity_dtr(struct dm_target *ti)
46064608
destroy_workqueue(ic->writer_wq);
46074609
if (ic->recalc_wq)
46084610
destroy_workqueue(ic->recalc_wq);
4609-
vfree(ic->recalc_buffer);
4610-
kvfree(ic->recalc_tags);
46114611
kvfree(ic->bbs);
46124612
if (ic->bufio)
46134613
dm_bufio_client_destroy(ic->bufio);

0 commit comments

Comments
 (0)