操作系统课proc文件系统的读写实验(踩坑记录)

操作系统课的实验,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_readmyproc_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");

个人博客:https://www.rainc.top/2020/06/01/essay/proc

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。