转载地址:http://blog.chinaunix.net/space.php?uid=20648784&do=blog&id=1592834
1. /proc文件系统简介
/proc文件系统,这是内核模块和系统交互的两种主要方式之一。
/proc文件系统也是Linux操作系统的特色之一。
/proc文件系统不是普通意义上的文件系统,它是一个伪文件系统。
通过/proc,可以用标准Unix系统调用(比如open()、read()、write()、 ioctl()等等)访问进程地址空间。
可以用cat、more等命令查看/proc文件中的信息。
用户和应用程序可以通过/proc得到系统的信息,并可以改变内核的某些参数。
当调试程序或者试图获取指定进程状态的时候,/proc文件系统将是你强有力的支持者。通过它可以创建更强大的工具,获取更多信息
|
有些 /proc 的文件是经过编码的,不同的工具可以被用来解释这些编码过的信息并输出成可读的形式。这样的工具包括:'top', 'ps', 'apm' 等。
proc 文件系统可以被用于收集有用的关于系统和运行中的内核的信息。下面是一些重要的文件:
/proc/cpuinfo - CPU 的信息 (型号, 家族, 缓存大小等)
/proc/meminfo - 物理内存、交换空间等的信息
/proc/mounts - 已加载的文件系统的列表
/proc/devices - 可用设备的列表
/proc/filesystems - 被支持的文件系统
/proc/modules - 已加载的模块
/proc/version - 内核版本
/proc/cmdline - 系统启动时输入的内核命令行参数
2 /proc文件系统源码分析
在分析/proc文件系统时:先得对VFS文件系统模式,inode数据结构,VFS超级块有一定的认识。
在linux代码树中,所有文件系统放在/linux/fs目录中。
|
可以看到,proc文件系统注册的过程:
1> 调用proc_init_inodecache()创建缓存。
2> 调用register_filesystem(&proc_fs_type),将proc文件类型加入到文件类型的单向链表中,如果发生错误,则返回。
3> 在proc目录下,创建文件目录。
2.2 /proc文件系统操作方法
1) proc_file_lseek
这个函数,用来实现lseek系统调用,其功能是设置file结构的->f_pos域。
2) proc_file_read
这个函数是file_operations结构中的成员,在后面我们将看到,在proc_dir_entry结构中实现的 file_operations和inode_operations将链接至VFS的inode中,因此,该函数将用来实现read系统调用。在这个函数中,首先根据file结构,得到相应的inode,然后由
3) proc_file_write与proc_file_read代码实现类似。
|
if (start == NULL) {
if (n > PAGE_SIZE) {
printk(KERN_ERR
"proc_file_read: Apparent buffer overflow!\n");
n = PAGE_SIZE;
}
n -= *ppos;
if (n <= 0)
break;
if (n > count)
n = count;
start = page + *ppos;
} else if (start < page) {
if (n > PAGE_SIZE) {
printk(KERN_ERR
"proc_file_read: Apparent buffer overflow!\n");
n = PAGE_SIZE;
}
if (n > count) {
/*
* Don't reduce n because doing so might
* cut off part of a data block.
*/
printk(KERN_WARNING
"proc_file_read: Read count exceeded\n");
}
} else /* start >= page */ {
unsigned long startoff = (unsigned long)(start - page);
if (n > (PAGE_SIZE - startoff)) {
printk(KERN_ERR
"proc_file_read: Apparent buffer overflow!\n");
n = PAGE_SIZE - startoff;
}
if (n > count)
n = count;
}
n -= copy_to_user(buf, start < page ? page : start, n);
if (n == 0) {
if (retval == 0)
retval = -EFAULT;
break;
}
*ppos += start < page ? (unsigned long)start : n;
nbytes -= n;
buf += n;
retval += n;
}
free_page((unsigned long) page);
return retval;
}
1> 其中dp=PDE(inode),返回inode数据结构的首地址。相当于dp指向inode结构。
2> 判断pos是否有地址越出MAX_NON_LFS,和读出的数据地址大于MAX_NON_LFS。
3> 根据系列的判断,最后定位到copy_to_user(buf, start < page ? page : start, n)。把数据从内核存储空间拷贝到用户空间。