Currently there is a possibility that a session name is reused and

passed to scst_sess_sysfs_create() before scst_sess_sysfs_del() has
finished removing a kobject that is using the same session name. This
patch fixes that. It works by maintaining yet another session list,
namely a list of sessions registered in sysfs, and by using that list to
check for duplicate session names.

Signed-off-by: Bart Van Assche <bvanassche@acm.org>



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@4464 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2012-08-10 02:02:35 +00:00
parent 1b68210cce
commit 0327e15440
3 changed files with 22 additions and 4 deletions

View File

@@ -1488,6 +1488,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;
@@ -1674,6 +1680,9 @@ struct scst_session {
/* 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;

View File

@@ -3291,6 +3291,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;
@@ -5107,6 +5108,8 @@ void scst_free_session(struct scst_session *sess)
mutex_lock(&scst_mutex);
list_del(&sess->sysfs_sess_list_entry);
/* Called under lock to protect from too early tgt release */
wake_up_all(&sess->tgt->unreg_waitQ);

View File

@@ -6440,7 +6440,7 @@ 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 *sess_list,
static char *scst_get_unique_sess_name(struct list_head *sysfs_sess_list,
const char *initiator_name)
{
char *name = (char *)initiator_name;
@@ -6453,8 +6453,9 @@ static char *scst_get_unique_sess_name(struct list_head *sess_list,
#endif
restart:
list_for_each_entry(s, sess_list, sess_list_entry) {
if (s->sess_name && strcmp(name, s->sess_name) == 0) {
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);
@@ -6498,6 +6499,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);
@@ -6513,7 +6516,7 @@ static int scst_init_session(struct scst_session *sess)
}
res = -ENOMEM;
sess->sess_name = scst_get_unique_sess_name(&sess->tgt->sess_list,
sess->sess_name = scst_get_unique_sess_name(&sess->tgt->sysfs_sess_list,
sess->initiator_name);
if (!sess->sess_name)
goto failed;
@@ -6522,6 +6525,9 @@ static int scst_init_session(struct scst_session *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()!