在linux内核中遍历进程树

时间:2011-11-21 05:54:02

标签: recursion linux-kernel kernel kernel-module

我在内核模块中有以下代码,它在进程树的基础上打印进程名称和uid直到init进程:

// recursivly walk the task's parent until we reach init

void parent_task_walk(struct task_struct *task) {

    struct task_struct *parent;
    char filename[MAX_FILE_LEN];

    if (task && task->mm) {

        parent = get_task_parent(task);

        printk("%s (uid:%d)", exe_from_mm(task->mm, filename, MAX_FILE_LEN),
            get_task_uid(task));

        if (parent && task->pid != 1) {
            printk(", ");
            parent_task_walk(parent);
        }
    }

}

注意:我使用了一些引用真实内核函数的宏,因为这是针对内核模块的多个版本。源代码位于此文件中:https://github.com/cormander/tpe-lkm/blob/319e1e29ea23055cca1c0a3bce3c865def14d3d2/core.c#L61

输出最终看起来像这样:

/bin/bash (uid:500), /usr/sbin/sshd (uid:500), /usr/sbin/sshd (uid:0), /usr/sbin/sshd (uid:0), /sbin/init (uid:0)

这是一个递归函数。你可以想象,当你启动200个bash shell然后触发事件时,事情会变得很糟糕。我不确定究竟发生了什么,但机器冻结了。内核耗尽了我假设的堆栈空间,去了OOM,然后自己拍摄了吗?

我想知道处理这种情况的最佳方法是什么。我看到了几个选项:

1)在N个进程

之后停止遍历进程树

2)在一些字符数组(最终将被打印)已满后停止行走

3)使用goto而不是递归函数,但仍然遵守选项#1和#2

中的新规则

4)使用一些你将为我阐述的其他非递归方法

这发生在内核空间,所以不是最好客的环境。任何人都可以指出最好的方法吗?

1 个答案:

答案 0 :(得分:5)

事实上,您可能会因为使用递归函数而发生内核崩溃。

你可以使用一个非常简单的循环而不是你的递归函数......你是来自一个只有函数编程的世界吗? while循环在C中是标准的,但如果你真的想使用goto,你可以......;)这是使用循环的代码。

void parent_task_walk(struct task_struct* task) 
{

    struct task_struct *parent = NULL;
    char filename[MAX_FILE_LEN];


    while (task && task->mm) {

        parent = get_task_parent(task);

        printk("%s (uid:%d)",
               exe_from_mm(task->mm, filename, MAX_FILE_LEN),
               get_task_uid(task));

        if (parent && task->pid != 1)
            printk(", ");

        task = parent;
    }

}