Skip to content

Commit 5ad4fe9

Browse files
committed
Merge tag 'for-6.3/dm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm
Pull device mapper fixes from Mike Snitzer: - Fix DM thin to work as a swap device by using 'limit_swap_bios' DM target flag (initially added to allow swap to dm-crypt) to throttle the amount of outstanding swap bios. - Fix DM crypt soft lockup warnings by calling cond_resched() from the cpu intensive loop in dmcrypt_write(). - Fix DM crypt to not access an uninitialized tasklet. This fix allows for consistent handling of IO completion, by _not_ needlessly punting to a workqueue when tasklets are not needed. - Fix DM core's alloc_dev() initialization for DM stats to check for and propagate alloc_percpu() failure. * tag 'for-6.3/dm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm: dm stats: check for and propagate alloc_percpu failure dm crypt: avoid accessing uninitialized tasklet dm crypt: add cond_resched() to dmcrypt_write() dm thin: fix deadlock when swapping to thin device
2 parents 8351147 + d3aa3e0 commit 5ad4fe9

File tree

5 files changed

+22
-9
lines changed

5 files changed

+22
-9
lines changed

drivers/md/dm-crypt.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ struct dm_crypt_io {
7272
struct crypt_config *cc;
7373
struct bio *base_bio;
7474
u8 *integrity_metadata;
75-
bool integrity_metadata_from_pool;
75+
bool integrity_metadata_from_pool:1;
76+
bool in_tasklet:1;
77+
7678
struct work_struct work;
7779
struct tasklet_struct tasklet;
7880

@@ -1730,6 +1732,7 @@ static void crypt_io_init(struct dm_crypt_io *io, struct crypt_config *cc,
17301732
io->ctx.r.req = NULL;
17311733
io->integrity_metadata = NULL;
17321734
io->integrity_metadata_from_pool = false;
1735+
io->in_tasklet = false;
17331736
atomic_set(&io->io_pending, 0);
17341737
}
17351738

@@ -1776,14 +1779,13 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
17761779
* our tasklet. In this case we need to delay bio_endio()
17771780
* execution to after the tasklet is done and dequeued.
17781781
*/
1779-
if (tasklet_trylock(&io->tasklet)) {
1780-
tasklet_unlock(&io->tasklet);
1781-
bio_endio(base_bio);
1782+
if (io->in_tasklet) {
1783+
INIT_WORK(&io->work, kcryptd_io_bio_endio);
1784+
queue_work(cc->io_queue, &io->work);
17821785
return;
17831786
}
17841787

1785-
INIT_WORK(&io->work, kcryptd_io_bio_endio);
1786-
queue_work(cc->io_queue, &io->work);
1788+
bio_endio(base_bio);
17871789
}
17881790

17891791
/*
@@ -1936,6 +1938,7 @@ static int dmcrypt_write(void *data)
19361938
io = crypt_io_from_node(rb_first(&write_tree));
19371939
rb_erase(&io->rb_node, &write_tree);
19381940
kcryptd_io_write(io);
1941+
cond_resched();
19391942
} while (!RB_EMPTY_ROOT(&write_tree));
19401943
blk_finish_plug(&plug);
19411944
}
@@ -2230,6 +2233,7 @@ static void kcryptd_queue_crypt(struct dm_crypt_io *io)
22302233
* it is being executed with irqs disabled.
22312234
*/
22322235
if (in_hardirq() || irqs_disabled()) {
2236+
io->in_tasklet = true;
22332237
tasklet_init(&io->tasklet, kcryptd_crypt_tasklet, (unsigned long)&io->work);
22342238
tasklet_schedule(&io->tasklet);
22352239
return;

drivers/md/dm-stats.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ static int dm_stat_in_flight(struct dm_stat_shared *shared)
188188
atomic_read(&shared->in_flight[WRITE]);
189189
}
190190

191-
void dm_stats_init(struct dm_stats *stats)
191+
int dm_stats_init(struct dm_stats *stats)
192192
{
193193
int cpu;
194194
struct dm_stats_last_position *last;
@@ -197,11 +197,16 @@ void dm_stats_init(struct dm_stats *stats)
197197
INIT_LIST_HEAD(&stats->list);
198198
stats->precise_timestamps = false;
199199
stats->last = alloc_percpu(struct dm_stats_last_position);
200+
if (!stats->last)
201+
return -ENOMEM;
202+
200203
for_each_possible_cpu(cpu) {
201204
last = per_cpu_ptr(stats->last, cpu);
202205
last->last_sector = (sector_t)ULLONG_MAX;
203206
last->last_rw = UINT_MAX;
204207
}
208+
209+
return 0;
205210
}
206211

207212
void dm_stats_cleanup(struct dm_stats *stats)

drivers/md/dm-stats.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ struct dm_stats_aux {
2121
unsigned long long duration_ns;
2222
};
2323

24-
void dm_stats_init(struct dm_stats *st);
24+
int dm_stats_init(struct dm_stats *st);
2525
void dm_stats_cleanup(struct dm_stats *st);
2626

2727
struct mapped_device;

drivers/md/dm-thin.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3369,6 +3369,7 @@ static int pool_ctr(struct dm_target *ti, unsigned int argc, char **argv)
33693369
pt->low_water_blocks = low_water_blocks;
33703370
pt->adjusted_pf = pt->requested_pf = pf;
33713371
ti->num_flush_bios = 1;
3372+
ti->limit_swap_bios = true;
33723373

33733374
/*
33743375
* Only need to enable discards if the pool should pass
@@ -4249,6 +4250,7 @@ static int thin_ctr(struct dm_target *ti, unsigned int argc, char **argv)
42494250
goto bad;
42504251

42514252
ti->num_flush_bios = 1;
4253+
ti->limit_swap_bios = true;
42524254
ti->flush_supported = true;
42534255
ti->accounts_remapped_io = true;
42544256
ti->per_io_data_size = sizeof(struct dm_thin_endio_hook);

drivers/md/dm.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2097,7 +2097,9 @@ static struct mapped_device *alloc_dev(int minor)
20972097
if (!md->pending_io)
20982098
goto bad;
20992099

2100-
dm_stats_init(&md->stats);
2100+
r = dm_stats_init(&md->stats);
2101+
if (r < 0)
2102+
goto bad;
21012103

21022104
/* Populate the mapping, nobody knows we exist yet */
21032105
spin_lock(&_minor_lock);

0 commit comments

Comments
 (0)