On Thu, May 20, 2021 at 11:36:09AM -0700, Peter Oskolkov wrote: > @@ -67,7 +137,75 @@ SYSCALL_DEFINE4(umcg_register_task, u32, api_version, u32, flags, u32, group_id, > */ > SYSCALL_DEFINE1(umcg_unregister_task, u32, flags) > { > - return -ENOSYS; > + struct umcg_task_data *utd; > + int ret = -EINVAL; > + > + rcu_read_lock(); > + utd = rcu_dereference(current->umcg_task_data); > + > + if (!utd || flags) > + goto out; > + > + task_lock(current); > + rcu_assign_pointer(current->umcg_task_data, NULL); > + task_unlock(current); > + > + ret = 0; > + > +out: > + rcu_read_unlock(); > + if (!ret && utd) { > + synchronize_rcu(); synchronize_rcu is expensive. Do we really need to call it here? Can we use kfree_rcu? Where is task->umcg_task_data freed when a task is destroyed? > + kfree(utd); > + } > + return ret; > +} > +