. 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:
commit
67b9d76f9e
5 changed files with 28 additions and 22 deletions
|
@ -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) 2004 Clemens Fruhwirth <clemens@endorphin.org>
|
||||||
* Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved.
|
||||||
* Copyright (C) 2013 Milan Broz <gmazyland@gmail.com>
|
* 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_init(dm_crypt_init);
|
||||||
module_exit(dm_crypt_exit);
|
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_DESCRIPTION(DM_NAME " target for transparent encryption / decryption");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <linux/device-mapper.h>
|
#include <linux/device-mapper.h>
|
||||||
|
|
||||||
#include <linux/bio.h>
|
#include <linux/bio.h>
|
||||||
|
#include <linux/completion.h>
|
||||||
#include <linux/mempool.h>
|
#include <linux/mempool.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
@ -32,7 +33,7 @@ struct dm_io_client {
|
||||||
struct io {
|
struct io {
|
||||||
unsigned long error_bits;
|
unsigned long error_bits;
|
||||||
atomic_t count;
|
atomic_t count;
|
||||||
struct task_struct *sleeper;
|
struct completion *wait;
|
||||||
struct dm_io_client *client;
|
struct dm_io_client *client;
|
||||||
io_notify_fn callback;
|
io_notify_fn callback;
|
||||||
void *context;
|
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,
|
invalidate_kernel_vmap_range(io->vma_invalidate_address,
|
||||||
io->vma_invalidate_size);
|
io->vma_invalidate_size);
|
||||||
|
|
||||||
if (io->sleeper)
|
if (io->wait)
|
||||||
wake_up_process(io->sleeper);
|
complete(io->wait);
|
||||||
|
|
||||||
else {
|
else {
|
||||||
unsigned long r = io->error_bits;
|
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];
|
volatile char io_[sizeof(struct io) + __alignof__(struct io) - 1];
|
||||||
struct io *io = (struct io *)PTR_ALIGN(&io_, __alignof__(struct io));
|
struct io *io = (struct io *)PTR_ALIGN(&io_, __alignof__(struct io));
|
||||||
|
DECLARE_COMPLETION_ONSTACK(wait);
|
||||||
|
|
||||||
if (num_regions > 1 && (rw & RW_MASK) != WRITE) {
|
if (num_regions > 1 && (rw & RW_MASK) != WRITE) {
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
|
@ -395,7 +397,7 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions,
|
||||||
|
|
||||||
io->error_bits = 0;
|
io->error_bits = 0;
|
||||||
atomic_set(&io->count, 1); /* see dispatch_io() */
|
atomic_set(&io->count, 1); /* see dispatch_io() */
|
||||||
io->sleeper = current;
|
io->wait = &wait;
|
||||||
io->client = client;
|
io->client = client;
|
||||||
|
|
||||||
io->vma_invalidate_address = dp->vma_invalidate_address;
|
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);
|
dispatch_io(rw, num_regions, where, dp, io, 1);
|
||||||
|
|
||||||
while (1) {
|
wait_for_completion_io(&wait);
|
||||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
|
||||||
|
|
||||||
if (!atomic_read(&io->count))
|
|
||||||
break;
|
|
||||||
|
|
||||||
io_schedule();
|
|
||||||
}
|
|
||||||
set_current_state(TASK_RUNNING);
|
|
||||||
|
|
||||||
if (error_bits)
|
if (error_bits)
|
||||||
*error_bits = io->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 = mempool_alloc(client->pool, GFP_NOIO);
|
||||||
io->error_bits = 0;
|
io->error_bits = 0;
|
||||||
atomic_set(&io->count, 1); /* see dispatch_io() */
|
atomic_set(&io->count, 1); /* see dispatch_io() */
|
||||||
io->sleeper = NULL;
|
io->wait = NULL;
|
||||||
io->client = client;
|
io->client = client;
|
||||||
io->callback = fn;
|
io->callback = fn;
|
||||||
io->context = context;
|
io->context = context;
|
||||||
|
|
|
@ -1611,8 +1611,9 @@ static int multipath_busy(struct dm_target *ti)
|
||||||
|
|
||||||
spin_lock_irqsave(&m->lock, flags);
|
spin_lock_irqsave(&m->lock, flags);
|
||||||
|
|
||||||
/* pg_init in progress, requeue until done */
|
/* pg_init in progress or no paths available */
|
||||||
if (!pg_ready(m)) {
|
if (m->pg_init_in_progress ||
|
||||||
|
(!m->nr_valid_paths && m->queue_if_no_path)) {
|
||||||
busy = 1;
|
busy = 1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
* This file is released under the GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -79,6 +79,6 @@ static void __exit dm_zero_exit(void)
|
||||||
module_init(dm_zero_init)
|
module_init(dm_zero_init)
|
||||||
module_exit(dm_zero_exit)
|
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_DESCRIPTION(DM_NAME " dummy target returning zeros");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -54,6 +54,8 @@ static void do_deferred_remove(struct work_struct *w);
|
||||||
|
|
||||||
static DECLARE_WORK(deferred_remove_work, do_deferred_remove);
|
static DECLARE_WORK(deferred_remove_work, do_deferred_remove);
|
||||||
|
|
||||||
|
static struct workqueue_struct *deferred_remove_workqueue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For bio-based dm.
|
* For bio-based dm.
|
||||||
* One of these is allocated per bio.
|
* One of these is allocated per bio.
|
||||||
|
@ -276,16 +278,24 @@ static int __init local_init(void)
|
||||||
if (r)
|
if (r)
|
||||||
goto out_free_rq_tio_cache;
|
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;
|
_major = major;
|
||||||
r = register_blkdev(_major, _name);
|
r = register_blkdev(_major, _name);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto out_uevent_exit;
|
goto out_free_workqueue;
|
||||||
|
|
||||||
if (!_major)
|
if (!_major)
|
||||||
_major = r;
|
_major = r;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
out_free_workqueue:
|
||||||
|
destroy_workqueue(deferred_remove_workqueue);
|
||||||
out_uevent_exit:
|
out_uevent_exit:
|
||||||
dm_uevent_exit();
|
dm_uevent_exit();
|
||||||
out_free_rq_tio_cache:
|
out_free_rq_tio_cache:
|
||||||
|
@ -299,6 +309,7 @@ out_free_io_cache:
|
||||||
static void local_exit(void)
|
static void local_exit(void)
|
||||||
{
|
{
|
||||||
flush_scheduled_work();
|
flush_scheduled_work();
|
||||||
|
destroy_workqueue(deferred_remove_workqueue);
|
||||||
|
|
||||||
kmem_cache_destroy(_rq_tio_cache);
|
kmem_cache_destroy(_rq_tio_cache);
|
||||||
kmem_cache_destroy(_io_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) &&
|
if (atomic_dec_and_test(&md->open_count) &&
|
||||||
(test_bit(DMF_DEFERRED_REMOVE, &md->flags)))
|
(test_bit(DMF_DEFERRED_REMOVE, &md->flags)))
|
||||||
schedule_work(&deferred_remove_work);
|
queue_work(deferred_remove_workqueue, &deferred_remove_work);
|
||||||
|
|
||||||
dm_put(md);
|
dm_put(md);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue