在玩mini2440的时候,发现自己要经常查看/proc目中的某些文件,如:modules,mtd,iomem等.其中每个目录和文件都是动态创建的.并不存在于磁盘上
[@mini2440 /proc]#ls
1 302 cmdline iomem mounts tty
11 306 cpu ioports mtd uptime
2 4 cpuinfo irq net version
209 416 crypto kallsyms pagetypeinfo vmallocinfo
211 5 devices kmsg partitions vmstat
213 628 diskstats kpagecount self yaffs
222 666 driver kpageflags slabinfo zoneinfo
228 669 execdomains loadavg softirqs
244 671 fb locks stat
251 asound filesystems meminfo sys
298 buddyinfo fs misc sysvipc
3 bus interrupts modules timer_list
上面为proc目录中的文件及文件夹,上面的文件及目录是怎么来的了?
在我们制作的根文件系统中,在文件/etc/fstab中又如下内容:
[@mini2440 /etc]#cat fstab
#device mount-point type option dump fsck order
proc /proc proc defaults 0 0
proc /testProcDirectory proc defaults 0 0 这个条是自己加的,来测试在目录/testProcDirectory中和/proc中的内容相同
sysfs /sys sysfs defaults 0 0
mdev /dev ramfs defaults 0 0
none /var ramfs defaults 0 0
none /tmp ramfs defaults 0 0
proc文件系统相当于内核的一个快照,该目录下的所有信息都是动态的从正在运行的内核中读取。
基于这种原因,/proc文件系统就成为了用户和内核之间交互的接口。
一方面,用户可以从/proc文件系统中读取很多内核释放出来的信息;另一方面,内核也可以在恰当的时候从用户那里得到输入信息,从而改变内核的相关状态和配置。
相比传统的文件系统,/proc是一种特殊的文件系统,即虚拟文件系统。这里的虚拟是强调/proc文件系统下的所有文件都存在于内存中而不是磁盘上。也就是说/proc文件系统只占用内存空间,而不占用系统的外存空间。
现在我们在linux内核中找个相关的代码来看看,究竟/proc目录中的文件时如何建立起来的?
#include <linux/fs.h> #include <linux/init.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> static int devinfo_show(struct seq_file *f, void *v) { int i = *(loff_t *) v; if (i < CHRDEV_MAJOR_HASH_SIZE) { if (i == 0) seq_printf(f, "Character devices:\n"); chrdev_show(f, i); } #ifdef CONFIG_BLOCK else { i -= CHRDEV_MAJOR_HASH_SIZE; if (i == 0) seq_printf(f, "\nBlock devices:\n"); blkdev_show(f, i); } #endif return 0; } static void *devinfo_start(struct seq_file *f, loff_t *pos) { if (*pos < (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE)) return pos; return NULL; } static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos) { (*pos)++; if (*pos >= (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE)) return NULL; return pos; } static void devinfo_stop(struct seq_file *f, void *v) { /* Nothing to do */ } static const struct seq_operations devinfo_ops = { .start = devinfo_start, .next = devinfo_next, .stop = devinfo_stop, .show = devinfo_show }; static int devinfo_open(struct inode *inode, struct file *filp) { return seq_open(filp, &devinfo_ops); } static const struct file_operations proc_devinfo_operations = { .open = devinfo_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; static int __init proc_devices_init(void) { proc_create("devices", 0, NULL, &proc_devinfo_operations); return 0; } module_init(proc_devices_init);
在看上面的代码之前,现看看/proc/devices 文件中的内容:
[@mini2440 /proc]#cat devices
Character devices:
1 mem
4 /dev/vc/0
4 tty
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
14 sound
21 sg
29 fb
81 video4linux
89 i2c
90 mtd
116 alsa
128 ptm
136 pts
400 leds
149 leds_01
180 usb
188 ttyUSB
189 usb_device
195 led1_dev_01
204 s3c2410_serial
254 rtc
Block devices:
259 blkext
7 loop
8 sd
31 mtdblock
65 sd
66 sd
67 sd
68 sd
69 sd
70 sd
71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc
上面的devices文件中有俩个标示符:Character devices和Block devices。
现在来看看上面的代码中的devinfo_show()函数中有上面所说的描述符。从上面的代码中,我们不难猜/proc目录中文件的创建方法。
下面自己写个测试程序,看看proc目录中的文件是如何创建的。
#include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> /* printk() */ #include <linux/slab.h> /* kmalloc() */ #include <linux/fs.h> /* everything... */ #include <linux/errno.h> /* error codes */ #include <linux/types.h> /* size_t */ #include <linux/proc_fs.h> #include <linux/fcntl.h> /* O_ACCMODE */ #include <linux/seq_file.h> #include <asm/system.h> /* cli(), *_flags */ #include <asm/uaccess.h> /* copy_*_user */ #define LEN 100 static char dataBuf[LEN]; static char *testString ="suiyuan19840208"; static ssize_t proc_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { int size =strlen(dataBuf); if(size == 0) { strcpy(dataBuf,testString); } if(copy_to_user(buf, dataBuf, strlen(dataBuf))) { return -EFAULT; printk("copy_to_user error \n"); } printk("proc_read: buf:%s\n",buf); return 0; } static int proc_write(struct file *file, const char *buffer, unsigned long count, void *data) { int len; if (count > LEN) { len = LEN; } else { len = count; } if (copy_from_user(dataBuf, buffer, len)) { return -EFAULT; } dataBuf[len-1]='\0'; printk("proc_write: len:%d \tdataBuf:%s\n",len,dataBuf); return len; } static int proc_open(struct inode *inode, struct file *file) { printk("proc_open:default string:%s\n",testString); return 0; } static const struct file_operations cmdline_proc_fops = { .open = proc_open, .read = proc_read, .write = proc_write, .llseek = seq_lseek, //注意:函数没有自己定义 .release = single_release, //注意:函数没有自己定义,测试时候需要将其注释
}; static int __init proc_cmdline_init(void) { proc_create("test_String", 0, NULL, &cmdline_proc_fops); return 0; } module_init(proc_cmdline_init);
将上面的代码添加到自己的可以编译的内核路径中,进行编译。
CHK include/linux/compile.h
CC drivers/suiyuan/testProc.o 我自己添加的路径为drivers/suiyuan/目录中
drivers/suiyuan/testProc.c:63: warning: initialization from incompatible pointer type
加载内核。
可以在目录/proc目录中看到以下:
[@mini2440 /proc]#ls
1 302 cmdline iomem mounts timer_list
11 306 cpu ioports mtd tty
2 4 cpuinfo irq net uptime
209 416 crypto kallsyms pagetypeinfo version
211 5 devices kmsg partitions vmallocinfo
213 628 diskstats kpagecount self vmstat
222 666 driver kpageflags slabinfo yaffs
228 668 execdomains loadavg softirqs zoneinfo
244 672 fb locks stat
251 asound filesystems meminfo sys
298 buddyinfo fs misc sysvipc
3 bus interrupts modules test_String 此文件就是上面代码所生成的目录
然而当对文件 test_string 进行读取的时候,出现如下错误:
[@mini2440 /proc]#cat test_String
proc_open:default string:suiyuan19840208
proc_read: buf:suiyuan19840208
Unable to handle kernel NULL pointer dereference at virtual address 00000034
pgd = c39b0000
[00000034] *pgd=339b4031, *pte=00000000, *ppte=00000000
Internal error: Oops: 17 [#2]
last sysfs file: /sys/devices/platform/soc-audio/sound/card0/mixer/dev
Modules linked in:
CPU: 0 Tainted: G D (2.6.32.2-FriendlyARM #40)
PC is at single_release+0x10/0x2c
LR is at proc_reg_release+0xbc/0x13c
pc : [<c00b3488>] lr : [<c00d38b4>] psr: a0000013
sp : c39b7ef8 ip : c39b7f10 fp : c39b7f0c
r10: 00000000 r9 : c39b6000 r8 : c39b5700
r7 : c00b3478 r6 : c392c600 r5 : c348cdf8 r4 : c3950600
r3 : 00000000 r2 : c3950600 r1 : c39b5700 r0 : c348cdf8
Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: c000717f Table: 339b0000 DAC: 00000015
Process cat (pid: 673, stack limit = 0xc39b6270)
Stack: (0xc39b7ef8 to 0xc39b8000)
7ee0: c3950600 c348cdf8
7f00: c39b7f34 c39b7f10 c00d38b4 c00b3488 c39b5700 c3934700 c348be00 c348cdf8
7f20: c0030088 c39b6000 c39b7f5c c39b7f38 c009c328 c00d3808 c39b5700 00000000
7f40: c39356c0 00000006 c0030088 c39b6000 c39b7f6c c39b7f60 c009c468 c009c2d4
7f60: c39b7f8c c39b7f70 c0099030 c009c444 0000000f 00000000 00000003 00000006
7f80: c39b7fa4 c39b7f90 c00990e8 c0098fe8 bedd8e68 00000000 00000000 c39b7fa8
7fa0: c002fee0 c0099060 bedd8e68 00000000 00000003 00000000 00001000 001e9e38
7fc0: bedd8e68 00000000 00000003 00000006 0000008f 00000000 00000000 00000000
7fe0: 00000000 bedd8cb0 0008c5c8 00008dbc 60000010 00000003 30539031 30539431
Backtrace:
[<c00b3478>] (single_release+0x0/0x2c) from [<c00d38b4>] (proc_reg_release+0xbc/0x13c)
r5:c348cdf8 r4:c3950600
[<c00d37f8>] (proc_reg_release+0x0/0x13c) from [<c009c328>] (__fput+0x64/0x170)
r9:c39b6000 r8:c0030088 r7:c348cdf8 r6:c348be00 r5:c3934700
r4:c39b5700
[<c009c2c4>] (__fput+0x0/0x170) from [<c009c468>] (fput+0x34/0x38)
r9:c39b6000 r8:c0030088 r7:00000006 r6:c39356c0 r5:00000000
r4:c39b5700
[<c009c434>] (fput+0x0/0x38) from [<c0099030>] (filp_close+0x58/0x78)
[<c0098fd8>] (filp_close+0x0/0x78) from [<c00990e8>] (sys_close+0x98/0xc4)
r7:00000006 r6:00000003 r5:00000000 r4:0000000f
[<c0099050>] (sys_close+0x0/0xc4) from [<c002fee0>] (ret_fast_syscall+0x0/0x28)
r5:00000000 r4:bedd8e68
Code: e1a0c00d e92dd830 e24cb004 e5913068 (e5934034)
---[ end trace 392f42bfaac48aec ]---
Segmentation fault
对上面的错误,到网上找了找,LDD 书上面有提到类似的信息。
最后自己看了看,自己没有实现,.llseek = seq_lseek和release = single_release,这俩个函数,在上面的提示中能得到帮助。故在读取时候,出现了如上的错误。
正确代码的测试结构如下:
[@mini2440 /proc]#cat test_String proc_open:default string:suiyuan19840208 proc_read: buf:suiyuan19840208 [@mini2440 /proc]#echo "suiyuan_testing" > test_String proc_open:default string:suiyuan19840208 proc_write: len:16 dataBuf:suiyuan_testing [@mini2440 /proc]#cat test_String proc_open:default string:suiyuan19840208 proc_read: buf:suiyuan_testing
在proc_create()函数中,涉及到如下的数据结构。
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; loff_t size; const struct inode_operations *proc_iops; /* * NULL ->proc_fops means "PDE is going away RSN" or * "PDE is just created". In either case, e.g. ->read_proc won't be * called because it's too late or too early, respectively. * * If you're allocating ->proc_fops dynamically, save a pointer * somewhere. */ const struct file_operations *proc_fops; 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 pde_users; /* number of callers into module in progress */ spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */ struct completion *pde_unload_completion; struct list_head pde_openers; /* who did ->open, but not ->release */ };