Merge branch 'svn-trunk' into master

This commit is contained in:
Bart Van Assche
2020-08-09 17:32:16 -07:00
3 changed files with 156 additions and 10 deletions

View File

@@ -1401,6 +1401,34 @@ struct scst_dev_type {
void (*ext_copy_remap)(struct scst_cmd *cmd,
struct scst_ext_copy_seg_descr *descr);
/*
* Called to notify dev handler that a ALUA state change is about to
* be started. Can be used to close open file handlers, which might
* prevent the state switch.
*
* Called under scst_dg_mutex and no activities on the dev handler level
* (for implicit ALUA case supposed to be done by the user space via
* "block" sysfs attribute as described in the README).
*
* OPTIONAL
*/
void (*on_alua_state_change_start)(struct scst_device *dev,
enum scst_tg_state old_state, enum scst_tg_state new_state);
/*
* Called to notify dev handler that a ALUA state change is about to
* be finished. Can be used to (re)open file handlers closed in
* on_alua_state_change_start().
*
* Called under scst_dg_mutex and no activities on the dev handler level
* (for implicit ALUA case supposed to be done by the user space via
* "block" sysfs attribute as described in the README).
*
* OPTIONAL
*/
void (*on_alua_state_change_finish)(struct scst_device *dev,
enum scst_tg_state old_state, enum scst_tg_state new_state);
/*
* Called to notify dev handler that a task management command received
*

View File

@@ -6441,6 +6441,86 @@ static enum compl_status_e nullio_exec_verify(struct vdisk_cmd_params *p)
return CMD_SUCCEEDED;
}
static void blockio_on_alua_state_change_start(struct scst_device *dev,
enum scst_tg_state old_state, enum scst_tg_state new_state)
{
struct scst_vdisk_dev *virt_dev = dev->dh_priv;
const bool close = virt_dev->dev_active &&
new_state != SCST_TG_STATE_OPTIMIZED &&
new_state != SCST_TG_STATE_NONOPTIMIZED;
TRACE_ENTRY();
/* No other fd activity may happen concurrently with this function. */
lockdep_assert_alua_lock_held();
if (!virt_dev->bind_alua_state)
return;
PRINT_INFO("dev %s: ALUA state change from %s to %s started,%s closing FD",
dev->virt_name, scst_alua_state_name(old_state),
scst_alua_state_name(new_state), close ? "" : " not");
if (!close)
return;
virt_dev->dev_active = 0;
vdisk_close_fd(virt_dev);
TRACE_EXIT();
return;
}
static void blockio_on_alua_state_change_finish(struct scst_device *dev,
enum scst_tg_state old_state, enum scst_tg_state new_state)
{
struct scst_vdisk_dev *virt_dev = dev->dh_priv;
const bool open = !virt_dev->dev_active &&
(new_state == SCST_TG_STATE_OPTIMIZED ||
new_state == SCST_TG_STATE_NONOPTIMIZED);
int rc = 0;
TRACE_ENTRY();
/* No other fd activity may happen concurrently with this function. */
lockdep_assert_alua_lock_held();
if (!virt_dev->bind_alua_state)
return;
PRINT_INFO("dev %s: ALUA state change from %s to %s finished,%s reopening FD",
dev->virt_name, scst_alua_state_name(old_state),
scst_alua_state_name(new_state), open ? "" : " not");
if (!open)
return;
virt_dev->dev_active = 1;
/*
* only reopen fd if tgt_dev_cnt is not zero, otherwise we will
* leak reference.
*/
if (virt_dev->tgt_dev_cnt)
rc = vdisk_open_fd(virt_dev, dev->dev_rd_only);
if (rc == 0) {
if (virt_dev->reexam_pending) {
rc = vdisk_reexamine(virt_dev);
WARN_ON(rc != 0);
virt_dev->reexam_pending = 0;
}
} else {
PRINT_ERROR("dev %s: opening after ALUA state change to %s failed",
dev->virt_name,
scst_alua_state_name(new_state));
}
TRACE_EXIT();
return;
}
static void vdisk_task_mgmt_fn_done(struct scst_mgmt_cmd *mcmd,
struct scst_tgt_dev *tgt_dev)
{
@@ -9316,7 +9396,10 @@ static int vdev_sysfs_process_active_store(
res = mutex_lock_interruptible(&scst_mutex);
if (res)
goto resume;
/* To do: verify whether this call is still necessary. */
/*
* This is used to serialize against the *_on_alua_state_change_*()
* calls in scst_tg.c
*/
scst_alua_lock();
/*
@@ -9798,6 +9881,8 @@ static struct scst_dev_type vdisk_blk_devtype = {
.detach_tgt = vdisk_detach_tgt,
.parse = non_fileio_parse,
.exec = blockio_exec,
.on_alua_state_change_start = blockio_on_alua_state_change_start,
.on_alua_state_change_finish = blockio_on_alua_state_change_finish,
.task_mgmt_fn_done = vdisk_task_mgmt_fn_done,
.get_supported_opcodes = vdisk_get_supported_opcodes,
.devt_priv = (void *)blockio_ops,

View File

@@ -963,6 +963,41 @@ out_fail:
goto out_unlock;
}
/*
* __scst_tgt_set_state - Update the ALUA filter of a LUN and invoke callbacks
* @tg: ALUA target group of which the state is changing.
* @tgt_dev: LUN to be updated.
* @state: new ALUA state.
* @invoke_callbacks: Whether or not to invoke the on_alua_state_changed_*
* callback functions.
*/
static void __scst_tgt_set_state(struct scst_target_group *tg,
struct scst_tgt_dev *tgt_dev, enum scst_tg_state state,
bool invoke_callbacks)
{
bool gen_ua = state != SCST_TG_STATE_TRANSITIONING;
struct scst_tgt *tgt = tgt_dev->sess->tgt;
enum scst_tg_state old_state = tg->state;
struct scst_device *dev = tgt_dev->dev;
struct scst_dev_group *dg = tg->dg;
if (invoke_callbacks && dev->handler->on_alua_state_change_start)
dev->handler->on_alua_state_change_start(dev, old_state,
state);
/*
* If the ALUA state transition is caused by an STPG command and if
* the STPG command has been received through the target port of which
* the state is being modified, do not generate a unit attention.
*/
if (dg->stpg_rel_tgt_id == tgt->rel_tgt_id &&
tid_equal(dg->stpg_transport_id, tgt_dev->sess->transport_id))
gen_ua = false;
scst_tg_change_tgt_dev_state(tgt_dev, state, gen_ua);
if (invoke_callbacks && dev->handler->on_alua_state_change_finish)
dev->handler->on_alua_state_change_finish(dev, old_state,
state);
}
/*
* Update the ALUA filter of those LUNs (tgt_dev) whose target port is a member
* of target group @tg and that export a device that is a member of the device
@@ -976,6 +1011,7 @@ static void __scst_tg_set_state(struct scst_target_group *tg,
struct scst_tgt_dev *tgt_dev;
struct scst_tg_tgt *tg_tgt;
struct scst_tgt *tgt;
bool invoke_callbacks;
sBUG_ON(state >= ARRAY_SIZE(scst_alua_filter));
lockdep_assert_held(&scst_dg_mutex);
@@ -983,28 +1019,25 @@ static void __scst_tg_set_state(struct scst_target_group *tg,
if (tg->state == state)
return;
tg->state = state;
list_for_each_entry(dg_dev, &tg->dg->dev_list, entry) {
invoke_callbacks = true;
dev = dg_dev->dev;
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
dev_tgt_dev_list_entry) {
tgt = tgt_dev->sess->tgt;
list_for_each_entry(tg_tgt, &tg->tgt_list, entry) {
if (tg_tgt->tgt == tgt) {
bool gen_ua = (state != SCST_TG_STATE_TRANSITIONING);
if ((tg->dg->stpg_rel_tgt_id == tgt_dev->sess->tgt->rel_tgt_id) &&
tid_equal(tg->dg->stpg_transport_id, tgt_dev->sess->transport_id))
gen_ua = false;
scst_tg_change_tgt_dev_state(tgt_dev,
state, gen_ua);
__scst_tgt_set_state(tg, tgt_dev, state,
invoke_callbacks);
invoke_callbacks = false;
break;
}
}
}
}
tg->state = state;
scst_check_alua_invariant();
PRINT_INFO("Changed ALUA state of %s/%s into %s", tg->dg->name,