drm/amdkfd: Handle restart of kfd_ioctl_wait_events
authorFelix Kuehling <Felix.Kuehling@amd.com>
Thu, 4 Aug 2022 22:19:38 +0000 (18:19 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 10 Aug 2022 19:41:23 +0000 (15:41 -0400)
When kfd_ioctl_wait_events needs to restart due to a signal, we need to
update the timeout to account for the time already elapsed. We also need
to undo auto_reset of events that have signaled already, so that the
restarted ioctl will be able to count those signals again.

This fixes infinite hangs when kfd_ioctl_wait_events is interrupted by a
signal.

Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com>
Reviewed-and-tested-by: Xiaogang Chen <Xiaogang.Chen@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
drivers/gpu/drm/amd/amdkfd/kfd_events.c
drivers/gpu/drm/amd/amdkfd/kfd_priv.h

index 2b3d8bc..dc774dd 100644 (file)
@@ -874,7 +874,7 @@ static int kfd_ioctl_wait_events(struct file *filp, struct kfd_process *p,
        err = kfd_wait_on_events(p, args->num_events,
                        (void __user *)args->events_ptr,
                        (args->wait_for_all != 0),
-                       args->timeout, &args->wait_result);
+                       &args->timeout, &args->wait_result);
 
        return err;
 }
index 3942a56..83e3ce9 100644 (file)
@@ -894,7 +894,8 @@ static long user_timeout_to_jiffies(uint32_t user_timeout_ms)
        return msecs_to_jiffies(user_timeout_ms) + 1;
 }
 
-static void free_waiters(uint32_t num_events, struct kfd_event_waiter *waiters)
+static void free_waiters(uint32_t num_events, struct kfd_event_waiter *waiters,
+                        bool undo_auto_reset)
 {
        uint32_t i;
 
@@ -903,6 +904,9 @@ static void free_waiters(uint32_t num_events, struct kfd_event_waiter *waiters)
                        spin_lock(&waiters[i].event->lock);
                        remove_wait_queue(&waiters[i].event->wq,
                                          &waiters[i].wait);
+                       if (undo_auto_reset && waiters[i].activated &&
+                           waiters[i].event && waiters[i].event->auto_reset)
+                               set_event(waiters[i].event);
                        spin_unlock(&waiters[i].event->lock);
                }
 
@@ -911,7 +915,7 @@ static void free_waiters(uint32_t num_events, struct kfd_event_waiter *waiters)
 
 int kfd_wait_on_events(struct kfd_process *p,
                       uint32_t num_events, void __user *data,
-                      bool all, uint32_t user_timeout_ms,
+                      bool all, uint32_t *user_timeout_ms,
                       uint32_t *wait_result)
 {
        struct kfd_event_data __user *events =
@@ -920,7 +924,7 @@ int kfd_wait_on_events(struct kfd_process *p,
        int ret = 0;
 
        struct kfd_event_waiter *event_waiters = NULL;
-       long timeout = user_timeout_to_jiffies(user_timeout_ms);
+       long timeout = user_timeout_to_jiffies(*user_timeout_ms);
 
        event_waiters = alloc_event_waiters(num_events);
        if (!event_waiters) {
@@ -970,15 +974,11 @@ int kfd_wait_on_events(struct kfd_process *p,
                }
 
                if (signal_pending(current)) {
-                       /*
-                        * This is wrong when a nonzero, non-infinite timeout
-                        * is specified. We need to use
-                        * ERESTARTSYS_RESTARTBLOCK, but struct restart_block
-                        * contains a union with data for each user and it's
-                        * in generic kernel code that I don't want to
-                        * touch yet.
-                        */
                        ret = -ERESTARTSYS;
+                       if (*user_timeout_ms != KFD_EVENT_TIMEOUT_IMMEDIATE &&
+                           *user_timeout_ms != KFD_EVENT_TIMEOUT_INFINITE)
+                               *user_timeout_ms = jiffies_to_msecs(
+                                       max(0l, timeout-1));
                        break;
                }
 
@@ -1019,7 +1019,7 @@ int kfd_wait_on_events(struct kfd_process *p,
                                               event_waiters, events);
 
 out_unlock:
-       free_waiters(num_events, event_waiters);
+       free_waiters(num_events, event_waiters, ret == -ERESTARTSYS);
        mutex_unlock(&p->event_mutex);
 out:
        if (ret)
index d03a3b9..bf610e3 100644 (file)
@@ -1317,7 +1317,7 @@ void kfd_event_free_process(struct kfd_process *p);
 int kfd_event_mmap(struct kfd_process *process, struct vm_area_struct *vma);
 int kfd_wait_on_events(struct kfd_process *p,
                       uint32_t num_events, void __user *data,
-                      bool all, uint32_t user_timeout_ms,
+                      bool all, uint32_t *user_timeout_ms,
                       uint32_t *wait_result);
 void kfd_signal_event_interrupt(u32 pasid, uint32_t partial_id,
                                uint32_t valid_id_bits);