. 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.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJTv+hvAAoJEMUj8QotnQNawwMH/2yQ7AE3dh44jGr1fp0UEP8e
 Vd7HWtUJAm4+lYkPH7AjLCw3YBwWh/ajLXAwMpPBI878o5sgoWTfnq0hbecqoWkt
 5EugETiZ20C3K/llNFpw9xdtlObFwI21WUGqmu8ygYvfSvdbg6THPT5o8BdtEvnb
 MDBrrrpBpUwMCGw3v7jIoYrKZbWmp46iy5KwVqBbXnD3shpOU8KpasyIOrqlrqjJ
 z7BzfprN6ut1zaVs83N4iPMPnSPrIloUisGpPn1r74qRYUv/AXQgiv09WPA3keTN
 erRGFU9Mr0I4MGOLTuqHyCVO0t4tze1pL8jwEk29GUkXXcr9Is4p9I307Cm7WvE=
 =pBlO
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2014-07-11 09:33:36 -07:00
commit 67b9d76f9e
5 changed files with 28 additions and 22 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2003 Christophe Saout <christophe@saout.de>
* Copyright (C) 2003 Jana Saout <jana@saout.de>
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved.
* Copyright (C) 2013 Milan Broz <gmazyland@gmail.com>
@ -1996,6 +1996,6 @@ static void __exit dm_crypt_exit(void)
module_init(dm_crypt_init);
module_exit(dm_crypt_exit);
MODULE_AUTHOR("Christophe Saout <christophe@saout.de>");
MODULE_AUTHOR("Jana Saout <jana@saout.de>");
MODULE_DESCRIPTION(DM_NAME " target for transparent encryption / decryption");
MODULE_LICENSE("GPL");

View file

@ -10,6 +10,7 @@
#include <linux/device-mapper.h>
#include <linux/bio.h>
#include <linux/completion.h>
#include <linux/mempool.h>
#include <linux/module.h>
#include <linux/sched.h>
@ -32,7 +33,7 @@ struct dm_io_client {
struct io {
unsigned long error_bits;
atomic_t count;
struct task_struct *sleeper;
struct completion *wait;
struct dm_io_client *client;
io_notify_fn callback;
void *context;
@ -121,8 +122,8 @@ static void dec_count(struct io *io, unsigned int region, int error)
invalidate_kernel_vmap_range(io->vma_invalidate_address,
io->vma_invalidate_size);
if (io->sleeper)
wake_up_process(io->sleeper);
if (io->wait)
complete(io->wait);
else {
unsigned long r = io->error_bits;
@ -387,6 +388,7 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions,
*/
volatile char io_[sizeof(struct io) + __alignof__(struct io) - 1];
struct io *io = (struct io *)PTR_ALIGN(&io_, __alignof__(struct io));
DECLARE_COMPLETION_ONSTACK(wait);
if (num_regions > 1 && (rw & RW_MASK) != WRITE) {
WARN_ON(1);
@ -395,7 +397,7 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions,
io->error_bits = 0;
atomic_set(&io->count, 1); /* see dispatch_io() */
io->sleeper = current;
io->wait = &wait;
io->client = client;
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,
dispatch_io(rw, num_regions, where, dp, io, 1);
while (1) {
set_current_state(TASK_UNINTERRUPTIBLE);
if (!atomic_read(&io->count))
break;
io_schedule();
}
set_current_state(TASK_RUNNING);
wait_for_completion_io(&wait);
if (error_bits)
*error_bits = io->error_bits;
@ -434,7 +428,7 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions,
io = mempool_alloc(client->pool, GFP_NOIO);
io->error_bits = 0;
atomic_set(&io->count, 1); /* see dispatch_io() */
io->sleeper = NULL;
io->wait = NULL;
io->client = client;
io->callback = fn;
io->context = context;

View file

@ -1611,8 +1611,9 @@ static int multipath_busy(struct dm_target *ti)
spin_lock_irqsave(&m->lock, flags);
/* pg_init in progress, requeue until done */
if (!pg_ready(m)) {
/* pg_init in progress or no paths available */
if (m->pg_init_in_progress ||
(!m->nr_valid_paths && m->queue_if_no_path)) {
busy = 1;
goto out;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2003 Christophe Saout <christophe@saout.de>
* Copyright (C) 2003 Jana Saout <jana@saout.de>
*
* This file is released under the GPL.
*/
@ -79,6 +79,6 @@ static void __exit dm_zero_exit(void)
module_init(dm_zero_init)
module_exit(dm_zero_exit)
MODULE_AUTHOR("Christophe Saout <christophe@saout.de>");
MODULE_AUTHOR("Jana Saout <jana@saout.de>");
MODULE_DESCRIPTION(DM_NAME " dummy target returning zeros");
MODULE_LICENSE("GPL");

View file

@ -54,6 +54,8 @@ static void do_deferred_remove(struct work_struct *w);
static DECLARE_WORK(deferred_remove_work, do_deferred_remove);
static struct workqueue_struct *deferred_remove_workqueue;
/*
* For bio-based dm.
* One of these is allocated per bio.
@ -276,16 +278,24 @@ static int __init local_init(void)
if (r)
goto out_free_rq_tio_cache;
deferred_remove_workqueue = alloc_workqueue("kdmremove", WQ_UNBOUND, 1);
if (!deferred_remove_workqueue) {
r = -ENOMEM;
goto out_uevent_exit;
}
_major = major;
r = register_blkdev(_major, _name);
if (r < 0)
goto out_uevent_exit;
goto out_free_workqueue;
if (!_major)
_major = r;
return 0;
out_free_workqueue:
destroy_workqueue(deferred_remove_workqueue);
out_uevent_exit:
dm_uevent_exit();
out_free_rq_tio_cache:
@ -299,6 +309,7 @@ static int __init local_init(void)
static void local_exit(void)
{
flush_scheduled_work();
destroy_workqueue(deferred_remove_workqueue);
kmem_cache_destroy(_rq_tio_cache);
kmem_cache_destroy(_io_cache);
@ -407,7 +418,7 @@ static void dm_blk_close(struct gendisk *disk, fmode_t mode)
if (atomic_dec_and_test(&md->open_count) &&
(test_bit(DMF_DEFERRED_REMOVE, &md->flags)))
schedule_work(&deferred_remove_work);
queue_work(deferred_remove_workqueue, &deferred_remove_work);
dm_put(md);