diff options
Diffstat (limited to 'drivers/md/dm-mpath.c')
| -rw-r--r-- | drivers/md/dm-mpath.c | 125 | 
1 files changed, 71 insertions, 54 deletions
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 0e325469a252..61ab1a8d2c9c 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only  /*   * Copyright (C) 2003 Sistina Software Limited.   * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. @@ -27,9 +28,11 @@  #include <linux/atomic.h>  #include <linux/blk-mq.h> +static struct workqueue_struct *dm_mpath_wq; +  #define DM_MSG_PREFIX "multipath"  #define DM_PG_INIT_DELAY_MSECS 2000 -#define DM_PG_INIT_DELAY_DEFAULT ((unsigned) -1) +#define DM_PG_INIT_DELAY_DEFAULT ((unsigned int) -1)  #define QUEUE_IF_NO_PATH_TIMEOUT_DEFAULT 0  static unsigned long queue_if_no_path_timeout_secs = QUEUE_IF_NO_PATH_TIMEOUT_DEFAULT; @@ -39,7 +42,7 @@ struct pgpath {  	struct list_head list;  	struct priority_group *pg;	/* Owning PG */ -	unsigned fail_count;		/* Cumulative failure count */ +	unsigned int fail_count;		/* Cumulative failure count */  	struct dm_path path;  	struct delayed_work activate_path; @@ -59,8 +62,8 @@ struct priority_group {  	struct multipath *m;		/* Owning multipath instance */  	struct path_selector ps; -	unsigned pg_num;		/* Reference number */ -	unsigned nr_pgpaths;		/* Number of paths in PG */ +	unsigned int pg_num;		/* Reference number */ +	unsigned int nr_pgpaths;		/* Number of paths in PG */  	struct list_head pgpaths;  	bool bypassed:1;		/* Temporarily bypass this PG? */ @@ -78,14 +81,14 @@ struct multipath {  	struct priority_group *next_pg;	/* Switch to this PG if set */  	atomic_t nr_valid_paths;	/* Total number of usable paths */ -	unsigned nr_priority_groups; +	unsigned int nr_priority_groups;  	struct list_head priority_groups;  	const char *hw_handler_name;  	char *hw_handler_params;  	wait_queue_head_t pg_init_wait;	/* Wait for pg_init completion */ -	unsigned pg_init_retries;	/* Number of times to retry pg_init */ -	unsigned pg_init_delay_msecs;	/* Number of msecs before pg_init retry */ +	unsigned int pg_init_retries;	/* Number of times to retry pg_init */ +	unsigned int pg_init_delay_msecs;	/* Number of msecs before pg_init retry */  	atomic_t pg_init_in_progress;	/* Only one pg_init allowed at once */  	atomic_t pg_init_count;		/* Number of times pg_init called */ @@ -117,10 +120,11 @@ static void activate_path_work(struct work_struct *work);  static void process_queued_bios(struct work_struct *work);  static void queue_if_no_path_timeout_work(struct timer_list *t); -/*----------------------------------------------- +/* + *-----------------------------------------------   * Multipath state flags. - *-----------------------------------------------*/ - + *----------------------------------------------- + */  #define MPATHF_QUEUE_IO 0			/* Must we queue all I/O? */  #define MPATHF_QUEUE_IF_NO_PATH 1		/* Queue I/O if last path fails? */  #define MPATHF_SAVED_QUEUE_IF_NO_PATH 2		/* Saved state during suspension */ @@ -135,6 +139,7 @@ static bool mpath_double_check_test_bit(int MPATHF_bit, struct multipath *m)  	if (r) {  		unsigned long flags; +  		spin_lock_irqsave(&m->lock, flags);  		r = test_bit(MPATHF_bit, &m->flags);  		spin_unlock_irqrestore(&m->lock, flags); @@ -143,10 +148,11 @@ static bool mpath_double_check_test_bit(int MPATHF_bit, struct multipath *m)  	return r;  } -/*----------------------------------------------- +/* + *-----------------------------------------------   * Allocation routines - *-----------------------------------------------*/ - + *----------------------------------------------- + */  static struct pgpath *alloc_pgpath(void)  {  	struct pgpath *pgpath = kzalloc(sizeof(*pgpath), GFP_KERNEL); @@ -302,10 +308,11 @@ static void multipath_init_per_bio_data(struct bio *bio, struct dm_mpath_io **mp  	dm_bio_record(bio_details, bio);  } -/*----------------------------------------------- +/* + *-----------------------------------------------   * Path selection - *-----------------------------------------------*/ - + *----------------------------------------------- + */  static int __pg_init_all_paths(struct multipath *m)  {  	struct pgpath *pgpath; @@ -397,7 +404,7 @@ static struct pgpath *choose_pgpath(struct multipath *m, size_t nr_bytes)  	unsigned long flags;  	struct priority_group *pg;  	struct pgpath *pgpath; -	unsigned bypassed = 1; +	unsigned int bypassed = 1;  	if (!atomic_read(&m->nr_valid_paths)) {  		spin_lock_irqsave(&m->lock, flags); @@ -467,13 +474,11 @@ failed:   * it has been invoked.   */  #define dm_report_EIO(m)						\ -do {									\  	DMDEBUG_LIMIT("%s: returning EIO; QIFNP = %d; SQIFNP = %d; DNFS = %d", \  		      dm_table_device_name((m)->ti->table),		\  		      test_bit(MPATHF_QUEUE_IF_NO_PATH, &(m)->flags),	\  		      test_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &(m)->flags), \ -		      dm_noflush_suspending((m)->ti));			\ -} while (0) +		      dm_noflush_suspending((m)->ti))  /*   * Check whether bios must be queued in the device-mapper core rather @@ -707,6 +712,7 @@ static void process_queued_bios(struct work_struct *work)  	blk_start_plug(&plug);  	while ((bio = bio_list_pop(&bios))) {  		struct dm_mpath_io *mpio = get_mpio_from_bio(bio); +  		dm_bio_restore(get_bio_details_from_mpio(mpio), bio);  		r = __multipath_map_bio(m, bio, mpio);  		switch (r) { @@ -733,15 +739,15 @@ static void process_queued_bios(struct work_struct *work)  /*   * If we run out of usable paths, should we queue I/O or error it?   */ -static int queue_if_no_path(struct multipath *m, bool queue_if_no_path, +static int queue_if_no_path(struct multipath *m, bool f_queue_if_no_path,  			    bool save_old_value, const char *caller)  {  	unsigned long flags;  	bool queue_if_no_path_bit, saved_queue_if_no_path_bit;  	const char *dm_dev_name = dm_table_device_name(m->ti->table); -	DMDEBUG("%s: %s caller=%s queue_if_no_path=%d save_old_value=%d", -		dm_dev_name, __func__, caller, queue_if_no_path, save_old_value); +	DMDEBUG("%s: %s caller=%s f_queue_if_no_path=%d save_old_value=%d", +		dm_dev_name, __func__, caller, f_queue_if_no_path, save_old_value);  	spin_lock_irqsave(&m->lock, flags); @@ -754,11 +760,11 @@ static int queue_if_no_path(struct multipath *m, bool queue_if_no_path,  			      dm_dev_name);  		} else  			assign_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags, queue_if_no_path_bit); -	} else if (!queue_if_no_path && saved_queue_if_no_path_bit) { +	} else if (!f_queue_if_no_path && saved_queue_if_no_path_bit) {  		/* due to "fail_if_no_path" message, need to honor it. */  		clear_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags);  	} -	assign_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags, queue_if_no_path); +	assign_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags, f_queue_if_no_path);  	DMDEBUG("%s: after %s changes; QIFNP = %d; SQIFNP = %d; DNFS = %d",  		dm_dev_name, __func__, @@ -768,7 +774,7 @@ static int queue_if_no_path(struct multipath *m, bool queue_if_no_path,  	spin_unlock_irqrestore(&m->lock, flags); -	if (!queue_if_no_path) { +	if (!f_queue_if_no_path) {  		dm_table_run_md_queue_async(m->ti->table);  		process_queued_io_list(m);  	} @@ -825,7 +831,8 @@ static void trigger_event(struct work_struct *work)  	dm_table_event(m->ti->table);  } -/*----------------------------------------------------------------- +/* + *---------------------------------------------------------------   * Constructor/argument parsing:   * <#multipath feature args> [<arg>]*   * <#hw_handler args> [hw_handler [<arg>]*] @@ -834,13 +841,14 @@ static void trigger_event(struct work_struct *work)   *     [<selector> <#selector args> [<arg>]*   *      <#paths> <#per-path selector args>   *         [<path> [<arg>]* ]+ ]+ - *---------------------------------------------------------------*/ + *--------------------------------------------------------------- + */  static int parse_path_selector(struct dm_arg_set *as, struct priority_group *pg,  			       struct dm_target *ti)  {  	int r;  	struct path_selector_type *pst; -	unsigned ps_argc; +	unsigned int ps_argc;  	static const struct dm_arg _args[] = {  		{0, 1024, "invalid number of path selector args"}, @@ -983,7 +991,7 @@ static struct priority_group *parse_priority_group(struct dm_arg_set *as,  	};  	int r; -	unsigned i, nr_selector_args, nr_args; +	unsigned int i, nr_selector_args, nr_args;  	struct priority_group *pg;  	struct dm_target *ti = m->ti; @@ -1049,7 +1057,7 @@ static struct priority_group *parse_priority_group(struct dm_arg_set *as,  static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m)  { -	unsigned hw_argc; +	unsigned int hw_argc;  	int ret;  	struct dm_target *ti = m->ti; @@ -1086,7 +1094,7 @@ static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m)  			goto fail;  		}  		j = sprintf(p, "%d", hw_argc - 1); -		for (i = 0, p+=j+1; i <= hw_argc - 2; i++, p+=j+1) +		for (i = 0, p += j + 1; i <= hw_argc - 2; i++, p += j + 1)  			j = sprintf(p, "%s", as->argv[i]);  	}  	dm_consume_args(as, hw_argc - 1); @@ -1101,7 +1109,7 @@ fail:  static int parse_features(struct dm_arg_set *as, struct multipath *m)  {  	int r; -	unsigned argc; +	unsigned int argc;  	struct dm_target *ti = m->ti;  	const char *arg_name; @@ -1170,7 +1178,7 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m)  	return r;  } -static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv) +static int multipath_ctr(struct dm_target *ti, unsigned int argc, char **argv)  {  	/* target arguments */  	static const struct dm_arg _args[] = { @@ -1181,8 +1189,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv)  	int r;  	struct multipath *m;  	struct dm_arg_set as; -	unsigned pg_count = 0; -	unsigned next_pg_num; +	unsigned int pg_count = 0; +	unsigned int next_pg_num;  	unsigned long flags;  	as.argc = argc; @@ -1224,7 +1232,7 @@ static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv)  	/* parse the priority groups */  	while (as.argc) {  		struct priority_group *pg; -		unsigned nr_valid_paths = atomic_read(&m->nr_valid_paths); +		unsigned int nr_valid_paths = atomic_read(&m->nr_valid_paths);  		pg = parse_priority_group(&as, m);  		if (IS_ERR(pg)) { @@ -1347,7 +1355,7 @@ static int fail_path(struct pgpath *pgpath)  	dm_path_uevent(DM_UEVENT_PATH_FAILED, m->ti,  		       pgpath->path.dev->name, atomic_read(&m->nr_valid_paths)); -	schedule_work(&m->trigger_event); +	queue_work(dm_mpath_wq, &m->trigger_event);  	enable_nopath_timeout(m); @@ -1365,7 +1373,7 @@ static int reinstate_path(struct pgpath *pgpath)  	int r = 0, run_queue = 0;  	unsigned long flags;  	struct multipath *m = pgpath->pg->m; -	unsigned nr_valid_paths; +	unsigned int nr_valid_paths;  	spin_lock_irqsave(&m->lock, flags); @@ -1454,13 +1462,13 @@ static void bypass_pg(struct multipath *m, struct priority_group *pg,  static int switch_pg_num(struct multipath *m, const char *pgstr)  {  	struct priority_group *pg; -	unsigned pgnum; +	unsigned int pgnum;  	unsigned long flags;  	char dummy;  	if (!pgstr || (sscanf(pgstr, "%u%c", &pgnum, &dummy) != 1) || !pgnum ||  	    !m->nr_priority_groups || (pgnum > m->nr_priority_groups)) { -		DMWARN("invalid PG number supplied to switch_pg_num"); +		DMWARN("invalid PG number supplied to %s", __func__);  		return -EINVAL;  	} @@ -1487,7 +1495,7 @@ static int switch_pg_num(struct multipath *m, const char *pgstr)  static int bypass_pg_num(struct multipath *m, const char *pgstr, bool bypassed)  {  	struct priority_group *pg; -	unsigned pgnum; +	unsigned int pgnum;  	char dummy;  	if (!pgstr || (sscanf(pgstr, "%u%c", &pgnum, &dummy) != 1) || !pgnum || @@ -1789,14 +1797,14 @@ static void multipath_resume(struct dm_target *ti)   *      num_paths num_selector_args [path_dev [selector_args]* ]+ ]+   */  static void multipath_status(struct dm_target *ti, status_type_t type, -			     unsigned status_flags, char *result, unsigned maxlen) +			     unsigned int status_flags, char *result, unsigned int maxlen)  {  	int sz = 0, pg_counter, pgpath_counter;  	unsigned long flags;  	struct multipath *m = ti->private;  	struct priority_group *pg;  	struct pgpath *p; -	unsigned pg_num; +	unsigned int pg_num;  	char state;  	spin_lock_irqsave(&m->lock, flags); @@ -1821,7 +1829,7 @@ static void multipath_status(struct dm_target *ti, status_type_t type,  		if (test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags))  			DMEMIT("retain_attached_hw_handler ");  		if (m->queue_mode != DM_TYPE_REQUEST_BASED) { -			switch(m->queue_mode) { +			switch (m->queue_mode) {  			case DM_TYPE_BIO_BASED:  				DMEMIT("queue_mode bio ");  				break; @@ -1948,8 +1956,8 @@ static void multipath_status(struct dm_target *ti, status_type_t type,  	spin_unlock_irqrestore(&m->lock, flags);  } -static int multipath_message(struct dm_target *ti, unsigned argc, char **argv, -			     char *result, unsigned maxlen) +static int multipath_message(struct dm_target *ti, unsigned int argc, char **argv, +			     char *result, unsigned int maxlen)  {  	int r = -EINVAL;  	struct dm_dev *dev; @@ -2116,6 +2124,7 @@ static int multipath_busy(struct dm_target *ti)  	/* no paths available, for blk-mq: rely on IO mapping to delay requeue */  	if (!atomic_read(&m->nr_valid_paths)) {  		unsigned long flags; +  		spin_lock_irqsave(&m->lock, flags);  		if (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) {  			spin_unlock_irqrestore(&m->lock, flags); @@ -2168,9 +2177,11 @@ static int multipath_busy(struct dm_target *ti)  	return busy;  } -/*----------------------------------------------------------------- +/* + *---------------------------------------------------------------   * Module setup - *---------------------------------------------------------------*/ + *--------------------------------------------------------------- + */  static struct target_type multipath_target = {  	.name = "multipath",  	.version = {1, 14, 0}, @@ -2196,12 +2207,11 @@ static struct target_type multipath_target = {  static int __init dm_multipath_init(void)  { -	int r; +	int r = -ENOMEM;  	kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM, 0);  	if (!kmultipathd) {  		DMERR("failed to create workqueue kmpathd"); -		r = -ENOMEM;  		goto bad_alloc_kmultipathd;  	} @@ -2215,10 +2225,15 @@ static int __init dm_multipath_init(void)  						  WQ_MEM_RECLAIM);  	if (!kmpath_handlerd) {  		DMERR("failed to create workqueue kmpath_handlerd"); -		r = -ENOMEM;  		goto bad_alloc_kmpath_handlerd;  	} +	dm_mpath_wq = alloc_workqueue("dm_mpath_wq", 0, 0); +	if (!dm_mpath_wq) { +		DMERR("failed to create workqueue dm_mpath_wq"); +		goto bad_alloc_dm_mpath_wq; +	} +  	r = dm_register_target(&multipath_target);  	if (r < 0) {  		DMERR("request-based register failed %d", r); @@ -2229,6 +2244,8 @@ static int __init dm_multipath_init(void)  	return 0;  bad_register_target: +	destroy_workqueue(dm_mpath_wq); +bad_alloc_dm_mpath_wq:  	destroy_workqueue(kmpath_handlerd);  bad_alloc_kmpath_handlerd:  	destroy_workqueue(kmultipathd); @@ -2238,6 +2255,7 @@ bad_alloc_kmultipathd:  static void __exit dm_multipath_exit(void)  { +	destroy_workqueue(dm_mpath_wq);  	destroy_workqueue(kmpath_handlerd);  	destroy_workqueue(kmultipathd); @@ -2247,8 +2265,7 @@ static void __exit dm_multipath_exit(void)  module_init(dm_multipath_init);  module_exit(dm_multipath_exit); -module_param_named(queue_if_no_path_timeout_secs, -		   queue_if_no_path_timeout_secs, ulong, S_IRUGO | S_IWUSR); +module_param_named(queue_if_no_path_timeout_secs, queue_if_no_path_timeout_secs, ulong, 0644);  MODULE_PARM_DESC(queue_if_no_path_timeout_secs, "No available paths queue IO timeout in seconds");  MODULE_DESCRIPTION(DM_NAME " multipath target");  |