mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-19 03:31:26 +00:00
scst: Rework sess_tgt_dev_list locking
Protect modifications of sess_tgt_dev_list with the new mutex tgt_dev_list_mutex. Protect read-only accesses of this list via RCU. Do no longer lock scst_mutex when invoking any of the following functions: * scst_queue_report_luns_changed_UA(). * scst_report_luns_changed_sess(). * scst_lookup_tgt_dev() when invoked outside of command context. * scst_nexus_loss(). * scst_do_nexus_loss_sess(). * scst_abort_all_nexus_loss_sess(). * scst_do_nexus_loss_tgt(). Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
This commit is contained in:
@@ -2071,10 +2071,14 @@ struct scst_session {
|
||||
/* session's async flags */
|
||||
unsigned long sess_aflags;
|
||||
|
||||
/* protects sess_tgt_dev_list[] modifications */
|
||||
struct mutex tgt_dev_list_mutex;
|
||||
|
||||
/*
|
||||
* Hash list for tgt_dev's for this session with size and fn. It isn't
|
||||
* hlist_entry, because we need ability to go over the list in the
|
||||
* reverse order. Protected by scst_mutex and suspended activity.
|
||||
* Hash list for tgt_dev's for this session with size and fn. Reading
|
||||
* is allowed either when holding an RCU read lock or when holding
|
||||
* tgt_dev_list_mutex. Modifying is only allowed when holding
|
||||
* tgt_dev_list_mutex.
|
||||
*/
|
||||
#define SESS_TGT_DEV_LIST_HASH_SIZE (1 << 5)
|
||||
#define SESS_TGT_DEV_LIST_HASH_FN(val) ((val) & (SESS_TGT_DEV_LIST_HASH_SIZE - 1))
|
||||
|
||||
@@ -2381,14 +2381,13 @@ void scst_set_initial_UA(struct scst_session *sess, int key, int asc, int ascq)
|
||||
TRACE_MGMT_DBG("Setting for sess %p initial UA %x/%x/%x", sess, key,
|
||||
asc, ascq);
|
||||
|
||||
/* To protect sess_tgt_dev_list */
|
||||
mutex_lock(&scst_mutex);
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[i];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
spin_lock_bh(&tgt_dev->tgt_dev_lock);
|
||||
if (!list_empty(&tgt_dev->UA_list)) {
|
||||
struct scst_tgt_dev_UA *ua;
|
||||
@@ -2413,8 +2412,7 @@ void scst_set_initial_UA(struct scst_session *sess, int key, int asc, int ascq)
|
||||
spin_unlock_bh(&tgt_dev->tgt_dev_lock);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
rcu_read_unlock();
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
@@ -2458,7 +2456,23 @@ void scst_free_aen(struct scst_aen *aen)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Must be called under scst_mutex */
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
static bool scst_is_active_tgt_dev(struct scst_tgt_dev *tgt_dev)
|
||||
{
|
||||
bool is_active;
|
||||
|
||||
rcu_read_lock();
|
||||
is_active = scst_lookup_tgt_dev(tgt_dev->sess, tgt_dev->lun) == tgt_dev;
|
||||
rcu_read_unlock();
|
||||
|
||||
return is_active;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The caller must ensure that tgt_dev does not disappear while this function
|
||||
* is in progress.
|
||||
*/
|
||||
void scst_gen_aen_or_ua(struct scst_tgt_dev *tgt_dev,
|
||||
int key, int asc, int ascq)
|
||||
{
|
||||
@@ -2564,7 +2578,6 @@ static inline bool scst_is_report_luns_changed_type(int type)
|
||||
}
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
static void scst_queue_report_luns_changed_UA(struct scst_session *sess,
|
||||
int flags)
|
||||
{
|
||||
@@ -2580,11 +2593,13 @@ static void scst_queue_report_luns_changed_UA(struct scst_session *sess,
|
||||
|
||||
local_bh_disable();
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
#if !defined(__CHECKER__)
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
head = &sess->sess_tgt_dev_list[i];
|
||||
|
||||
list_for_each_entry(tgt_dev, head,
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
/* Lockdep triggers here a false positive.. */
|
||||
spin_lock(&tgt_dev->tgt_dev_lock);
|
||||
@@ -2595,7 +2610,8 @@ static void scst_queue_report_luns_changed_UA(struct scst_session *sess,
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
head = &sess->sess_tgt_dev_list[i];
|
||||
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
int sl;
|
||||
|
||||
if (!scst_is_report_luns_changed_type(
|
||||
@@ -2615,20 +2631,21 @@ static void scst_queue_report_luns_changed_UA(struct scst_session *sess,
|
||||
for (i = SESS_TGT_DEV_LIST_HASH_SIZE-1; i >= 0; i--) {
|
||||
head = &sess->sess_tgt_dev_list[i];
|
||||
|
||||
list_for_each_entry_reverse(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
spin_unlock(&tgt_dev->tgt_dev_lock);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
local_bh_enable();
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
static void scst_report_luns_changed_sess(struct scst_session *sess)
|
||||
{
|
||||
int i;
|
||||
@@ -2644,13 +2661,14 @@ static void scst_report_luns_changed_sess(struct scst_session *sess)
|
||||
|
||||
TRACE_DBG("REPORTED LUNS DATA CHANGED (sess %p)", sess);
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct list_head *head;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
|
||||
head = &sess->sess_tgt_dev_list[i];
|
||||
|
||||
list_for_each_entry(tgt_dev, head,
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
if (scst_is_report_luns_changed_type(
|
||||
tgt_dev->dev->type)) {
|
||||
@@ -2662,6 +2680,8 @@ static void scst_report_luns_changed_sess(struct scst_session *sess)
|
||||
}
|
||||
|
||||
found:
|
||||
rcu_read_unlock();
|
||||
|
||||
if (tgtt->report_aen != NULL) {
|
||||
struct scst_aen *aen;
|
||||
int rc;
|
||||
@@ -2694,13 +2714,15 @@ out:
|
||||
return;
|
||||
}
|
||||
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
void scst_report_luns_changed(struct scst_acg *acg)
|
||||
{
|
||||
struct scst_session *sess;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
/* To protect acg_sess_list */
|
||||
lockdep_assert_held(&scst_mutex);
|
||||
|
||||
TRACE_DBG("REPORTED LUNS DATA CHANGED (acg %s)", acg->acg_name);
|
||||
|
||||
list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) {
|
||||
@@ -2738,10 +2760,8 @@ void scst_aen_done(struct scst_aen *aen)
|
||||
if (scst_analyze_sense(aen->aen_sense, aen->aen_sense_len,
|
||||
SCST_SENSE_ALL_VALID, SCST_LOAD_SENSE(
|
||||
scst_sense_reported_luns_data_changed))) {
|
||||
mutex_lock(&scst_mutex);
|
||||
scst_queue_report_luns_changed_UA(aen->sess,
|
||||
SCST_SET_UA_FLAG_AT_HEAD);
|
||||
mutex_unlock(&scst_mutex);
|
||||
} else {
|
||||
struct scst_session *sess = aen->sess;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
@@ -2749,8 +2769,7 @@ void scst_aen_done(struct scst_aen *aen)
|
||||
|
||||
lun = scst_unpack_lun((uint8_t *)&aen->lun, sizeof(aen->lun));
|
||||
|
||||
mutex_lock(&scst_mutex);
|
||||
|
||||
rcu_read_lock();
|
||||
/* tgt_dev might get dead, so we need to reseek it */
|
||||
tgt_dev = scst_lookup_tgt_dev(sess, lun);
|
||||
if (tgt_dev) {
|
||||
@@ -2760,8 +2779,7 @@ void scst_aen_done(struct scst_aen *aen)
|
||||
aen->aen_sense_len,
|
||||
SCST_SET_UA_FLAG_AT_HEAD);
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
out_free:
|
||||
@@ -2785,10 +2803,8 @@ void scst_requeue_ua(struct scst_cmd *cmd, const uint8_t *buf, int size)
|
||||
SCST_LOAD_SENSE(scst_sense_reported_luns_data_changed))) {
|
||||
TRACE_MGMT_DBG("Requeuing REPORTED LUNS DATA CHANGED UA "
|
||||
"for delivery failed cmd %p", cmd);
|
||||
mutex_lock(&scst_mutex);
|
||||
scst_queue_report_luns_changed_UA(cmd->sess,
|
||||
SCST_SET_UA_FLAG_AT_HEAD);
|
||||
mutex_unlock(&scst_mutex);
|
||||
} else {
|
||||
TRACE_MGMT_DBG("Requeuing UA for delivery failed cmd %p", cmd);
|
||||
scst_check_set_UA(cmd->tgt_dev, buf, size, SCST_SET_UA_FLAG_AT_HEAD);
|
||||
@@ -2835,10 +2851,11 @@ retry_add:
|
||||
list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
|
||||
bool inq_changed_ua_needed = false;
|
||||
|
||||
mutex_lock(&sess->tgt_dev_list_mutex);
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
head = &sess->sess_tgt_dev_list[i];
|
||||
|
||||
list_for_each_entry(tgt_dev, head,
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
if ((tgt_dev->dev == acg_dev->dev) &&
|
||||
(tgt_dev->lun == acg_dev->lun) &&
|
||||
@@ -2848,6 +2865,8 @@ retry_add:
|
||||
sess, tgt_dev,
|
||||
(unsigned long long)tgt_dev->lun);
|
||||
tgt_dev->acg_dev = acg_dev;
|
||||
mutex_unlock(&sess->tgt_dev_list_mutex);
|
||||
|
||||
goto next;
|
||||
} else if (tgt_dev->lun == acg_dev->lun) {
|
||||
TRACE_MGMT_DBG("Replacing LUN %lld",
|
||||
@@ -2858,6 +2877,7 @@ retry_add:
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&sess->tgt_dev_list_mutex);
|
||||
|
||||
luns_changed = true;
|
||||
|
||||
@@ -2878,6 +2898,8 @@ next:
|
||||
}
|
||||
|
||||
something_freed = false;
|
||||
|
||||
mutex_lock(&sess->tgt_dev_list_mutex);
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct scst_tgt_dev *t;
|
||||
head = &sess->sess_tgt_dev_list[i];
|
||||
@@ -2895,6 +2917,7 @@ next:
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&sess->tgt_dev_list_mutex);
|
||||
|
||||
if (add_failed && something_freed) {
|
||||
TRACE_MGMT_DBG("sess %p: Retrying adding new tgt_devs", sess);
|
||||
@@ -2917,10 +2940,11 @@ next:
|
||||
if (luns_changed) {
|
||||
scst_report_luns_changed_sess(sess);
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
head = &sess->sess_tgt_dev_list[i];
|
||||
|
||||
list_for_each_entry(tgt_dev, head,
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
if (tgt_dev->inq_changed_ua_needed) {
|
||||
TRACE_MGMT_DBG("sess %p: Setting "
|
||||
@@ -2934,6 +2958,7 @@ next:
|
||||
}
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -4242,6 +4267,7 @@ int scst_acg_del_lun(struct scst_acg *acg, uint64_t lun,
|
||||
int res = 0;
|
||||
struct scst_acg_dev *acg_dev = NULL, *a;
|
||||
struct scst_tgt_dev *tgt_dev, *tt;
|
||||
struct scst_session *sess;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -4259,8 +4285,13 @@ int scst_acg_del_lun(struct scst_acg *acg, uint64_t lun,
|
||||
|
||||
list_for_each_entry_safe(tgt_dev, tt, &acg_dev->dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
if (tgt_dev->acg_dev == acg_dev)
|
||||
if (tgt_dev->acg_dev == acg_dev) {
|
||||
sess = tgt_dev->sess;
|
||||
|
||||
mutex_lock(&sess->tgt_dev_list_mutex);
|
||||
scst_free_tgt_dev(tgt_dev);
|
||||
mutex_unlock(&sess->tgt_dev_list_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
scst_del_free_acg_dev(acg_dev, true);
|
||||
@@ -4388,6 +4419,7 @@ static void scst_free_acg(struct scst_acg *acg)
|
||||
{
|
||||
struct scst_acg_dev *acg_dev, *acg_dev_tmp;
|
||||
struct scst_acn *acn, *acnt;
|
||||
struct scst_session *sess;
|
||||
|
||||
TRACE_DBG("Freeing acg %s/%s", acg->tgt->tgt_name, acg->acg_name);
|
||||
|
||||
@@ -4397,8 +4429,13 @@ static void scst_free_acg(struct scst_acg *acg)
|
||||
list_for_each_entry_safe(tgt_dev, tt,
|
||||
&acg_dev->dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
if (tgt_dev->acg_dev == acg_dev)
|
||||
if (tgt_dev->acg_dev == acg_dev) {
|
||||
sess = tgt_dev->sess;
|
||||
|
||||
mutex_lock(&sess->tgt_dev_list_mutex);
|
||||
scst_free_tgt_dev(tgt_dev);
|
||||
mutex_unlock(&sess->tgt_dev_list_mutex);
|
||||
}
|
||||
}
|
||||
scst_free_acg_dev(acg_dev);
|
||||
}
|
||||
@@ -4850,6 +4887,7 @@ static int scst_alloc_add_tgt_dev(struct scst_session *sess,
|
||||
goto out;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&tgt_dev->sess_tgt_dev_list_entry);
|
||||
tgt_dev->dev = dev;
|
||||
tgt_dev->lun = acg_dev->lun;
|
||||
tgt_dev->acg_dev = acg_dev;
|
||||
@@ -4968,8 +5006,10 @@ static int scst_alloc_add_tgt_dev(struct scst_session *sess,
|
||||
list_add_tail(&tgt_dev->dev_tgt_dev_list_entry, &dev->dev_tgt_dev_list);
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
|
||||
mutex_lock(&sess->tgt_dev_list_mutex);
|
||||
head = &sess->sess_tgt_dev_list[SESS_TGT_DEV_LIST_HASH_FN(tgt_dev->lun)];
|
||||
list_add_tail(&tgt_dev->sess_tgt_dev_list_entry, head);
|
||||
list_add_tail_rcu(&tgt_dev->sess_tgt_dev_list_entry, head);
|
||||
mutex_unlock(&sess->tgt_dev_list_mutex);
|
||||
|
||||
scst_tg_init_tgt_dev(tgt_dev);
|
||||
|
||||
@@ -5003,7 +5043,10 @@ out_free:
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
/*
|
||||
* The caller must ensure that tgt_dev does not disappear while this function
|
||||
* is in progress.
|
||||
*/
|
||||
void scst_nexus_loss(struct scst_tgt_dev *tgt_dev, bool queue_UA)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
@@ -5022,8 +5065,8 @@ void scst_nexus_loss(struct scst_tgt_dev *tgt_dev, bool queue_UA)
|
||||
}
|
||||
|
||||
/*
|
||||
* scst_mutex supposed to be held, there must not be parallel activity in this
|
||||
* session.
|
||||
* The caller must either ensure that tgt_dev is not on sess->tgt_dev_list
|
||||
* or must hold sess->tgt_dev_list_mutex.
|
||||
*/
|
||||
static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev)
|
||||
{
|
||||
@@ -5032,14 +5075,23 @@ static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
lockdep_assert_held(&scst_mutex);
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
if (scst_is_active_tgt_dev(tgt_dev))
|
||||
lockdep_assert_held(&tgt_dev->sess->tgt_dev_list_mutex);
|
||||
#endif
|
||||
WARN_ON_ONCE(atomic_read(&tgt_dev->tgt_dev_cmd_count) != 0);
|
||||
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
list_del(&tgt_dev->dev_tgt_dev_list_entry);
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
|
||||
list_del(&tgt_dev->sess_tgt_dev_list_entry);
|
||||
list_del_rcu(&tgt_dev->sess_tgt_dev_list_entry);
|
||||
|
||||
scst_tgt_dev_sysfs_del(tgt_dev);
|
||||
|
||||
synchronize_rcu();
|
||||
|
||||
if (tgtt->get_initiator_port_transport_id == NULL)
|
||||
dev->not_pr_supporting_tgt_devs_num--;
|
||||
|
||||
@@ -5089,10 +5141,6 @@ out_free:
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* scst_mutex supposed to be held, there must not be parallel activity in this
|
||||
* session.
|
||||
*/
|
||||
void scst_sess_free_tgt_devs(struct scst_session *sess)
|
||||
{
|
||||
int i;
|
||||
@@ -5100,7 +5148,7 @@ void scst_sess_free_tgt_devs(struct scst_session *sess)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
/* The session is going down, no users, so no locks */
|
||||
mutex_lock(&sess->tgt_dev_list_mutex);
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[i];
|
||||
list_for_each_entry_safe(tgt_dev, t, head,
|
||||
@@ -5109,6 +5157,7 @@ void scst_sess_free_tgt_devs(struct scst_session *sess)
|
||||
}
|
||||
INIT_LIST_HEAD(head);
|
||||
}
|
||||
mutex_unlock(&sess->tgt_dev_list_mutex);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
@@ -6082,6 +6131,7 @@ struct scst_session *scst_alloc_session(struct scst_tgt *tgt, gfp_t gfp_mask,
|
||||
sess->init_phase = SCST_SESS_IPH_INITING;
|
||||
sess->shut_phase = SCST_SESS_SPH_READY;
|
||||
atomic_set(&sess->refcnt, 0);
|
||||
mutex_init(&sess->tgt_dev_list_mutex);
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[i];
|
||||
INIT_LIST_HEAD(head);
|
||||
@@ -11421,23 +11471,19 @@ again:
|
||||
#if !defined(__CHECKER__)
|
||||
spin_unlock_bh(&cmd->tgt_dev->tgt_dev_lock);
|
||||
|
||||
/*
|
||||
* cmd won't allow to suspend activities, so we can access
|
||||
* sess->sess_tgt_dev_list without any additional
|
||||
* protection.
|
||||
*/
|
||||
|
||||
local_bh_disable();
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[i];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, head,
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
/* Lockdep triggers here a false positive.. */
|
||||
spin_lock(&tgt_dev->tgt_dev_lock);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
#endif
|
||||
|
||||
first = false;
|
||||
@@ -11467,11 +11513,12 @@ again:
|
||||
list_del(&UA_entry->UA_list_entry);
|
||||
|
||||
if (UA_entry->global_UA) {
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[i];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
|
||||
list_for_each_entry(tgt_dev, head,
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
struct scst_tgt_dev_UA *ua;
|
||||
list_for_each_entry(ua, &tgt_dev->UA_list,
|
||||
@@ -11490,6 +11537,7 @@ again:
|
||||
}
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
mempool_free(UA_entry, scst_ua_mempool);
|
||||
@@ -11502,14 +11550,16 @@ again:
|
||||
out_unlock:
|
||||
if (global_unlock) {
|
||||
#if !defined(__CHECKER__)
|
||||
rcu_read_lock();
|
||||
for (i = SESS_TGT_DEV_LIST_HASH_SIZE-1; i >= 0; i--) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[i];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry_reverse(tgt_dev, head,
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
spin_unlock(&tgt_dev->tgt_dev_lock);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
local_bh_enable();
|
||||
spin_lock_bh(&cmd->tgt_dev->tgt_dev_lock);
|
||||
@@ -11583,6 +11633,8 @@ static void __scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
lockdep_assert_held(&tgt_dev->tgt_dev_lock);
|
||||
|
||||
list_for_each_entry(UA_entry_tmp, &tgt_dev->UA_list,
|
||||
UA_list_entry) {
|
||||
if (memcmp(sense, UA_entry_tmp->UA_sense_buffer, len) == 0) {
|
||||
|
||||
@@ -591,11 +591,12 @@ static int lat_info_show(struct seq_file *seq, void *v)
|
||||
seq_printf(seq, "%-46s\n", buf);
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
for (t = SESS_TGT_DEV_LIST_HASH_SIZE-1; t >= 0; t--) {
|
||||
struct list_head *head =
|
||||
&sess->sess_tgt_dev_list[t];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, head,
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
|
||||
seq_printf(seq, "\nLUN: %llu\n", tgt_dev->lun);
|
||||
@@ -677,6 +678,7 @@ static int lat_info_show(struct seq_file *seq, void *v)
|
||||
}
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
scst_time = sess->scst_time;
|
||||
tgt_time = sess->tgt_time;
|
||||
@@ -744,7 +746,9 @@ static ssize_t scst_proc_scsi_tgt_gen_write_lat(struct file *file,
|
||||
acg_sess_list_entry) {
|
||||
PRINT_INFO("Zeroing latency statistics for initiator "
|
||||
"%s", sess->initiator_name);
|
||||
|
||||
spin_lock_bh(&sess->lat_lock);
|
||||
rcu_read_lock();
|
||||
|
||||
sess->scst_time = 0;
|
||||
sess->tgt_time = 0;
|
||||
@@ -763,7 +767,7 @@ static ssize_t scst_proc_scsi_tgt_gen_write_lat(struct file *file,
|
||||
struct list_head *head =
|
||||
&sess->sess_tgt_dev_list[t];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, head,
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
tgt_dev->scst_time = 0;
|
||||
tgt_dev->tgt_time = 0;
|
||||
@@ -774,6 +778,7 @@ static ssize_t scst_proc_scsi_tgt_gen_write_lat(struct file *file,
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
spin_unlock_bh(&sess->lat_lock);
|
||||
}
|
||||
}
|
||||
@@ -2427,15 +2432,19 @@ static int scst_sessions_info_show(struct seq_file *seq, void *v)
|
||||
list_for_each_entry(sess, &acg->acg_sess_list,
|
||||
acg_sess_list_entry) {
|
||||
int active_cmds = 0, t;
|
||||
|
||||
rcu_read_lock();
|
||||
for (t = SESS_TGT_DEV_LIST_HASH_SIZE-1; t >= 0; t--) {
|
||||
struct list_head *head =
|
||||
&sess->sess_tgt_dev_list[t];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, head,
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
active_cmds += atomic_read(&tgt_dev->tgt_dev_cmd_count);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
seq_printf(seq, "%-20s %-45s %-35s %d/%d\n",
|
||||
sess->tgt->tgtt->name,
|
||||
sess->initiator_name,
|
||||
|
||||
@@ -1886,16 +1886,20 @@ static ssize_t __scst_acg_black_hole_store(struct scst_acg *acg,
|
||||
|
||||
list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) {
|
||||
int i;
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[i];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
if (t != SCST_ACG_BLACK_HOLE_NONE)
|
||||
set_bit(SCST_TGT_DEV_BLACK_HOLE, &tgt_dev->tgt_dev_flags);
|
||||
else
|
||||
clear_bit(SCST_TGT_DEV_BLACK_HOLE, &tgt_dev->tgt_dev_flags);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
PRINT_INFO("Black hole set to %d for ACG %s", t, acg->acg_name);
|
||||
@@ -1984,10 +1988,12 @@ static int __scst_acg_process_cpu_mask_store(struct scst_tgt *tgt,
|
||||
|
||||
list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) {
|
||||
int i;
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[i];
|
||||
list_for_each_entry(tgt_dev, head,
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
int rc;
|
||||
|
||||
@@ -1999,6 +2005,8 @@ static int __scst_acg_process_cpu_mask_store(struct scst_tgt *tgt,
|
||||
" failed: %d", rc);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (tgt->tgtt->report_aen != NULL) {
|
||||
struct scst_aen *aen;
|
||||
int rc;
|
||||
@@ -4205,14 +4213,11 @@ static int scst_sess_zero_latency(struct scst_sysfs_work_item *work)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
res = mutex_lock_interruptible(&scst_mutex);
|
||||
if (res != 0)
|
||||
goto out_put;
|
||||
|
||||
PRINT_INFO("Zeroing latency statistics for initiator "
|
||||
"%s", sess->initiator_name);
|
||||
|
||||
spin_lock_bh(&sess->lat_lock);
|
||||
rcu_read_lock();
|
||||
|
||||
sess->scst_time = 0;
|
||||
sess->tgt_time = 0;
|
||||
@@ -4230,7 +4235,8 @@ static int scst_sess_zero_latency(struct scst_sysfs_work_item *work)
|
||||
for (t = SESS_TGT_DEV_LIST_HASH_SIZE-1; t >= 0; t--) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[t];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
tgt_dev->scst_time = 0;
|
||||
tgt_dev->tgt_time = 0;
|
||||
tgt_dev->dev_time = 0;
|
||||
@@ -4240,11 +4246,9 @@ static int scst_sess_zero_latency(struct scst_sysfs_work_item *work)
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
spin_unlock_bh(&sess->lat_lock);
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
out_put:
|
||||
kobject_put(&sess->sess_kobj);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
@@ -4306,23 +4310,19 @@ static int scst_sysfs_sess_get_active_commands(struct scst_session *sess)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
res = mutex_lock_interruptible(&scst_mutex);
|
||||
if (res != 0)
|
||||
goto out_put;
|
||||
|
||||
rcu_read_lock();
|
||||
for (t = SESS_TGT_DEV_LIST_HASH_SIZE-1; t >= 0; t--) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[t];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
active_cmds += atomic_read(&tgt_dev->tgt_dev_cmd_count);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
rcu_read_unlock();
|
||||
|
||||
res = active_cmds;
|
||||
|
||||
out_put:
|
||||
kobject_put(&sess->sess_kobj);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
@@ -4375,14 +4375,11 @@ static int scst_sysfs_sess_get_dif_checks_failed_work_fn(struct scst_sysfs_work_
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
res = mutex_lock_interruptible(&scst_mutex);
|
||||
if (res != 0)
|
||||
goto out_put;
|
||||
|
||||
rcu_read_lock();
|
||||
for (t = SESS_TGT_DEV_LIST_HASH_SIZE-1; t >= 0; t--) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[t];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
list_for_each_entry_rcu(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
app_failed_tgt += atomic_read(&tgt_dev->tgt_dev_dif_app_failed_tgt);
|
||||
ref_failed_tgt += atomic_read(&tgt_dev->tgt_dev_dif_ref_failed_tgt);
|
||||
guard_failed_tgt += atomic_read(&tgt_dev->tgt_dev_dif_guard_failed_tgt);
|
||||
@@ -4394,8 +4391,7 @@ static int scst_sysfs_sess_get_dif_checks_failed_work_fn(struct scst_sysfs_work_
|
||||
guard_failed_dev += atomic_read(&tgt_dev->tgt_dev_dif_guard_failed_dev);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
rcu_read_unlock();
|
||||
|
||||
work->res_buf = kasprintf(GFP_KERNEL, "\tapp\tref\tguard\n"
|
||||
"tgt\t%d\t%d\t%d\nscst\t%d\t%d\t%d\ndev\t%d\t%d\t%d\n",
|
||||
@@ -4404,7 +4400,6 @@ static int scst_sysfs_sess_get_dif_checks_failed_work_fn(struct scst_sysfs_work_
|
||||
app_failed_dev, ref_failed_dev, guard_failed_dev);
|
||||
res = work->res_buf ? 0 : -ENOMEM;
|
||||
|
||||
out_put:
|
||||
kobject_put(&sess->sess_kobj);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
@@ -4455,14 +4450,12 @@ static int scst_sess_zero_dif_checks_failed(struct scst_sysfs_work_item *work)
|
||||
PRINT_INFO("Zeroing DIF failures statistics for initiator "
|
||||
"%s, target %s", sess->initiator_name, sess->tgt->tgt_name);
|
||||
|
||||
res = mutex_lock_interruptible(&scst_mutex);
|
||||
if (res != 0)
|
||||
goto out_put;
|
||||
|
||||
rcu_read_lock();
|
||||
for (t = SESS_TGT_DEV_LIST_HASH_SIZE-1; t >= 0; t--) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[t];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_app_failed_tgt, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_ref_failed_tgt, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_guard_failed_tgt, 0);
|
||||
@@ -4474,12 +4467,10 @@ static int scst_sess_zero_dif_checks_failed(struct scst_sysfs_work_item *work)
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_guard_failed_dev, 0);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
rcu_read_unlock();
|
||||
|
||||
res = 0;
|
||||
|
||||
out_put:
|
||||
kobject_put(&sess->sess_kobj);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
|
||||
@@ -1899,13 +1899,11 @@ static int scst_report_luns_local(struct scst_cmd *cmd)
|
||||
memset(buffer, 0, buffer_size);
|
||||
offs = 8;
|
||||
|
||||
/*
|
||||
* cmd won't allow to suspend activities, so we can access
|
||||
* sess->sess_tgt_dev_list without any additional protection.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct list_head *head = &cmd->sess->sess_tgt_dev_list[i];
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
if (!overflow) {
|
||||
if ((buffer_size - offs) < 8) {
|
||||
overflow = 1;
|
||||
@@ -1920,6 +1918,7 @@ inc_dev_cnt:
|
||||
dev_cnt++;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
/* Set the response header */
|
||||
dev_cnt *= 8;
|
||||
@@ -1936,14 +1935,12 @@ out_compl:
|
||||
|
||||
/* Clear left sense_reported_luns_data_changed UA, if any. */
|
||||
|
||||
/*
|
||||
* cmd won't allow to suspend activities, so we can access
|
||||
* sess->sess_tgt_dev_list without any additional protection.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct list_head *head = &cmd->sess->sess_tgt_dev_list[i];
|
||||
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
struct scst_tgt_dev_UA *ua;
|
||||
|
||||
spin_lock_bh(&tgt_dev->tgt_dev_lock);
|
||||
@@ -1963,6 +1960,7 @@ out_compl:
|
||||
spin_unlock_bh(&tgt_dev->tgt_dev_lock);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
/* Report the result */
|
||||
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME);
|
||||
@@ -4392,18 +4390,25 @@ out:
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be invoked either under RCU read lock or with sess->tgt_dev_list_mutex
|
||||
* held.
|
||||
*/
|
||||
struct scst_tgt_dev *scst_lookup_tgt_dev(struct scst_session *sess, u64 lun)
|
||||
{
|
||||
struct list_head *head;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
if (scst_get_cmd_counter() == 0)
|
||||
lockdep_assert_held(&scst_mutex);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && \
|
||||
defined(CONFIG_SCST_EXTRACHECKS) && defined(CONFIG_PREEMPT_RCU) && \
|
||||
defined(CONFIG_DEBUG_LOCK_ALLOC)
|
||||
WARN_ON_ONCE(debug_locks &&
|
||||
!lockdep_is_held(&sess->tgt_dev_list_mutex) &&
|
||||
rcu_preempt_depth() == 0);
|
||||
#endif
|
||||
|
||||
head = &sess->sess_tgt_dev_list[SESS_TGT_DEV_LIST_HASH_FN(lun)];
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
list_for_each_entry_rcu(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
if (tgt_dev->lun == lun)
|
||||
return tgt_dev;
|
||||
}
|
||||
@@ -4432,7 +4437,11 @@ static int scst_translate_lun(struct scst_cmd *cmd)
|
||||
TRACE_DBG("Finding tgt_dev for cmd %p (lun %lld)", cmd,
|
||||
(unsigned long long int)cmd->lun);
|
||||
res = -1;
|
||||
|
||||
rcu_read_lock();
|
||||
tgt_dev = scst_lookup_tgt_dev(cmd->sess, cmd->lun);
|
||||
rcu_read_unlock();
|
||||
|
||||
if (tgt_dev) {
|
||||
TRACE_DBG("tgt_dev %p found", tgt_dev);
|
||||
|
||||
@@ -5090,7 +5099,10 @@ static int scst_mgmt_translate_lun(struct scst_mgmt_cmd *mcmd)
|
||||
if (unlikely(res != 0))
|
||||
goto out;
|
||||
|
||||
rcu_read_lock();
|
||||
tgt_dev = scst_lookup_tgt_dev(mcmd->sess, mcmd->lun);
|
||||
rcu_read_unlock();
|
||||
|
||||
if (tgt_dev) {
|
||||
TRACE_DBG("tgt_dev %p found", tgt_dev);
|
||||
mcmd->mcmd_tgt_dev = tgt_dev;
|
||||
@@ -5740,8 +5752,10 @@ static bool scst_is_cmd_belongs_to_dev(struct scst_cmd *cmd,
|
||||
TRACE_DBG("Finding match for dev %s and cmd %p (lun %lld)",
|
||||
dev->virt_name, cmd, (unsigned long long int)cmd->lun);
|
||||
|
||||
rcu_read_lock();
|
||||
tgt_dev = scst_lookup_tgt_dev(cmd->sess, cmd->lun);
|
||||
res = tgt_dev && tgt_dev->dev == dev;
|
||||
rcu_read_unlock();
|
||||
|
||||
TRACE_EXIT_HRES(res);
|
||||
return res;
|
||||
@@ -6112,7 +6126,6 @@ static int scst_lun_reset(struct scst_mgmt_cmd *mcmd)
|
||||
return res;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
static void scst_do_nexus_loss_sess(struct scst_mgmt_cmd *mcmd)
|
||||
{
|
||||
int i;
|
||||
@@ -6121,13 +6134,16 @@ static void scst_do_nexus_loss_sess(struct scst_mgmt_cmd *mcmd)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[i];
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
scst_nexus_loss(tgt_dev,
|
||||
(mcmd->fn != SCST_UNREG_SESS_TM));
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
@@ -6152,11 +6168,11 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd,
|
||||
sess, mcmd);
|
||||
}
|
||||
|
||||
mutex_lock(&scst_mutex);
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[i];
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
__scst_abort_task_set(mcmd, tgt_dev);
|
||||
|
||||
scst_call_dev_task_mgmt_fn_received(mcmd, tgt_dev);
|
||||
@@ -6166,10 +6182,9 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd,
|
||||
(mcmd->fn == SCST_UNREG_SESS_TM));
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
scst_unblock_aborted_cmds(NULL, sess, NULL, true);
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
scst_unblock_aborted_cmds(NULL, sess, NULL, false);
|
||||
|
||||
res = scst_set_mcmd_next_state(mcmd);
|
||||
|
||||
@@ -6177,7 +6192,6 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd,
|
||||
return res;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
static void scst_do_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd)
|
||||
{
|
||||
int i;
|
||||
@@ -6186,16 +6200,18 @@ static void scst_do_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry(sess, &tgt->sess_list, sess_list_entry) {
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[i];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, head,
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
scst_nexus_loss(tgt_dev, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
@@ -6221,11 +6237,12 @@ static int scst_abort_all_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd,
|
||||
|
||||
mutex_lock(&scst_mutex);
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry(sess, &tgt->sess_list, sess_list_entry) {
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[i];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, head,
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
__scst_abort_task_set(mcmd, tgt_dev);
|
||||
|
||||
@@ -6238,6 +6255,7 @@ static int scst_abort_all_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd,
|
||||
}
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
scst_unblock_aborted_cmds(tgt, NULL, NULL, true);
|
||||
|
||||
@@ -6386,8 +6404,6 @@ static int scst_mgmt_affected_cmds_done(struct scst_mgmt_cmd *mcmd)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
mutex_lock(&scst_mutex);
|
||||
|
||||
switch (mcmd->fn) {
|
||||
case SCST_NEXUS_LOSS_SESS:
|
||||
case SCST_UNREG_SESS_TM:
|
||||
@@ -6399,8 +6415,6 @@ static int scst_mgmt_affected_cmds_done(struct scst_mgmt_cmd *mcmd)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
if (!mcmd->task_mgmt_fn_received_called)
|
||||
goto tgt_done;
|
||||
|
||||
@@ -6417,7 +6431,9 @@ static int scst_mgmt_affected_cmds_done(struct scst_mgmt_cmd *mcmd)
|
||||
{
|
||||
struct scst_acg *acg = sess->acg;
|
||||
struct scst_acg_dev *acg_dev;
|
||||
|
||||
mutex_lock(&scst_mutex);
|
||||
rcu_read_lock();
|
||||
list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
|
||||
dev = acg_dev->dev;
|
||||
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
|
||||
@@ -6428,6 +6444,7 @@ static int scst_mgmt_affected_cmds_done(struct scst_mgmt_cmd *mcmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
mutex_unlock(&scst_mutex);
|
||||
break;
|
||||
}
|
||||
@@ -6435,14 +6452,14 @@ static int scst_mgmt_affected_cmds_done(struct scst_mgmt_cmd *mcmd)
|
||||
case SCST_ABORT_ALL_TASKS_SESS:
|
||||
case SCST_NEXUS_LOSS_SESS:
|
||||
case SCST_UNREG_SESS_TM:
|
||||
mutex_lock(&scst_mutex);
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[i];
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
list_for_each_entry_rcu(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
scst_call_dev_task_mgmt_fn_done(mcmd, tgt_dev);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&scst_mutex);
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
|
||||
case SCST_ABORT_ALL_TASKS:
|
||||
@@ -6450,12 +6467,14 @@ static int scst_mgmt_affected_cmds_done(struct scst_mgmt_cmd *mcmd)
|
||||
{
|
||||
struct scst_session *s;
|
||||
struct scst_tgt *tgt = sess->tgt;
|
||||
|
||||
mutex_lock(&scst_mutex);
|
||||
rcu_read_lock();
|
||||
list_for_each_entry(s, &tgt->sess_list, sess_list_entry) {
|
||||
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
|
||||
struct list_head *head = &s->sess_tgt_dev_list[i];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, head,
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
if (mcmd->sess == tgt_dev->sess)
|
||||
scst_call_dev_task_mgmt_fn_done(
|
||||
@@ -6463,6 +6482,7 @@ static int scst_mgmt_affected_cmds_done(struct scst_mgmt_cmd *mcmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
mutex_unlock(&scst_mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user