|
From: Gleb C. <lna...@ya...> - 2023-04-17 14:17:18
|
Commit: c9198bb GitHub URL: https://github.com/SCST-project/scst/commit/c9198bb027afd42590e780eb579e35a387929136 Author: Gleb Chesnokov Date: 2023-04-17T17:16:42+03:00 Log Message: ----------- 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 3e64094b0c14 ("scst_sysfs: Do not suspend I/O for LUN management"). Modified Paths: -------------- scst/src/scst_lib.c | 20 ++++++++++----- scst/src/scst_sysfs.c | 4 ++- scst/src/scst_targ.c | 18 +++++++------ 3 files changed, 26 insertions(+), 16 deletions(-) =================================================================== diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 3de9fbc..d7b1c6b 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -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); diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index b5d1cfe..14db134 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -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) diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index d57a706..8667b3b 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -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)); } |