aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-07-11 12:33:36 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-07-11 12:33:36 -0400
commit67b9d76f9e2f9f87f94a11521cc996dc2e43ce14 (patch)
tree6a2fda0dc7b24ea253c03e879e1c388dc6c6e87c
parentc7c3ae2596d19ad0ed82f30d0e76a4b201b6b0a8 (diff)
parent7a7a3b45fed9a144dbf766ee842a4c5d0632b81d (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.c4
-rw-r--r--drivers/md/dm-io.c22
-rw-r--r--drivers/md/dm-mpath.c5
-rw-r--r--drivers/md/dm-zero.c4
-rw-r--r--drivers/md/dm.c15
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)
1996module_init(dm_crypt_init); 1996module_init(dm_crypt_init);
1997module_exit(dm_crypt_exit); 1997module_exit(dm_crypt_exit);
1998 1998
1999MODULE_AUTHOR("Christophe Saout <christophe@saout.de>"); 1999MODULE_AUTHOR("Jana Saout <jana@saout.de>");
2000MODULE_DESCRIPTION(DM_NAME " target for transparent encryption / decryption"); 2000MODULE_DESCRIPTION(DM_NAME " target for transparent encryption / decryption");
2001MODULE_LICENSE("GPL"); 2001MODULE_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 {
32struct io { 33struct 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)
79module_init(dm_zero_init) 79module_init(dm_zero_init)
80module_exit(dm_zero_exit) 80module_exit(dm_zero_exit)
81 81
82MODULE_AUTHOR("Christophe Saout <christophe@saout.de>"); 82MODULE_AUTHOR("Jana Saout <jana@saout.de>");
83MODULE_DESCRIPTION(DM_NAME " dummy target returning zeros"); 83MODULE_DESCRIPTION(DM_NAME " dummy target returning zeros");
84MODULE_LICENSE("GPL"); 84MODULE_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
55static DECLARE_WORK(deferred_remove_work, do_deferred_remove); 55static DECLARE_WORK(deferred_remove_work, do_deferred_remove);
56 56
57static 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
297out_free_workqueue:
298 destroy_workqueue(deferred_remove_workqueue);
289out_uevent_exit: 299out_uevent_exit:
290 dm_uevent_exit(); 300 dm_uevent_exit();
291out_free_rq_tio_cache: 301out_free_rq_tio_cache:
@@ -299,6 +309,7 @@ out_free_io_cache:
299static void local_exit(void) 309static 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