diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 2e322d9a1..50d60e339 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -4758,11 +4758,9 @@ int scst_acg_del_lun(struct scst_acg *acg, uint64_t lun, synchronize_rcu(); mutex_lock(&scst_mutex); - - list_for_each_entry_safe(tgt_dev, tt, &tgt_dev_list, - extra_tgt_dev_list_entry) { + list_for_each_entry_safe(tgt_dev, tt, &tgt_dev_list, extra_tgt_dev_list_entry) scst_free_tgt_dev(tgt_dev); - } + scst_free_acg_dev(acg_dev); out: @@ -4808,10 +4806,9 @@ int scst_acg_repl_lun(struct scst_acg *acg, struct kobject *parent, synchronize_rcu(); mutex_lock(&scst_mutex); - list_for_each_entry_safe(tgt_dev, tt, &tgt_dev_list, - extra_tgt_dev_list_entry) { + list_for_each_entry_safe(tgt_dev, tt, &tgt_dev_list, extra_tgt_dev_list_entry) scst_free_tgt_dev(tgt_dev); - } + if (acg_dev) scst_free_acg_dev(acg_dev); @@ -4931,20 +4928,20 @@ static void scst_del_acg(struct scst_acg *acg) 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_acn *acn, *acn_tmp; struct scst_session *sess; struct scst_tgt *tgt = acg->tgt; + struct scst_tgt_dev *tgt_dev, *tt; + LIST_HEAD(tgt_dev_list); + + lockdep_assert_held(&scst_mutex); /* For procfs acg->tgt could be NULL */ TRACE_DBG("Freeing acg %s/%s", tgt ? tgt->tgt_name : "(tgt=NULL)", acg->acg_name); - list_for_each_entry_safe(acg_dev, acg_dev_tmp, &acg->acg_dev_list, - acg_dev_list_entry) { - struct scst_tgt_dev *tgt_dev, *tt; - - list_for_each_entry_safe(tgt_dev, tt, - &acg_dev->dev->dev_tgt_dev_list, - dev_tgt_dev_list_entry) { + list_for_each_entry_safe(acg_dev, acg_dev_tmp, &acg->acg_dev_list, acg_dev_list_entry) { + 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) { sess = tgt_dev->sess; @@ -4952,17 +4949,19 @@ static void scst_free_acg(struct scst_acg *acg) scst_del_tgt_dev(tgt_dev); mutex_unlock(&sess->tgt_dev_list_mutex); - synchronize_rcu(); - scst_free_tgt_dev(tgt_dev); + list_add_tail(&tgt_dev->extra_tgt_dev_list_entry, &tgt_dev_list); } } scst_free_acg_dev(acg_dev); } - list_for_each_entry_safe(acn, acnt, &acg->acn_list, acn_list_entry) { - scst_free_acn(acn, - list_is_last(&acn->acn_list_entry, &acg->acn_list)); - } + synchronize_rcu(); + + list_for_each_entry_safe(tgt_dev, tt, &tgt_dev_list, extra_tgt_dev_list_entry) + scst_free_tgt_dev(tgt_dev); + + list_for_each_entry_safe(acn, acn_tmp, &acg->acn_list, acn_list_entry) + scst_free_acn(acn, list_is_last(&acn->acn_list_entry, &acg->acn_list)); kfree(acg->acg_name); kfree(acg); @@ -4982,7 +4981,10 @@ static void scst_release_acg_work(struct work_struct *work) struct scst_acg *acg = release_work->acg; kfree(release_work); + + mutex_lock(&scst_mutex); scst_free_acg(acg); + mutex_unlock(&scst_mutex); } static void scst_release_acg(struct kref *kref) @@ -5701,6 +5703,37 @@ static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev) return; } +/* scst_mutex supposed to be held */ +static void scst_sess_free_tgt_devs(struct scst_session *sess) +{ + int i; + struct scst_tgt_dev *tgt_dev, *tt; + LIST_HEAD(tgt_dev_list); + + TRACE_ENTRY(); + + lockdep_assert_held(&scst_mutex); + + 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, tt, head, sess_tgt_dev_list_entry) { + scst_del_tgt_dev(tgt_dev); + list_add_tail(&tgt_dev->extra_tgt_dev_list_entry, &tgt_dev_list); + } + INIT_LIST_HEAD(head); + } + mutex_unlock(&sess->tgt_dev_list_mutex); + + synchronize_rcu(); + + list_for_each_entry_safe(tgt_dev, tt, &tgt_dev_list, extra_tgt_dev_list_entry) + scst_free_tgt_dev(tgt_dev); + + TRACE_EXIT(); +} + /* scst_mutex supposed to be held */ int scst_sess_alloc_tgt_devs(struct scst_session *sess) { @@ -5710,6 +5743,8 @@ int scst_sess_alloc_tgt_devs(struct scst_session *sess) TRACE_ENTRY(); + lockdep_assert_held(&scst_mutex); + list_for_each_entry(acg_dev, &sess->acg->acg_dev_list, acg_dev_list_entry) { res = scst_alloc_add_tgt_dev(sess, acg_dev, &tgt_dev); @@ -5728,31 +5763,6 @@ int scst_sess_alloc_tgt_devs(struct scst_session *sess) goto out; } -void scst_sess_free_tgt_devs(struct scst_session *sess) -{ - int i; - struct scst_tgt_dev *tgt_dev, *t; - - TRACE_ENTRY(); - - 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, - sess_tgt_dev_list_entry) { - scst_del_tgt_dev(tgt_dev); - synchronize_rcu(); - scst_free_tgt_dev(tgt_dev); - } - INIT_LIST_HEAD(head); - } - mutex_unlock(&sess->tgt_dev_list_mutex); - - TRACE_EXIT(); - return; -} - /* The activity supposed to be suspended and scst_mutex held */ int scst_acg_add_acn(struct scst_acg *acg, const char *name) { diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 492763029..88545647e 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -365,7 +365,6 @@ struct scst_acg *scst_find_acg(const struct scst_session *sess); void scst_check_reassign_sessions(void); int scst_sess_alloc_tgt_devs(struct scst_session *sess); -void scst_sess_free_tgt_devs(struct scst_session *sess); struct scst_tgt_dev *scst_lookup_tgt_dev(struct scst_session *sess, u64 lun); void scst_nexus_loss(struct scst_tgt_dev *tgt_dev, bool queue_UA);