proc文件系统相关操作

proc文件系统相关操作 (1)

August 22, 2015 10:13 PM

  • proc文件系统相关操作 1
    • 数据结构
      • 1 read操作
      • 2 write操作
      • 3 info操作
    • proc API
      • 1 创建目录
      • 2 创建普通文件
      • 3 创建符号链接文件
      • 4 删除文件或目录
      • 5 读写proc文件

本文的主要内容整理,转载自: http://edsionte.com/techblog/archives/3030

1. 数据结构

/proc下每个文件对应下面一个数据结构

struct proc_dir_entry {
    unsigned int low_ino;
    unsigned short namelen;
    const char *name;
    mode_t mode;
    nlink_t nlink;
    uid_t uid;
    gid_t gid;
    unsigned long size;
    struct inode_operations * proc_iops;
    struct file_operations * proc_fops;
    get_info_t *get_info;
    struct module *owner;
    struct proc_dir_entry *next, *parent, *subdir;
    void *data;
    read_proc_t *read_proc;
    write_proc_t *write_proc;
    atomic_t count;     /* use count */
    int deleted;        /* delete flag */
};

这个结构比较重要的就是3个钩子函数,分别用于 read write info操作.

1.1 read操作

typedef int (read_proc_t)(char *page, char **start, off_t off, int count, int *eof, void *data);
  • page: 指示用来写入数据的缓冲区;
  • offcount: 与read函数对应的参数相同;
  • starteof: 用于读取大于1个page数据时实现;

1.2 write操作

typedef int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data);
  • filp: 一个打开文件结构(可以忽略这个参数);
  • buffer: 用户空间要写入的数据. 缓冲区地址实际上是一个用户空间的缓冲区, 不能直接读取它;
  • len: 定义了在buffer中有多少数据要被写入;
  • data: 一个指向私有数据的指针;

1.3 info操作

typedef int (get_info_t)(char *, char **, off_t, int);

2 proc API

2.1 创建目录

/proc文件系统中创建一个目录对应的函数接口如下:

proc_dir_entry *proc_mkdir(const char *,struct proc_dir_entry *);
  • name: 要创建的目录名;
  • parent: 确定这个目录的父目录,如果置NULL,则位置为/proc下;

比如我们使用该函数在/proc下创建一个目录edsionte_procfs。

#define MODULE_NAME "edsionte_procfs"
struct proc_dir_entry *example_dir;

example_dir = proc_mkdir(MODULE_NAME, NULL);
if (example_dir == NULL) {
    rv = -ENOMEM;
    goto out;
}

2.2 创建普通文件

在/proc文件系统中创建一个虚拟文件可以使用如下的函数. 这是最直接,包装最少的创建方法.

struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent);
  • name: 是要创建的proc文件名;
  • mode: 是该文件权限值,例如S_IRUGO,可传入0表示采用系统默认值;
  • parent: 指定该文件的上层proc目录项,如果为 NULL,表示创建在 /proc 根目录下;

create_proc_entry() 完成的任务主要包括:检测 mode 值,分配 proc_dir_entry 结构,注册 proc_dir_entry.

比如我们通过该函数在/proc/edsionte_procfs目录下创建一个虚拟文件foo, 其权限为644。其中example_dir指向我们刚创建的目录文件edsionte_procfs

struct proc_dir_entry  *foo_file;

foo_file = create_proc_entry("foo", 0644, example_dir);
if (foo_file == NULL) {
    rv = -ENOMEM;
    goto no_foo;
}

2.3 创建符号链接文件

当我们需要在/proc文件系统下创建一个符号链接文件时,可使用如下接口:

struct proc_dir_entry *proc_symlink(const char *name, struct proc_dir_entry *parent, const char *dest);
  • name: 要创建的符号链接文件名;
  • parent: 该符号链接文件的父目录;
  • dest: 符号链接所指向的目标文件;

下面的代码演示了如何通过该函数来对已存在的虚拟文件jiffies创建符号链接文件jiffies_too:

symlink = proc_symlink("jiffies_too", example_dir, "jiffies");
if (symlink == NULL) {
    rv = -ENOMEM;
    goto no_symlink;
}

2.4 删除文件或目录

既然有创建虚拟文件的函数,必然也就有删除虚拟文件的函数接口:

void remove_proc_entry(const char *name, struct proc_dir_entry *parent);

该函数中的参数name和parent与上述函数的参数意义相同.
在示例程序中,我们在卸载函数中完成上述几个文件的删除工作:

remove_proc_entry("jiffies_too", example_dir);
remove_proc_entry("foo", example_dir);
remove_proc_entry("MODULE_NAME", NULL);

2.5 读写proc文件

如果只是创建了虚拟文件,那么它并不能被读写。为此,我们必须为每个虚拟文件挂接读写函数,如果该虚拟文件是只读的,那么只需挂载相应的读函数。

正如上面所述,每个虚拟文件对应的proc_dir_entry结构都有read_procwrite_proc两个字段,它们均为函数指针,其各自的类型定义如下:

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

typedef int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data);

在前面也已经介绍过了. 如果要实现对虚拟文件的读写,则需要实现上述两个函数接口。对于我们的示例程序,我们的实现方法如下:

static int proc_read_foobar(char *page, char **start, off_t off, int count, int *eof, void *data)
{
    int len;
    struct fb_data_t *fb_data = (struct fb_data_t *)data;

    //将fb_data的数据写入page
    len = sprintf(page, "%s = %s\n", fb_data->name, fb_data->value);

    return len;
}

static int proc_write_foobar(struct file *file, const char *buffer, unsigned long count, void *data)
{
    int len;
    struct fb_data_t *fb_data = (struct fb_data_t *)data;

    if (count > FOOBAR_LEN)
        len = FOOBAR_LEN;
    else
        len = count;

    //写函数的核心语句,将用户态的buffer写入内核态的value中
    if (copy_from_user(fb_data->value, buffer, len))
        return -EFAULT;

    fb_data->value[len] = '\0';

    return len;
}

当用户读我们刚创建的虚拟文件时,该文件对应的read_proc函数将被调用。该函数将数据写入内核的缓冲区中。上述读函数的例子中,缓冲区即为page。当用户给虚拟文件写数据时,write_proc函数将被调用,该函数从缓冲区buffer中读取count个字节的数据。

你可能感兴趣的:(文件系统,linux内核)