五。内核代码调试方法——proc文件系统、seqfile文件系统

如有错误大家一定告诉我,一起学习了



############## proc 文件系统 ##################
1、    mount -t proc none /proc
    ps ---> /proc/(每个结构体(每个进程)在这创建一个目录。以pid名字命名,进程的状态,关系等属性都是内核写在相应的目录下)
    内核:找的是proc文件系统,我们只是通过上面的命令挂载到/proc下,找的不是proc目录,但是用户态的ps命令只会在proc目录下找,所以习惯放在proc目录
        
    task_struct(每个进程都对应这么一个结构体) ---> task_struct的list(链表) --->

    创建一个新的进程内核会自动分配一个这样的结构体(task_struct),再分配一个pid,然后把父进程的页表拷贝过来,所以父子进程共享前半段,当子进程进行不同的操作时会重新写页表    

    这些创建都是在磁盘上创建,proc文件系统上的文件在硬盘是不存在的,是存在于内存的;所以/proc里的文件只有内核代码能够创建,我们需要写模块来执行这些操作
    不能这么创建,在/proc 下进行下列操作是错误的    
    mkdir /proc/test                X(错)
    touch /proc/test/hello             X(错)

2、功能:
    1>.调试:
        a.printk
        b.创建/proc/test/hello   打印到这个文件中。代替printk
    2>.给内核传数据:
        echo abc > /proc/test/hello
        hello文件不能容纳数据,只是一个标识,是内核接口;abc的内容是传到内核的。

3、proc文件系统的头文件,包含各种函数的实现
    <linux>/include/linux/proc_fs.h
        struct proc_dir_entry{         //proc目录每个文件都对应这么一个结构体
            void *data;        
            //这个值是写驱动的人提前写好的,内核不会操作这个值;在调用函数时会把这个值传给读写函数,无用就是NULL
            //这是一个指针
            read_proc_t *read_proc;        //proc下文件的读函数指针
            write_proc_t *write_proc;    //proc下文件的写函数指针
            loff_t size;//偏移
            const struct inode_operations *proc_iops;//该文件的一组操作
            ... //还包含其它的很多
        };
        当执行 cat /proc/test/hello 时,调用的就是read_proc
        当执行 echo abc > /proc/test/hello 时,调用的就是write_proc


        create_proc_entry    创建一个proc文件
        remove_proc_entry    删除一个proc文件
        proc_mkdir        创建一个目录
        proc_symlink    创建一个符号链接
        create_proc_read_entry    创建一个只读的proc文件
        proc_create_data    创建seqfile文件,proc存在问题,seqfile是用来解决proc函数一次只能读一页(4K)数据的问题;seqfile文件系统是自动检测分配内存的,不够时会自动给添加一页

4、为什么在写内核模块函数的时候加上 static?
答:内核模块函数默认是 static 的,但是内核默认是 extern,加上 static 就是 静态的;
    又因为最后内核模块的函数最后都会被写到内核中,为了以后方便,也是一个习惯,就都加上

