/proc详解

转载地址: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文件系统将是你强有力的支持者。通过它可以创建更强大的工具,获取更多信息

wugang@wugang-desktop:/$ ls -l /proc/cpuinfo
-r--r--r-- 1 root root 0 2009-03-03 17:21 /proc/cpuinfo
wugang@wugang-desktop:/$ cat /proc/cpuinfo
processor    : 0
vendor_id    : GenuineIntel
cpu family    : 15
model        : 1
model name    : Intel(R) Pentium(R) 4 CPU 1.70GHz
stepping    : 2
cpu MHz        : 1700.091
cache size    : 256 KB
fdiv_bug    : no
hlt_bug        : no
f00f_bug    : no
coma_bug    : no
fpu        : yes
fpu_exception    : yes
cpuid level    : 2
wp        : yes
flags        : fpu vme de pse tsc msr pae mce cx8 sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm up pebs bts sync_rdtsc
bogomips    : 3404.03
clflush size    : 64


有些 /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目录中。

2.1 /proc文件系统的注册
void __init proc_root_init(void)
 {
    int err = proc_init_inodecache();
    if (err)
        return;
    err = register_filesystem(&proc_fs_type);
     if (err)
        return;
    proc_mnt = kern_mount(&proc_fs_type);
    err = PTR_ERR(proc_mnt);
    if (IS_ERR(proc_mnt)) {
        unregister_filesystem(&proc_fs_type);
    return;
    }
    proc_misc_init();
    proc_net = proc_mkdir("net", NULL);
    proc_net_stat = proc_mkdir("net/stat", NULL);
#ifdef CONFIG_SYSVIPC
    proc_mkdir("sysvipc", NULL);
#endif
    proc_root_fs = proc_mkdir("fs", NULL);
    proc_root_driver = proc_mkdir("driver", NULL);
    proc_mkdir("fs/nfsd", NULL);
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
    proc_mkdir("openprom", NULL);
#endif
    proc_tty_init();
#ifdef CONFIG_PROC_DEVICETREE
    proc_device_tree_init();
#endif
    proc_bus = proc_mkdir("bus", NULL);
    proc_sys_init();
}


可以看到,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代码实现类似。

static ssize_t
  proc_file_read(struct file *file, char __user *buf, size_t nbytes,
                 loff_t *ppos)
  {
          struct inode * inode = file->f_path.dentry->d_inode;
          char *page;
          ssize_t retval=0;
          int eof=0;
          ssize_t n, count;
          char *start;
          struct proc_dir_entry * dp;
          unsigned long long pos;
  
          /*
           * Gaah, please just use "seq_file" instead. The legacy /proc
           * interfaces cut loff_t down to off_t for reads, and ignore
           * the offset entirely for writes..
           */

          pos = *ppos;
          if (pos > MAX_NON_LFS)
                  return 0;
          if (nbytes > MAX_NON_LFS - pos)
                  nbytes = MAX_NON_LFS - pos;
  
          dp = PDE(inode);
          if (!(page = (char*) __get_free_page(GFP_KERNEL)))
                  return -ENOMEM;
  
          while ((nbytes > 0) && !eof) {
                  count = min_t(size_t, PROC_BLOCK_SIZE, nbytes);
  
                  start = NULL;
                  if (dp->get_info) {
                          /* Handle old net routines */
                          n = dp->get_info(page, &start, *ppos, count);
                          if (n < count)
                                  eof = ;
                  } else if (dp->read_proc) {
                         n = dp->read_proc(page, &start, *ppos,
                                           count, &eof, dp->data);
                 } else
                         break;
 
                 if (n == 0) /* end of file */
                         break;
                 if (n < 0) { /* error */
                         if (retval == 0)
                                 retval = n;
                         break;
                 }



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)。把数据从内核存储空间拷贝到用户空间。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值