【问题标题】:Reading Data From STDIN in Kernel Space在内核空间从 STDIN 读取数据
【发布时间】:2015-06-07 18:01:29
【问题描述】:

我正在尝试为FreeBSD 9.3.0 编写一个内核模块,并且我想在其中使用read 系统调用。我已经包含了适当的标题(除其他外):

#include<sys/sysproto.h>
#include<sys/unistd.h>
#include<sys/types.h>
#include<sys/uio.h>
#include<sys/cdefs.h>

但是当我运行 make 我得到以下错误:

函数read的隐式声明

我也查看了上述头文件的源文件,并在sys/syssys/kern中搜索了很多源代码树寻找上述功能,但我找不到。 注意:我可以成功使用同一程序中的printf 系统调用。(编译时没有read 调用)

更新:文档实际上声明包含unistd.h。但那是在 C 标准库中,我不能在内核中使用它。所以问题变成了这个,我还有什么其他选择? (我正在尝试阅读STDIN

【问题讨论】:

  • 你正在尝试做一些非常奇怪的事情。在内核中调用read 的目的是什么?您是否代表用户这样做?数据会被放入用户级缓冲区吗?
  • 是的,数据将被送往用户区。(这是一个作业)
  • 如果你想做的是在数据到达用户应用程序之前从用户的 tty 设备读取数据,那么写一个 line 规程可能更容易。

标签: kernel freebsd system-calls


【解决方案1】:

我同意@qarma 的观点,即在内核空间中代表用户进程执行读取有点奇怪 - 用户空间应该发出自己的读取调用,特别是因为所有的安全检查和进程当您在内核模式下运行时,策略检查以及进程记帐、统计信息等都不会出现。内核模式在处理数据和访问时需要格外小心。

有很多更好的方法可以将数据输入和输出内核模块。 This post on the FreeBSD forums提一:

如果您想了解如何正确处理驱动程序中的文件, 看看 pf(4) 如何使用用户空间帮助程序 pfctl(8) 读取配置文件并将其转换为二进制数据 然后通过 /dev/pf 提供给内核驱动程序的结构 设备。

或者,您可以使用用户模式程序将数据从磁盘/等加载到某处的缓冲区中,然后执行 ioctl 以获取数据;然而,读取和写入 /dev/MyDriver 端点可能会更好。

如果你真的发现自己需要完全按照你的要求去做,那么同一篇文章表明至少有一部分内核写入文件系统 - 进程 coredumper - 该帖子指向 kern/kern_sig.c 作为示例:

static int
coredump(struct thread *td)
{
    struct proc *p = td->td_proc;
    struct ucred *cred = td->td_ucred;
    struct vnode *vp;
    struct flock lf;
    struct vattr vattr;
    int error, error1, locked;
    struct mount *mp;
    char *name;         /* name of corefile */
    off_t limit;
    int compress;

...
    error = corefile_open(p->p_comm, cred->cr_uid, p->p_pid, td, compress, &vp, &name);

coredump 调用corefile_open 打开文件,将vpvname 作为输出,其中vp 是一个指向vnode 对象的指针。

深入corefile_open,我们看到:

static int
corefile_open(const char *comm, uid_t uid, pid_t pid, struct thread *td,
    int compress, struct vnode **vpp, char **namep)
{
    struct nameidata nd;
    struct sbuf sb;
    const char *format;
    char *hostname, *name;
    int indexpos, i, error, cmode, flags, oflags;

...

    flags = O_CREAT | FWRITE | O_NOFOLLOW;
    NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name, td);
    error = vn_open_cred(&nd, &flags, cmode, oflags, td->td_ucred, NULL);
...
    NDFREE(&nd, NDF_ONLY_PNBUF);
    *vpp = nd.ni_vp;

注意对vn_open_cred的调用——完成后,我们可以使用刚刚初始化的nd.ni_vp变量来获取我们的vnode指针。注意对 NDINIT 和 NDFREE 的调用。

如果您愿意,可以深入挖掘 - vfs_cnops.c 包含 vn_open_cred 的实现,可能看起来很熟悉:

int
vn_open_cred(struct nameidata *ndp, int *flagp, int cmode, u_int vn_open_flags,
    struct ucred *cred, struct file *fp)
{
    struct vnode *vp;
    struct mount *mp;
    struct thread *td = ndp->ni_cnd.cn_thread;
    struct vattr vat;
    struct vattr *vap = &vat;
    int fmode, error;

... lots of setup ...

    error = vn_open_vnode(vp, fmode, cred, td, fp);

你有了它 - vn_open_vnode 终于完成了真正的工作。

您最好的选择可能是通过vn_open_cred

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-11
    • 2012-08-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-06
    • 1970-01-01
    • 2016-03-13
    相关资源
    最近更新 更多