Efficient way to find task_struct by pid

Solution 1:

What's wrong with using one of the following?

extern struct task_struct *find_task_by_vpid(pid_t nr);
extern struct task_struct *find_task_by_pid_ns(pid_t nr,
            struct pid_namespace *ns);

Solution 2:

If you want to find the task_struct from a module, find_task_by_vpid(pid_t nr) etc. are not going to work since these functions are not exported.

In a module, you can use the following function instead:

pid_task(find_vpid(pid), PIDTYPE_PID);

Solution 3:

There is a better way to get the instance of task_struct from a module. Always try to use wrapper function/ helper routines because they are designed in such a way if driver programmer missed something, the kernel can take care by own. For eg - error handling, conditions checks etc.

/* Use below API and you will get a pointer of (struct task_struct *) */

taskp = get_pid_task(pid, PIDTYPE_PID);

and to get the PID of type pid_t, you need to use below API:

find_get_pid(pid_no);

You don't need to use rcu_read_lock() and rcu_read_unlock() while calling these API's because get_pid_task() internally calls rcu_read_lock(), rcu_read_unlock() before calling pid_task() and handles concurrency properly. That's why I have said above use these kind of wrapper always.

Snippet of get_pid_task() and find_get_pid() function below:

struct task_struct *get_pid_task(struct pid *pid, enum pid_type type)
{
    struct task_struct *result;
    rcu_read_lock();
    result = pid_task(pid, type);
    if (result)
        get_task_struct(result);
    rcu_read_unlock();
    return result;
}
EXPORT_SYMBOL_GPL(get_pid_task);

struct pid *find_get_pid(pid_t nr)
{
    struct pid *pid;

    rcu_read_lock();
    pid = get_pid(find_vpid(nr));
    rcu_read_unlock();

    return pid;
}
EXPORT_SYMBOL_GPL(find_get_pid);

PS: for more information on API's you can look at kernel/pid.c

Note that since get_pid_task() increases the reference count of the struct task_struct by one, you need to call put_task_struct() to reduce the refcount of the task by one.

Also, find_get_pid calls get_pid will increment the reference count of the struct pid by one, so don't forget to put_pid() when you no longer need it as well.