Linux内核:来自“open”系统调用的printk不起作用

6

我有一个疑问。

我打开了内核并更改了目录linux-3.1.1/fs/open.c

我在open.c中更改了以下代码。

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)
{
    long ret;
    printk(KERN_EMERG "Testing\n");
    ... 
}

我只加了这一行:printk(KERN_EMERG "Testing"); 并包括库:<linux/kernel.h><linux/printk.h> 所以我编译并重新启动了我的Linux(Ubuntu)。 在重启过程中,屏幕上出现了很多"Testing",所以到目前为止还好。
但现在我有一个问题。 我用C语言创建了这个程序。
int main()
{
    size_t filedesc = open("testefile2.txt",O_CREAT | O_WRONLY,0640);
    printf("%d",filedesc);
}

我编译并执行了这个程序,它的表现良好。但是我不明白为什么“Testing”没有出现在shell中。我的意思是,如果当我重新启动电脑时会出现很多单词“Testing”,为什么当我执行上面的程序时这个单词不会出现。只是补充一下,我在上面的代码中包含了以下库:unistd.hfcntl.hstdio.hstdlib.h。谢谢大家。

我试图修复这个格式,但似乎我弄得更糟了。有人看到哪里出了问题吗?我没有发现代码块的格式有任何问题... :( - Tim Coker
我觉得现在好了。抱歉,我不知道如何正确使用这种格式。谢谢。 - UserJ
5
也许你的 printk() 并不会出现在你期望的位置。当你打开另一个虚拟控制台(或终端)并输入 sudo tail -f /var/log/dmesg,你能看到你的 Testing 消息吗? - mpontillo
Mike可能是正确的。您的shell在与内核连接的控制台下运行的不同进程中。Ubuntu几乎肯定会将输出重定向到系统日志中。 - Falmarri
当我输入sudo tail -f /var/log/dmesg时,它没有出现"Testing"。基本上我打开一个shell并输入:gcc -o t test.c,然后:./t。但是它只打印了3。 - UserJ
2个回答

6

printk调用出现在内核消息缓冲区中,而不是在您的进程的标准输出/错误输出(stdout/stderr)中。


请问我如何打开内核消息缓冲区并查看单词“Testing”?因为我找不到它。谢谢。 - UserJ
1
@UserJ 使用 'dmesg' 命令,或查看其中一个系统日志(位于 /var/log/ 目录下)。 - nos

4

但我不明白为什么“Testing”没有出现在shell上。

我认为这是 printk 消息被抑制的影响(更确切地说是限速)。

检查消息日志或控制台以获取更多信息。

printk: ### messages suppressed.

字符串。

如果最近有很多消息,此功能将停止打印消息。

实际代码如3.1内核: http://lxr.linux.no/#linux+v3.1.1/kernel/printk.c#L1621

1621 * printk rate limiting, lifted from the networking subsystem.
1622 *
1623 * This enforces a rate limit: not more than 10 kernel messages
1624 * every 5s to make a denial-of-service attack impossible.
1625 */
1626 DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10);
1627
1628 int __printk_ratelimit(const char *func)

因为 open syscall 非常流行(只需执行一个 strace -e open /bin/ls 命令,就会出现 15 次 open syscall,仅仅是启动最简单的 ls),所以速率限制将生效。它将限制您的消息每5秒钟只能打印一次;在单个“burst”中不超过10条消息。
我建议创建一个特殊用户,并添加 UID 检查以及在你的其他 printk-in-open 代码中在 printk 前调用该 UID。

实际上,我希望shell打印出单词“测试”,因为我想使用系统调用进行一些测试。谢谢你的回答。 - UserJ
抱歉,我现在认为我理解了这个注释。 - UserJ
printk 发出的消息不会被 shell 打印。它会在内核上某些文本控制台(通过 Alt-F1 打开)上打印,并保存在 dmesg 缓冲区中,同时也发送到 syslog 守护进程。你只是在做比允许打印更多的 printk。你应该在 printk 之前添加一些条件,因为 open 是最常用的系统调用之一。你应该仅在你感兴趣的情况下进行 printk,例如通过测试 UID 或路径。 - osgx
你能建议我在printk(KERN_EMERG "Testing\n")之前加入什么来显示“Testing”吗?我对如何修改代码并不是很清楚。谢谢。 - UserJ
[ 24.295775] audit_printk_skb: 30 个回调被抑制 这是问题吗? - UserJ
如果(current->uid == YOUR_SPECIAL_UID) { printk(...);},并且您可以在/kernel/printk.c文件中降低限制DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10)。将其更改为... DEFINE_RATELIMIT_STATE(printk_ratelimit_state, HZ, 100)-每秒100条消息的限制。进行两个更改。'30 callbacks suppressed'不是问题,它只是说有很多消息由您的printk生成,并且问题是printk消息的速率非常高。 - osgx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接