Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fdbd1c5e authored by Christof Schmitt's avatar Christof Schmitt Committed by James Bottomley
Browse files

[SCSI] zfcp: Allow running unit/LUN shutdown without acquiring reference



With the change for the LUN data to be part of the scsi_device, the
slave_destroy callback will be the final call to the
zfcp_erp_unit_shutdown function. The erp tries to acquire a reference
to run the action asynchronously and fail, if it cannot get the
reference. But calling scsi_device_get from slave_destroy will fail,
because the scsi_device is already in the state SDEV_DEL.

Introduce a new call into the zfcp erp to solve this: The function
zfcp_erp_unit_shutdown_wait will close the LUN and wait for the erp to
finish without acquiring an additional reference. The wait allows to
omit the reference; the caller waiting for the erp to finish already
has a reference that holds the struct in place.

Reviewed-by: default avatarSwen Schillig <swen@vnet.ibm.com>
Signed-off-by: default avatarChristof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent e4b9857f
Loading
Loading
Loading
Loading
+62 −36
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ enum zfcp_erp_act_flags {
	ZFCP_STATUS_ERP_DISMISSING	= 0x00100000,
	ZFCP_STATUS_ERP_DISMISSING	= 0x00100000,
	ZFCP_STATUS_ERP_DISMISSED	= 0x00200000,
	ZFCP_STATUS_ERP_DISMISSED	= 0x00200000,
	ZFCP_STATUS_ERP_LOWMEM		= 0x00400000,
	ZFCP_STATUS_ERP_LOWMEM		= 0x00400000,
	ZFCP_STATUS_ERP_NO_REF		= 0x00800000,
};
};


enum zfcp_erp_steps {
enum zfcp_erp_steps {
@@ -169,22 +170,22 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
	return need;
	return need;
}
}


static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,
						  struct zfcp_adapter *adapter,
						  struct zfcp_adapter *adapter,
						  struct zfcp_port *port,
						  struct zfcp_port *port,
						  struct zfcp_unit *unit)
						  struct zfcp_unit *unit)
{
{
	struct zfcp_erp_action *erp_action;
	struct zfcp_erp_action *erp_action;
	u32 status = 0;


	switch (need) {
	switch (need) {
	case ZFCP_ERP_ACTION_REOPEN_UNIT:
	case ZFCP_ERP_ACTION_REOPEN_UNIT:
		if (!(act_status & ZFCP_STATUS_ERP_NO_REF))
			if (!get_device(&unit->dev))
			if (!get_device(&unit->dev))
				return NULL;
				return NULL;
		atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status);
		atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status);
		erp_action = &unit->erp_action;
		erp_action = &unit->erp_action;
		if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING))
		if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING))
			status = ZFCP_STATUS_ERP_CLOSE_ONLY;
			act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
		break;
		break;


	case ZFCP_ERP_ACTION_REOPEN_PORT:
	case ZFCP_ERP_ACTION_REOPEN_PORT:
@@ -195,7 +196,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
		atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
		atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
		erp_action = &port->erp_action;
		erp_action = &port->erp_action;
		if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
		if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
			status = ZFCP_STATUS_ERP_CLOSE_ONLY;
			act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
		break;
		break;


	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
@@ -205,7 +206,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
		erp_action = &adapter->erp_action;
		erp_action = &adapter->erp_action;
		if (!(atomic_read(&adapter->status) &
		if (!(atomic_read(&adapter->status) &
		      ZFCP_STATUS_COMMON_RUNNING))
		      ZFCP_STATUS_COMMON_RUNNING))
			status = ZFCP_STATUS_ERP_CLOSE_ONLY;
			act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
		break;
		break;


	default:
	default:
@@ -217,14 +218,15 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
	erp_action->port = port;
	erp_action->port = port;
	erp_action->unit = unit;
	erp_action->unit = unit;
	erp_action->action = need;
	erp_action->action = need;
	erp_action->status = status;
	erp_action->status = act_status;


	return erp_action;
	return erp_action;
}
}


