diff --git a/scst/include/scst.h b/scst/include/scst.h index a68def432..bdb88a519 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -2876,13 +2876,22 @@ struct scst_device { /* Device lock */ spinlock_t dev_lock ____cacheline_aligned_in_smp; - /* One more than the number of commands associated with this device. */ - struct percpu_ref dev_cmd_count; +#ifdef CONFIG_SCST_PER_DEVICE_CMD_COUNT_LIMIT + /* Number of commands associated with this device. */ + atomic_t dev_cmd_count; +#endif + + /* + * One more than the number of commands associated with this device + * and the number of SCST data structures holding a reference on this + * data structure. + */ + struct percpu_ref refcnt; 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 612946eb6..8b128036d 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -4191,7 +4191,7 @@ static void scst_finally_free_device(struct work_struct *work) scst_pr_cleanup(dev); kfree(dev->virt_name); - percpu_ref_exit(&dev->dev_cmd_count); + percpu_ref_exit(&dev->refcnt); kmem_cache_free(scst_dev_cachep, dev); if (c) @@ -4201,9 +4201,8 @@ static void scst_finally_free_device(struct work_struct *work) /* RCU callback. Must not sleep. */ static void scst_release_device(struct percpu_ref *ref) { - struct scst_device *dev; + struct scst_device *dev = container_of(ref, typeof(*dev), refcnt); - dev = container_of(ref, typeof(*dev), dev_cmd_count); schedule_work(&dev->free_work); } @@ -4226,12 +4225,13 @@ int scst_alloc_device(gfp_t gfp_mask, int nodeid, struct scst_device **out_dev) dev->handler = &scst_null_devtype; INIT_WORK(&dev->free_work, scst_finally_free_device); - res = percpu_ref_init(&dev->dev_cmd_count, scst_release_device, + res = percpu_ref_init(&dev->refcnt, 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); + percpu_ref_switch_to_percpu(&dev->refcnt); +#ifdef CONFIG_SCST_PER_DEVICE_CMD_COUNT_LIMIT + atomic_set(&dev->dev_cmd_count, 0); #endif scst_init_mem_lim(&dev->dev_mem_lim); spin_lock_init(&dev->dev_lock); @@ -4295,7 +4295,7 @@ void scst_free_device(struct scst_device *dev) scst_deinit_threads(&dev->dev_cmd_threads); dev->dev_freed_cmpl = &c; - percpu_ref_kill(&dev->dev_cmd_count); + percpu_ref_kill(&dev->refcnt); wait_for_completion(&c); diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 282e56724..d03063ebe 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -4505,7 +4505,10 @@ static int scst_pre_xmit_response1(struct scst_cmd *cmd) */ smp_mb__before_atomic_dec(); atomic_dec(&cmd->tgt_dev->tgt_dev_cmd_count); - percpu_ref_put(&cmd->dev->dev_cmd_count); + percpu_ref_put(&cmd->dev->refcnt); +#ifdef CONFIG_SCST_PER_DEVICE_CMD_COUNT_LIMIT + atomic_dec(&cmd->dev->dev_cmd_count); +#endif 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,7 +5137,6 @@ 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; @@ -5150,10 +5152,10 @@ static int __scst_init_cmd(struct scst_cmd *cmd) failure = true; } - percpu_ref_get(&dev->dev_cmd_count); + percpu_ref_get(&dev->refcnt); #ifdef CONFIG_SCST_PER_DEVICE_CMD_COUNT_LIMIT - sBUG_ON(__ref_is_percpu(&dev->dev_cmd_count, &a)); - cnt = atomic_long_read(&dev->dev_cmd_count.count); + atomic_inc(&dev->dev_cmd_count); + cnt = atomic_read(&dev->dev_cmd_count); if (unlikely(cnt > SCST_MAX_DEV_COMMANDS)) { if (!failure) { TRACE(TRACE_FLOW_CONTROL,