Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dm io: fix a race condition in the wake up code for sync_io

There's a race condition between the atomic_dec_and_test(&io->count)
in dec_count() and the waking of the sync_io() thread. If the thread
is spuriously woken immediately after the decrement it may exit,
making the on stack io struct invalid, yet the dec_count could still
be using it.

Fix this race by using a completion in sync_io() and dec_count().

Reported-by: Minfei Huang <huangminfei@ucloud.cn>
Signed-off-by: Joe Thornber <thornber@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Acked-by: Mikulas Patocka <mpatocka@redhat.com>
Cc: stable@vger.kernel.org

authored by

Joe Thornber and committed by
Mike Snitzer
10f1d5d1 bf14299f

+8 -14
+8 -14
drivers/md/dm-io.c
··· 10 10 #include <linux/device-mapper.h> 11 11 12 12 #include <linux/bio.h> 13 + #include <linux/completion.h> 13 14 #include <linux/mempool.h> 14 15 #include <linux/module.h> 15 16 #include <linux/sched.h> ··· 33 32 struct io { 34 33 unsigned long error_bits; 35 34 atomic_t count; 36 - struct task_struct *sleeper; 35 + struct completion *wait; 37 36 struct dm_io_client *client; 38 37 io_notify_fn callback; 39 38 void *context; ··· 122 121 invalidate_kernel_vmap_range(io->vma_invalidate_address, 123 122 io->vma_invalidate_size); 124 123 125 - if (io->sleeper) 126 - wake_up_process(io->sleeper); 124 + if (io->wait) 125 + complete(io->wait); 127 126 128 127 else { 129 128 unsigned long r = io->error_bits; ··· 388 387 */ 389 388 volatile char io_[sizeof(struct io) + __alignof__(struct io) - 1]; 390 389 struct io *io = (struct io *)PTR_ALIGN(&io_, __alignof__(struct io)); 390 + DECLARE_COMPLETION_ONSTACK(wait); 391 391 392 392 if (num_regions > 1 && (rw & RW_MASK) != WRITE) { 393 393 WARN_ON(1); ··· 397 395 398 396 io->error_bits = 0; 399 397 atomic_set(&io->count, 1); /* see dispatch_io() */ 400 - io->sleeper = current; 398 + io->wait = &wait; 401 399 io->client = client; 402 400 403 401 io->vma_invalidate_address = dp->vma_invalidate_address; ··· 405 403 406 404 dispatch_io(rw, num_regions, where, dp, io, 1); 407 405 408 - while (1) { 409 - set_current_state(TASK_UNINTERRUPTIBLE); 410 - 411 - if (!atomic_read(&io->count)) 412 - break; 413 - 414 - io_schedule(); 415 - } 416 - set_current_state(TASK_RUNNING); 406 + wait_for_completion_io(&wait); 417 407 418 408 if (error_bits) 419 409 *error_bits = io->error_bits; ··· 428 434 io = mempool_alloc(client->pool, GFP_NOIO); 429 435 io->error_bits = 0; 430 436 atomic_set(&io->count, 1); /* see dispatch_io() */ 431 - io->sleeper = NULL; 437 + io->wait = NULL; 432 438 io->client = client; 433 439 io->callback = fn; 434 440 io->context = context;