Skip to content

Commit 38cfff5

Browse files
Mikulas PatockaMike Snitzer
authored andcommitted
dm-delay: fix bugs introduced by kthread mode
This commit fixes the following bugs introduced by commit 70bbeb2 ("dm delay: for short delays, use kthread instead of timers and wq"): * the function flush_worker_fn has no exit path - on unload, this function will just loop and consume 100% CPU without any progress * the wake-up mechanism in flush_worker_fn is racy - a wake up will be missed if the process adds entries to the delayed_bios list just before set_current_state(TASK_INTERRUPTIBLE) * flush_delayed_bios_fast submits a bio while holding a global mutex; this may deadlock if we have multiple stacked dm-delay devices and the underlying device attempts to acquire the mutex too * if the target constructor fails, it will call delay_dtr. delay_dtr would attempt to free dc->timer_lock without it being initialized by the constructor. * if the target constructor's kthread allocation fails, delay_dtr would crash trying to dereference dc->worker because it is non-NULL due to ERR_PTR. Fixes: 70bbeb2 ("dm delay: for short delays, use kthread instead of timers and wq") Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Mike Snitzer <snitzer@kernel.org>
1 parent 6fc45b6 commit 38cfff5

File tree

1 file changed

+35
-26
lines changed

1 file changed

+35
-26
lines changed

drivers/md/dm-delay.c

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -73,65 +73,74 @@ static inline bool delay_is_fast(struct delay_c *dc)
7373
return !!dc->worker;
7474
}
7575

76+
static void flush_bios(struct bio *bio)
77+
{
78+
struct bio *n;
79+
80+
while (bio) {
81+
n = bio->bi_next;
82+
bio->bi_next = NULL;
83+
dm_submit_bio_remap(bio, NULL);
84+
bio = n;
85+
}
86+
}
87+
7688
static void flush_delayed_bios_fast(struct delay_c *dc, bool flush_all)
7789
{
7890
struct dm_delay_info *delayed, *next;
91+
struct bio_list flush_bio_list;
92+
bio_list_init(&flush_bio_list);
7993

8094
mutex_lock(&delayed_bios_lock);
8195
list_for_each_entry_safe(delayed, next, &dc->delayed_bios, list) {
8296
if (flush_all || time_after_eq(jiffies, delayed->expires)) {
8397
struct bio *bio = dm_bio_from_per_bio_data(delayed,
8498
sizeof(struct dm_delay_info));
8599
list_del(&delayed->list);
86-
dm_submit_bio_remap(bio, NULL);
100+
bio_list_add(&flush_bio_list, bio);
87101
delayed->class->ops--;
88102
}
89103
}
90104
mutex_unlock(&delayed_bios_lock);
105+
106+
flush_bios(bio_list_get(&flush_bio_list));
91107
}
92108

93109
static int flush_worker_fn(void *data)
94110
{
95111
struct delay_c *dc = data;
96112

97-
while (1) {
113+
while (!kthread_should_stop()) {
98114
flush_delayed_bios_fast(dc, false);
115+
mutex_lock(&delayed_bios_lock);
99116
if (unlikely(list_empty(&dc->delayed_bios))) {
100117
set_current_state(TASK_INTERRUPTIBLE);
118+
mutex_unlock(&delayed_bios_lock);
101119
schedule();
102-
} else
120+
} else {
121+
mutex_unlock(&delayed_bios_lock);
103122
cond_resched();
123+
}
104124
}
105125

106126
return 0;
107127
}
108128

109-
static void flush_bios(struct bio *bio)
110-
{
111-
struct bio *n;
112-
113-
while (bio) {
114-
n = bio->bi_next;
115-
bio->bi_next = NULL;
116-
dm_submit_bio_remap(bio, NULL);
117-
bio = n;
118-
}
119-
}
120-
121-
static struct bio *flush_delayed_bios(struct delay_c *dc, bool flush_all)
129+
static void flush_delayed_bios(struct delay_c *dc, bool flush_all)
122130
{
123131
struct dm_delay_info *delayed, *next;
124132
unsigned long next_expires = 0;
125133
unsigned long start_timer = 0;
126-
struct bio_list flush_bios = { };
134+
struct bio_list flush_bio_list;
135+
bio_list_init(&flush_bio_list);
127136

128137
mutex_lock(&delayed_bios_lock);
129138
list_for_each_entry_safe(delayed, next, &dc->delayed_bios, list) {
130139
if (flush_all || time_after_eq(jiffies, delayed->expires)) {
131140
struct bio *bio = dm_bio_from_per_bio_data(delayed,
132141
sizeof(struct dm_delay_info));
133142
list_del(&delayed->list);
134-
bio_list_add(&flush_bios, bio);
143+
bio_list_add(&flush_bio_list, bio);
135144
delayed->class->ops--;
136145
continue;
137146
}
@@ -147,7 +156,7 @@ static struct bio *flush_delayed_bios(struct delay_c *dc, bool flush_all)
147156
if (start_timer)
148157
queue_timeout(dc, next_expires);
149158

150-
return bio_list_get(&flush_bios);
159+
flush_bios(bio_list_get(&flush_bio_list));
151160
}
152161

153162
static void flush_expired_bios(struct work_struct *work)
@@ -158,7 +167,7 @@ static void flush_expired_bios(struct work_struct *work)
158167
if (delay_is_fast(dc))
159168
flush_delayed_bios_fast(dc, false);
160169
else
161-
flush_bios(flush_delayed_bios(dc, false));
170+
flush_delayed_bios(dc, false);
162171
}
163172

164173
static void delay_dtr(struct dm_target *ti)
@@ -177,8 +186,7 @@ static void delay_dtr(struct dm_target *ti)
177186
if (dc->worker)
178187
kthread_stop(dc->worker);
179188

180-
if (!delay_is_fast(dc))
181-
mutex_destroy(&dc->timer_lock);
189+
mutex_destroy(&dc->timer_lock);
182190

183191
kfree(dc);
184192
}
@@ -236,6 +244,7 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
236244

237245
ti->private = dc;
238246
INIT_LIST_HEAD(&dc->delayed_bios);
247+
mutex_init(&dc->timer_lock);
239248
dc->may_delay = true;
240249
dc->argc = argc;
241250

@@ -282,12 +291,12 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
282291
"dm-delay-flush-worker");
283292
if (IS_ERR(dc->worker)) {
284293
ret = PTR_ERR(dc->worker);
294+
dc->worker = NULL;
285295
goto bad;
286296
}
287297
} else {
288298
timer_setup(&dc->delay_timer, handle_delayed_timer, 0);
289299
INIT_WORK(&dc->flush_expired_bios, flush_expired_bios);
290-
mutex_init(&dc->timer_lock);
291300
dc->kdelayd_wq = alloc_workqueue("kdelayd", WQ_MEM_RECLAIM, 0);
292301
if (!dc->kdelayd_wq) {
293302
ret = -EINVAL;
@@ -345,11 +354,11 @@ static void delay_presuspend(struct dm_target *ti)
345354
dc->may_delay = false;
346355
mutex_unlock(&delayed_bios_lock);
347356

348-
if (delay_is_fast(dc))
357+
if (delay_is_fast(dc)) {
349358
flush_delayed_bios_fast(dc, true);
350-
else {
359+
} else {
351360
del_timer_sync(&dc->delay_timer);
352-
flush_bios(flush_delayed_bios(dc, true));
361+
flush_delayed_bios(dc, true);
353362
}
354363
}
355364

0 commit comments

Comments
 (0)