在 Linux 4.9
移植 MT7603U
时遇到 no file read method
错误导致读取配置出错,设备工作不正常,本文记录解决方法及相关知识点
现象
在 Linux 4.9
编译 MT7603U
之后,复制 MT7603USTA.dat
,启动之后出现错误
[ 2804.262246] no file read method
[ 2804.265509] Read file "/etc/Wireless/RT2870STA/MT7603USTA.dat" failed(errCode=-1)!
[ 2804.273097] ERROR!!! [ 2804.275221] RTMPReadParametersHook failed, Status[=0xffffffff]
[ 2804.338301] !!! rt28xx init fail !!!
分析
内核中可以使用
printk("func name:%pF\n", ptr)
来打印函数名
搜索驱动代码找到出错函数代码并添加打印如下
int RtmpOSFileRead(RTMP_OS_FD osfd, char *pDataPtr, int readLen)
{
printk("read:%p\n", osfd->f_op->read);
printk("open:%pF\n", osfd->f_op->open);
printk("name:%s\n", osfd->f_op->owner->name);
/* The object must have a read method */
if (osfd->f_op && osfd->f_op->read) {
return osfd->f_op->read(osfd, pDataPtr, readLen, &osfd->f_pos);
} else {
DBGPRINT(RT_DEBUG_ERROR, ("no file read method\n"));
return -1;
}
}
打印信息如下
[ 3886.638124] read: (null)
[ 3886.640808] open:nfs_file_open+0x0/0x54
[ 3886.644741] name:(null)
[ 3886.647211] no file read method
[ 3886.650381] Read file "/etc/Wireless/RT2870STA/MT7603USTA.dat" failed(errCode=-1)!
[ 3886.658037] ERROR!!! [ 3886.660161] RTMPReadParametersHook failed, Status[=0xffffffff]
[ 3886.722205] !!! rt28xx init fail !!!
内核中找到 kernel/4.9.y/fs/nfs/file.c
const struct file_operations nfs_file_operations = {
.llseek = nfs_file_llseek,
.read_iter = nfs_file_read,
.write_iter = nfs_file_write,
.mmap = nfs_file_mmap,
.open = nfs_file_open,
.flush = nfs_file_flush,
.release = nfs_file_release,
.fsync = nfs_file_fsync,
.lock = nfs_lock,
.flock = nfs_flock,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.check_flags = nfs_check_flags,
.setlease = simple_nosetlease,
};
在 nfs
文件系统下确实不存在 read/write
导致不正常,但是 Linux 2.6
下工作正常,代码如下
const struct file_operations nfs_file_operations = {
.llseek = nfs_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
.aio_read = nfs_file_read,
.aio_write = nfs_file_write,
#ifdef CONFIG_MMU
.mmap = nfs_file_mmap,
#else
.mmap = generic_file_mmap,
#endif
.open = nfs_file_open,
.flush = nfs_file_flush,
.release = nfs_file_release,
.fsync = nfs_file_fsync,
.lock = nfs_lock,
.flock = nfs_flock,
.splice_read = nfs_file_splice_read,
.check_flags = nfs_check_flags,
.setlease = nfs_setlease,
};
查找 do_sync_read/do_sync_write
在文件 fs/read_write.c
,在 Linux 4.9
中查找替换函数如下
static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
struct kiocb kiocb;
struct iov_iter iter;
ssize_t ret;
init_sync_kiocb(&kiocb, filp);
kiocb.ki_pos = *ppos;
iov_iter_init(&iter, WRITE, &iov, 1, len);
ret = filp->f_op->write_iter(&kiocb, &iter);
BUG_ON(ret == -EIOCBQUEUED);
if (ret > 0)
*ppos = kiocb.ki_pos;
return ret;
}
ssize_t __vfs_write(struct file *file, const char __user *p, size_t count,
loff_t *pos)
{
if (file->f_op->write)
return file->f_op->write(file, p, count, pos);
else if (file->f_op->write_iter)
return new_sync_write(file, p, count, pos);
else
return -EINVAL;
}
EXPORT_SYMBOL(__vfs_write);
ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos)
{
mm_segment_t old_fs;
const char __user *p;
ssize_t ret;
if (!(file->f_mode & FMODE_CAN_WRITE))
return -EINVAL;
old_fs = get_fs();
set_fs(get_ds());
p = (__force const char __user *)buf;
if (count > MAX_RW_COUNT)
count = MAX_RW_COUNT;
ret = __vfs_write(file, p, count, pos);
set_fs(old_fs);
if (ret > 0) {
fsnotify_modify(file);
add_wchar(current, ret);
}
inc_syscw(current);
return ret;
}
EXPORT_SYMBOL(__kernel_write);
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{
ssize_t ret;
if (!(file->f_mode & FMODE_WRITE))
return -EBADF;
if (!(file->f_mode & FMODE_CAN_WRITE))
return -EINVAL;
if (unlikely(!access_ok(VERIFY_READ, buf, count)))
return -EFAULT;
ret = rw_verify_area(WRITE, file, pos, count);
if (!ret) {
if (count > MAX_RW_COUNT)
count = MAX_RW_COUNT;
file_start_write(file);
ret = __vfs_write(file, buf, count, pos);
if (ret > 0) {
fsnotify_modify(file);
add_wchar(current, ret);
}
inc_syscw(current);
file_end_write(file);
}
return ret;
}
EXPORT_SYMBOL(vfs_write);
使用 vfs_write/vfs_read
来替换之前的函数解决这个问题,修改如下
int RtmpOSFileRead(RTMP_OS_FD osfd, char *pDataPtr, int readLen)
{
/* The object must have a read method */
if (osfd->f_op && osfd->f_op->read) {
return vfs_read(osfd, pDataPtr, readLen, &osfd->f_pos);
} else {
DBGPRINT(RT_DEBUG_ERROR, ("no file read method\n"));
return -1;
}
}