On Fri, May 21, 2021 at 9:09 PM Andrei Vagin <avagin@xxxxxxxxx> wrote: > 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? or executed - the umcg stuff includes a userspace pointer, so it probably shouldn't normally be kept around across execve?