drm/amdkfd: Clean up kfd_wait_on_events

Cleaned up the code while resolving some potential bugs and
inconsistencies in the process.

Clean-ups:
* Remove enum kfd_event_wait_result, which duplicates
  KFD_IOC_EVENT_RESULT definitions
* alloc_event_waiters can be called without holding p->event_mutex
* Return an error code from copy_signaled_event_data instead of bool
* Clean up error handling code paths to minimize duplication in
  kfd_wait_on_events

Fixes:
* Consistently return an error code from kfd_wait_on_events and set
  wait_result to KFD_IOC_WAIT_RESULT_FAIL in all failure cases.
* Always call free_waiters while holding p->event_mutex
* copy_signaled_event_data might sleep. Don't call it while the task state
  is TASK_INTERRUPTIBLE.

Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com>
Acked-by: Oded Gabbay <oded.gabbay@gmail.com>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
This commit is contained in:
Felix Kuehling 2017-10-27 19:35:22 -04:00 committed by Oded Gabbay
parent d9aeec4cbb
commit fdf0c8332a
3 changed files with 32 additions and 52 deletions

View File

@ -835,15 +835,12 @@ static int kfd_ioctl_wait_events(struct file *filp, struct kfd_process *p,
void *data) void *data)
{ {
struct kfd_ioctl_wait_events_args *args = data; struct kfd_ioctl_wait_events_args *args = data;
enum kfd_event_wait_result wait_result;
int err; int err;
err = kfd_wait_on_events(p, args->num_events, err = kfd_wait_on_events(p, args->num_events,
(void __user *)args->events_ptr, (void __user *)args->events_ptr,
(args->wait_for_all != 0), (args->wait_for_all != 0),
args->timeout, &wait_result); args->timeout, &args->wait_result);
args->wait_result = wait_result;
return err; return err;
} }

View File

