proc 文件系统是由内核创建的虚拟文件系统,被内核用来向外界报告信息的一个文件系统,存储着当前内核运行状态的一系列特殊文件,是在系统运行时才创建的,所以它仅存在于内存之中而不在外存(硬盘、Flash)上。通过proc虚拟文件可以实现Linux内核空间和用户间之间进行通信,可以说是内核向用户空间打开的一扇窗户。
Linux系统开机完成进入文件系统后,进入proc目录
这边对proc目录下常见文件进行简要分析:
1.cat /proc/number
proc目录下包含许多以数字命名的子目录,这些数字表示系统当前正在运行进程的进程号,里面包含对应该进程相关的多个信息文件。
例如打开进程270的目录,如下:
/proc/270# lsauxv exe net stackcgroup fd ns statclear_refs fdinfo oom_adj statmcmdline limits oom_score statuscomm maps oom_score_adj taskcoredump_filter mem pagemap wchancpuset mountinfo personalitycwd mounts rootenviron mountstats smaps其中每一个文件都有具体的含义,
如:cmdline-启动当前进程的完整命令,mem-当前进程所占用的内存空间等
2.cat /proc/cmdline
在启动时传递至内核的相关参数信息,这些信息通常由u-boot传递的;
/proc# cat cmdline console=ttyS0,115200n8, init=/etc/preinit mac_addr=00:0A:0B:0C:0D:0E,, ip=none root=ubi0:rootfs ubi.mtd=4 rootfstype=ubifs rw noinitrd3.cat /proc/cpuinfo
处理器的相关信息的文件;
proc# cat cpuinfo Processor : ARMv7 Processor rev 1 (v7l)processor : 0BogoMIPS : 1292.69processor : 1BogoMIPS : 1292.69Features : swp half thumb fastmult vfp edsp neon vfpv3 tls CPU implementer : 0x41CPU architecture: 7CPU variant : 0x2CPU part : 0xc09CPU revision : 14.cat /proc/crypto
系统上已安装的内核使用的密码算法及每个算法的详细信息列表;
/proc# cat crypto name : hmac(sha256)driver : hmac(sha256-generic)module : kernelpriority : 0refcnt : 1selftest : passedtype : shashblocksize : 64digestsize : 32name : md5driver : md5-genericmodule : kernelpriority : 0refcnt : 1selftest : passedtype : shashblocksize : 64digestsize : 165.cat /proc/devices
系统已经加载的所有块设备和字符设备的信息,包含主设备号和设备组名;
/proc# cat devices Character devices: 1 mem 4 ttyS 5 /dev/tty 5 /dev/console 5 /dev/ptmx 10 misc 13 input 89 i2c 90 mtd180 usb188 ttyUSBBlock devices:259 blkext 8 sd 9 md 31 mtdblock 65 sd 66 sd6.cat /proc/filesystems
当前被内核支持的文件系统类型列表文件,被标示为nodev的文件系统表示不需要块设备的支持;通常mount一个设备时,如果没有指定文件系统类型将通过此文件来决定其所需文件系统的类型;
/proc# cat filesystems nodev sysfsnodev rootfsnodev bdevnodev procnodev cgroupnodev cpusetnodev tmpfsnodev debugfsnodev sockfsnodev usbfsnodev pipefsnodev anon_inodefsnodev rpc_pipefsnodev devptsnodev ramfsnodev nfsnodev jffs2 yaffs yaffs2nodev mtd_inodefsnodev ubifs vfat fuseblknodev fusenodev fusectl7.cat /proc/interrupts
架构系统上每个IRQ相关的中断号列表,多路处理器平台上每个CPU对于每个I/O设备均有自己的中断号;
/proc# cat interrupts CPU0 CPU1 29: 351743 3480462 GIC twd 36: 2005 0 GIC pfe_hif 37: 0 0 GIC pfe_hif_nocpy 45: 0 0 GIC spacc 53: 1 0 GIC dwc_otg, dwc_otg:usb3 54: 0 0 GIC xhci-hcd:usb1 59: 1621 0 GIC serial 60: 192 0 GIC comcerto_spi 61: 0 0 GIC comcerto_spi 62: 12 0 GIC I2C 90: 0 0 GIC pmutimer 91: 15 0 GIC timer4 92: 0 0 GIC timer5 94: 0 0 GIC rtc-alarmIPI0: 0 0 Timer broadcast interruptsIPI1: 17381 7533 Rescheduling interruptsIPI2: 0 0 Function call interruptsIPI3: 92 63 Single function call interruptsIPI4: 0 0 CPU stop interruptsErr: 08.cat /proc/iomem
每个物理设备在系统内存中的映射信息;
/proc# cat iomem 00000000-02bfffff : System RAM03400000-03ffffff : ddr04000000-3fffffff : System RAM04008000-0455dfff : Kernel text0458a000-0461ea07 : Kernel data83000000-83001fff : iram904500d0-904500d8 : comcerto_wdt90498000-90498fff : comcerto_spi.09049c000-9049cfff : I2C904e0000-904e001f : c2k-rtc90500000-9050ffff : apb905e0000-905e0403 : c2k mdma base address92000000-92ffffff : dwc_otg.096000000-960002c0 : dw_dmac.096400000-9640001f : serial96500000-96500fff : comcerto_spi.19a000000-9affffff : ipsec9b000000-9bffffff : elp9c000000-9cffffff : axi9d000000-9d00ffff : ahci9f000000-9f7fffff : xhci-hcdc0000000-c3ffffff : comcertoflash.0c8300000-c8301fff : comcertonand9.cat /proc/meminfo
系统中关于当前内存的利用状况等的信息,其内容显示为两列,前者为统计属性,后者为对应的值;
/proc# cat meminfo MemTotal: 1012928 kBMemFree: 901932 kBBuffers: 0 kBCached: 32764 kBSwapCached: 0 kBActive: 56176 kBInactive: 21676 kBActive(anon): 46048 kBInactive(anon): 4644 kBActive(file): 10128 kBInactive(file): 17032 kBUnevictable: 0 kBMlocked: 0 kBHighTotal: 0 kBAnonPages: 45120 kBMapped: 9912 kBShmem: 5604 kBSlab: 17872 kBSReclaimable: 2860 kBSUnreclaim: 15012 kBKernelStack: 1072 kBPageTables: 1276 kB10.cat /proc/mounts
系统当前挂载的所有文件系统,此文件指向/proc/self/mounts。
如下所示,其中第一列表示挂载的设备,第二列表示在当前目录树中的挂载点,第三点表示当前文件系统的类型,第四列表示挂载属性(ro或者rw),第五列和第六列用来匹配/etc/mtab文件中的转储(dump)属性;
/proc# cat mountsrootfs / rootfs rw 0 0ubi0:rootfs / ubifs rw,noatime 0 0proc /proc proc rw,noatime 0 0sysfs /sys sysfs rw,noatime 0 0tmpfs /tmp tmpfs rw,nosuid,nodev,noatime 0 0tmpfs /dev tmpfs rw,noatime,size=512k,mode=755 0 0devpts /dev/pts devpts rw,noatime,mode=600 0 0debugfs /sys/kernel/debug debugfs rw,relatime 0 0none /proc/bus/usb usbfs rw,relatime 0 011.cat /proc/modules
当前装入内核的所有模块名称列表,其实与lsmod命令得到的结果一样,只不过lsmod排版的更好看,/proc/modules的信息更全面。
如下所示,其中第一列表示模块名,第二列表示此模块占用内存空间大小,第三列表示此模块有多少实例被装入,第四列表示此模块依赖于其它哪些模块,第五列表示此模块的装载状态(Live:已经装入;Loading:正在装入;Unloading:正在卸载),第六列表示此模块在内核内存(kernel memory)中的偏移量;
/proc# cat modules cls_fw 3409 0 - Live 0x8352d000sbr_cdev 1970 0 - Live 0x83529000 (O)nbvpn 4111 1 sbr_cdev, Live 0x83524000 (O)nf_nat_ftp 1346 0 - Live 0x834ee000nf_conntrack_ftp 4626 1 nf_nat_ftp, Live 0x834e4000fci 3474 5 - Live 0x834c2000 (O)/proc# lsmod Module Size Used by Tainted: P cls_fw 3409 0 sbr_cdev 1970 0 nbvpn 4111 1 sbr_cdevnf_nat_ftp 1346 0 nf_conntrack_ftp 4626 1 nf_nat_ftpfci 3474 512.cat /proc/partitions
块设备每个分区的主设备号(major)和次设备号(minor)等信息,同时包括每个分区所包含的块 (block)数目,可以与/proc/mtd的内容一起查看;
/proc# cat partitions major minor #blocks name 31 0 1024 mtdblock0 31 1 1024 mtdblock1 31 2 1024 mtdblock2 31 3 8192 mtdblock3 31 4 94208 mtdblock4 31 5 1024 mtdblock5 31 6 8192 mtdblock6 31 7 94208 mtdblock7 31 8 1024 mtdblock8 31 9 2048 mtdblock9 31 10 12288 mtdblock10 31 11 32768 mtdblock11 31 12 2048 mtdblock12 31 13 128 mtdblock13 31 14 512 mtdblock14 31 15 128 mtdblock15 31 16 128 mtdblock16 31 17 64 mtdblock17 31 18 64 mtdblock18 31 19 84320 mtdblock19/proc# cat mtd dev: size erasesize namemtd0: 00100000 00020000 "barebox"mtd1: 00100000 00020000 "bareboxfact"mtd2: 00100000 00020000 "env"mtd3: 00800000 00020000 "kernel1"mtd4: 05c00000 00020000 "rootfs1"mtd5: 00100000 00020000 "reserved_dtb1"mtd6: 00800000 00020000 "kernel2"mtd7: 05c00000 00020000 "rootfs2"mtd8: 00100000 00020000 "reserved_dtb2"mtd9: 00200000 00020000 "configcert"mtd10: 00c00000 00020000 "reserved_avcsign"mtd11: 02000000 00020000 "webrootdb"mtd12: 00200000 00020000 "license"mtd13: 00020000 00010000 "uloader"mtd14: 00080000 00010000 "barebox"mtd15: 00020000 00010000 "env"mtd16: 00020000 00010000 "boardinfo"mtd17: 00010000 00010000 "md5sum1"mtd18: 00010000 00010000 "md5sum2"mtd19: 05258000 0001f000 "rootfs"以上内容只是对proc目录进行简单的分析,更具体的可以查看proc文件系统详解。
在proc文件系统中,我们可以将对虚拟文件的读写作为与内核中实体进行通信的一种手段,进行传输操作内核数据,但是与普通文件不同的是,这些虚拟文件的内容都是动态创建的。
proc的定义在include/linux/proc_fs.h
下,接口函数的实现在/fs/proc/generic.c
或/fs/proc/
文件夹下寻找,第一节的proc目录分析,很多都是在/fs/proc/
文件夹在实现的,从文件名称就可以看出,如下:。
proc接口的创建有两种方式,create_proc_entry
和proc_create
,下面分别举例说明:
直接查看源码,应该比较容易理解
//包含proc头文件#include <linux/proc_fs.h>//定义proc接口static struct proc_dir_entry *proc_dir = NULL;static struct proc_dir_entry *proc_test1 = NULL;static struct proc_dir_entry *proc_test2 = NULL;//proc read的实现函数static int proc_test1_read(char *page, char **start, off_t off, int count, int *eof, void *data){ int len = 0; len = sprintf(page, "proc_test1 read ok!/n"); return len;}//proc write的实现函数static int proc_test1_write(struct file *file, const char __user * buf, unsigned long count, void *data){ int val; if(sscanf(buf, "%d", &val) != 1) return -EINVAL; if(val == 1) printk("proc_test1 write true/n"); else printk("proc_test1 write false/n"); return val;}//proc接口创建static int proc_test_fs_create(void){ proc_dir = proc_mkdir("proc_test", NULL); if(!proc_dir) return -ENOMEM; proc_test1 = create_proc_entry("proc_test1", 0644, proc_dir); if(!proc_test1) return -ENOMEM; proc_test1->read_proc = proc_test1_read; proc_test1->write_proc = proc_test1_write;}要使用proc虚拟文件需要包含头文件我们首先查看这两个创建函数的结构:
create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent)
proc_create(const char *name,mode_t mode, struct proc_dir_entry *parent, const struct file_Operations *proc_fops)
可以观察到proc_create
函数增加一个struct file_operations
结构体,那在实现的时候有什么区别呢?
proc_create
方式的实现其实在/fs/proc/
文件夹下有很多例子,如cmdline.c/version.c等,对应申明等动作上面已经给出,这边就不再重复了,直接写一个proc_create
方式的例子吧。
注意到proc_create
函数增加一个struct file_operations
结构 ,而不是像create_proc_entry
那样直接返回。其实原理也一样,一个是将成员函数write、read等指向proc接口proc_dir_entry
,而这边是将成员函数wriet、read等指向结构体file_operations
。
使用proc_create
方式则不使用read成员,因为当cat该proc成员时,seq_read()函数被反复调用,导致一直打印read函数的内容,不过也可以通过判断off_t *off
变量进行处理,这边不过多描述。
既然不使用read的方式,那就有新的方式代替,这边使用成员open,通过上面的例子可以很直观的看到,open函数会调用show函数,所以show函数的内容就是cat时得到的内容,write成员则与create_proc_entry
的实现方式一致。
Linux proc system的分析就到这边,有感悟时会持续会更新。
注:以上内容都是本人在学习过程积累的一些心得,难免会有参考到其他文章的一些知识,如有侵权,请及时通知我,我将及时删除或标注内容出处,如有错误之处也请指出,进行探讨学习。文章只是起一个引导作用,详细的数据解析内容还请查看Linux相关教程,感谢您的查阅。
新闻热点
疑难解答