scst_local: Avoid that session deletion triggers a kernel warning (merge r5601 and 5631 from trunk)

git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/3.0.x@5922 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Bart Van Assche
2014-12-05 12:24:23 +00:00
parent d8da2ff95d
commit 31daca921d

View File

@@ -142,6 +142,8 @@ struct scst_local_sess {
spinlock_t aen_lock;
struct list_head aen_work_list; /* protected by aen_lock */
struct work_struct remove_work;
struct list_head sessions_list_entry;
};
@@ -152,6 +154,8 @@ static int __scst_local_add_adapter(struct scst_local_tgt *tgt,
const char *initiator_name, bool locked);
static int scst_local_add_adapter(struct scst_local_tgt *tgt,
const char *initiator_name);
static void scst_local_close_session_impl(struct scst_local_sess *sess,
bool async);
static void scst_local_remove_adapter(struct scst_local_sess *sess);
static int scst_local_add_target(const char *target_name,
struct scst_local_tgt **out_tgt);
@@ -786,7 +790,7 @@ static ssize_t scst_local_sysfs_mgmt_cmd(char *buf)
res = -EINVAL;
goto out_unlock;
}
scst_local_remove_adapter(sess);
scst_local_close_session_impl(sess, false);
}
res = 0;
@@ -1385,6 +1389,56 @@ static int scst_local_targ_release(struct scst_tgt *tgt)
return 0;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
static void scst_remove_work_fn(void *ctx)
#else
static void scst_remove_work_fn(struct work_struct *work)
#endif
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
struct scst_local_sess *sess = ctx;
#else
struct scst_local_sess *sess =
container_of(work, struct scst_local_sess, remove_work);
#endif
scst_local_remove_adapter(sess);
}
static void scst_local_close_session_impl(struct scst_local_sess *sess,
bool async)
{
bool unregistering;
spin_lock(&sess->aen_lock);
unregistering = sess->unregistering;
sess->unregistering = 1;
spin_unlock(&sess->aen_lock);
if (!unregistering) {
if (async)
schedule_work(&sess->remove_work);
else
scst_local_remove_adapter(sess);
}
}
/*
* Perform removal from the context of another thread since the caller may
* already hold an SCST mutex, since scst_local_remove_adapter() triggers a
* call of device_unregister(), since device_unregister() invokes
* device_del(), since device_del() locks the same mutex that is held while
* invoking scst_add() from class_interface_register() and since scst_add()
* also may lock an SCST mutex.
*/
static int scst_local_close_session(struct scst_session *scst_sess)
{
struct scst_local_sess *sess = scst_sess_get_tgt_priv(scst_sess);
scst_local_close_session_impl(sess, true);
return 0;
}
static int scst_local_targ_xmit_response(struct scst_cmd *scst_cmd)
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
@@ -1525,6 +1579,7 @@ static struct scst_tgt_template scst_local_targ_tmpl = {
#endif
.detect = scst_local_targ_detect,
.release = scst_local_targ_release,
.close_session = scst_local_close_session,
.pre_exec = scst_local_targ_pre_exec,
.xmit_response = scst_local_targ_xmit_response,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
@@ -1783,8 +1838,10 @@ static int __scst_local_add_adapter(struct scst_local_tgt *tgt,
*/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
INIT_WORK(&sess->aen_work, scst_aen_work_fn, sess);
INIT_WORK(&sess->remove_work, scst_remove_work_fn, sess);
#else
INIT_WORK(&sess->aen_work, scst_aen_work_fn);
INIT_WORK(&sess->remove_work, scst_remove_work_fn);
#endif
spin_lock_init(&sess->aen_lock);
INIT_LIST_HEAD(&sess->aen_work_list);
@@ -1927,11 +1984,7 @@ static void __scst_local_remove_target(struct scst_local_tgt *tgt)
list_for_each_entry_safe(sess, ts, &tgt->sessions_list,
sessions_list_entry) {
spin_lock(&sess->aen_lock);
sess->unregistering = 1;
spin_unlock(&sess->aen_lock);
scst_local_remove_adapter(sess);
scst_local_close_session_impl(sess, false);
}
list_del(&tgt->tgts_list_entry);