⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cgroup.c

📁 Kernel code of linux kernel
💻 C
📖 第 1 页 / 共 5 页
字号:
		struct inode *inode;		int i;		BUG_ON(sb->s_root != NULL);		ret = cgroup_get_rootdir(sb);		if (ret)			goto drop_new_super;		inode = sb->s_root->d_inode;		mutex_lock(&inode->i_mutex);		mutex_lock(&cgroup_mutex);		/*		 * We're accessing css_set_count without locking		 * css_set_lock here, but that's OK - it can only be		 * increased by someone holding cgroup_lock, and		 * that's us. The worst that can happen is that we		 * have some link structures left over		 */		ret = allocate_cg_links(css_set_count, &tmp_cg_links);		if (ret) {			mutex_unlock(&cgroup_mutex);			mutex_unlock(&inode->i_mutex);			goto drop_new_super;		}		ret = rebind_subsystems(root, root->subsys_bits);		if (ret == -EBUSY) {			mutex_unlock(&cgroup_mutex);			mutex_unlock(&inode->i_mutex);			goto drop_new_super;		}		/* EBUSY should be the only error here */		BUG_ON(ret);		list_add(&root->root_list, &roots);		root_count++;		sb->s_root->d_fsdata = &root->top_cgroup;		root->top_cgroup.dentry = sb->s_root;		/* Link the top cgroup in this hierarchy into all		 * the css_set objects */		write_lock(&css_set_lock);		for (i = 0; i < CSS_SET_TABLE_SIZE; i++) {			struct hlist_head *hhead = &css_set_table[i];			struct hlist_node *node;			struct css_set *cg;			hlist_for_each_entry(cg, node, hhead, hlist) {				struct cg_cgroup_link *link;				BUG_ON(list_empty(&tmp_cg_links));				link = list_entry(tmp_cg_links.next,						  struct cg_cgroup_link,						  cgrp_link_list);				list_del(&link->cgrp_link_list);				link->cg = cg;				list_add(&link->cgrp_link_list,					 &root->top_cgroup.css_sets);				list_add(&link->cg_link_list, &cg->cg_links);			}		}		write_unlock(&css_set_lock);		free_cg_links(&tmp_cg_links);		BUG_ON(!list_empty(&cgrp->sibling));		BUG_ON(!list_empty(&cgrp->children));		BUG_ON(root->number_of_cgroups != 1);		cgroup_populate_dir(cgrp);		mutex_unlock(&inode->i_mutex);		mutex_unlock(&cgroup_mutex);	}	return simple_set_mnt(mnt, sb); drop_new_super:	up_write(&sb->s_umount);	deactivate_super(sb);	free_cg_links(&tmp_cg_links);	return ret;}static void cgroup_kill_sb(struct super_block *sb) {	struct cgroupfs_root *root = sb->s_fs_info;	struct cgroup *cgrp = &root->top_cgroup;	int ret;	struct cg_cgroup_link *link;	struct cg_cgroup_link *saved_link;	BUG_ON(!root);	BUG_ON(root->number_of_cgroups != 1);	BUG_ON(!list_empty(&cgrp->children));	BUG_ON(!list_empty(&cgrp->sibling));	mutex_lock(&cgroup_mutex);	/* Rebind all subsystems back to the default hierarchy */	ret = rebind_subsystems(root, 0);	/* Shouldn't be able to fail ... */	BUG_ON(ret);	/*	 * Release all the links from css_sets to this hierarchy's	 * root cgroup	 */	write_lock(&css_set_lock);	list_for_each_entry_safe(link, saved_link, &cgrp->css_sets,				 cgrp_link_list) {		list_del(&link->cg_link_list);		list_del(&link->cgrp_link_list);		kfree(link);	}	write_unlock(&css_set_lock);	if (!list_empty(&root->root_list)) {		list_del(&root->root_list);		root_count--;	}	mutex_unlock(&cgroup_mutex);	kfree(root);	kill_litter_super(sb);}static struct file_system_type cgroup_fs_type = {	.name = "cgroup",	.get_sb = cgroup_get_sb,	.kill_sb = cgroup_kill_sb,};static inline struct cgroup *__d_cgrp(struct dentry *dentry){	return dentry->d_fsdata;}static inline struct cftype *__d_cft(struct dentry *dentry){	return dentry->d_fsdata;}/** * cgroup_path - generate the path of a cgroup * @cgrp: the cgroup in question * @buf: the buffer to write the path into * @buflen: the length of the buffer * * Called with cgroup_mutex held. Writes path of cgroup into buf. * Returns 0 on success, -errno on error. */int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen){	char *start;	if (cgrp == dummytop) {		/*		 * Inactive subsystems have no dentry for their root		 * cgroup		 */		strcpy(buf, "/");		return 0;	}	start = buf + buflen;	*--start = '\0';	for (;;) {		int len = cgrp->dentry->d_name.len;		if ((start -= len) < buf)			return -ENAMETOOLONG;		memcpy(start, cgrp->dentry->d_name.name, len);		cgrp = cgrp->parent;		if (!cgrp)			break;		if (!cgrp->parent)			continue;		if (--start < buf)			return -ENAMETOOLONG;		*start = '/';	}	memmove(buf, start, buf + buflen - start);	return 0;}/* * Return the first subsystem attached to a cgroup's hierarchy, and * its subsystem id. */static void get_first_subsys(const struct cgroup *cgrp,			struct cgroup_subsys_state **css, int *subsys_id){	const struct cgroupfs_root *root = cgrp->root;	const struct cgroup_subsys *test_ss;	BUG_ON(list_empty(&root->subsys_list));	test_ss = list_entry(root->subsys_list.next,			     struct cgroup_subsys, sibling);	if (css) {		*css = cgrp->subsys[test_ss->subsys_id];		BUG_ON(!*css);	}	if (subsys_id)		*subsys_id = test_ss->subsys_id;}/** * cgroup_attach_task - attach task 'tsk' to cgroup 'cgrp' * @cgrp: the cgroup the task is attaching to * @tsk: the task to be attached * * Call holding cgroup_mutex. May take task_lock of * the task 'tsk' during call. */int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk){	int retval = 0;	struct cgroup_subsys *ss;	struct cgroup *oldcgrp;	struct css_set *cg = tsk->cgroups;	struct css_set *newcg;	struct cgroupfs_root *root = cgrp->root;	int subsys_id;	get_first_subsys(cgrp, NULL, &subsys_id);	/* Nothing to do if the task is already in that cgroup */	oldcgrp = task_cgroup(tsk, subsys_id);	if (cgrp == oldcgrp)		return 0;	for_each_subsys(root, ss) {		if (ss->can_attach) {			retval = ss->can_attach(ss, cgrp, tsk);			if (retval)				return retval;		}	}	/*	 * Locate or allocate a new css_set for this task,	 * based on its final set of cgroups	 */	newcg = find_css_set(cg, cgrp);	if (!newcg)		return -ENOMEM;	task_lock(tsk);	if (tsk->flags & PF_EXITING) {		task_unlock(tsk);		put_css_set(newcg);		return -ESRCH;	}	rcu_assign_pointer(tsk->cgroups, newcg);	task_unlock(tsk);	/* Update the css_set linked lists if we're using them */	write_lock(&css_set_lock);	if (!list_empty(&tsk->cg_list)) {		list_del(&tsk->cg_list);		list_add(&tsk->cg_list, &newcg->tasks);	}	write_unlock(&css_set_lock);	for_each_subsys(root, ss) {		if (ss->attach)			ss->attach(ss, cgrp, oldcgrp, tsk);	}	set_bit(CGRP_RELEASABLE, &oldcgrp->flags);	synchronize_rcu();	put_css_set(cg);	return 0;}/* * Attach task with pid 'pid' to cgroup 'cgrp'. Call with cgroup_mutex * held. May take task_lock of task */static int attach_task_by_pid(struct cgroup *cgrp, u64 pid){	struct task_struct *tsk;	int ret;	if (pid) {		rcu_read_lock();		tsk = find_task_by_vpid(pid);		if (!tsk || tsk->flags & PF_EXITING) {			rcu_read_unlock();			return -ESRCH;		}		get_task_struct(tsk);		rcu_read_unlock();		if ((current->euid) && (current->euid != tsk->uid)		    && (current->euid != tsk->suid)) {			put_task_struct(tsk);			return -EACCES;		}	} else {		tsk = current;		get_task_struct(tsk);	}	ret = cgroup_attach_task(cgrp, tsk);	put_task_struct(tsk);	return ret;}static int cgroup_tasks_write(struct cgroup *cgrp, struct cftype *cft, u64 pid){	int ret;	if (!cgroup_lock_live_group(cgrp))		return -ENODEV;	ret = attach_task_by_pid(cgrp, pid);	cgroup_unlock();	return ret;}/* The various types of files and directories in a cgroup file system */enum cgroup_filetype {	FILE_ROOT,	FILE_DIR,	FILE_TASKLIST,	FILE_NOTIFY_ON_RELEASE,	FILE_RELEASE_AGENT,};/** * cgroup_lock_live_group - take cgroup_mutex and check that cgrp is alive. * @cgrp: the cgroup to be checked for liveness * * On success, returns true; the lock should be later released with * cgroup_unlock(). On failure returns false with no lock held. */bool cgroup_lock_live_group(struct cgroup *cgrp){	mutex_lock(&cgroup_mutex);	if (cgroup_is_removed(cgrp)) {		mutex_unlock(&cgroup_mutex);		return false;	}	return true;}static int cgroup_release_agent_write(struct cgroup *cgrp, struct cftype *cft,				      const char *buffer){	BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);	if (!cgroup_lock_live_group(cgrp))		return -ENODEV;	strcpy(cgrp->root->release_agent_path, buffer);	cgroup_unlock();	return 0;}static int cgroup_release_agent_show(struct cgroup *cgrp, struct cftype *cft,				     struct seq_file *seq){	if (!cgroup_lock_live_group(cgrp))		return -ENODEV;	seq_puts(seq, cgrp->root->release_agent_path);	seq_putc(seq, '\n');	cgroup_unlock();	return 0;}/* A buffer size big enough for numbers or short strings */#define CGROUP_LOCAL_BUFFER_SIZE 64static ssize_t cgroup_write_X64(struct cgroup *cgrp, struct cftype *cft,				struct file *file,				const char __user *userbuf,				size_t nbytes, loff_t *unused_ppos){	char buffer[CGROUP_LOCAL_BUFFER_SIZE];	int retval = 0;	char *end;	if (!nbytes)		return -EINVAL;	if (nbytes >= sizeof(buffer))		return -E2BIG;	if (copy_from_user(buffer, userbuf, nbytes))		return -EFAULT;	buffer[nbytes] = 0;     /* nul-terminate */	strstrip(buffer);	if (cft->write_u64) {		u64 val = simple_strtoull(buffer, &end, 0);		if (*end)			return -EINVAL;		retval = cft->write_u64(cgrp, cft, val);	} else {		s64 val = simple_strtoll(buffer, &end, 0);		if (*end)			return -EINVAL;		retval = cft->write_s64(cgrp, cft, val);	}	if (!retval)		retval = nbytes;	return retval;}static ssize_t cgroup_write_string(struct cgroup *cgrp, struct cftype *cft,				   struct file *file,				   const char __user *userbuf,				   size_t nbytes, loff_t *unused_ppos){	char local_buffer[CGROUP_LOCAL_BUFFER_SIZE];	int retval = 0;	size_t max_bytes = cft->max_write_len;	char *buffer = local_buffer;	if (!max_bytes)		max_bytes = sizeof(local_buffer) - 1;	if (nbytes >= max_bytes)		return -E2BIG;	/* Allocate a dynamic buffer if we need one */	if (nbytes >= sizeof(local_buffer)) {		buffer = kmalloc(nbytes + 1, GFP_KERNEL);		if (buffer == NULL)			return -ENOMEM;	}	if (nbytes && copy_from_user(buffer, userbuf, nbytes)) {		retval = -EFAULT;		goto out;	}	buffer[nbytes] = 0;     /* nul-terminate */	strstrip(buffer);	retval = cft->write_string(cgrp, cft, buffer);	if (!retval)		retval = nbytes;out:	if (buffer != local_buffer)		kfree(buffer);	return retval;}static ssize_t cgroup_file_write(struct file *file, const char __user *buf,						size_t nbytes, loff_t *ppos){	struct cftype *cft = __d_cft(file->f_dentry);	struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent);	if (!cft || cgroup_is_removed(cgrp))		return -ENODEV;	if (cft->write)		return cft->write(cgrp, cft, file, buf, nbytes, ppos);	if (cft->write_u64 || cft->write_s64)		return cgroup_write_X64(cgrp, cft, file, buf, nbytes, ppos);	if (cft->write_string)		return cgroup_write_string(cgrp, cft, file, buf, nbytes, ppos);	if (cft->trigger) {		int ret = cft->trigger(cgrp, (unsigned int)cft->private);		return ret ? ret : nbytes;	}	return -EINVAL;}static ssize_t cgroup_read_u64(struct cgroup *cgrp, struct cftype *cft,			       struct file *file,			       char __user *buf, size_t nbytes,			       loff_t *ppos){	char tmp[CGROUP_LOCAL_BUFFER_SIZE];	u64 val = cft->read_u64(cgrp, cft);	int len = sprintf(tmp, "%llu\n", (unsigned long long) val);	return simple_read_from_buffer(buf, nbytes, ppos, tmp, len);}static ssize_t cgroup_read_s64(struct cgroup *cgrp, struct cftype *cft,			       struct file *file,			       char __user *buf, size_t nbytes,			       loff_t *ppos){	char tmp[CGROUP_LOCAL_BUFFER_SIZE];	s64 val = cft->read_s64(cgrp, cft);	int len = sprintf(tmp, "%lld\n", (long long) val);	return simple_read_from_buffer(buf, nbytes, ppos, tmp, len);}static ssize_t cgroup_file_read(struct file *file, char __user *buf,				   size_t nbytes, loff_t *ppos){	struct cftype *cft = __d_cft(file->f_dentry);	struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent);	if (!cft || cgroup_is_removed(cgrp))

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -