diff --git a/qla2x00t/qla_def.h b/qla2x00t/qla_def.h index ea5d578b2..1e6922adf 100644 --- a/qla2x00t/qla_def.h +++ b/qla2x00t/qla_def.h @@ -2362,8 +2362,9 @@ typedef struct scsi_qla_host { uint16_t atio_q_length; /* - * Protected by tgt_mutex AND hardware_lock for writing and - * tgt_mutex OR hardware_lock for reading. + * Processing Q2T tgt reference. NULL on not enabled targets. Protected + * by tgt_mutex AND hardware_lock for writing and tgt_mutex OR + * hardware_lock for reading. */ struct q2t_tgt *tgt; @@ -2632,7 +2633,10 @@ typedef struct scsi_qla_host { struct mutex tgt_host_action_mutex; - /* Protected by tgt_host_action_mutex */ + /* + * Main Q2T tgt reference, which always points to the target, if the + * target mode addon loaded. Protected by tgt_host_action_mutex. + */ struct q2t_tgt *q2t_tgt; struct list_head ha_list_entry; diff --git a/scst/include/scst.h b/scst/include/scst.h index d376c4383..fef7e7567 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -1445,6 +1445,12 @@ struct scst_tgt { /* List of remote sessions per target, protected by scst_mutex */ struct list_head sess_list; + /* + * List of remote sessions registered in sysfs per target, protected + * by scst_mutex. + */ + struct list_head sysfs_sess_list; + /* List entry of targets per template (tgts_list) */ struct list_head tgt_list_entry; @@ -1609,9 +1615,15 @@ struct scst_session { /* Name of attached initiator */ const char *initiator_name; + /* Unique session name: initiator name + optional _%d. */ + const char *sess_name; + /* List entry of sessions per target */ struct list_head sess_list_entry; + /* Per target list entry for sessions registered in sysfs. */ + struct list_head sysfs_sess_list_entry; + /* List entry for the list that keeps session, waiting for the init */ struct list_head sess_init_list_entry; diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 4a10df60d..964ea7db3 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -2555,6 +2555,7 @@ int scst_alloc_tgt(struct scst_tgt_template *tgtt, struct scst_tgt **tgt) } INIT_LIST_HEAD(&t->sess_list); + INIT_LIST_HEAD(&t->sysfs_sess_list); init_waitqueue_head(&t->unreg_waitQ); t->tgtt = tgtt; t->sg_tablesize = tgtt->sg_tablesize; @@ -4013,6 +4014,12 @@ void scst_free_session(struct scst_session *sess) scst_sess_free_tgt_devs(sess); + TRACE_DBG("Removing sess %p from the list", sess); + list_del(&sess->sess_list_entry); + + TRACE_DBG("Removing session %p from acg %s", sess, sess->acg->acg_name); + list_del(&sess->acg_sess_list_entry); + mutex_unlock(&scst_mutex); #ifndef CONFIG_SCST_PROC @@ -4026,15 +4033,7 @@ void scst_free_session(struct scst_session *sess) mutex_lock(&scst_mutex); - /* - * The lists delete must be after sysfs del. Otherwise it would break - * logic in scst_sess_sysfs_create() to avoid duplicate sysfs names. - */ - - TRACE_DBG("Removing sess %p from the list", sess); - list_del(&sess->sess_list_entry); - TRACE_DBG("Removing session %p from acg %s", sess, sess->acg->acg_name); - list_del(&sess->acg_sess_list_entry); + list_del(&sess->sysfs_sess_list_entry); /* Called under lock to protect from too early tgt release */ wake_up_all(&sess->tgt->unreg_waitQ); @@ -4047,6 +4046,8 @@ void scst_free_session(struct scst_session *sess) kfree(sess->transport_id); kfree(sess->initiator_name); + if (sess->sess_name != sess->initiator_name) + kfree(sess->sess_name); kmem_cache_free(scst_sess_cachep, sess); diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index 5257dce4e..d51eac34c 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -3645,48 +3645,18 @@ int scst_recreate_sess_luns_link(struct scst_session *sess) int scst_sess_sysfs_create(struct scst_session *sess) { int res = 0; - struct scst_session *s; - char *name = (char *)sess->initiator_name; - int len = strlen(name) + 1, n = 1; + const char *name; TRACE_ENTRY(); -restart: - list_for_each_entry(s, &sess->tgt->sess_list, sess_list_entry) { - if (!s->sess_kobj_ready) - continue; - - if (strcmp(name, kobject_name(&s->sess_kobj)) == 0) { - if (s == sess) - continue; - - TRACE_DBG("Duplicated session from the same initiator " - "%s found", name); - - if (name == sess->initiator_name) { - len = strlen(sess->initiator_name); - len += 20; - name = kmalloc(len, GFP_KERNEL); - if (name == NULL) { - PRINT_ERROR("Unable to allocate a " - "replacement name (size %d)", - len); - } - } - - snprintf(name, len, "%s_%d", sess->initiator_name, n); - n++; - goto restart; - } - } - + name = sess->sess_name; TRACE_DBG("Adding session %s to sysfs", name); res = kobject_init_and_add(&sess->sess_kobj, &scst_session_ktype, sess->tgt->tgt_sess_kobj, name); if (res != 0) { PRINT_ERROR("Can't add session %s to sysfs", name); - goto out_free; + goto out; } sess->sess_kobj_ready = 1; @@ -3706,10 +3676,7 @@ restart: goto out_del; } -out_free: - if (name != sess->initiator_name) - kfree(name); - +out: TRACE_EXIT_RES(res); return res; @@ -3717,7 +3684,7 @@ out_del: kobject_del(&sess->sess_kobj); kobject_put(&sess->sess_kobj); sess->sess_kobj_ready = 0; - goto out_free; + goto out; } /* diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index b4c588397..a7b471ae2 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -6276,6 +6276,44 @@ bool scst_initiator_has_luns(struct scst_tgt *tgt, const char *initiator_name) } EXPORT_SYMBOL_GPL(scst_initiator_has_luns); +/* Supposed to be called under scst_mutex */ +static char *scst_get_unique_sess_name(struct list_head *sysfs_sess_list, + const char *initiator_name) +{ + char *name = (char *)initiator_name; + struct scst_session *s; + int len = 0, n = 1; + + BUG_ON(!initiator_name); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) + lockdep_assert_held(&scst_mutex); +#endif + +restart: + list_for_each_entry(s, sysfs_sess_list, sysfs_sess_list_entry) { + BUG_ON(!s->sess_name); + if (strcmp(name, s->sess_name) == 0) { + TRACE_DBG("Duplicated session from the same initiator " + "%s found", name); + + if (name == initiator_name) { + len = strlen(initiator_name) + 20; + name = kmalloc(len, GFP_KERNEL); + if (name == NULL) { + PRINT_ERROR("Unable to allocate a " + "replacement name (size %d)", + len); + } + } + + snprintf(name, len, "%s_%d", initiator_name, n); + n++; + goto restart; + } + } + return name; +} + static int scst_init_session(struct scst_session *sess) { int res = 0; @@ -6298,6 +6336,8 @@ static int scst_init_session(struct scst_session *sess) TRACE_DBG("Adding sess %p to tgt->sess_list", sess); list_add_tail(&sess->sess_list_entry, &sess->tgt->sess_list); + INIT_LIST_HEAD(&sess->sysfs_sess_list_entry); + if (sess->tgt->tgtt->get_initiator_port_transport_id != NULL) { res = sess->tgt->tgtt->get_initiator_port_transport_id( sess->tgt, sess, &sess->transport_id); @@ -6312,10 +6352,19 @@ static int scst_init_session(struct scst_session *sess) sess->transport_id), sess->tgt->rel_tgt_id); } + res = -ENOMEM; + sess->sess_name = scst_get_unique_sess_name(&sess->tgt->sysfs_sess_list, + sess->initiator_name); + if (!sess->sess_name) + goto failed; + res = scst_sess_sysfs_create(sess); if (res != 0) goto failed; + list_add_tail(&sess->sysfs_sess_list_entry, + &sess->tgt->sysfs_sess_list); + /* * scst_sess_alloc_tgt_devs() must be called after session added in the * sess_list to not race with scst_check_reassign_sess()!