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 | ||