Skip to content

Commit c542ee1

Browse files
bmarzinsMike Snitzer
authored andcommitted
dm-delay: change locking to avoid contention
The delayed_bios list is protected by one mutex shared by all dm-delay devices. This mutex must be held whenever a bio is added or expired bios are removed from the list. Since a large number of expired bios could be on the list, flush_delayed_bios() can schedule while holding the mutex. This means a flush_delayed_bios() call on any dm-delay device can slow down delay_map() calls on any other dm-delay device. To keep dm-delay devices from slowing each other down and keep processing delay bios from slowing adding delayed bios, the global mutex has been removed, and each dm-delay device now has two locks. delayed_bios_lock is a spinlock that must be held whenever the delayed_bios list is accessed. process_bios_lock is a mutex that must be held whenever a process has temporarily pulled bios off the delayed_bios list to check which ones should be processed. It must be held until all the bios that won't be processed are returned to the list. This is what flush_delayed_bios() now does. The mutex is necessary to guarantee that delay_presuspend() sees the entire list of delayed bios when it calls flush_delayed_bios(). Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com> Signed-off-by: Mike Snitzer <snitzer@kernel.org>
1 parent 64eb88d commit c542ee1

File tree

1 file changed

+23
-13
lines changed

1 file changed

+23
-13
lines changed

drivers/md/dm-delay.c

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ struct delay_class {
2929
struct delay_c {
3030
struct timer_list delay_timer;
3131
struct mutex timer_lock;
32+
struct mutex process_bios_lock; /* hold while removing bios to be processed from list */
33+
spinlock_t delayed_bios_lock; /* hold on all accesses to delayed_bios list */
3234
struct workqueue_struct *kdelayd_wq;
3335
struct work_struct flush_expired_bios;
3436
struct list_head delayed_bios;
@@ -49,8 +51,6 @@ struct dm_delay_info {
4951
unsigned long expires;
5052
};
5153

52-
static DEFINE_MUTEX(delayed_bios_lock);
53-
5454
static void handle_delayed_timer(struct timer_list *t)
5555
{
5656
struct delay_c *dc = from_timer(dc, t, delay_timer);
@@ -89,12 +89,16 @@ static void flush_delayed_bios(struct delay_c *dc, bool flush_all)
8989
{
9090
struct dm_delay_info *delayed, *next;
9191
struct bio_list flush_bio_list;
92+
LIST_HEAD(local_list);
9293
unsigned long next_expires = 0;
9394
bool start_timer = false;
9495
bio_list_init(&flush_bio_list);
9596

96-
mutex_lock(&delayed_bios_lock);
97-
list_for_each_entry_safe(delayed, next, &dc->delayed_bios, list) {
97+
mutex_lock(&dc->process_bios_lock);
98+
spin_lock(&dc->delayed_bios_lock);
99+
list_replace_init(&dc->delayed_bios, &local_list);
100+
spin_unlock(&dc->delayed_bios_lock);
101+
list_for_each_entry_safe(delayed, next, &local_list, list) {
98102
cond_resched();
99103
if (flush_all || time_after_eq(jiffies, delayed->expires)) {
100104
struct bio *bio = dm_bio_from_per_bio_data(delayed,
@@ -114,7 +118,10 @@ static void flush_delayed_bios(struct delay_c *dc, bool flush_all)
114118
}
115119
}
116120
}
117-
mutex_unlock(&delayed_bios_lock);
121+
spin_lock(&dc->delayed_bios_lock);
122+
list_splice(&local_list, &dc->delayed_bios);
123+
spin_unlock(&dc->delayed_bios_lock);
124+
mutex_unlock(&dc->process_bios_lock);
118125

119126
if (start_timer)
120127
queue_timeout(dc, next_expires);
@@ -128,13 +135,13 @@ static int flush_worker_fn(void *data)
128135

129136
while (!kthread_should_stop()) {
130137
flush_delayed_bios(dc, false);
131-
mutex_lock(&delayed_bios_lock);
138+
spin_lock(&dc->delayed_bios_lock);
132139
if (unlikely(list_empty(&dc->delayed_bios))) {
133140
set_current_state(TASK_INTERRUPTIBLE);
134-
mutex_unlock(&delayed_bios_lock);
141+
spin_unlock(&dc->delayed_bios_lock);
135142
schedule();
136143
} else {
137-
mutex_unlock(&delayed_bios_lock);
144+
spin_unlock(&dc->delayed_bios_lock);
138145
cond_resched();
139146
}
140147
}
@@ -168,6 +175,7 @@ static void delay_dtr(struct dm_target *ti)
168175
if (dc->worker)
169176
kthread_stop(dc->worker);
170177

178+
mutex_destroy(&dc->process_bios_lock);
171179
mutex_destroy(&dc->timer_lock);
172180

173181
kfree(dc);
@@ -227,6 +235,8 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
227235
ti->private = dc;
228236
INIT_LIST_HEAD(&dc->delayed_bios);
229237
mutex_init(&dc->timer_lock);
238+
mutex_init(&dc->process_bios_lock);
239+
spin_lock_init(&dc->delayed_bios_lock);
230240
dc->may_delay = true;
231241
dc->argc = argc;
232242

@@ -309,14 +319,14 @@ static int delay_bio(struct delay_c *dc, struct delay_class *c, struct bio *bio)
309319
delayed->context = dc;
310320
delayed->expires = expires = jiffies + msecs_to_jiffies(c->delay);
311321

312-
mutex_lock(&delayed_bios_lock);
322+
spin_lock(&dc->delayed_bios_lock);
313323
if (unlikely(!dc->may_delay)) {
314-
mutex_unlock(&delayed_bios_lock);
324+
spin_unlock(&dc->delayed_bios_lock);
315325
return DM_MAPIO_REMAPPED;
316326
}
317327
c->ops++;
318328
list_add_tail(&delayed->list, &dc->delayed_bios);
319-
mutex_unlock(&delayed_bios_lock);
329+
spin_unlock(&dc->delayed_bios_lock);
320330

321331
if (delay_is_fast(dc))
322332
wake_up_process(dc->worker);
@@ -330,9 +340,9 @@ static void delay_presuspend(struct dm_target *ti)
330340
{
331341
struct delay_c *dc = ti->private;
332342

333-
mutex_lock(&delayed_bios_lock);
343+
spin_lock(&dc->delayed_bios_lock);
334344
dc->may_delay = false;
335-
mutex_unlock(&delayed_bios_lock);
345+
spin_unlock(&dc->delayed_bios_lock);
336346

337347
if (!delay_is_fast(dc))
338348
timer_delete(&dc->delay_timer);

0 commit comments

Comments
 (0)