1. proc_root_init()函数
路径:linux-3.10.x\init\main.c-->start_kernel()
static struct file_system_type proc_fs_type = {
.name = "proc",
.mount = proc_mount,
.kill_sb = proc_kill_sb,
.fs_flags = FS_USERNS_MOUNT,
};
void __init proc_root_init(void)
{
int err;
proc_init_inodecache(); //为proc_inode创建slab cache --proc_inode_cachep
err = register_filesystem(&proc_fs_type); //注册proc文件系统
if (err)
return;
proc_self_init(); //没有看懂函数内部,从函数定义应该是proc文件系统自身的初始化???
proc_symlink("mounts", NULL, "self/mounts");
proc_net_init(); //proc下网络注册
#ifdef CONFIG_SYSVIPC
proc_mkdir("sysvipc", NULL);
#endif
proc_mkdir("fs", NULL);
proc_mkdir("driver", NULL);
proc_mkdir("fs/nfsd", NULL); /* somewhere for the nfsd filesystem to be mounted */
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
/* just give it a mountpoint */
proc_mkdir("openprom", NULL);
#endif
proc_tty_init();
#ifdef CONFIG_PROC_DEVICETREE
proc_device_tree_init();
#endif
proc_mkdir("bus", NULL);
proc_sys_init();
}
2. 文件系统注册register_filesystem()
int register_filesystem(struct file_system_type * fs)
{
int res = 0;
struct file_system_type ** p;
BUG_ON(strchr(fs->name, '.')); //BUG_ON:可以当作断言unlikely使用,它用panic()引发更严重的错误。调用panic()不但会打印错误消息(Oops)而且还会挂起整个系统
if (fs->next)
return -EBUSY;
write_lock(&file_systems_lock);
p = find_filesystem(fs->name, strlen(fs->name)); //查找fs注册的文件系统是否已经注册过
if (*p)
res = -EBUSY;
else
*p = fs; //文件系统没有注册过
write_unlock(&file_systems_lock);
return res;
}
register_filesystem函数内部逻辑比较简单,不在此赘述。
3. 创建proc下的符号链接proc_symlink()——> "/proc/mounts"
proc_symlink("mounts", NULL, "self/mounts");
struct proc_dir_entry *proc_symlink(const char *name,
struct proc_dir_entry *parent, const char *dest)
{
struct proc_dir_entry *ent;
//注意mode参数S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO = 符号链接|读|写|可执行(用户、组、其它)
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);//ent->data=“self/mounts”
if (proc_register(parent, ent) < 0) { //parent在__proc_create()已经指向了ent,proc文件注册 这里增加/proc/mounts
kfree(ent->data);
kfree(ent);
ent = NULL;
}
} else {
kfree(ent);
ent = NULL;
}
}
return ent;
}
EXPORT_SYMBOL(proc_symlink);
__proc_create()函数实现:
static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
const char *name,
umode_t mode,
nlink_t nlink)
{
struct proc_dir_entry *ent = NULL;
const char *fn = name;
unsigned int len;
/* make sure name is valid */
if (!name || !strlen(name))
goto out;
if (xlate_proc_name(name, parent, &fn) != 0) //xlate: 转换proc的名字
goto out;
//到这里,fn=“mounts”, name=“mounts”
/* At this point there must not be any '/' characters beyond *fn */
if (strchr(fn, '/'))
goto out;
len = strlen(fn);
ent = kzalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
if (!ent)
goto out;
memcpy(ent->name, fn, len + 1); //ent->name="mounts"
ent->namelen = len; //"mounts"长度
ent->mode = mode;
ent->nlink = nlink;
atomic_set(&ent->count, 1); //原子操作,设置为1
spin_lock_init(&ent->pde_unload_lock);
INIT_LIST_HEAD(&ent->pde_openers); //初始化链表
out:
return ent;//这里将返回“mounts”,这就是我们要需要的
}
proc_dir_entry结构体:
struct proc_dir_entry {
unsigned int low_ino;
umode_t mode; //文件权限
nlink_t nlink; //符号链接
kuid_t uid;//用户
kgid_t gid; //组
loff_t size;
const struct inode_operations *proc_iops; //节点操作,相当于对目录操作
const struct file_operations *proc_fops; //目录下的文件操作
struct proc_dir_entry *next, *parent, *subdir;
void *data;
atomic_t count; /* use count */
atomic_t in_use; /* number of callers into module in progress; */
/* negative -> it's going away RSN */
struct completion *pde_unload_completion;
struct list_head pde_openers; /* who did ->open, but not ->release */
spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */
u8 namelen;
char name[];
};
xlate_proc_name() 转换proc名称函数:
static int xlate_proc_name(const char *name, struct proc_dir_entry **ret,
const char **residual)
{
int rv;
spin_lock(&proc_subdir_lock);
rv = __xlate_proc_name(name, ret, residual);
spin_unlock(&proc_subdir_lock);
return rv;
}
_xlate_proc_name() 转换proc名称函数:
struct proc_dir_entry proc_root = {
.low_ino = PROC_ROOT_INO,
.namelen = 5,
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
.nlink = 2,
.count = ATOMIC_INIT(1),
.proc_iops = &proc_root_inode_operations,
.proc_fops = &proc_root_operations,
.parent = &proc_root,
.name = "/proc",
};
/*
* This function parses a name such as "tty/driver/serial", and
* returns the struct proc_dir_entry for "/proc/tty/driver", and
* returns "serial" in residual.
*/
static int __xlate_proc_name(const char *name, struct proc_dir_entry **ret,
const char **residual)
{
const char *cp = name, *next;
struct proc_dir_entry *de;
unsigned int len;
de = *ret;
if (!de) //proc创建时ret为NULL
de = &proc_root;
while (1) {
next = strchr(cp, '/'); //name="mounts",这里不成立,break
if (!next)
break;
len = next - cp;
for (de = de->subdir; de ; de = de->next) {
if (proc_match(len, cp, de)) //确定‘/’之前,即cp到cp+len的字符长度,如"proc/mounts",那么这里的len是“proc”的长度
break; //目录匹配就直接退出
}
if (!de) {
WARN(1, "name '%s'\n", name);
return -ENOENT;
}
cp += len + 1;
}
*residual = cp;
*ret = de; //这里返回的是&proc_root
return 0;
}
proc_register()函数注册,这里会创建/proc/mounts符号链接:
static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
{
struct proc_dir_entry *tmp;
int ret;
ret = proc_alloc_inum(&dp->low_ino);
if (ret)
return ret;
//针对不同的模式(目录、文件、符号链接),提供的函数句柄不一样,
if (S_ISDIR(dp->mode)) {//目录
dp->proc_fops = &proc_dir_operations;
dp->proc_iops = &proc_dir_inode_operations;
dir->nlink++;
} else if (S_ISLNK(dp->mode)) { //符号链接
dp->proc_iops = &proc_link_inode_operations;
} else if (S_ISREG(dp->mode)) { //普通文件
BUG_ON(dp->proc_fops == NULL);
dp->proc_iops = &proc_file_inode_operations;
} else {
WARN_ON(1);
return -EINVAL;
}
spin_lock(&proc_subdir_lock);
for (tmp = dir->subdir; tmp; tmp = tmp->next)
if (strcmp(tmp->name, dp->name) == 0) {
WARN(1, "proc_dir_entry '%s/%s' already registered\n",
dir->name, dp->name);
break;
}
//dir指向/proc目录,至此,到这里就在/proc/目录下增加了mounts符号链接
dp->next = dir->subdir;
dp->parent = dir;
dir->subdir = dp;
spin_unlock(&proc_subdir_lock);
return 0;
}
3. proc_net_init()函数
static struct pernet_operations __net_initdata proc_net_ns_ops = {
.init = proc_net_ns_init,
.exit = proc_net_ns_exit,
};
int __init proc_net_init(void)
{
proc_symlink("net", NULL, "self/net");
return register_pernet_subsys(&proc_net_ns_ops);
}
proc_symlink("net", NULL, "self/net");函数已经在第2点中分析过了,就是在/proc目录下新建符号链接“net”
static struct list_head *first_device = &pernet_list;
int register_pernet_subsys(struct pernet_operations *ops)
{
int error;
mutex_lock(&net_mutex);
error = register_pernet_operations(first_device, ops);
mutex_unlock(&net_mutex);
return error;
}
register_pernet_operations函数的功能没有看明白???
static int register_pernet_operations(struct list_head *list,
struct pernet_operations *ops)
{
int error;
if (ops->id) {
again:
error = ida_get_new_above(&net_generic_ids, 1, ops->id);
if (error < 0) {
if (error == -EAGAIN) {
ida_pre_get(&net_generic_ids, GFP_KERNEL);
goto again;
}
return error;
}
max_gen_ptrs = max_t(unsigned int, max_gen_ptrs, *ops->id);
}
error = __register_pernet_operations(list, ops);
if (error) {
rcu_barrier();
if (ops->id)
ida_remove(&net_generic_ids, *ops->id);
}
return error;
}
4. proc_mkdir()函数
proc_mkdir("fs", NULL);
struct proc_dir_entry *proc_mkdir(const char *name,
struct proc_dir_entry *parent)
{
return proc_mkdir_data(name, 0, parent, NULL);
}
struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode,
struct proc_dir_entry *parent, void *data)
{
struct proc_dir_entry *ent;
if (mode == 0)
mode = S_IRUGO | S_IXUGO;
ent = __proc_create(&parent, name, S_IFDIR | mode, 2); //S_IFDIR 表示为目录
if (ent) {
ent->data = data;
if (proc_register(parent, ent) < 0) {
kfree(ent);
ent = NULL;
}
}
return ent;
}
proc_mkdir()最终也是调用__proc_create(),在/proc目录下创建“fs”目录,该函数前面已分析,在此不在赘述。
5. proc_tty_init()
/*
* Called by proc_root_init() to initialize the /proc/tty subtree
*/
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);
}
proc_mkdir_mode(...)和proc_create(...)内部都会调用__proc_create(),前面已分析,再次不在赘述!
6. proc_sys_init()
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 sysctl_init();
}