mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-14 09:11:27 +00:00
scst: Use RCU read lock when accessing sess_tgt_dev_list
We must always protect sess_tgt_dev_list during access and
modification.
There are two mechanisms for that:
- tgt_dev_list_mutex for list modifications.
- RCU for read-only list accesses.
Currently, the codebase doesn't consistently apply protection when
accessing the list. Fix this by adding RCU protection.
See also commit 3e64094b0c ("scst_sysfs: Do not suspend I/O for LUN
management").
This commit is contained in:
@@ -14101,31 +14101,37 @@ int scst_get_max_lun_commands(struct scst_session *sess, uint64_t lun)
|
||||
}
|
||||
|
||||
if (lun != NO_SUCH_LUN) {
|
||||
struct list_head *head =
|
||||
&sess->sess_tgt_dev_list[SESS_TGT_DEV_LIST_HASH_FN(lun)];
|
||||
struct list_head *head;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
rcu_read_lock();
|
||||
head = &sess->sess_tgt_dev_list[SESS_TGT_DEV_LIST_HASH_FN(lun)];
|
||||
|
||||
list_for_each_entry_rcu(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
if (tgt_dev->lun == lun) {
|
||||
res = tgt_dev->dev->max_tgt_dev_commands;
|
||||
TRACE_DBG("tgt_dev %p, dev %s, max_tgt_dev_commands "
|
||||
"%d (res %d)", tgt_dev, tgt_dev->dev->virt_name,
|
||||
tgt_dev->dev->max_tgt_dev_commands, res);
|
||||
TRACE_DBG("tgt_dev %p, dev %s, max_tgt_dev_commands %d (res %d)",
|
||||
tgt_dev, tgt_dev->dev->virt_name,
|
||||
tgt_dev->dev->max_tgt_dev_commands, res);
|
||||
break;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
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 (res > tgt_dev->dev->max_tgt_dev_commands)
|
||||
res = tgt_dev->dev->max_tgt_dev_commands;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
@@ -2557,11 +2557,12 @@ static ssize_t scst_tgt_forward_dst_store(struct kobject *kobj,
|
||||
list_for_each_entry(sess, &tgt->sess_list, 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 (tgt->tgt_forward_dst)
|
||||
set_bit(SCST_TGT_DEV_FORWARD_DST,
|
||||
&tgt_dev->tgt_dev_flags);
|
||||
@@ -2570,6 +2571,7 @@ static ssize_t scst_tgt_forward_dst_store(struct kobject *kobj,
|
||||
&tgt_dev->tgt_dev_flags);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
if (tgt->tgt_forward_dst)
|
||||
|
||||
@@ -6153,7 +6153,6 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd,
|
||||
int res;
|
||||
int i;
|
||||
struct scst_session *sess = mcmd->sess;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -6168,6 +6167,7 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd,
|
||||
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_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
@@ -6175,8 +6175,8 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd,
|
||||
|
||||
scst_call_dev_task_mgmt_fn_received(mcmd, tgt_dev);
|
||||
|
||||
tm_dbg_task_mgmt(tgt_dev->dev, "NEXUS LOSS SESS or "
|
||||
"ABORT ALL SESS or UNREG SESS",
|
||||
tm_dbg_task_mgmt(tgt_dev->dev,
|
||||
"NEXUS LOSS SESS or ABORT ALL SESS or UNREG SESS",
|
||||
(mcmd->fn == SCST_UNREG_SESS_TM));
|
||||
}
|
||||
if (nexus_loss_unreg_sess) {
|
||||
@@ -6184,7 +6184,8 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd,
|
||||
* We need at first abort all affected commands and
|
||||
* only then release them as part of clearing ACA
|
||||
*/
|
||||
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_clear_aca(tgt_dev,
|
||||
(tgt_dev != mcmd->mcmd_tgt_dev));
|
||||
}
|
||||
@@ -6253,22 +6254,23 @@ static int scst_abort_all_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd,
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
|
||||
list_for_each_entry_rcu(tgt_dev, head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
sess_tgt_dev_list_entry) {
|
||||
__scst_abort_task_set(mcmd, tgt_dev);
|
||||
|
||||
if (mcmd->sess == tgt_dev->sess)
|
||||
scst_call_dev_task_mgmt_fn_received(
|
||||
mcmd, tgt_dev);
|
||||
|
||||
tm_dbg_task_mgmt(tgt_dev->dev, "NEXUS LOSS or "
|
||||
"ABORT ALL", 0);
|
||||
tm_dbg_task_mgmt(tgt_dev->dev,
|
||||
"NEXUS LOSS or ABORT ALL", 0);
|
||||
}
|
||||
if (nexus_loss) {
|
||||
/*
|
||||
* We need at first abort all affected commands and
|
||||
* only then release them as part of clearing ACA
|
||||
*/
|
||||
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_clear_aca(tgt_dev,
|
||||
(tgt_dev != mcmd->mcmd_tgt_dev));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user