diff options
Diffstat (limited to 'drivers/md/dm-mpath.c')
| -rw-r--r-- | drivers/md/dm-mpath.c | 256 | 
1 files changed, 104 insertions, 152 deletions
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index de570a55876..f4167b013d9 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -87,15 +87,12 @@ struct multipath {  	unsigned queue_if_no_path:1;	/* Queue I/O if last path fails? */  	unsigned saved_queue_if_no_path:1; /* Saved state during suspension */  	unsigned retain_attached_hw_handler:1; /* If there's already a hw_handler present, don't change it. */ +	unsigned pg_init_disabled:1;	/* pg_init is not currently allowed */  	unsigned pg_init_retries;	/* Number of times to retry pg_init */  	unsigned pg_init_count;		/* Number of times pg_init called */  	unsigned pg_init_delay_msecs;	/* Number of msecs before pg_init retry */ -	unsigned queue_size; -	struct work_struct process_queued_ios; -	struct list_head queued_ios; -  	struct work_struct trigger_event;  	/* @@ -120,9 +117,9 @@ typedef int (*action_fn) (struct pgpath *pgpath);  static struct kmem_cache *_mpio_cache;  static struct workqueue_struct *kmultipathd, *kmpath_handlerd; -static void process_queued_ios(struct work_struct *work);  static void trigger_event(struct work_struct *work);  static void activate_path(struct work_struct *work); +static int __pgpath_busy(struct pgpath *pgpath);  /*----------------------------------------------- @@ -194,11 +191,9 @@ static struct multipath *alloc_multipath(struct dm_target *ti)  	m = kzalloc(sizeof(*m), GFP_KERNEL);  	if (m) {  		INIT_LIST_HEAD(&m->priority_groups); -		INIT_LIST_HEAD(&m->queued_ios);  		spin_lock_init(&m->lock);  		m->queue_io = 1;  		m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT; -		INIT_WORK(&m->process_queued_ios, process_queued_ios);  		INIT_WORK(&m->trigger_event, trigger_event);  		init_waitqueue_head(&m->pg_init_wait);  		mutex_init(&m->work_mutex); @@ -255,13 +250,21 @@ static void clear_mapinfo(struct multipath *m, union map_info *info)   * Path selection   *-----------------------------------------------*/ -static void __pg_init_all_paths(struct multipath *m) +static int __pg_init_all_paths(struct multipath *m)  {  	struct pgpath *pgpath;  	unsigned long pg_init_delay = 0; +	if (m->pg_init_in_progress || m->pg_init_disabled) +		return 0; +  	m->pg_init_count++;  	m->pg_init_required = 0; + +	/* Check here to reset pg_init_required */ +	if (!m->current_pg) +		return 0; +  	if (m->pg_init_delay_retry)  		pg_init_delay = msecs_to_jiffies(m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT ?  						 m->pg_init_delay_msecs : DM_PG_INIT_DELAY_MSECS); @@ -273,6 +276,7 @@ static void __pg_init_all_paths(struct multipath *m)  				       pg_init_delay))  			m->pg_init_in_progress++;  	} +	return m->pg_init_in_progress;  }  static void __switch_pg(struct multipath *m, struct pgpath *pgpath) @@ -364,19 +368,26 @@ failed:   */  static int __must_push_back(struct multipath *m)  { -	return (m->queue_if_no_path != m->saved_queue_if_no_path && -		dm_noflush_suspending(m->ti)); +	return (m->queue_if_no_path || +		(m->queue_if_no_path != m->saved_queue_if_no_path && +		 dm_noflush_suspending(m->ti)));  } -static int map_io(struct multipath *m, struct request *clone, -		  union map_info *map_context, unsigned was_queued) +#define pg_ready(m) (!(m)->queue_io && !(m)->pg_init_required) + +/* + * Map cloned requests + */ +static int multipath_map(struct dm_target *ti, struct request *clone, +			 union map_info *map_context)  { -	int r = DM_MAPIO_REMAPPED; +	struct multipath *m = (struct multipath *) ti->private; +	int r = DM_MAPIO_REQUEUE;  	size_t nr_bytes = blk_rq_bytes(clone);  	unsigned long flags;  	struct pgpath *pgpath;  	struct block_device *bdev; -	struct dm_mpath_io *mpio = map_context->ptr; +	struct dm_mpath_io *mpio;  	spin_lock_irqsave(&m->lock, flags); @@ -387,35 +398,33 @@ static int map_io(struct multipath *m, struct request *clone,  	pgpath = m->current_pgpath; -	if (was_queued) -		m->queue_size--; - -	if ((pgpath && m->queue_io) || -	    (!pgpath && m->queue_if_no_path)) { -		/* Queue for the daemon to resubmit */ -		list_add_tail(&clone->queuelist, &m->queued_ios); -		m->queue_size++; -		if ((m->pg_init_required && !m->pg_init_in_progress) || -		    !m->queue_io) -			queue_work(kmultipathd, &m->process_queued_ios); -		pgpath = NULL; -		r = DM_MAPIO_SUBMITTED; -	} else if (pgpath) { -		bdev = pgpath->path.dev->bdev; -		clone->q = bdev_get_queue(bdev); -		clone->rq_disk = bdev->bd_disk; -	} else if (__must_push_back(m)) -		r = DM_MAPIO_REQUEUE; -	else -		r = -EIO;	/* Failed */ +	if (!pgpath) { +		if (!__must_push_back(m)) +			r = -EIO;	/* Failed */ +		goto out_unlock; +	} +	if (!pg_ready(m)) { +		__pg_init_all_paths(m); +		goto out_unlock; +	} +	if (set_mapinfo(m, map_context) < 0) +		/* ENOMEM, requeue */ +		goto out_unlock; +	bdev = pgpath->path.dev->bdev; +	clone->q = bdev_get_queue(bdev); +	clone->rq_disk = bdev->bd_disk; +	clone->cmd_flags |= REQ_FAILFAST_TRANSPORT; +	mpio = map_context->ptr;  	mpio->pgpath = pgpath;  	mpio->nr_bytes = nr_bytes; - -	if (r == DM_MAPIO_REMAPPED && pgpath->pg->ps.type->start_io) -		pgpath->pg->ps.type->start_io(&pgpath->pg->ps, &pgpath->path, +	if (pgpath->pg->ps.type->start_io) +		pgpath->pg->ps.type->start_io(&pgpath->pg->ps, +					      &pgpath->path,  					      nr_bytes); +	r = DM_MAPIO_REMAPPED; +out_unlock:  	spin_unlock_irqrestore(&m->lock, flags);  	return r; @@ -436,73 +445,12 @@ static int queue_if_no_path(struct multipath *m, unsigned queue_if_no_path,  	else  		m->saved_queue_if_no_path = queue_if_no_path;  	m->queue_if_no_path = queue_if_no_path; -	if (!m->queue_if_no_path && m->queue_size) -		queue_work(kmultipathd, &m->process_queued_ios); -  	spin_unlock_irqrestore(&m->lock, flags); -	return 0; -} - -/*----------------------------------------------------------------- - * The multipath daemon is responsible for resubmitting queued ios. - *---------------------------------------------------------------*/ - -static void dispatch_queued_ios(struct multipath *m) -{ -	int r; -	unsigned long flags; -	union map_info *info; -	struct request *clone, *n; -	LIST_HEAD(cl); - -	spin_lock_irqsave(&m->lock, flags); -	list_splice_init(&m->queued_ios, &cl); -	spin_unlock_irqrestore(&m->lock, flags); - -	list_for_each_entry_safe(clone, n, &cl, queuelist) { -		list_del_init(&clone->queuelist); - -		info = dm_get_rq_mapinfo(clone); +	if (!queue_if_no_path) +		dm_table_run_md_queue_async(m->ti->table); -		r = map_io(m, clone, info, 1); -		if (r < 0) { -			clear_mapinfo(m, info); -			dm_kill_unmapped_request(clone, r); -		} else if (r == DM_MAPIO_REMAPPED) -			dm_dispatch_request(clone); -		else if (r == DM_MAPIO_REQUEUE) { -			clear_mapinfo(m, info); -			dm_requeue_unmapped_request(clone); -		} -	} -} - -static void process_queued_ios(struct work_struct *work) -{ -	struct multipath *m = -		container_of(work, struct multipath, process_queued_ios); -	struct pgpath *pgpath = NULL; -	unsigned must_queue = 1; -	unsigned long flags; - -	spin_lock_irqsave(&m->lock, flags); - -	if (!m->current_pgpath) -		__choose_pgpath(m, 0); - -	pgpath = m->current_pgpath; - -	if ((pgpath && !m->queue_io) || -	    (!pgpath && !m->queue_if_no_path)) -		must_queue = 0; - -	if (m->pg_init_required && !m->pg_init_in_progress && pgpath) -		__pg_init_all_paths(m); - -	spin_unlock_irqrestore(&m->lock, flags); -	if (!must_queue) -		dispatch_queued_ios(m); +	return 0;  }  /* @@ -942,10 +890,20 @@ static void multipath_wait_for_pg_init_completion(struct multipath *m)  static void flush_multipath_work(struct multipath *m)  { +	unsigned long flags; + +	spin_lock_irqsave(&m->lock, flags); +	m->pg_init_disabled = 1; +	spin_unlock_irqrestore(&m->lock, flags); +  	flush_workqueue(kmpath_handlerd);  	multipath_wait_for_pg_init_completion(m);  	flush_workqueue(kmultipathd);  	flush_work(&m->trigger_event); + +	spin_lock_irqsave(&m->lock, flags); +	m->pg_init_disabled = 0; +	spin_unlock_irqrestore(&m->lock, flags);  }  static void multipath_dtr(struct dm_target *ti) @@ -957,27 +915,6 @@ static void multipath_dtr(struct dm_target *ti)  }  /* - * Map cloned requests - */ -static int multipath_map(struct dm_target *ti, struct request *clone, -			 union map_info *map_context) -{ -	int r; -	struct multipath *m = (struct multipath *) ti->private; - -	if (set_mapinfo(m, map_context) < 0) -		/* ENOMEM, requeue */ -		return DM_MAPIO_REQUEUE; - -	clone->cmd_flags |= REQ_FAILFAST_TRANSPORT; -	r = map_io(m, clone, map_context, 0); -	if (r < 0 || r == DM_MAPIO_REQUEUE) -		clear_mapinfo(m, map_context); - -	return r; -} - -/*   * Take a path out of use.   */  static int fail_path(struct pgpath *pgpath) @@ -1017,7 +954,7 @@ out:   */  static int reinstate_path(struct pgpath *pgpath)  { -	int r = 0; +	int r = 0, run_queue = 0;  	unsigned long flags;  	struct multipath *m = pgpath->pg->m; @@ -1039,9 +976,9 @@ static int reinstate_path(struct pgpath *pgpath)  	pgpath->is_active = 1; -	if (!m->nr_valid_paths++ && m->queue_size) { +	if (!m->nr_valid_paths++) {  		m->current_pgpath = NULL; -		queue_work(kmultipathd, &m->process_queued_ios); +		run_queue = 1;  	} else if (m->hw_handler_name && (m->current_pg == pgpath->pg)) {  		if (queue_work(kmpath_handlerd, &pgpath->activate_path.work))  			m->pg_init_in_progress++; @@ -1054,6 +991,8 @@ static int reinstate_path(struct pgpath *pgpath)  out:  	spin_unlock_irqrestore(&m->lock, flags); +	if (run_queue) +		dm_table_run_md_queue_async(m->ti->table);  	return r;  } @@ -1164,7 +1103,7 @@ static int pg_init_limit_reached(struct multipath *m, struct pgpath *pgpath)  	spin_lock_irqsave(&m->lock, flags); -	if (m->pg_init_count <= m->pg_init_retries) +	if (m->pg_init_count <= m->pg_init_retries && !m->pg_init_disabled)  		m->pg_init_required = 1;  	else  		limit_reached = 1; @@ -1237,11 +1176,12 @@ static void pg_init_done(void *data, int errors)  		/* Activations of other paths are still on going */  		goto out; -	if (!m->pg_init_required) -		m->queue_io = 0; - -	m->pg_init_delay_retry = delay_retry; -	queue_work(kmultipathd, &m->process_queued_ios); +	if (m->pg_init_required) { +		m->pg_init_delay_retry = delay_retry; +		if (__pg_init_all_paths(m)) +			goto out; +	} +	m->queue_io = 0;  	/*  	 * Wake up any thread waiting to suspend. @@ -1257,8 +1197,11 @@ static void activate_path(struct work_struct *work)  	struct pgpath *pgpath =  		container_of(work, struct pgpath, activate_path.work); -	scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev), -				pg_init_done, pgpath); +	if (pgpath->is_active) +		scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev), +				 pg_init_done, pgpath); +	else +		pg_init_done(pgpath, SCSI_DH_DEV_OFFLINED);  }  static int noretry_error(int error) @@ -1299,17 +1242,8 @@ static int do_end_io(struct multipath *m, struct request *clone,  	if (!error && !clone->errors)  		return 0;	/* I/O complete */ -	if (noretry_error(error)) { -		if ((clone->cmd_flags & REQ_WRITE_SAME) && -		    !clone->q->limits.max_write_same_sectors) { -			struct queue_limits *limits; - -			/* device doesn't really support WRITE SAME, disable it */ -			limits = dm_get_queue_limits(dm_table_get_md(m->ti->table)); -			limits->max_write_same_sectors = 0; -		} +	if (noretry_error(error))  		return error; -	}  	if (mpio->pgpath)  		fail_path(mpio->pgpath); @@ -1418,7 +1352,7 @@ static void multipath_status(struct dm_target *ti, status_type_t type,  	/* Features */  	if (type == STATUSTYPE_INFO) -		DMEMIT("2 %u %u ", m->queue_size, m->pg_init_count); +		DMEMIT("2 %u %u ", m->queue_io, m->pg_init_count);  	else {  		DMEMIT("%u ", m->queue_if_no_path +  			      (m->pg_init_retries > 0) * 2 + @@ -1537,7 +1471,7 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)  	}  	if (argc != 2) { -		DMWARN("Unrecognised multipath message received."); +		DMWARN("Invalid multipath message arguments. Expected 2 arguments, got %d.", argc);  		goto out;  	} @@ -1555,7 +1489,7 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)  	else if (!strcasecmp(argv[0], "fail_path"))  		action = fail_path;  	else { -		DMWARN("Unrecognised multipath message received."); +		DMWARN("Unrecognised multipath message received: %s", argv[0]);  		goto out;  	} @@ -1611,11 +1545,23 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,  	/*  	 * Only pass ioctls through if the device sizes match exactly.  	 */ -	if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) -		r = scsi_verify_blk_ioctl(NULL, cmd); +	if (!bdev || ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) { +		int err = scsi_verify_blk_ioctl(NULL, cmd); +		if (err) +			r = err; +	} -	if (r == -ENOTCONN && !fatal_signal_pending(current)) -		queue_work(kmultipathd, &m->process_queued_ios); +	if (r == -ENOTCONN && !fatal_signal_pending(current)) { +		spin_lock_irqsave(&m->lock, flags); +		if (!m->current_pg) { +			/* Path status changed, redo selection */ +			__choose_pgpath(m, 0); +		} +		if (m->pg_init_required) +			__pg_init_all_paths(m); +		spin_unlock_irqrestore(&m->lock, flags); +		dm_table_run_md_queue_async(m->ti->table); +	}  	return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);  } @@ -1665,6 +1611,12 @@ static int multipath_busy(struct dm_target *ti)  	spin_lock_irqsave(&m->lock, flags); +	/* 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; +	}  	/* Guess which priority_group will be used at next mapping time */  	if (unlikely(!m->current_pgpath && m->next_pg))  		pg = m->next_pg; @@ -1714,7 +1666,7 @@ out:   *---------------------------------------------------------------*/  static struct target_type multipath_target = {  	.name = "multipath", -	.version = {1, 5, 1}, +	.version = {1, 7, 0},  	.module = THIS_MODULE,  	.ctr = multipath_ctr,  	.dtr = multipath_dtr,  | 
