From 2093dd75619681e2df5e45790fa0cc55cec60dda Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Sat, 18 May 2013 00:52:46 +0000 Subject: [PATCH] Make it possible to forcibly close SRP and FC sessions via sysfs That patch contains the following changes: * Move the code for creating a "close_sess" sysfs attribute from iscsi-scst to the SCST core such that it becomes available for other target drivers. This does not change the functionality of iscsi-scst. * Add code in ib_srpt and qla2x00t to allow a session to be forcibly closed from user space. Signed-off-by: Bart Van Assche git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@4852 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/kernel/iscsi.c | 19 ++++++++++++++++++ iscsi-scst/kernel/session.c | 31 ----------------------------- qla2x00t/qla2x00-target/qla2x00t.c | 16 +++++++++++++++ scst/include/scst.h | 13 ++++++++++++ scst/src/scst_sysfs.c | 32 ++++++++++++++++++++++++++++++ srpt/src/ib_srpt.c | 9 +++++++++ 6 files changed, 89 insertions(+), 31 deletions(-) diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index 124f30dc9..263f2eeec 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -3822,6 +3822,24 @@ out_err: return; } +static int iscsi_close_sess(struct scst_session *scst_sess) +{ + struct iscsi_session *sess = scst_sess_get_tgt_priv(scst_sess); + struct iscsi_target *target = sess->target; + int res; + + res = mutex_lock_interruptible(&target->target_mutex); + if (res) + goto out; + iscsi_sess_force_close(sess); + mutex_unlock(&target->target_mutex); + + res = 0; + +out: + return res; +} + static int iscsi_target_detect(struct scst_tgt_template *templ) { /* Nothing to do */ @@ -3869,6 +3887,7 @@ struct scst_tgt_template iscsi_template = { .add_target = iscsi_sysfs_add_target, .del_target = iscsi_sysfs_del_target, .mgmt_cmd = iscsi_sysfs_mgmt_cmd, + .close_session = iscsi_close_sess, .tgtt_optional_attributes = "IncomingUser, OutgoingUser", .tgt_optional_attributes = "IncomingUser, OutgoingUser, allowed_portal", #endif diff --git a/iscsi-scst/kernel/session.c b/iscsi-scst/kernel/session.c index a552b8efe..0ddf38a91 100644 --- a/iscsi-scst/kernel/session.c +++ b/iscsi-scst/kernel/session.c @@ -540,36 +540,6 @@ static ssize_t iscsi_sess_reinstating_show(struct kobject *kobj, static struct kobj_attribute iscsi_sess_attr_reinstating = __ATTR(reinstating, S_IRUGO, iscsi_sess_reinstating_show, NULL); -static ssize_t iscsi_sess_force_close_store(struct kobject *kobj, - struct kobj_attribute *attr, const char *buf, size_t count) -{ - int res; - struct scst_session *scst_sess; - struct iscsi_session *sess; - - TRACE_ENTRY(); - - scst_sess = container_of(kobj, struct scst_session, sess_kobj); - sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess); - - res = mutex_lock_interruptible(&sess->target->target_mutex); - if (res != 0) - goto out; - - iscsi_sess_force_close(sess); - - mutex_unlock(&sess->target->target_mutex); - - res = count; - -out: - TRACE_EXIT_RES(res); - return res; -} - -static struct kobj_attribute iscsi_sess_attr_force_close = - __ATTR(force_close, S_IWUSR, NULL, iscsi_sess_force_close_store); - const struct attribute *iscsi_sess_attrs[] = { &iscsi_sess_attr_initial_r2t.attr, &iscsi_sess_attr_immediate_data.attr, @@ -582,7 +552,6 @@ const struct attribute *iscsi_sess_attrs[] = { &iscsi_sess_attr_data_digest.attr, &iscsi_attr_sess_sid.attr, &iscsi_sess_attr_reinstating.attr, - &iscsi_sess_attr_force_close.attr, NULL, }; diff --git a/qla2x00t/qla2x00-target/qla2x00t.c b/qla2x00t/qla2x00-target/qla2x00t.c index 18ec0580f..7660508b6 100644 --- a/qla2x00t/qla2x00-target/qla2x00t.c +++ b/qla2x00t/qla2x00-target/qla2x00t.c @@ -102,6 +102,7 @@ static int q2t_cut_cmd_data_head(struct q2t_cmd *cmd, unsigned int offset); static void q2t_clear_tgt_db(struct q2t_tgt *tgt, bool local_only); static void q2t_on_hw_pending_cmd_timeout(struct scst_cmd *scst_cmd); static int q2t_unreg_sess(struct q2t_sess *sess); +static int q2t_close_session(struct scst_session *scst_sess); static uint16_t q2t_get_scsi_transport_version(struct scst_tgt *scst_tgt); static uint16_t q2t_get_phys_transport_version(struct scst_tgt *scst_tgt); @@ -219,6 +220,7 @@ static struct scst_tgt_template tgt2x_template = { .rdy_to_xfer = q2t_rdy_to_xfer, .on_free_cmd = q2t_on_free_cmd, .task_mgmt_fn_done = q2t_task_mgmt_fn_done, + .close_session = q2t_close_session, .get_initiator_port_transport_id = q2t_get_initiator_port_transport_id, .get_scsi_transport_version = q2t_get_scsi_transport_version, .get_phys_transport_version = q2t_get_phys_transport_version, @@ -796,6 +798,20 @@ out: return; } +static int q2t_close_session(struct scst_session *scst_sess) +{ + struct q2t_sess *sess = scst_sess_get_tgt_priv(scst_sess); + scsi_qla_host_t *ha = sess->tgt->ha; + scsi_qla_host_t *pha = to_qla_parent(ha); + unsigned long flags; + + spin_lock_irqsave(&pha->hardware_lock, flags); + q2t_schedule_sess_for_deletion(sess); + spin_unlock_irqrestore(&pha->hardware_lock, flags); + + return 0; +} + /* pha->hardware_lock supposed to be held on entry */ static void q2t_clear_tgt_db(struct q2t_tgt *tgt, bool local_only) { diff --git a/scst/include/scst.h b/scst/include/scst.h index 2361e4bb1..e723f66fb 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -997,6 +997,19 @@ struct scst_tgt_template { */ ssize_t (*mgmt_cmd) (char *cmd); + /* + * Forcibly close a session. Note: this function may operate + * asynchronously - there is no guarantee the session will actually + * have been closed at the time this function returns. May be called + * with scst_mutex held. Activity may be suspended while this function + * is invoked. May sleep but must not wait until session + * unregistration finished. Must return 0 upon success and -EINTR if + * the session has not been closed because a signal has been received. + * + * OPTIONAL + */ + int (*close_session)(struct scst_session *sess); + /* * Should return physical transport version. Used in the corresponding * INQUIRY version descriptor. See SPC for the list of available codes. diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index 6749ef3c7..f35d49726 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -3553,6 +3553,28 @@ SCST_SESS_SYSFS_STAT_ATTR(cmd_count, bidi_cmd_count, SCST_DATA_BIDI, 0); SCST_SESS_SYSFS_STAT_ATTR(io_byte_count, bidi_io_count_kb, SCST_DATA_BIDI, 1); SCST_SESS_SYSFS_STAT_ATTR(cmd_count, none_cmd_count, SCST_DATA_NONE, 0); + +static ssize_t scst_sess_force_close_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct scst_session *sess = container_of(kobj, struct scst_session, + sess_kobj); + int res; + + res = sess->tgt->tgtt->close_session(sess); + if (res < 0) + goto out; + res = count; + +out: + return res; +} + +static struct kobj_attribute session_force_close_attr = + __ATTR(force_close, S_IWUSR, NULL, scst_sess_force_close_store); + + static struct attribute *scst_session_attrs[] = { &session_commands_attr.attr, &session_active_commands_attr.attr, @@ -3640,6 +3662,16 @@ int scst_sess_sysfs_create(struct scst_session *sess) sess->sess_kobj_ready = 1; + if (sess->tgt->tgtt->close_session) { + res = sysfs_create_file(&sess->sess_kobj, + &session_force_close_attr.attr); + if (res != 0) { + PRINT_ERROR("Adding force_close sysfs attribute to session %s failed (%d)", + name, res); + goto out_del; + } + } + if (sess->tgt->tgtt->sess_attrs) { res = sysfs_create_files(&sess->sess_kobj, sess->tgt->tgtt->sess_attrs); diff --git a/srpt/src/ib_srpt.c b/srpt/src/ib_srpt.c index e35a7050d..451825f46 100644 --- a/srpt/src/ib_srpt.c +++ b/srpt/src/ib_srpt.c @@ -3528,6 +3528,14 @@ static int srpt_detect(struct scst_tgt_template *tp) return device_count; } +static int srpt_close_session(struct scst_session *sess) +{ + struct srpt_rdma_ch *ch = scst_sess_get_tgt_priv(sess); + + srpt_close_ch(ch); + return 0; +} + static int srpt_ch_list_empty(struct srpt_tgt *srpt_tgt) { int res; @@ -3752,6 +3760,7 @@ static struct scst_tgt_template srpt_template = { .on_hw_pending_cmd_timeout = srpt_pending_cmd_timeout, .on_free_cmd = srpt_on_free_cmd, .task_mgmt_fn_done = srpt_tsk_mgmt_done, + .close_session = srpt_close_session, .get_initiator_port_transport_id = srpt_get_initiator_port_transport_id, .get_scsi_transport_version = srpt_get_scsi_transport_version, };