我同意@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 打开文件,将vp 和vname 作为输出,其中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。