diff options
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/target_core_user.c | 25 |
1 files changed, 17 insertions, 8 deletions
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index b1539f357429..d0655913896b 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -560,9 +560,13 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * struct tcmu_dev *udev = cmd->tcmu_dev; if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) { - /* cmd has been completed already from timeout, just reclaim data - ring space */ + /* + * cmd has been completed already from timeout, just reclaim + * data ring space and free cmd + */ free_data_area(udev, cmd); + + kmem_cache_free(tcmu_cmd_cache, cmd); return; } @@ -976,12 +980,12 @@ err_vzalloc: return ret; } -static int tcmu_check_pending_cmd(int id, void *p, void *data) +static int tcmu_check_and_free_pending_cmd(struct tcmu_cmd *cmd) { - struct tcmu_cmd *cmd = p; - - if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) + if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) { + kmem_cache_free(tcmu_cmd_cache, cmd); return 0; + } return -EINVAL; } @@ -996,6 +1000,8 @@ static void tcmu_dev_call_rcu(struct rcu_head *p) static void tcmu_free_device(struct se_device *dev) { struct tcmu_dev *udev = TCMU_DEV(dev); + struct tcmu_cmd *cmd; + bool all_expired = true; int i; del_timer_sync(&udev->timeout); @@ -1004,10 +1010,13 @@ static void tcmu_free_device(struct se_device *dev) /* Upper layer should drain all requests before calling this */ spin_lock_irq(&udev->commands_lock); - i = idr_for_each(&udev->commands, tcmu_check_pending_cmd, NULL); + idr_for_each_entry(&udev->commands, cmd, i) { + if (tcmu_check_and_free_pending_cmd(cmd) != 0) + all_expired = false; + } idr_destroy(&udev->commands); spin_unlock_irq(&udev->commands_lock); - WARN_ON(i); + WARN_ON(!all_expired); /* Device was configured */ if (udev->uio_info.uio_dev) { |