开发平台:Ubuntu 11.04
编译器:gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)
内核源码:linux-2.6.38.8.tar.bz2
proc是基于内存的文件系统,用来实现外界与Linux内核的信息交互(通过/proc目录下的各种文件)。
1、proc文件系统的初始化
proc文件系统的初始化函数proc_root_init被start_kernel函数所调用,用来完成注册、挂载文件系统以及创建必要的目录和符号链接文件等工作。
(1)、创建proc_inode_cache高速缓存
/* linux-2.6.38.8/fs/proc/inode.c */ void __init proc_init_inodecache(void) { proc_inode_cachep = kmem_cache_create("proc_inode_cache", sizeof(struct proc_inode), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD|SLAB_PANIC), init_once); }
在Ubuntu 11.04中通过以下命令可查看到此高速缓存相关的信息。
$ sudo cat /proc/slabinfo | grep "proc_inode_cache" proc_inode_cache 310 310 384 10 1 : tunables 0 0 0 : slabdata 31 31 0
(2)、proc文件系统的注册和挂载
/* linux-2.6.38.8/fs/proc/root.c */ err = register_filesystem(&proc_fs_type); if (err) return; proc_mnt = kern_mount_data(&proc_fs_type, &init_pid_ns); if (IS_ERR(proc_mnt)) { unregister_filesystem(&proc_fs_type); return; } init_pid_ns.proc_mnt = proc_mnt;
(3)、创建符号链接文件的函数
/* linux-2.6.38.8/fs/proc/generic.c */ struct proc_dir_entry *proc_symlink(const char *name, struct proc_dir_entry *parent, const char *dest) { struct proc_dir_entry *ent; ent = __proc_create(&parent, name, (S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO),1); if (ent) { ent->data = kmalloc((ent->size=strlen(dest))+1, GFP_KERNEL); if (ent->data) { strcpy((char*)ent->data,dest); if (proc_register(parent, ent) < 0) { kfree(ent->data); kfree(ent); ent = NULL; } } else { kfree(ent); ent = NULL; } } return ent; }
proc_symlink函数用于在parent(如果parent为NULL则是在/proc目录下)目录下为dest创建名为name的符号链接文件。
可在Ubuntu 11.04的/proc目录下查看到mounts文件是链接到self/mounts文件的。
$ cd /proc/ $ ls -l mounts lrwxrwxrwx 1 root root 11 2012-01-13 04:32 mounts -> self/mounts
(4)、创建net符号链接文件
/* linux-2.6.38.8/fs/proc/proc_net.c */ int __init proc_net_init(void) { proc_symlink("net", NULL, "self/net"); return register_pernet_subsys(&proc_net_ns_ops); }
register_pernet_subsys函数用来注册网络命名空间。网络命名空间被创建或注销时会分别调用proc_net_ns_ops结构体变量中的初始化函数proc_net_ns_init或退出函数proc_net_ns_exit。
(5)、创建目录的函数
/* linux-2.6.38.8/fs/proc/generic.c */ struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent) { return proc_mkdir_mode(name, S_IRUGO | S_IXUGO, parent); }
proc_mkdir函数用于在parent(parent为NULL时则是在/proc目录下)目录下创建名为name的目录,其实质是参数mode指定为S_IRUGO | S_IXUGO的proc_mkdir_mode函数。
(6)、初始化/proc/tty目录树
/* linux-2.6.38.8/fs/proc/proc_tty.c */ void __init proc_tty_init(void) { if (!proc_mkdir("tty", NULL)) return; proc_tty_ldisc = proc_mkdir("tty/ldisc", NULL); /* * /proc/tty/driver/serial reveals the exact character counts for * serial links which is just too easy to abuse for inferring * password lengths and inter-keystroke timings during password * entry. */ proc_tty_driver = proc_mkdir_mode("tty/driver", S_IRUSR|S_IXUSR, NULL); proc_create("tty/ldiscs", 0, NULL, &tty_ldiscs_proc_fops); proc_create("tty/drivers", 0, NULL, &proc_tty_drivers_operations); }
/* linux-2.6.38.8/include/linux/proc_fs.h */ static inline struct proc_dir_entry *proc_create(const char *name, mode_t mode, struct proc_dir_entry *parent, const struct file_operations *proc_fops) { return proc_create_data(name, mode, parent, proc_fops, NULL); }
proc_create函数用于在parent(当parent为NULL时则是在/proc目录下)目录下创建一个名为name的proc条目,参数proc_fops指的是访问此条目的操作函数,参数mode用于设置此条目的访问权限以及文件类型。
(7)、初始化/proc/sys目录的操作函数
/* linux-2.6.38.8/fs/proc/proc_sysctl.c */ int __init proc_sys_init(void) { struct proc_dir_entry *proc_sys_root; proc_sys_root = proc_mkdir("sys", NULL); proc_sys_root->proc_iops = &proc_sys_dir_operations; proc_sys_root->proc_fops = &proc_sys_dir_file_operations; proc_sys_root->nlink = 0; return 0; }
(8)、初始化/proc/drivers-tree目录树
/* linux-2.6.38.8/fs/proc/proc_devtree.c */ void __init proc_device_tree_init(void) { struct device_node *root; proc_device_tree = proc_mkdir("device-tree", NULL); if (proc_device_tree == NULL) return; root = of_find_node_by_path("/"); if (root == NULL) { pr_debug("/proc/device-tree: can't find root\n"); return; } proc_device_tree_add_node(root, proc_device_tree); of_node_put(root); }