5、参考代码 <path>/02proc/*

6、在内核环境中,一定要注意出错处理,出错要将之前占用的全部资源释放

######################################    
# 错误码的出处:
# include/asm-generic/errno.h
# include/asm-generic/errno-base.h
######################################

7、proc文件系统读函数
    //先打开一个文件 fd = open("/proc/test_dir/test_att", xx(权限))
    //用户态读 read(fd, buf, len)
    //内核分配一页内存(4K)(page)
    //len ---> count  读取长度
    //*eof = 1;代表文件读取结束
    //读取的时候,将读到的东西放到page内存中,结束时内核会自动将page内的东西放到buf(用户态传进来的)中
    //读取大小受page大小限制,最大读4K;seqfile文件系统解决这个问题

    int (read_proc_t)(char *page, char **start, off_t off, int count, int *eof, void *data)

8、proc文件系统写函数
    //ret = write(fd, buf, len)
    //struct file *file ---> 就是用户态的 FILE *,fopen 打开的文件流;封装后在用户态无法看到这个结构体
    //__user   代表是用户态分配的缓存;[4G - 1, 3G]内核缓存,[3G - 1,0]用户态缓存;两种缓存的使用方式是不一样
    //buf ---> buffer
    //len ---> count
    //data --->  初始化时的100,随便传的, 写内核的人自己定义的

    int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data)
    
9、proc文件系统中从用户态拷贝
    #include <asm/uaccess.h>    //包含在这个头文件

    //用户态 buffer ---> 内核buf
    //user ---> kernel
    //使用 memcpy()从内核把东西拷贝到用户态,不是一定出错,是可能出错,内核不容许隐患
        因为拷贝内核的东西时会有权限问题,造成拷贝的数据不完全
    //内核提供的宏定义
    //  min(count, 1024)    //1024 是定义的 buf 的大小
    //  max(count, 1024)
    //copy_from_user  是内核实现的函数

    copy_from_user(buf, buffer, count)

############### seqfile 文件系统 ##############
1、对 proc 文件的操作只有简单的读写;对 seqfile 文件有一个操作集 ops,是一个结构体:
    struct file_operations ops = {
        .owner = THIS_MODULE,
        .open = test_seq_open,        //open,用户态,自己实现
        .release = seq_release,        //close    ,用户态,内核实现
        .llseek = seq_lseek,        //lseek,用户态,内核实现
        .read = seq_read,            //read,用户态,内核实现
        .write = test_seq_write,    //write,用户态,自己实现
    };
    ================================================
    = 此结构体包含在头文件 <path>/include/linux/fs.h
    = 这组操作于用户态的 I/O 操作对应
    ================================================
    ==========================================================================
    = test_seq_open 自己实现的原因:因为类型不匹配,需要把 seq_open 函数封装一下
    = test_seq_write 自己实现原因:因为需要我们自己决定要以什么样的方式写
    =================================================================

2、seqfile 文件系统打开函数
    int test_seq_open(struct inode *no, struct file *fp)
    {
        return seq_open(fp, &seq_ops);
    }
    
    //open--->vfs-inode file->sys_open-->test_seq_open
        调用用户态的open函数,经过VFS(虚拟文件系统),进入系统调用的函数,再到test_seq_open
    struct inode *nu 是在执行时内核创建的,
    //seq_open 函数的 seq_ops 结构体是让 seq_read 用的

3、seq_read 函数操作:
    struct seq_operations seq_ops = {
        .start = seq_start,
        .stop = seq_stop,
        .next = seq_next,
        .show = seq_show,
    };
    //seq_read 函数的执行过程
    //read-->vfs-->sys_read-->seq_read-->start-show-next-show-next-show-......-stop

4.seq_read 的过程函数
    void *seq_start(struct seq_file *m, loff_t *pos)
    {
        //返回第*pos个结点的指针
    }

    void seq_stop(struct seq_file *m, void *v)
    {
        //seq_start的反操作
    }
    //如果该函数返回一个NULL,则seq_read结束
    void *seq_next(struct seq_file *m, void *v, loff_t *pos)
    {
        //++*pos
        //返回第*pos个结点的指针
    }
    //v是seq_start和seq_next的返回值
    int seq_show(struct seq_file *m, void *v)
    {
        struct item_st *tmp = v;
            //ret += sprintf(page + ret, .....);
        //sprintf(m->buf, "No:%d     Len:%d  Content:%s", tmp->no, tmp->len, tmp->content);
        //在seq_read结束之后,内核会用copy_to_user(buffer, m->buf, xxxxxx)
        return seq_printf(m, "No:%d    Len:%d    Content:%s", tmp->no, tmp->len, tmp->content);
    }

5、简述 seqfile 过程:
    创建seq_file
    创建的时候绑定了一组操作ops(open,close,read,write,...)
    这组操作用于:用户态--->VFS---->sys_open系列函数--->test_seq_open-->seq_open-->...
    write里也要实现链表(自己选择的数据存储方式),把数据存住(临时)
    read:start - show - next - show - next - show - stop
    每一个 seq_file 都对应自己的结构体,必须在 seq_open 之前把函数保存进去,然后在read的时候才能找到这些函数
    next返回个NULL,sig_read就结束了


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值