static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
				   struct zfcp_port *port,
				   struct zfcp_port *port,
				   struct zfcp_unit *unit, char *id, void *ref)
				   struct zfcp_unit *unit, char *id, void *ref,
				   u32 act_status)
{
{
	int retval = 1, need;
	int retval = 1, need;
	struct zfcp_erp_action *act = NULL;
	struct zfcp_erp_action *act = NULL;
@@ -236,10 +238,10 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
	if (!need)
	if (!need)
		goto out;
		goto out;


	atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
	act = zfcp_erp_setup_act(need, act_status, adapter, port, unit);
	act = zfcp_erp_setup_act(need, adapter, port, unit);
	if (!act)
	if (!act)
		goto out;
		goto out;
	atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
	++adapter->erp_total_count;
	++adapter->erp_total_count;
	list_add_tail(&act->list, &adapter->erp_ready_head);
	list_add_tail(&act->list, &adapter->erp_ready_head);
	wake_up(&adapter->erp_ready_wq);
	wake_up(&adapter->erp_ready_wq);
@@ -262,7 +264,7 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
		return -EIO;
		return -EIO;
	}
	}
	return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
	return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
				       adapter, NULL, NULL, id, ref);
				       adapter, NULL, NULL, id, ref, 0);
}
}


/**
/**
@@ -285,7 +287,7 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
		zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
		zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
	else
	else
		zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
		zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
					NULL, NULL, id, ref);
					NULL, NULL, id, ref, 0);
	write_unlock_irqrestore(&adapter->erp_lock, flags);
	write_unlock_irqrestore(&adapter->erp_lock, flags);
}
}


@@ -317,20 +319,6 @@ void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id,
	zfcp_erp_port_reopen(port, clear | flags, id, ref);
	zfcp_erp_port_reopen(port, clear | flags, id, ref);
}
}


/**
 * zfcp_erp_unit_shutdown - Shutdown unit
 * @unit: Unit to shut down.
 * @clear: Status flags to clear.
 * @id: Id for debug trace event.
 * @ref: Reference for debug trace event.
 */
void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, char *id,
			    void *ref)
{
	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
	zfcp_erp_unit_reopen(unit, clear | flags, id, ref);
}

static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
{
{
	zfcp_erp_modify_port_status(port, "erpblk1", NULL,
	zfcp_erp_modify_port_status(port, "erpblk1", NULL,
@@ -348,7 +336,7 @@ static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
		return;
		return;


	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
				port->adapter, port, NULL, id, ref);
				port->adapter, port, NULL, id, ref, 0);
}
}


/**
/**
@@ -381,7 +369,7 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
	}
	}


	return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
	return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
				       port->adapter, port, NULL, id, ref);
				       port->adapter, port, NULL, id, ref, 0);
}
}


/**
/**
@@ -412,7 +400,7 @@ static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask)
}
}


static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
				  void *ref)
				  void *ref, u32 act_status)
{
{
	struct zfcp_adapter *adapter = unit->port->adapter;
	struct zfcp_adapter *adapter = unit->port->adapter;


@@ -422,7 +410,7 @@ static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
		return;
		return;


	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT,
	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT,
				adapter, unit->port, unit, id, ref);
				adapter, unit->port, unit, id, ref, act_status);
}
}


/**
/**
@@ -439,8 +427,45 @@ void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
	struct zfcp_adapter *adapter = port->adapter;
	struct zfcp_adapter *adapter = port->adapter;


	write_lock_irqsave(&adapter->erp_lock, flags);
	write_lock_irqsave(&adapter->erp_lock, flags);
	_zfcp_erp_unit_reopen(unit, clear, id, ref);
	_zfcp_erp_unit_reopen(unit, clear, id, ref, 0);
	write_unlock_irqrestore(&adapter->erp_lock, flags);
}

/**
 * zfcp_erp_unit_shutdown - Shutdown unit
 * @unit: Unit to shut down.
 * @clear: Status flags to clear.
 * @id: Id for debug trace event.
 * @ref: Reference for debug trace event.
 */
void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, char *id,
			    void *ref)
{
	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
	zfcp_erp_unit_reopen(unit, clear | flags, id, ref);
}