@ -668,7 +668,7 @@ static bool test_event_condition(bool all, uint32_t num_events,
* Copy event specific data, if defined. * Copy event specific data, if defined.
* Currently only memory exception events have additional data to copy to user * Currently only memory exception events have additional data to copy to user
*/ */
static bool copy_signaled_event_data(uint32_t num_events, static int copy_signaled_event_data(uint32_t num_events,
struct kfd_event_waiter *event_waiters, struct kfd_event_waiter *event_waiters,
struct kfd_event_data __user *data) struct kfd_event_data __user *data)
{ {
@ -686,11 +686,11 @@ static bool copy_signaled_event_data(uint32_t num_events,
src = &event->memory_exception_data; src = &event->memory_exception_data;
if (copy_to_user(dst, src, if (copy_to_user(dst, src,
sizeof(struct kfd_hsa_memory_exception_data))) sizeof(struct kfd_hsa_memory_exception_data)))
return false; return -EFAULT;
} }
} }
return true; return 0;
} }
@ -727,7 +727,7 @@ static void free_waiters(uint32_t num_events, struct kfd_event_waiter *waiters)
int kfd_wait_on_events(struct kfd_process *p, int kfd_wait_on_events(struct kfd_process *p,
uint32_t num_events, void __user *data, uint32_t num_events, void __user *data,
bool all, uint32_t user_timeout_ms, bool all, uint32_t user_timeout_ms,
enum kfd_event_wait_result *wait_result) uint32_t *wait_result)
{ {
struct kfd_event_data __user *events = struct kfd_event_data __user *events =
(struct kfd_event_data __user *) data; (struct kfd_event_data __user *) data;
@ -737,18 +737,18 @@ int kfd_wait_on_events(struct kfd_process *p,
struct kfd_event_waiter *event_waiters = NULL; 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) {
ret = -ENOMEM;
goto out;
}
mutex_lock(&p->event_mutex); mutex_lock(&p->event_mutex);
/* Set to something unreasonable - this is really /* Set to something unreasonable - this is really
* just a bool for now. * just a bool for now.
*/ */
*wait_result = KFD_WAIT_TIMEOUT; *wait_result = KFD_IOC_WAIT_RESULT_TIMEOUT;
event_waiters = alloc_event_waiters(num_events);
if (!event_waiters) {
ret = -ENOMEM;
goto fail;
}
for (i = 0; i < num_events; i++) { for (i = 0; i < num_events; i++) {
struct kfd_event_data event_data; struct kfd_event_data event_data;
@ -756,23 +756,21 @@ int kfd_wait_on_events(struct kfd_process *p,
if (copy_from_user(&event_data, &events[i], if (copy_from_user(&event_data, &events[i],
sizeof(struct kfd_event_data))) { sizeof(struct kfd_event_data))) {
ret = -EFAULT; ret = -EFAULT;
goto fail; goto out_unlock;
} }
ret = init_event_waiter_get_status(p, &event_waiters[i], ret = init_event_waiter_get_status(p, &event_waiters[i],
event_data.event_id, i); event_data.event_id, i);
if (ret) if (ret)
goto fail; goto out_unlock;
} }
/* Check condition once. */ /* Check condition once. */
if (test_event_condition(all, num_events, event_waiters)) { if (test_event_condition(all, num_events, event_waiters)) {
if (copy_signaled_event_data(num_events, *wait_result = KFD_IOC_WAIT_RESULT_COMPLETE;
event_waiters, events)) ret = copy_signaled_event_data(num_events,
*wait_result = KFD_WAIT_COMPLETE; event_waiters, events);
else goto out_unlock;
*wait_result = KFD_WAIT_ERROR;
free_waiters(num_events, event_waiters);
} else { } else {
/* Add to wait lists if we need to wait. */ /* Add to wait lists if we need to wait. */
for (i = 0; i < num_events; i++) for (i = 0; i < num_events; i++)
@ -781,12 +779,6 @@ int kfd_wait_on_events(struct kfd_process *p,
mutex_unlock(&p->event_mutex); mutex_unlock(&p->event_mutex);
/* Return if all waits were already satisfied. */
if (*wait_result != KFD_WAIT_TIMEOUT) {
__set_current_state(TASK_RUNNING);
return ret;
}
while (true) { while (true) {
if (fatal_signal_pending(current)) { if (fatal_signal_pending(current)) {
ret = -EINTR; ret = -EINTR;
@ -818,16 +810,12 @@ int kfd_wait_on_events(struct kfd_process *p,
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (test_event_condition(all, num_events, event_waiters)) { if (test_event_condition(all, num_events, event_waiters)) {
if (copy_signaled_event_data(num_events, *wait_result = KFD_IOC_WAIT_RESULT_COMPLETE;
event_waiters, events))
*wait_result = KFD_WAIT_COMPLETE;
else
*wait_result = KFD_WAIT_ERROR;
break; break;
} }
if (timeout <= 0) { if (timeout <= 0) {
*wait_result = KFD_WAIT_TIMEOUT; *wait_result = KFD_IOC_WAIT_RESULT_TIMEOUT;
break; break;
} }
@ -835,19 +823,20 @@ int kfd_wait_on_events(struct kfd_process *p,
} }
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
/* copy_signaled_event_data may sleep. So this has to happen
* after the task state is set back to RUNNING.
*/
if (!ret && *wait_result == KFD_IOC_WAIT_RESULT_COMPLETE)
ret = copy_signaled_event_data(num_events,
event_waiters, events);
mutex_lock(&p->event_mutex); mutex_lock(&p->event_mutex);
out_unlock:
free_waiters(num_events, event_waiters); free_waiters(num_events, event_waiters);
mutex_unlock(&p->event_mutex); mutex_unlock(&p->event_mutex);
out:
return ret; if (ret)
*wait_result = KFD_IOC_WAIT_RESULT_FAIL;
fail:
if (event_waiters)
free_waiters(num_events, event_waiters);
mutex_unlock(&p->event_mutex);
*wait_result = KFD_WAIT_ERROR;
return ret; return ret;
} }

View File

@ -726,19 +726,13 @@ uint64_t kfd_get_number_elems(struct kfd_dev *kfd);
extern const struct kfd_event_interrupt_class event_interrupt_class_cik; extern const struct kfd_event_interrupt_class event_interrupt_class_cik;
extern const struct kfd_device_global_init_class device_global_init_class_cik; extern const struct kfd_device_global_init_class device_global_init_class_cik;
enum kfd_event_wait_result {
KFD_WAIT_COMPLETE,
KFD_WAIT_TIMEOUT,
KFD_WAIT_ERROR
};
void kfd_event_init_process(struct kfd_process *p); void kfd_event_init_process(struct kfd_process *p);
void kfd_event_free_process(struct kfd_process *p); void kfd_event_free_process(struct kfd_process *p);
int kfd_event_mmap(struct kfd_process *process, struct vm_area_struct *vma); int kfd_event_mmap(struct kfd_process *process, struct vm_area_struct *vma);
int kfd_wait_on_events(struct kfd_process *p, int kfd_wait_on_events(struct kfd_process *p,
uint32_t num_events, void __user *data, uint32_t num_events, void __user *data,
bool all, uint32_t user_timeout_ms, bool all, uint32_t user_timeout_ms,
enum kfd_event_wait_result *wait_result); uint32_t *wait_result);
void kfd_signal_event_interrupt(unsigned int pasid, uint32_t partial_id, void kfd_signal_event_interrupt(unsigned int pasid, uint32_t partial_id,
uint32_t valid_id_bits); uint32_t valid_id_bits);
void kfd_signal_iommu_event(struct kfd_dev *dev, void kfd_signal_iommu_event(struct kfd_dev *dev,