Which would result in NPE after when userspace connected again. Expired command would be freed either when handling command(by userspace), or when device was tearing down Signed-off-by: Sheng Yang <sheng@xxxxxxxxxx> --- drivers/target/target_core_user.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index f039d48..07cdfe4 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -572,9 +572,14 @@ 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); + + kfree(cmd->data_bitmap); + kmem_cache_free(tcmu_cmd_cache, cmd); return; } @@ -692,9 +697,6 @@ static int tcmu_check_expired_cmd(int id, void *p, void *data) target_complete_cmd(cmd->se_cmd, SAM_STAT_CHECK_CONDITION); cmd->se_cmd = NULL; - kfree(cmd->data_bitmap); - kmem_cache_free(tcmu_cmd_cache, cmd); - return 0; } @@ -999,12 +1001,13 @@ 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)) { + kfree(cmd->data_bitmap); + kmem_cache_free(tcmu_cmd_cache, cmd); return 0; + } return -EINVAL; } @@ -1019,6 +1022,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); @@ -1028,10 +1033,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) { -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe target-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html