From 46698cc77d42a7cf5705366c10ba47b61f808f16 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 10 Mar 2019 01:01:59 +0000 Subject: [PATCH 1/4] scstadmin: Enable Perl warnings Make the Perl interpreter complain about dubious Perl constructs. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@8024 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scstadmin/scstadmin.sysfs/scst-1.0.0/lib/SCST/SCST.pm | 3 ++- scstadmin/scstadmin.sysfs/scstadmin | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/scstadmin/scstadmin.sysfs/scst-1.0.0/lib/SCST/SCST.pm b/scstadmin/scstadmin.sysfs/scst-1.0.0/lib/SCST/SCST.pm index 75d14a76a..b16bb135e 100644 --- a/scstadmin/scstadmin.sysfs/scst-1.0.0/lib/SCST/SCST.pm +++ b/scstadmin/scstadmin.sysfs/scst-1.0.0/lib/SCST/SCST.pm @@ -7,11 +7,12 @@ package SCST::SCST; # Copyright (c) 2005-2011 Mark R. Buechler # Copyright (c) 2011-2019 Bart Van Assche . +use strict; +use warnings; use 5.005; use Fcntl ':mode'; use IO::Handle; use IO::File; -use strict; use Carp qw(cluck); use POSIX; diff --git a/scstadmin/scstadmin.sysfs/scstadmin b/scstadmin/scstadmin.sysfs/scstadmin index 89fbe6928..93f953162 100755 --- a/scstadmin/scstadmin.sysfs/scstadmin +++ b/scstadmin/scstadmin.sysfs/scstadmin @@ -1,5 +1,8 @@ #!/usr/bin/perl +use strict; +use warnings; + my $Version = 'SCST Configurator v3.3.0-pre1'; # Configures SCST @@ -242,7 +245,6 @@ Examples: EndUsage } -use strict; use Cwd qw(abs_path); use File::Basename; use File::Spec; From 26d7fd0e3a4ca8940b57e3a419e8cb819d91c0b3 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 10 Mar 2019 01:10:11 +0000 Subject: [PATCH 2/4] scst: Do not suspend SCSI command processing when adding a device Since the only global data structure that is modified by the code that adds a device (scst_dev_list) is consistently protected by scst_mutex, suspending command processing when adding a device is not necessary. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@8025 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/scst_copy_mgr.c | 4 ---- scst/src/scst_lib.c | 6 +++--- scst/src/scst_main.c | 5 ----- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/scst/src/scst_copy_mgr.c b/scst/src/scst_copy_mgr.c index 5d3d3cb47..90eb25a7a 100644 --- a/scst/src/scst_copy_mgr.c +++ b/scst/src/scst_copy_mgr.c @@ -2547,7 +2547,6 @@ out: return res; } -/* scst_mutex supposed to be held and activities suspended */ static int scst_cm_dev_register(struct scst_device *dev, uint64_t lun) { int res, i; @@ -2556,7 +2555,6 @@ static int scst_cm_dev_register(struct scst_device *dev, uint64_t lun) TRACE_ENTRY(); - scst_assert_activity_suspended(); lockdep_assert_held(&scst_mutex); TRACE_DBG("dev %s, LUN %ld", dev->virt_name, (unsigned long)lun); @@ -2709,14 +2707,12 @@ out_unblock: goto out_resume; } -/* scst_mutex supposed to be held and activities suspended */ int scst_cm_on_dev_register(struct scst_device *dev) { int res = 0; TRACE_ENTRY(); - scst_assert_activity_suspended(); lockdep_assert_held(&scst_mutex); if (!scst_auto_cm_assignment || !dev->handler->auto_cm_assignment_possible) diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 877b4e893..d726c84e7 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -4181,15 +4181,15 @@ static int scst_dif_none_type1(struct scst_cmd *cmd); #define scst_dif_none_type1 scst_dif_none #endif -/* Called under scst_mutex and suspended activity */ -int scst_alloc_device(gfp_t gfp_mask, int nodeid, - struct scst_device **out_dev) +int scst_alloc_device(gfp_t gfp_mask, int nodeid, struct scst_device **out_dev) { struct scst_device *dev; int res = 0; TRACE_ENTRY(); + lockdep_assert_held(&scst_mutex); + dev = kmem_cache_alloc_node(scst_dev_cachep, gfp_mask, nodeid); if (dev == NULL) { PRINT_ERROR("%s", "Allocation of scst_device failed"); diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index 1abab803c..2c662ae8f 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -1347,10 +1347,6 @@ int scst_register_virtual_device_node(struct scst_dev_type *dev_handler, if (res != 0) goto out; - res = scst_suspend_activity(SCST_SUSPEND_TIMEOUT_USER); - if (res != 0) - goto out; - res = mutex_lock_interruptible(&scst_mutex); if (res != 0) goto out_resume; @@ -1419,7 +1415,6 @@ int scst_register_virtual_device_node(struct scst_dev_type *dev_handler, goto out_unreg; mutex_unlock(&scst_mutex); - scst_resume_activity(); res = dev->virt_id; From 53fdc293e25190a7712d214a17c30b6a02189bee Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 10 Mar 2019 01:18:17 +0000 Subject: [PATCH 3/4] scst: Use a per-cpu counter for sessions Make scst_alloc_session() initialize sess->refcnt to 1 instead of 0. Compensate this by removing an scst_get() call from __scst_register_session(). git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@8026 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/include/scst.h | 2 +- scst/src/scst_lib.c | 22 +++++++++++++++++++--- scst/src/scst_main.c | 2 ++ scst/src/scst_priv.h | 9 ++------- scst/src/scst_targ.c | 5 ++--- 5 files changed, 26 insertions(+), 14 deletions(-) diff --git a/scst/include/scst.h b/scst/include/scst.h index a3f608932..fec636745 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -1909,7 +1909,7 @@ struct scst_session { spinlock_t sess_list_lock; /* protects sess_cmd_list, etc */ - atomic_t refcnt; /* get/put counter */ + struct percpu_ref refcnt; /* get/put counter */ /* * Alive commands for this session. ToDo: make it part of the common diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index d726c84e7..4dd415c08 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -6995,11 +6995,18 @@ static void scst_clear_reservation(struct scst_tgt_dev *tgt_dev) return; } +static void scst_sess_release(struct percpu_ref *ref) +{ + struct scst_session *sess = container_of(ref, typeof(*sess), refcnt); + + scst_sched_session_free(sess); +} + struct scst_session *scst_alloc_session(struct scst_tgt *tgt, gfp_t gfp_mask, const char *initiator_name) { struct scst_session *sess; - int i; + int i, ret; TRACE_ENTRY(); @@ -7011,7 +7018,11 @@ 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); + ret = percpu_ref_init(&sess->refcnt, scst_sess_release, + PERCPU_REF_INIT_ATOMIC, GFP_KERNEL); + if (ret < 0) + goto out_free; + percpu_ref_switch_to_percpu(&sess->refcnt); 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]; @@ -7038,7 +7049,7 @@ struct scst_session *scst_alloc_session(struct scst_tgt *tgt, gfp_t gfp_mask, sess->initiator_name = kstrdup(initiator_name, gfp_mask); if (sess->initiator_name == NULL) { PRINT_ERROR("%s", "Unable to dup sess->initiator_name"); - goto out_free; + goto out_free_refcnt; } if (atomic_read(&scst_measure_latency)) { @@ -7054,6 +7065,9 @@ out: out_free_name: kfree(sess->initiator_name); +out_free_refcnt: + percpu_ref_exit(&sess->refcnt); + out_free: kmem_cache_free(scst_sess_cachep, sess); sess = NULL; @@ -7103,6 +7117,8 @@ void scst_free_session(struct scst_session *sess) if (sess->sess_name != sess->initiator_name) kfree(sess->sess_name); + percpu_ref_exit(&sess->refcnt); + kmem_cache_free(scst_sess_cachep, sess); TRACE_EXIT(); diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index 2c662ae8f..8941186e0 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -2676,6 +2676,8 @@ static void __exit exit_scst(void) scst_event_exit(); + rcu_barrier(); + #define DEINIT_CACHEP(p) do { \ kmem_cache_destroy(p); \ p = NULL; \ diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 9b1edb170..e0d378e0e 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -720,17 +720,12 @@ void scst_sched_session_free(struct scst_session *sess); static inline void scst_sess_get(struct scst_session *sess) { - atomic_inc(&sess->refcnt); - TRACE_DBG("Incrementing sess %p refcnt (new value %d)", - sess, atomic_read(&sess->refcnt)); + percpu_ref_get(&sess->refcnt); } static inline void scst_sess_put(struct scst_session *sess) { - TRACE_DBG("Decrementing sess %p refcnt (new value %d)", - sess, atomic_read(&sess->refcnt)-1); - if (atomic_dec_and_test(&sess->refcnt)) - scst_sched_session_free(sess); + percpu_ref_put(&sess->refcnt); } struct scst_cmd *scst_alloc_cmd(const uint8_t *cdb, diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 53aa4c651..b06826b51 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -8173,7 +8173,6 @@ static struct scst_session *__scst_register_session(struct scst_tgt *tgt, int at scst_sess_set_tgt_priv(sess, tgt_priv); sess->sess_mq = mq; - scst_sess_get(sess); /* one for registered session */ scst_sess_get(sess); /* one held until sess is inited */ if (atomic) { @@ -8372,7 +8371,7 @@ void scst_unregister_session(struct scst_session *sess, int wait, spin_unlock_irqrestore(&scst_mgmt_lock, flags); - scst_sess_put(sess); + percpu_ref_kill(&sess->refcnt); if (wait) { TRACE_DBG("Waiting for session %p to complete", sess); @@ -8464,7 +8463,7 @@ int scst_global_mgmt_thread(void *arg) switch (sess->shut_phase) { case SCST_SESS_SPH_SHUTDOWN: - sBUG_ON(atomic_read(&sess->refcnt) != 0); + sBUG_ON(!percpu_ref_is_zero(&sess->refcnt)); scst_free_session_callback(sess); break; default: From 759bdca73a332fcc5c397701291cdce29805be0b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 10 Mar 2019 01:24:43 +0000 Subject: [PATCH 4/4] scst: Use a per-cpu counter to track the number of commands per device git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@8027 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/include/scst.h | 10 +++++---- scst/src/scst_lib.c | 49 ++++++++++++++++++++++++++++++++++++++------ scst/src/scst_targ.c | 9 ++++---- 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/scst/include/scst.h b/scst/include/scst.h index fec636745..a68def432 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -2876,11 +2876,13 @@ struct scst_device { /* Device lock */ spinlock_t dev_lock ____cacheline_aligned_in_smp; -#ifdef CONFIG_SCST_PER_DEVICE_CMD_COUNT_LIMIT - /* How many cmds alive on this dev */ - atomic_t dev_cmd_count; -#endif + /* One more than the number of commands associated with this device. */ + struct percpu_ref dev_cmd_count; + struct work_struct free_work; + + struct completion *dev_freed_cmpl; + /* * Maximum count of uncompleted commands that an initiator could * queue on this device. Then it will start getting TASK QUEUE FULL diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 4dd415c08..28d1967e7 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -4181,6 +4181,32 @@ static int scst_dif_none_type1(struct scst_cmd *cmd); #define scst_dif_none_type1 scst_dif_none #endif +/* Called from thread context and hence may sleep. */ +static void scst_finally_free_device(struct work_struct *work) +{ + struct scst_device *dev = container_of(work, typeof(*dev), + free_work); + struct completion *c = dev->dev_freed_cmpl; + + scst_pr_cleanup(dev); + + kfree(dev->virt_name); + percpu_ref_exit(&dev->dev_cmd_count); + kmem_cache_free(scst_dev_cachep, dev); + + if (c) + complete(c); +} + +/* RCU callback. Must not sleep. */ +static void scst_release_device(struct percpu_ref *ref) +{ + struct scst_device *dev; + + dev = container_of(ref, typeof(*dev), dev_cmd_count); + schedule_work(&dev->free_work); +} + int scst_alloc_device(gfp_t gfp_mask, int nodeid, struct scst_device **out_dev) { struct scst_device *dev; @@ -4199,8 +4225,13 @@ int scst_alloc_device(gfp_t gfp_mask, int nodeid, struct scst_device **out_dev) memset(dev, 0, sizeof(*dev)); dev->handler = &scst_null_devtype; -#ifdef CONFIG_SCST_PER_DEVICE_CMD_COUNT_LIMIT - atomic_set(&dev->dev_cmd_count, 0); + INIT_WORK(&dev->free_work, scst_finally_free_device); + res = percpu_ref_init(&dev->dev_cmd_count, scst_release_device, + PERCPU_REF_INIT_ATOMIC, GFP_KERNEL); + if (res < 0) + goto free_dev; +#ifndef CONFIG_SCST_PER_DEVICE_CMD_COUNT_LIMIT + percpu_ref_switch_to_percpu(&dev->dev_cmd_count); #endif scst_init_mem_lim(&dev->dev_mem_lim); spin_lock_init(&dev->dev_lock); @@ -4234,10 +4265,16 @@ int scst_alloc_device(gfp_t gfp_mask, int nodeid, struct scst_device **out_dev) out: TRACE_EXIT_RES(res); return res; + +free_dev: + kmem_cache_free(scst_dev_cachep, dev); + goto out; } void scst_free_device(struct scst_device *dev) { + DECLARE_COMPLETION_ONSTACK(c); + TRACE_ENTRY(); EXTRACHECKS_BUG_ON(dev->dev_scsi_atomic_cmd_active != 0); @@ -4257,11 +4294,11 @@ void scst_free_device(struct scst_device *dev) scst_deinit_threads(&dev->dev_cmd_threads); - scst_pr_cleanup(dev); - - kfree(dev->virt_name); - kmem_cache_free(scst_dev_cachep, dev); + dev->dev_freed_cmpl = &c; + percpu_ref_kill(&dev->dev_cmd_count); + wait_for_completion(&c); + TRACE_EXIT(); return; } diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index b06826b51..5ca787b74 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -4503,9 +4503,7 @@ static int scst_pre_xmit_response1(struct scst_cmd *cmd) */ smp_mb__before_atomic_dec(); atomic_dec(&cmd->tgt_dev->tgt_dev_cmd_count); -#ifdef CONFIG_SCST_PER_DEVICE_CMD_COUNT_LIMIT - atomic_dec(&cmd->dev->dev_cmd_count); -#endif + percpu_ref_put(&cmd->dev->dev_cmd_count); if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE)) scst_on_hq_cmd_response(cmd); else if (unlikely(!cmd->sent_for_exec)) { @@ -5134,6 +5132,7 @@ static int __scst_init_cmd(struct scst_cmd *cmd) if (likely(res == 0)) { struct scst_tgt_dev *tgt_dev = cmd->tgt_dev; struct scst_device *dev = cmd->dev; + unsigned long __percpu *a __maybe_unused; bool failure = false; int cnt; @@ -5149,8 +5148,10 @@ static int __scst_init_cmd(struct scst_cmd *cmd) failure = true; } + percpu_ref_get(&dev->dev_cmd_count); #ifdef CONFIG_SCST_PER_DEVICE_CMD_COUNT_LIMIT - cnt = atomic_inc_return(&dev->dev_cmd_count); + sBUG_ON(__ref_is_percpu(&dev->dev_cmd_count, &a)); + cnt = atomic_long_read(&dev->dev_cmd_count.count); if (unlikely(cnt > SCST_MAX_DEV_COMMANDS)) { if (!failure) { TRACE(TRACE_FLOW_CONTROL,