]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
target/user: Don't free expired command when time out
authorSheng Yang <sheng@yasker.org>
Fri, 26 Feb 2016 22:59:58 +0000 (14:59 -0800)
committerChuck Anderson <chuck.anderson@oracle.com>
Fri, 23 Jun 2017 04:10:48 +0000 (21:10 -0700)
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

Reviewed-by: Andy Grover <agrover@redhat.com>
Signed-off-by: Sheng Yang <sheng@yasker.org>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Orabug: 25395066
(cherry picked from commit b25c786399367b9a8bd955d8496669d019409bec)
Signed-off-by: Kyle Fortin <kyle.fortin@oracle.com>
Reviewed-by: Shan Hai <shan.hai@oracle.com>
drivers/target/target_core_user.c

index 51ba5c370816958a1a07c96d91b11707dca8b070..e0e98c66323c63cb088fec0b743c4c958886edb5 100644 (file)
@@ -558,9 +558,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;
        }
 
@@ -974,18 +978,20 @@ 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;
 }
 
 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);
@@ -994,10 +1000,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) {