linux proc_root_init

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();
}

 

 

 

 

 

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页