编译出错,出现 vfs_read[******.ko] undefined !

出现类似问题的原因是所使用的函数在内核中没有被导出符号。在linux-4.0以后的版本中,vfs_read()的符号没有被导出,也就是早期版本中的EXPORT_SYMBOL(vfs_read)这句话没有了。
解决办法:
(1)使用fp->f_op->read()函数,但是使用这个,虽然可以编译通过,但是在加载时,fp->f_op->read的返回值是NULL,原因未找到;
(2)使用修改内核(不建议,会污染内核):在vfs_read()函数后添加EXPORT_SYMBOL(vfs_read);导出符号表
(3)(推荐)使用int kernel_read(struct file *file, loff_t offset, char *addr, unsigned long count)函数:
file:文件; offset:读位址; addr:地址指针; count:读的字节数,返回值是成功返回字节数,失败返回负值;
理由vfs_read()的定义为ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos),其中,参数__user 表示buf是用户态指针,在内核中是无法使用,因此需要设置使用环境,如下(也就是说,你想直接使用vfs_read这个一句话是不行的,它要用一个代码块才能满足从文件里面读取一些字节的需求,而这个代码块主要是解决__user *buf的使用的问题。),代码块一般如下所示:

        mm_segment_t old_fs;
        old_fs = get_fs();
        set_fs(get_ds());
        vfs_read(file, (void __user *)addr, count, &pos);
        set_fs(old_fs);

相比于vfs_read(),kernel_read()就是通上述操作进行封装(也就是说,kernel_read()把上面代码块组合成了一个新函数,可以给用户直接使用,不需要用户再把上面代码块抄一遍了),因此使用kernel_read更便捷。此外,在linux-4.0以后的版本中取消了对vfs_read()的符号导出,因此无法在编译成模块时使用,而kernel_read()有符号导出,可以在编译成模块时使用。

在linux内核源码linux-4.19.90/fs目录下搜索vfs_read的出处(grep -rn "vfs_read" ./*),得到在

ok@u20:~/data/linux-4.19.90/fs$ grep -rn "vfs_read" ./*
./9p/vfs_addr.c:91: * v9fs_vfs_readpage - read an entire page in from 9P
./9p/vfs_addr.c:98:static int v9fs_vfs_readpage(struct file *filp, struct page *page)
./9p/vfs_addr.c:104: * v9fs_vfs_readpages - read a set of pages from 9P
./9p/vfs_addr.c:113:static int v9fs_vfs_readpages(struct file *filp, struct address_space *mapping,
./9p/vfs_addr.c:341:	.readpage = v9fs_vfs_readpage,
./9p/vfs_addr.c:342:	.readpages = v9fs_vfs_readpages,
./9p/cache.c:242:static void v9fs_vfs_readpage_complete(struct page *page, void *data,
./9p/cache.c:269:					 v9fs_vfs_readpage_complete,
./9p/cache.c:307:					  v9fs_vfs_readpage_complete,
匹配到二进制文件 ./9p/vfs_addr.o
./dax.c:1254:		 * validated via access_ok() in either vfs_read() or
./exec.c:999:	ssize_t res = vfs_read(file, (void __user *)addr, len, &pos);
匹配到二进制文件 ./exec.o
./namei.c:4705: * vfs_readlink - copy symlink body into userspace buffer
./namei.c:4714:int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
./namei.c:4743:EXPORT_SYMBOL(vfs_readlink);
匹配到二进制文件 ./namei.o
./nfsd/nfs4xdr.c:3640:	 * XXX: By default, vfs_readlink() will truncate symlinks if they
./nfsd/nfs4xdr.c:3642:	 * easy fix is: if vfs_readlink() precisely fills the buffer, assume
./read_write.c:412:ssize_t __vfs_read(struct file *file, char __user *buf, size_t count,
./read_write.c:431:	result = vfs_read(file, (void __user *)buf, count, pos);
./read_write.c:437:ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
./read_write.c:452:		ret = __vfs_read(file, buf, count, pos);
./read_write.c:579:		ret = vfs_read(f.file, buf, count, &pos);
./read_write.c:627:			ret = vfs_read(f.file, buf, count, &pos);
./read_write.c:977:ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
./read_write.c:1020:		ret = vfs_readv(f.file, vec, vlen, &pos, flags);
./read_write.c:1071:			ret = vfs_readv(f.file, vec, vlen, &pos, flags);
匹配到二进制文件 ./read_write.o
./splice.c:362:	res = vfs_readv(file, (const struct iovec __user *)vec, vlen, &pos, 0);
匹配到二进制文件 ./splice.o
./stat.c:406:				error = vfs_readlink(path.dentry, buf, bufsiz);
匹配到二进制文件 ./stat.o
./xfs/xfs_ioctl.c:292:	error = vfs_readlink(dentry, hreq->ohandle, olen);

得到其定义在read_write.c文件中定义: 


可以发现,vfs_read确实没有导出,而kernel_read导出符号了。
原文链接:https://blog.csdn.net/MM_man/article/details/100603683

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值