资料:
Linux系统中存在以下几类伪文件系统:
1.procfs:proc提供内核和用户交互的平台,由于其文件格式是ASCII,所以用户可以使用cat,vim,echo等命令查看或修改文件,当然必须在root用户下才有相应权限。
在系统中增设了了一个/proc目录,每当创建一个进程时就以pid为目录名在这个目录下建立起一个特殊文件,使得通过这个文件就可以读写相应进程的用户空间。而当进程exit()时则将这个进程文件删除。称为 伪文件系统
2.sysfs:与procfs类似,由于出现的比较晚,所以它克服了proc的一些缺点,比proc功能更强大。但是由于其文件格式是二进制形式,所以需要特殊工具。该文件系统主要为开发人员提供。
3.其它伪文件系统如:libfs,debugfs等。
在这些文件系统中,proc出现比较早,其实现也很典型。proc最初的设计目的是提供内核和用户交互的平台,使用户可以动态的管理系统,同时获取系统的运行时的信息。在proc中主要的信息便是系统进程信息。
我们可以通过cat和echo等文件操作函数来查看和设置这些proc文件。
2.sysfs:与procfs类似,由于出现的比较晚,所以它克服了proc的一些缺点,比proc功能更强大。但是由于其文件格式是二进制形式,所以需要特殊工具。该文件系统主要为开发人员提供。
3.其它伪文件系统如:libfs,debugfs等。
在这些文件系统中,proc出现比较早,其实现也很典型。proc最初的设计目的是提供内核和用户交互的平台,使用户可以动态的管理系统,同时获取系统的运行时的信息。在proc中主要的信息便是系统进程信息。
proc_fs.h头文件 src/include/linux/proc_fs.h
在 proc_dir_entry结构体中,定义如下:
- 51struct proc_dir_entry {
- 52 unsigned int low_ino;
- 53 unsigned short namelen;
- 54 const char *name;
- 55 mode_t mode; // 0444
- 56 nlink_t nlink;
- 57 uid_t uid;
- 58 gid_t gid;
- 59 loff_t size;
- 60 const struct inode_operations *proc_iops;
- 61 /*
- 62 * NULL ->proc_fops means "PDE is going away RSN" or
- 63 * "PDE is just created". In either case, e.g. ->read_proc won't be
- 64 * called because it's too late or too early, respectively.
- 65 *
- 66 * If you're allocating ->proc_fops dynamically, save a pointer
- 67 * somewhere.
- 68 */
- 69 const struct file_operations *proc_fops;
- 70 struct proc_dir_entry *next, *parent, *subdir;
- 71 void *data;
- 72 read_proc_t *read_proc; //实现接口函数
- 73 write_proc_t *write_proc;
- 74 atomic_t count; /* use count */
- 75 int pde_users; /* number of callers into module in progress */
- 76 spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */
- 77 struct completion *pde_unload_completion;
- 78 struct list_head pde_openers; /* who did ->open, but not ->release */
- 79};
1.建立目录proc_mkdir
- 148 extern struct proc_dir_entry *proc_mkdir(const char *,struct proc_dir_entry *);
struct proc_dir_entry *:=NULL, 在/proc下新建目录
!=NULL, 表示上级目录
- mydir = proc_mkdir("mydir", NULL);//在/proc目录下新建mydir目录
2.建立文件create_proc_entry()
- 109extern struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
- 110 struct proc_dir_entry *parent);
const char *name :文件名称
mode_t mode: 文件权限值 0666 mode_t内核文件权限值
struct proc_dir_entry:若 parent=mydir,在../mydidr/新建文件
若 parent=null, 在 /proc/下 新建文件
- pfile = create_proc_entry("pool", 0666, mydir); 在/proc/mydir/下新建pool文件
3.移除目录或文件remove_proc_entry
- 115 extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
const char *name: 要移除的目录或文件的名称
struct proc_dir_entry *parent: 若parent=null,在/proc/删除 目录
若parent!=NULL,删除 ../proc/parent 文件
- remove_proc_entry("pool", mydir); //删除/proc/mydir/下的 pool文件
- remove_proc_entry("mydir",NULL);//删除 /proc/下的mydir目录
我们可以通过cat和echo等文件操作函数来查看和设置这些proc文件。
4.实现proc_dir_entry结构体中 *read_proc函数
- 46typedef int (read_proc_t)(char *page, char **start, off_t off, int count, int *eof, void *data);
- 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;
- }
5. 实现proc_dir_entry中 *proc_write函数
- 48typedef int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data);
- 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;
- }
例子:
这个例子创建一个 /proc/mydir/pool,它相当于一个池子,你向它写什么,你读它的时候它就返回什么,当然它的容量是有限的 :)
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/proc_fs.h>
- #include <asm/uaccess.h>
- MODULE_LICENSE("GPL");
- 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;
- printk("pool init\n");
- return 0;
- }
- static void __exit myproc_exit(void)
- {
- remove_proc_entry("pool", mydir);
- remove_proc_entry("mydir", NULL);
- printk("pool exit\n");
- }
- module_init(myproc_init);
- module_exit(myproc_exit);
- //MODULE_LICENSE("GPL");
- obj-m:=pool.o
- KERNELDIR := /lib/modules/2.6.35-31-generic/build
- PWD :=$(shell pwd)
- modules:
- $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
- modules_install:
- $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
- clean:
- rm -rf *.o *.ko *.mod.c *.order *.symvers
- ywx@ywx:~/desktop/module/proc/pool$ sudo insmod ./pool.ko
- ywx@ywx:~/desktop/module/proc/pool$ echo "hello linux" > /proc/mydir/pool
- ywx@ywx:~/desktop/module/proc/pool$ cat /proc/mydir/pool
- hello linux
- ywx@ywx:~/desktop/module/proc/pool$ sudo rmmod pool