diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-07-11 12:33:36 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-07-11 12:33:36 -0400 |
| commit | 67b9d76f9e2f9f87f94a11521cc996dc2e43ce14 (patch) | |
| tree | 6a2fda0dc7b24ea253c03e879e1c388dc6c6e87c | |
| parent | c7c3ae2596d19ad0ed82f30d0e76a4b201b6b0a8 (diff) | |
| parent | 7a7a3b45fed9a144dbf766ee842a4c5d0632b81d (diff) | |
Merge tag 'dm-3.16-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm
Pull device mapper fixes from Mike Snitzer:
- Fix DM multipath IO hang regression from 3.15 due to logic bug in
multipath_busy. This impacted cable-pull testing and also the
ability to boot with IPR SCSI on a POWER8 box.
- Fix possible deadlock with deferred device removal by using a new
dedicated workqueue rather than using the system workqueue.
- Fix NULL pointer crash due to race condition in dm-io's wake up code
for sync_io by using a completion.
- Update dm-crypt and dm-zero author name following legal name change;
this is important to Jana so I didn't see any reason to hold it back.
* tag 'dm-3.16-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
dm mpath: fix IO hang due to logic bug in multipath_busy
dm io: fix a race condition in the wake up code for sync_io
dm crypt, dm zero: update author name following legal name change
dm: allocate a special workqueue for deferred device removal
| -rw-r--r-- | drivers/md/dm-crypt.c | 4 | ||||
| -rw-r--r-- | drivers/md/dm-io.c | 22 | ||||
| -rw-r--r-- | drivers/md/dm-mpath.c | 5 | ||||
| -rw-r--r-- | drivers/md/dm-zero.c | 4 | ||||
| -rw-r--r-- | drivers/md/dm.c | 15 |
5 files changed, 28 insertions, 22 deletions
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 53b213226c01..4cba2d808afb 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 2003 Christophe Saout <christophe@saout.de> | 2 | * Copyright (C) 2003 Jana Saout <jana@saout.de> |
| 3 | * Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org> | 3 | * Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org> |
| 4 | * Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved. | 4 | * Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved. |
| 5 | * Copyright (C) 2013 Milan Broz <gmazyland@gmail.com> | 5 | * Copyright (C) 2013 Milan Broz <gmazyland@gmail.com> |
| @@ -1996,6 +1996,6 @@ static void __exit dm_crypt_exit(void) | |||
| 1996 | module_init(dm_crypt_init); | 1996 | module_init(dm_crypt_init); |
| 1997 | module_exit(dm_crypt_exit); | 1997 | module_exit(dm_crypt_exit); |
| 1998 | 1998 | ||
| 1999 | MODULE_AUTHOR("Christophe Saout <christophe@saout.de>"); | 1999 | MODULE_AUTHOR("Jana Saout <jana@saout.de>"); |
| 2000 | MODULE_DESCRIPTION(DM_NAME " target for transparent encryption / decryption"); | 2000 | MODULE_DESCRIPTION(DM_NAME " target for transparent encryption / decryption"); |
| 2001 | MODULE_LICENSE("GPL"); | 2001 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 3842ac738f98..db404a0f7e2c 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <linux/device-mapper.h> | 10 | #include <linux/device-mapper.h> |
| 11 | 11 | ||
| 12 | #include <linux/bio.h> | 12 | #include <linux/bio.h> |
| 13 | #include <linux/completion.h> | ||
| 13 | #include <linux/mempool.h> | 14 | #include <linux/mempool.h> |
| 14 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 15 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
| @@ -32,7 +33,7 @@ struct dm_io_client { | |||
| 32 | struct io { | 33 | struct io { |
| 33 | unsigned long error_bits; | 34 | unsigned long error_bits; |
| 34 | atomic_t count; | 35 | atomic_t count; |
| 35 | struct task_struct *sleeper; | 36 | struct completion *wait; |
| 36 | struct dm_io_client *client; | 37 | struct dm_io_client *client; |
| 37 | io_notify_fn callback; | 38 | io_notify_fn callback; |
| 38 | void *context; | 39 | void *context; |
| @@ -121,8 +122,8 @@ static void dec_count(struct io *io, unsigned int region, int error) | |||
| 121 | invalidate_kernel_vmap_range(io->vma_invalidate_address, | 122 | invalidate_kernel_vmap_range(io->vma_invalidate_address, |
| 122 | io->vma_invalidate_size); | 123 | io->vma_invalidate_size); |
| 123 | 124 | ||
| 124 | if (io->sleeper) | 125 | if (io->wait) |
| 125 | wake_up_process(io->sleeper); | 126 | complete(io->wait); |
| 126 | 127 | ||
| 127 | else { | 128 | else { |
| 128 | unsigned long r = io->error_bits; | 129 | unsigned long r = io->error_bits; |
| @@ -387,6 +388,7 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, | |||
| 387 | */ | 388 | */ |
| 388 | volatile char io_[sizeof(struct io) + __alignof__(struct io) - 1]; | 389 | volatile char io_[sizeof(struct io) + __alignof__(struct io) - 1]; |
| 389 | struct io *io = (struct io *)PTR_ALIGN(&io_, __alignof__(struct io)); | 390 | struct io *io = (struct io *)PTR_ALIGN(&io_, __alignof__(struct io)); |
| 391 | DECLARE_COMPLETION_ONSTACK(wait); | ||
| 390 | 392 | ||
| 391 | if (num_regions > 1 && (rw & RW_MASK) != WRITE) { | 393 | if (num_regions > 1 && (rw & RW_MASK) != WRITE) { |
| 392 | WARN_ON(1); | 394 | WARN_ON(1); |
| @@ -395,7 +397,7 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, | |||
| 395 | 397 | ||
| 396 | io->error_bits = 0; | 398 | io->error_bits = 0; |
| 397 | atomic_set(&io->count, 1); /* see dispatch_io() */ | 399 | atomic_set(&io->count, 1); /* see dispatch_io() */ |
| 398 | io->sleeper = current; | 400 | io->wait = &wait; |
| 399 | io->client = client; | 401 | io->client = client; |
| 400 | 402 | ||
| 401 | io->vma_invalidate_address = dp->vma_invalidate_address; | 403 | io->vma_invalidate_address = dp->vma_invalidate_address; |
| @@ -403,15 +405,7 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, | |||
| 403 | 405 | ||
| 404 | dispatch_io(rw, num_regions, where, dp, io, 1); | 406 | dispatch_io(rw, num_regions, where, dp, io, 1); |
| 405 | 407 | ||
| 406 | while (1) { | 408 | wait_for_completion_io(&wait); |
| 407 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
| 408 | |||
| 409 | if (!atomic_read(&io->count)) | ||
| 410 | break; | ||
| 411 | |||
| 412 | io_schedule(); | ||
| 413 | } | ||
| 414 | set_current_state(TASK_RUNNING); | ||
| 415 | 409 | ||
| 416 | if (error_bits) | 410 | if (error_bits) |
| 417 | *error_bits = io->error_bits; | 411 | *error_bits = io->error_bits; |
| @@ -434,7 +428,7 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions, | |||
| 434 | io = mempool_alloc(client->pool, GFP_NOIO); | 428 | io = mempool_alloc(client->pool, GFP_NOIO); |
| 435 | io->error_bits = 0; | 429 | io->error_bits = 0; |
| 436 | atomic_set(&io->count, 1); /* see dispatch_io() */ | 430 | atomic_set(&io->count, 1); /* see dispatch_io() */ |
| 437 | io->sleeper = NULL; | 431 | io->wait = NULL; |
| 438 | io->client = client; | 432 | io->client = client; |
| 439 | io->callback = fn; | 433 | io->callback = fn; |
| 440 | io->context = context; | 434 | io->context = context; |
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 3f6fd9d33ba3..f4167b013d99 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
| @@ -1611,8 +1611,9 @@ static int multipath_busy(struct dm_target *ti) | |||
| 1611 | 1611 | ||
| 1612 | spin_lock_irqsave(&m->lock, flags); | 1612 | spin_lock_irqsave(&m->lock, flags); |
| 1613 | 1613 | ||
| 1614 | /* pg_init in progress, requeue until done */ | 1614 | /* pg_init in progress or no paths available */ |
| 1615 | if (!pg_ready(m)) { | 1615 | if (m->pg_init_in_progress || |
| 1616 | (!m->nr_valid_paths && m->queue_if_no_path)) { | ||
| 1616 | busy = 1; | 1617 | busy = 1; |
| 1617 | goto out; | 1618 | goto out; |
| 1618 | } | 1619 | } |
diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c index c99003e0d47a..b9a64bbce304 100644 --- a/drivers/md/dm-zero.c +++ b/drivers/md/dm-zero.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 2003 Christophe Saout <christophe@saout.de> | 2 | * Copyright (C) 2003 Jana Saout <jana@saout.de> |
| 3 | * | 3 | * |
| 4 | * This file is released under the GPL. | 4 | * This file is released under the GPL. |
| 5 | */ | 5 | */ |
| @@ -79,6 +79,6 @@ static void __exit dm_zero_exit(void) | |||
| 79 | module_init(dm_zero_init) | 79 | module_init(dm_zero_init) |
| 80 | module_exit(dm_zero_exit) | 80 | module_exit(dm_zero_exit) |
| 81 | 81 | ||
| 82 | MODULE_AUTHOR("Christophe Saout <christophe@saout.de>"); | 82 | MODULE_AUTHOR("Jana Saout <jana@saout.de>"); |
| 83 | MODULE_DESCRIPTION(DM_NAME " dummy target returning zeros"); | 83 | MODULE_DESCRIPTION(DM_NAME " dummy target returning zeros"); |
| 84 | MODULE_LICENSE("GPL"); | 84 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 437d99045ef2..32b958dbc499 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
| @@ -54,6 +54,8 @@ static void do_deferred_remove(struct work_struct *w); | |||
| 54 | 54 | ||
| 55 | static DECLARE_WORK(deferred_remove_work, do_deferred_remove); | 55 | static DECLARE_WORK(deferred_remove_work, do_deferred_remove); |
| 56 | 56 | ||
| 57 | static struct workqueue_struct *deferred_remove_workqueue; | ||
| 58 | |||
| 57 | /* | 59 | /* |
| 58 | * For bio-based dm. | 60 | * For bio-based dm. |
| 59 | * One of these is allocated per bio. | 61 | * One of these is allocated per bio. |
| @@ -276,16 +278,24 @@ static int __init local_init(void) | |||
| 276 | if (r) | 278 | if (r) |
| 277 | goto out_free_rq_tio_cache; | 279 | goto out_free_rq_tio_cache; |
| 278 | 280 | ||
| 281 | deferred_remove_workqueue = alloc_workqueue("kdmremove", WQ_UNBOUND, 1); | ||
| 282 | if (!deferred_remove_workqueue) { | ||
| 283 | r = -ENOMEM; | ||
| 284 | goto out_uevent_exit; | ||
| 285 | } | ||
| 286 | |||
| 279 | _major = major; | 287 | _major = major; |
| 280 | r = register_blkdev(_major, _name); | 288 | r = register_blkdev(_major, _name); |
| 281 | if (r < 0) | 289 | if (r < 0) |
| 282 | goto out_uevent_exit; | 290 | goto out_free_workqueue; |
| 283 | 291 | ||
| 284 | if (!_major) | 292 | if (!_major) |
| 285 | _major = r; | 293 | _major = r; |
| 286 | 294 | ||
| 287 | return 0; | 295 | return 0; |
| 288 | 296 | ||
| 297 | out_free_workqueue: | ||
| 298 | destroy_workqueue(deferred_remove_workqueue); | ||
| 289 | out_uevent_exit: | 299 | out_uevent_exit: |
| 290 | dm_uevent_exit(); | 300 | dm_uevent_exit(); |
| 291 | out_free_rq_tio_cache: | 301 | out_free_rq_tio_cache: |
| @@ -299,6 +309,7 @@ out_free_io_cache: | |||
| 299 | static void local_exit(void) | 309 | static void local_exit(void) |
| 300 | { | 310 | { |
| 301 | flush_scheduled_work(); | 311 | flush_scheduled_work(); |
| 312 | destroy_workqueue(deferred_remove_workqueue); | ||
| 302 | 313 | ||
| 303 | kmem_cache_destroy(_rq_tio_cache); | 314 | kmem_cache_destroy(_rq_tio_cache); |
| 304 | kmem_cache_destroy(_io_cache); | 315 | kmem_cache_destroy(_io_cache); |
| @@ -407,7 +418,7 @@ static void dm_blk_close(struct gendisk *disk, fmode_t mode) | |||
| 407 | 418 | ||
| 408 | if (atomic_dec_and_test(&md->open_count) && | 419 | if (atomic_dec_and_test(&md->open_count) && |
| 409 | (test_bit(DMF_DEFERRED_REMOVE, &md->flags))) | 420 | (test_bit(DMF_DEFERRED_REMOVE, &md->flags))) |
| 410 | schedule_work(&deferred_remove_work); | 421 | queue_work(deferred_remove_workqueue, &deferred_remove_work); |
| 411 | 422 | ||
| 412 | dm_put(md); | 423 | dm_put(md); |
| 413 | 424 | ||