/**
 * zfcp_erp_unit_shutdown_wait - Shutdown unit and wait for erp completion
 * @unit: Unit to shut down.
 * @id: Id for debug trace event.
 *
 * Do not acquire a reference for the unit when creating the ERP
 * action. It is safe, because this function waits for the ERP to
 * complete first.
 */
void zfcp_erp_unit_shutdown_wait(struct zfcp_unit *unit, char *id)
{
	unsigned long flags;
	struct zfcp_port *port = unit->port;
	struct zfcp_adapter *adapter = port->adapter;
	int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;

	write_lock_irqsave(&adapter->erp_lock, flags);
	_zfcp_erp_unit_reopen(unit, clear, id, NULL, ZFCP_STATUS_ERP_NO_REF);
	write_unlock_irqrestore(&adapter->erp_lock, flags);
	write_unlock_irqrestore(&adapter->erp_lock, flags);

	zfcp_erp_wait(adapter);
}
}


static int status_change_set(unsigned long mask, atomic_t *status)
static int status_change_set(unsigned long mask, atomic_t *status)
@@ -566,7 +591,7 @@ static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,


	read_lock(&port->unit_list_lock);
	read_lock(&port->unit_list_lock);
	list_for_each_entry(unit, &port->unit_list, list)
	list_for_each_entry(unit, &port->unit_list, list)
		_zfcp_erp_unit_reopen(unit, clear, id, ref);
		_zfcp_erp_unit_reopen(unit, clear, id, ref, 0);
	read_unlock(&port->unit_list_lock);
	read_unlock(&port->unit_list_lock);
}
}


@@ -583,7 +608,7 @@ static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
		_zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL);
		_zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL);
		break;
		break;
	case ZFCP_ERP_ACTION_REOPEN_UNIT:
	case ZFCP_ERP_ACTION_REOPEN_UNIT:
		_zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL);
		_zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL, 0);
		break;
		break;
	}
	}
}
}
@@ -1143,7 +1168,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
		if (zfcp_erp_strat_change_det(&unit->status, erp_status)) {
		if (zfcp_erp_strat_change_det(&unit->status, erp_status)) {
			_zfcp_erp_unit_reopen(unit,
			_zfcp_erp_unit_reopen(unit,
					      ZFCP_STATUS_COMMON_ERP_FAILED,
					      ZFCP_STATUS_COMMON_ERP_FAILED,
					      "ersscg3", NULL);
					      "ersscg3", NULL, 0);
			return ZFCP_ERP_EXIT;
			return ZFCP_ERP_EXIT;
		}
		}
		break;
		break;
@@ -1191,6 +1216,7 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)


	switch (act->action) {
	switch (act->action) {
	case ZFCP_ERP_ACTION_REOPEN_UNIT:
	case ZFCP_ERP_ACTION_REOPEN_UNIT:
		if (!(act->status & ZFCP_STATUS_ERP_NO_REF))
			put_device(&unit->dev);
			put_device(&unit->dev);
		break;
		break;


+1 −0
Original line number Original line Diff line number Diff line
@@ -80,6 +80,7 @@ extern void zfcp_erp_modify_unit_status(struct zfcp_unit *, char *, void *, u32,
					int);
					int);
extern void zfcp_erp_unit_reopen(struct zfcp_unit *, int, char *, void *);
extern void zfcp_erp_unit_reopen(struct zfcp_unit *, int, char *, void *);
extern void zfcp_erp_unit_shutdown(struct zfcp_unit *, int, char *, void *);
extern void zfcp_erp_unit_shutdown(struct zfcp_unit *, int, char *, void *);
extern void zfcp_erp_unit_shutdown_wait(struct zfcp_unit *, char *);
extern void zfcp_erp_unit_failed(struct zfcp_unit *, char *, void *);
extern void zfcp_erp_unit_failed(struct zfcp_unit *, char *, void *);
extern int  zfcp_erp_thread_setup(struct zfcp_adapter *);
extern int  zfcp_erp_thread_setup(struct zfcp_adapter *);
extern void zfcp_erp_thread_kill(struct zfcp_adapter *);
extern void zfcp_erp_thread_kill(struct zfcp_adapter *);