操作系统课的实验,proc文件系统踩坑,及解决记录
老师给的代码
//proc.c
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
static struct proc_dir_entry *mydir;
static struct proc_dir_entry *pfile;
static char msg[255];
static int myproc_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int len = strlen(msg);
if (off >= len)
return 0;
if (count > len - off)
count = len - off;
memcpy(page + off, msg + off, count);
return off + count;
}
static int myproc_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
unsigned long count2 = count;
if (count2 >= sizeof(msg))
count2 = sizeof(msg) - 1;
if (copy_from_user(msg, buffer, count2))
return -EFAULT;
msg[count2] = '\0';
return count;
}
static int __init myproc_init(void)
{
mydir = proc_mkdir("mydir", NULL);
if (!mydir) {
printk(KERN_ERR "Can't create /proc/mydir\n");
return -1;
}
pfile = create_proc_entry("pool", 0666, mydir);
if (!pfile) {
printk(KERN_ERR "Can't create /proc/mydir/pool\n");
remove_proc_entry("mydir", NULL);
return -1;
}
pfile->read_proc = myproc_read;
pfile->write_proc = myproc_write;
return 0;
}
static void __exit myproc_exit(void)
{
remove_proc_entry("pool", mydir);
remove_proc_entry("mydir", NULL);
}
module_init(myproc_init);
module_exit(myproc_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Lilan");
问题
当我按照实验指导使用make指令编译时出现了implicit declaration of function ‘copy_from_user’
,implicit declaration of function ‘create_proc_entry’
和dereferencing pointer to incomplete type ‘struct proc_dir_entry’
三个错误。
解决
implicit declaration of function ‘copy_from_user’
错误位置
if (copy_from_user(msg, buffer, count2))
解决过程
打开编译时所依赖的库(我这是 /lib/modules/5.3.0-53-generic/build/include)找到asm文件夹下的uaccess.h后发现里面的copy_from_user
变动成了raw_copy_from_user()
参数没有变动,修改函数名后问题就解决了
implicit declaration of function ‘create_proc_entry’
错误位置
pfile = create_proc_entry("pool", 0666, mydir);
if (!pfile) {
printk(KERN_ERR "Can't create /proc/mydir/pool\n");
remove_proc_entry("mydir", NULL);
return -1;
}
pfile->read_proc = myproc_read;
pfile->write_proc = myproc_write;
return 0;
解决过程
按和上面一样的方法找到linux文件夹下的proc_fs.h,查看后发现找不到create_proc_entry
这个函数,不过找到了一个名为proc_create
的函数,于是猜测这是否就create_proc_entry
的替代。
查看函数后蒙了,原本的函数只有三个参数,而这个函数居然有四个参数。
于是面向百度编程,搜索一番后果然猜想没错,确实是由proc_create
替代了之前的create_proc_entry
,并且博客上还写出了使用方法。参考的博客
根据博客上所写,第四个参数是用来指定read和write函数用的结构体,那么dereferencing pointer to incomplete type ‘struct proc_dir_entry’
这个错误也就明白了,因为通过定义结构体来指定read和write函数了,所以原本用来指定的struct proc_dir_entry
结构体中自然就已经没有了这两个指针。
修改后
static struct file_operations my_ops={//新增的结构体
.read=myproc_read,
.write=myproc_write,
.owner=THIS_MODULE,
};
.
.
.
pfile = proc_create("pool", 0666, mydir,&my_ops);//在这里新增了结构体的地址
if (!pfile) {
printk(KERN_ERR "Can't create /proc/mydir/pool\n");
remove_proc_entry("mydir", NULL);
return -1;
}
//两个pfile->都删除
return 0;
然后
本以为这样就解决了,然后再次make,这下好了myproc_read
和myproc_write
也出现了implicit declaration of function 的错误(老师啊,不带这么坑学生的……)
解决
于是我打开找到file_operations这个结构体,找到了里面read和write函数的结构一看
//file_operations中的
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
//我的
int myproc_read(char *page, char **start, off_t off, int count, int *eof, void *data)
int myproc_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
这尼玛相差也太大了,唉看来是要把老师给的代码来一个大整改了啊(吐血)
修改的过程我就不描述了,这里贴上改好的代码,如果未来恰好有学弟学妹的也碰上了同样的实验,遇见了同样的问题,希望能有所帮助。因为实验报告要求代码详细注释,注释我也就保留不删了(注释是我自己的理解有错别喷,哈哈)。
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
static struct proc_dir_entry *mydir;
static struct proc_dir_entry *pfile;
static ssize_t myproc_write(struct file *file, const char __user *buff, size_t len, loff_t *pos);
static ssize_t myproc_read(struct file *filp,char __user *buff,size_t len, loff_t *pos);
static char msg[255];
static struct file_operations my_ops={//定义file_operations的结构体指定read和write函数
.read=myproc_read,
.write=myproc_write,
.owner=THIS_MODULE,
};
static ssize_t myproc_read(struct file *filp,char __user *buff,size_t count, loff_t *pos)
{
unsigned int len=strlen(msg);//得到内核空间大小
unsigned long p = *pos;//获取偏移量
if(p>=len)//如果偏移超过了空间容量则返回0
return 0;
if (count > len-p)//如果用户读取大于内核空间,修正为全部读出
count = len-p;
if(raw_copy_to_user(buff+p,msg+p, count))//将内核空间内容复制进用户空间
return -EFAULT;//如果失败返回错误码
*pos+=count;//偏移量修正
printk("read pos:%ld,count:%ld\n",p,count);
return count;//返回读取长度
}
static ssize_t myproc_write(struct file *file, const char __user *buff, size_t len, loff_t *pos)
{
unsigned long len2 = len;
if (len2>=sizeof(msg))//如果写入的内容超出内核空间容量
len2=sizeof(msg)-1;//只保留可存储部分
if (raw_copy_from_user(msg, buff, len2))//将缓存的内容写入内核空间
return -EFAULT;//返回错误码
msg[len2] = '\0';//结束标识符
return len;//返回写入长度
}
static int __init myproc_init(void)
{
mydir = proc_mkdir("mydir", NULL);//创建proc文件夹mydir
if (!mydir) {
printk(KERN_ERR "Can't create /proc/mydir\n");//创建失败系统报错并结束模块
return -1;
}
pfile = proc_create("pool", 0666, mydir,&my_ops);//创建proc文件pool并赋予用户读写权限,并指定读写方法
if (!pfile) {
printk(KERN_ERR "Can't create /proc/mydir/pool\n");
remove_proc_entry("mydir", NULL);
return -1;//如果创建失败删除mydir文件夹并报错结束模块
}
return 0;
}
static void __exit myproc_exit(void)
{
remove_proc_entry("pool", mydir);//删除mydir文件夹中的pool文件
remove_proc_entry("mydir", NULL);//删除mydir文件夹
}
module_init(myproc_init);//模块初始化调用myproc_init函数
module_exit(myproc_exit);//模块卸载时调用myproc_exit函数
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Rainc");