Linux 通过pid查找task_struct的有效方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8547332/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 03:42:18  来源:igfitidea点击:

Efficient way to find task_struct by pid

clinuxprocesslinux-kernel

提问by zer0stimulus

Is there an efficient way of finding the task_structfor a specified PID, without iterating through the task_structlist?

是否有一种有效的方法可以找到task_struct指定 PID 的 ,而无需遍历task_struct列表?

采纳答案by j?rgensen

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);

回答by mdd

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

如果你想task_struct从一个模块中找到,find_task_by_vpid(pid_t nr)等等都不会工作,因为这些函数没有被导出。

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

在模块中,您可以改用以下函数:

pid_task(find_vpid(pid), PIDTYPE_PID);

回答by red0ct

No one mentioned that the pid_task()function and the pointer(which you obtain from it) should be used inside RCU critical section(because it uses RCU-protected data structure). Otherwisethere can be use-after-free BUG.
There are lots of cases of using pid_task()in Linux kernel sources (e.g. in posix_timer_event()).
For example:

没有人提到应该在 RCU 临界区中使用pid_task()函数和指针(您从中获得)(因为它使用 RCU 保护的数据结构)。否则会出现use-after-free BUG。 有很多在 Linux 内核源代码中使用的情况(例如在 中)。 例如:
pid_task()posix_timer_event()

rcu_read_lock();
/* search through the global namespace */
task = pid_task(find_pid_ns(pid_num, &init_pid_ns), PIDTYPE_PID);
if (task)
    printk(KERN_INFO "1. pid: %d, state: %#lx\n",
           pid_num, task->state); /* valid task dereference */
rcu_read_unlock(); /* after it returns - task pointer becomes invalid! */

if (task)
    printk(KERN_INFO "2. pid: %d, state: %#lx\n",
           pid_num, task->state); /* may be successful,
                                   * but is buggy (task dereference is INVALID!) */

Find out more about RCU API from Kernel.org

Kernel.org了解有关 RCU API 的更多信息



P.S. also you can just use the special API functions like find_task_by_pid_ns()and find_task_by_vpid()under the rcu_read_lock().

PS你也可以只使用特殊的API功能,如find_task_by_pid_ns()find_task_by_vpid()rcu_read_lock()

The first one is for searching through the particular namespace:

第一个用于搜索特定的命名空间:

task = find_task_by_pid_ns(pid_num, &init_pid_ns); /* e.g. init namespace */

The second one is for searching through the namespace of currenttask.

第二个用于搜索current任务的命名空间。

回答by shashank arora

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.

有一种更好的方法可以从模块中获取 task_struct 的实例。总是尝试使用包装函数/帮助程序,因为它们的设计方式是如果驱动程序程序员遗漏了什么,内核可以自行处理。例如 - 错误处理、条件检查等。

/* 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 -

并获取 pid_t 类型的 PID。您需要使用以下 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.

在调用这些 API 时,您不需要使用“ rcu_read_lock()”和“ rcu_read_unlock()”,因为“ get_pid_task()”在调用“ pid_task()”之前会在内部调用 rcu_read_lock(),rcu_read_unlock()并正确处理并发。这就是为什么我在上面说过总是使用这种包装器。

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

下面的 get_pid_task() 和 find_get_pid() 函数的片段:-

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);

In a kernel module, you can use wrapper function in the following way as well -

在内核模块中,您也可以通过以下方式使用包装函数 -

taskp = get_pid_task(find_get_pid(PID),PIDTYPE_PID);

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

PS:有关 API 的更多信息,您可以查看 kernel/pid.c