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

📄 cpuset.c

📁 linux 2.6.19 kernel source code before patching
💻 C
📖 第 1 页 / 共 5 页
字号:
		break;	case FILE_CPU_EXCLUSIVE:		retval = update_flag(CS_CPU_EXCLUSIVE, cs, buffer);		break;	case FILE_MEM_EXCLUSIVE:		retval = update_flag(CS_MEM_EXCLUSIVE, cs, buffer);		break;	case FILE_NOTIFY_ON_RELEASE:		retval = update_flag(CS_NOTIFY_ON_RELEASE, cs, buffer);		break;	case FILE_MEMORY_MIGRATE:		retval = update_flag(CS_MEMORY_MIGRATE, cs, buffer);		break;	case FILE_MEMORY_PRESSURE_ENABLED:		retval = update_memory_pressure_enabled(cs, buffer);		break;	case FILE_MEMORY_PRESSURE:		retval = -EACCES;		break;	case FILE_SPREAD_PAGE:		retval = update_flag(CS_SPREAD_PAGE, cs, buffer);		cs->mems_generation = cpuset_mems_generation++;		break;	case FILE_SPREAD_SLAB:		retval = update_flag(CS_SPREAD_SLAB, cs, buffer);		cs->mems_generation = cpuset_mems_generation++;		break;	case FILE_TASKLIST:		retval = attach_task(cs, buffer, &pathbuf);		break;	default:		retval = -EINVAL;		goto out2;	}	if (retval == 0)		retval = nbytes;out2:	mutex_unlock(&manage_mutex);	cpuset_release_agent(pathbuf);out1:	kfree(buffer);	return retval;}static ssize_t cpuset_file_write(struct file *file, const char __user *buf,						size_t nbytes, loff_t *ppos){	ssize_t retval = 0;	struct cftype *cft = __d_cft(file->f_path.dentry);	if (!cft)		return -ENODEV;	/* special function ? */	if (cft->write)		retval = cft->write(file, buf, nbytes, ppos);	else		retval = cpuset_common_file_write(file, buf, nbytes, ppos);	return retval;}/* * These ascii lists should be read in a single call, by using a user * buffer large enough to hold the entire map.  If read in smaller * chunks, there is no guarantee of atomicity.  Since the display format * used, list of ranges of sequential numbers, is variable length, * and since these maps can change value dynamically, one could read * gibberish by doing partial reads while a list was changing. * A single large read to a buffer that crosses a page boundary is * ok, because the result being copied to user land is not recomputed * across a page fault. */static int cpuset_sprintf_cpulist(char *page, struct cpuset *cs){	cpumask_t mask;	mutex_lock(&callback_mutex);	mask = cs->cpus_allowed;	mutex_unlock(&callback_mutex);	return cpulist_scnprintf(page, PAGE_SIZE, mask);}static int cpuset_sprintf_memlist(char *page, struct cpuset *cs){	nodemask_t mask;	mutex_lock(&callback_mutex);	mask = cs->mems_allowed;	mutex_unlock(&callback_mutex);	return nodelist_scnprintf(page, PAGE_SIZE, mask);}static ssize_t cpuset_common_file_read(struct file *file, char __user *buf,				size_t nbytes, loff_t *ppos){	struct cftype *cft = __d_cft(file->f_path.dentry);	struct cpuset *cs = __d_cs(file->f_path.dentry->d_parent);	cpuset_filetype_t type = cft->private;	char *page;	ssize_t retval = 0;	char *s;	if (!(page = (char *)__get_free_page(GFP_KERNEL)))		return -ENOMEM;	s = page;	switch (type) {	case FILE_CPULIST:		s += cpuset_sprintf_cpulist(s, cs);		break;	case FILE_MEMLIST:		s += cpuset_sprintf_memlist(s, cs);		break;	case FILE_CPU_EXCLUSIVE:		*s++ = is_cpu_exclusive(cs) ? '1' : '0';		break;	case FILE_MEM_EXCLUSIVE:		*s++ = is_mem_exclusive(cs) ? '1' : '0';		break;	case FILE_NOTIFY_ON_RELEASE:		*s++ = notify_on_release(cs) ? '1' : '0';		break;	case FILE_MEMORY_MIGRATE:		*s++ = is_memory_migrate(cs) ? '1' : '0';		break;	case FILE_MEMORY_PRESSURE_ENABLED:		*s++ = cpuset_memory_pressure_enabled ? '1' : '0';		break;	case FILE_MEMORY_PRESSURE:		s += sprintf(s, "%d", fmeter_getrate(&cs->fmeter));		break;	case FILE_SPREAD_PAGE:		*s++ = is_spread_page(cs) ? '1' : '0';		break;	case FILE_SPREAD_SLAB:		*s++ = is_spread_slab(cs) ? '1' : '0';		break;	default:		retval = -EINVAL;		goto out;	}	*s++ = '\n';	retval = simple_read_from_buffer(buf, nbytes, ppos, page, s - page);out:	free_page((unsigned long)page);	return retval;}static ssize_t cpuset_file_read(struct file *file, char __user *buf, size_t nbytes,								loff_t *ppos){	ssize_t retval = 0;	struct cftype *cft = __d_cft(file->f_path.dentry);	if (!cft)		return -ENODEV;	/* special function ? */	if (cft->read)		retval = cft->read(file, buf, nbytes, ppos);	else		retval = cpuset_common_file_read(file, buf, nbytes, ppos);	return retval;}static int cpuset_file_open(struct inode *inode, struct file *file){	int err;	struct cftype *cft;	err = generic_file_open(inode, file);	if (err)		return err;	cft = __d_cft(file->f_path.dentry);	if (!cft)		return -ENODEV;	if (cft->open)		err = cft->open(inode, file);	else		err = 0;	return err;}static int cpuset_file_release(struct inode *inode, struct file *file){	struct cftype *cft = __d_cft(file->f_path.dentry);	if (cft->release)		return cft->release(inode, file);	return 0;}/* * cpuset_rename - Only allow simple rename of directories in place. */static int cpuset_rename(struct inode *old_dir, struct dentry *old_dentry,                  struct inode *new_dir, struct dentry *new_dentry){	if (!S_ISDIR(old_dentry->d_inode->i_mode))		return -ENOTDIR;	if (new_dentry->d_inode)		return -EEXIST;	if (old_dir != new_dir)		return -EIO;	return simple_rename(old_dir, old_dentry, new_dir, new_dentry);}static const struct file_operations cpuset_file_operations = {	.read = cpuset_file_read,	.write = cpuset_file_write,	.llseek = generic_file_llseek,	.open = cpuset_file_open,	.release = cpuset_file_release,};static const struct inode_operations cpuset_dir_inode_operations = {	.lookup = simple_lookup,	.mkdir = cpuset_mkdir,	.rmdir = cpuset_rmdir,	.rename = cpuset_rename,};static int cpuset_create_file(struct dentry *dentry, int mode){	struct inode *inode;	if (!dentry)		return -ENOENT;	if (dentry->d_inode)		return -EEXIST;	inode = cpuset_new_inode(mode);	if (!inode)		return -ENOMEM;	if (S_ISDIR(mode)) {		inode->i_op = &cpuset_dir_inode_operations;		inode->i_fop = &simple_dir_operations;		/* start off with i_nlink == 2 (for "." entry) */		inc_nlink(inode);	} else if (S_ISREG(mode)) {		inode->i_size = 0;		inode->i_fop = &cpuset_file_operations;	}	d_instantiate(dentry, inode);	dget(dentry);	/* Extra count - pin the dentry in core */	return 0;}/* *	cpuset_create_dir - create a directory for an object. *	cs:	the cpuset we create the directory for. *		It must have a valid ->parent field *		And we are going to fill its ->dentry field. *	name:	The name to give to the cpuset directory. Will be copied. *	mode:	mode to set on new directory. */static int cpuset_create_dir(struct cpuset *cs, const char *name, int mode){	struct dentry *dentry = NULL;	struct dentry *parent;	int error = 0;	parent = cs->parent->dentry;	dentry = cpuset_get_dentry(parent, name);	if (IS_ERR(dentry))		return PTR_ERR(dentry);	error = cpuset_create_file(dentry, S_IFDIR | mode);	if (!error) {		dentry->d_fsdata = cs;		inc_nlink(parent->d_inode);		cs->dentry = dentry;	}	dput(dentry);	return error;}static int cpuset_add_file(struct dentry *dir, const struct cftype *cft){	struct dentry *dentry;	int error;	mutex_lock(&dir->d_inode->i_mutex);	dentry = cpuset_get_dentry(dir, cft->name);	if (!IS_ERR(dentry)) {		error = cpuset_create_file(dentry, 0644 | S_IFREG);		if (!error)			dentry->d_fsdata = (void *)cft;		dput(dentry);	} else		error = PTR_ERR(dentry);	mutex_unlock(&dir->d_inode->i_mutex);	return error;}/* * Stuff for reading the 'tasks' file. * * Reading this file can return large amounts of data if a cpuset has * *lots* of attached tasks. So it may need several calls to read(), * but we cannot guarantee that the information we produce is correct * unless we produce it entirely atomically. * * Upon tasks file open(), a struct ctr_struct is allocated, that * will have a pointer to an array (also allocated here).  The struct * ctr_struct * is stored in file->private_data.  Its resources will * be freed by release() when the file is closed.  The array is used * to sprintf the PIDs and then used by read(). *//* cpusets_tasks_read array */struct ctr_struct {	char *buf;	int bufsz;};/* * Load into 'pidarray' up to 'npids' of the tasks using cpuset 'cs'. * Return actual number of pids loaded.  No need to task_lock(p) * when reading out p->cpuset, as we don't really care if it changes * on the next cycle, and we are not going to try to dereference it. */static int pid_array_load(pid_t *pidarray, int npids, struct cpuset *cs){	int n = 0;	struct task_struct *g, *p;	read_lock(&tasklist_lock);	do_each_thread(g, p) {		if (p->cpuset == cs) {			if (unlikely(n == npids))				goto array_full;			pidarray[n++] = p->pid;		}	} while_each_thread(g, p);array_full:	read_unlock(&tasklist_lock);	return n;}static int cmppid(const void *a, const void *b){	return *(pid_t *)a - *(pid_t *)b;}/* * Convert array 'a' of 'npids' pid_t's to a string of newline separated * decimal pids in 'buf'.  Don't write more than 'sz' chars, but return * count 'cnt' of how many chars would be written if buf were large enough. */static int pid_array_to_buf(char *buf, int sz, pid_t *a, int npids){	int cnt = 0;	int i;	for (i = 0; i < npids; i++)		cnt += snprintf(buf + cnt, max(sz - cnt, 0), "%d\n", a[i]);	return cnt;}/* * Handle an open on 'tasks' file.  Prepare a buffer listing the * process id's of tasks currently attached to the cpuset being opened. * * Does not require any specific cpuset mutexes, and does not take any. */static int cpuset_tasks_open(struct inode *unused, struct file *file){	struct cpuset *cs = __d_cs(file->f_path.dentry->d_parent);	struct ctr_struct *ctr;	pid_t *pidarray;	int npids;	char c;	if (!(file->f_mode & FMODE_READ))		return 0;	ctr = kmalloc(sizeof(*ctr), GFP_KERNEL);	if (!ctr)		goto err0;	/*	 * If cpuset gets more users after we read count, we won't have	 * enough space - tough.  This race is indistinguishable to the	 * caller from the case that the additional cpuset users didn't	 * show up until sometime later on.	 */	npids = atomic_read(&cs->count);	pidarray = kmalloc(npids * sizeof(pid_t), GFP_KERNEL);	if (!pidarray)		goto err1;	npids = pid_array_load(pidarray, npids, cs);	sort(pidarray, npids, sizeof(pid_t), cmppid, NULL);	/* Call pid_array_to_buf() twice, first just to get bufsz */	ctr->bufsz = pid_array_to_buf(&c, sizeof(c), pidarray, npids) + 1;	ctr->buf = kmalloc(ctr->bufsz, GFP_KERNEL);	if (!ctr->buf)		goto err2;	ctr->bufsz = pid_array_to_buf(ctr->buf, ctr->bufsz, pidarray, npids);	kfree(pidarray);	file->private_data = ctr;	return 0;err2:	kfree(pidarray);err1:	kfree(ctr);err0:	return -ENOMEM;}static ssize_t cpuset_tasks_read(struct file *file, char __user *buf,						size_t nbytes, loff_t *ppos){	struct ctr_struct *ctr = file->private_data;	return simple_read_from_buffer(buf, nbytes, ppos, ctr->buf, ctr->bufsz);}static int cpuset_tasks_release(struct inode *unused_inode, struct file *file){	struct ctr_struct *ctr;	if (file->f_mode & FMODE_READ) {		ctr = file->private_data;		kfree(ctr->buf);		kfree(ctr);	}	return 0;}

⌨️ 快捷键说明

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