1688 lines · 43.9 KB · C
RawDownload
/* *  kernel/cpuset.c * *  Processor and Memory placement constraints for sets of tasks. * *  Copyright (C) 2003 BULL SA. *  Copyright (C) 2004 Silicon Graphics, Inc. * *  Portions derived from Patrick Mochel's sysfs code. *  sysfs is Copyright (c) 2001-3 Patrick Mochel *  Portions Copyright (c) 2004 Silicon Graphics, Inc. * *  2003-10-10 Written by Simon Derr <simon.derr@bull.net> *  2003-10-22 Updates by Stephen Hemminger. *  2004 May-July Rework by Paul Jackson <pj@sgi.com> * *  This file is subject to the terms and conditions of the GNU General Public *  License.  See the file COPYING in the main directory of the Linux *  distribution for more details. */ #include <linux/config.h>#include <linux/cpu.h>#include <linux/cpumask.h>#include <linux/cpuset.h>#include <linux/err.h>#include <linux/errno.h>#include <linux/file.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/kernel.h>#include <linux/kmod.h>#include <linux/list.h>#include <linux/mm.h>#include <linux/module.h>#include <linux/mount.h>#include <linux/namei.h>#include <linux/pagemap.h>#include <linux/proc_fs.h>#include <linux/sched.h>#include <linux/seq_file.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/spinlock.h>#include <linux/stat.h>#include <linux/string.h>#include <linux/time.h>#include <linux/backing-dev.h>#include <linux/sort.h> #include <asm/uaccess.h>#include <asm/atomic.h>#include <asm/semaphore.h> #define CPUSET_SUPER_MAGIC 		0x27e0eb struct cpuset {	unsigned long flags;		/* "unsigned long" so bitops work */	cpumask_t cpus_allowed;		/* CPUs allowed to tasks in cpuset */	nodemask_t mems_allowed;	/* Memory Nodes allowed to tasks */ 	atomic_t count;			/* count tasks using this cpuset */ 	/*	 * We link our 'sibling' struct into our parents 'children'.	 * Our children link their 'sibling' into our 'children'.	 */	struct list_head sibling;	/* my parents children */	struct list_head children;	/* my children */ 	struct cpuset *parent;		/* my parent */	struct dentry *dentry;		/* cpuset fs entry */ 	/*	 * Copy of global cpuset_mems_generation as of the most	 * recent time this cpuset changed its mems_allowed.	 */	 int mems_generation;}; /* bits in struct cpuset flags field */typedef enum {	CS_CPU_EXCLUSIVE,	CS_MEM_EXCLUSIVE,	CS_REMOVED,	CS_NOTIFY_ON_RELEASE} cpuset_flagbits_t; /* convenient tests for these bits */static inline int is_cpu_exclusive(const struct cpuset *cs){	return !!test_bit(CS_CPU_EXCLUSIVE, &cs->flags);} static inline int is_mem_exclusive(const struct cpuset *cs){	return !!test_bit(CS_MEM_EXCLUSIVE, &cs->flags);} static inline int is_removed(const struct cpuset *cs){	return !!test_bit(CS_REMOVED, &cs->flags);} static inline int notify_on_release(const struct cpuset *cs){	return !!test_bit(CS_NOTIFY_ON_RELEASE, &cs->flags);} /* * Increment this atomic integer everytime any cpuset changes its * mems_allowed value.  Users of cpusets can track this generation * number, and avoid having to lock and reload mems_allowed unless * the cpuset they're using changes generation. * * A single, global generation is needed because attach_task() could * reattach a task to a different cpuset, which must not have its * generation numbers aliased with those of that tasks previous cpuset. * * Generations are needed for mems_allowed because one task cannot * modify anothers memory placement.  So we must enable every task, * on every visit to __alloc_pages(), to efficiently check whether * its current->cpuset->mems_allowed has changed, requiring an update * of its current->mems_allowed. */static atomic_t cpuset_mems_generation = ATOMIC_INIT(1); static struct cpuset top_cpuset = {	.flags = ((1 << CS_CPU_EXCLUSIVE) | (1 << CS_MEM_EXCLUSIVE)),	.cpus_allowed = CPU_MASK_ALL,	.mems_allowed = NODE_MASK_ALL,	.count = ATOMIC_INIT(0),	.sibling = LIST_HEAD_INIT(top_cpuset.sibling),	.children = LIST_HEAD_INIT(top_cpuset.children),	.parent = NULL,	.dentry = NULL,	.mems_generation = 0,}; static struct vfsmount *cpuset_mount;static struct super_block *cpuset_sb = NULL; /* * cpuset_sem should be held by anyone who is depending on the children * or sibling lists of any cpuset, or performing non-atomic operations * on the flags or *_allowed values of a cpuset, such as raising the * CS_REMOVED flag bit iff it is not already raised, or reading and * conditionally modifying the *_allowed values.  One kernel global * cpuset semaphore should be sufficient - these things don't change * that much. * * The code that modifies cpusets holds cpuset_sem across the entire * operation, from cpuset_common_file_write() down, single threading * all cpuset modifications (except for counter manipulations from * fork and exit) across the system.  This presumes that cpuset * modifications are rare - better kept simple and safe, even if slow. * * The code that reads cpusets, such as in cpuset_common_file_read() * and below, only holds cpuset_sem across small pieces of code, such * as when reading out possibly multi-word cpumasks and nodemasks, as * the risks are less, and the desire for performance a little greater. * The proc_cpuset_show() routine needs to hold cpuset_sem to insure * that no cs->dentry is NULL, as it walks up the cpuset tree to root. * * The hooks from fork and exit, cpuset_fork() and cpuset_exit(), don't * (usually) grab cpuset_sem.  These are the two most performance * critical pieces of code here.  The exception occurs on exit(), * when a task in a notify_on_release cpuset exits.  Then cpuset_sem * is taken, and if the cpuset count is zero, a usermode call made * to /sbin/cpuset_release_agent with the name of the cpuset (path * relative to the root of cpuset file system) as the argument. * * A cpuset can only be deleted if both its 'count' of using tasks is * zero, and its list of 'children' cpusets is empty.  Since all tasks * in the system use _some_ cpuset, and since there is always at least * one task in the system (init, pid == 1), therefore, top_cpuset * always has either children cpusets and/or using tasks.  So no need * for any special hack to ensure that top_cpuset cannot be deleted. */ static DECLARE_MUTEX(cpuset_sem); /* * A couple of forward declarations required, due to cyclic reference loop: *  cpuset_mkdir -> cpuset_create -> cpuset_populate_dir -> cpuset_add_file *  -> cpuset_create_file -> cpuset_dir_inode_operations -> cpuset_mkdir. */ static int cpuset_mkdir(struct inode *dir, struct dentry *dentry, int mode);static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry); static struct backing_dev_info cpuset_backing_dev_info = {	.ra_pages = 0,		/* No readahead */	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,}; static struct inode *cpuset_new_inode(mode_t mode){	struct inode *inode = new_inode(cpuset_sb); 	if (inode) {		inode->i_mode = mode;		inode->i_uid = current->fsuid;		inode->i_gid = current->fsgid;		inode->i_blksize = PAGE_CACHE_SIZE;		inode->i_blocks = 0;		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;		inode->i_mapping->backing_dev_info = &cpuset_backing_dev_info;	}	return inode;} static void cpuset_diput(struct dentry *dentry, struct inode *inode){	/* is dentry a directory ? if so, kfree() associated cpuset */	if (S_ISDIR(inode->i_mode)) {		struct cpuset *cs = dentry->d_fsdata;		BUG_ON(!(is_removed(cs)));		kfree(cs);	}	iput(inode);} static struct dentry_operations cpuset_dops = {	.d_iput = cpuset_diput,}; static struct dentry *cpuset_get_dentry(struct dentry *parent, const char *name){	struct dentry *d = lookup_one_len(name, parent, strlen(name));	if (!IS_ERR(d))		d->d_op = &cpuset_dops;	return d;} static void remove_dir(struct dentry *d){	struct dentry *parent = dget(d->d_parent); 	d_delete(d);	simple_rmdir(parent->d_inode, d);	dput(parent);} /* * NOTE : the dentry must have been dget()'ed */static void cpuset_d_remove_dir(struct dentry *dentry){	struct list_head *node; 	spin_lock(&dcache_lock);	node = dentry->d_subdirs.next;	while (node != &dentry->d_subdirs) {		struct dentry *d = list_entry(node, struct dentry, d_child);		list_del_init(node);		if (d->d_inode) {			d = dget_locked(d);			spin_unlock(&dcache_lock);			d_delete(d);			simple_unlink(dentry->d_inode, d);			dput(d);			spin_lock(&dcache_lock);		}		node = dentry->d_subdirs.next;	}	list_del_init(&dentry->d_child);	spin_unlock(&dcache_lock);	remove_dir(dentry);} static struct super_operations cpuset_ops = {	.statfs = simple_statfs,	.drop_inode = generic_delete_inode,}; static int cpuset_fill_super(struct super_block *sb, void *unused_data,							int unused_silent){	struct inode *inode;	struct dentry *root; 	sb->s_blocksize = PAGE_CACHE_SIZE;	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;	sb->s_magic = CPUSET_SUPER_MAGIC;	sb->s_op = &cpuset_ops;	cpuset_sb = sb; 	inode = cpuset_new_inode(S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR);	if (inode) {		inode->i_op = &simple_dir_inode_operations;		inode->i_fop = &simple_dir_operations;		/* directories start off with i_nlink == 2 (for "." entry) */		inode->i_nlink++;	} else {		return -ENOMEM;	} 	root = d_alloc_root(inode);	if (!root) {		iput(inode);		return -ENOMEM;	}	sb->s_root = root;	return 0;} static struct super_block *cpuset_get_sb(struct file_system_type *fs_type,					int flags, const char *unused_dev_name,					void *data){	return get_sb_single(fs_type, flags, data, cpuset_fill_super);} static struct file_system_type cpuset_fs_type = {	.name = "cpuset",	.get_sb = cpuset_get_sb,	.kill_sb = kill_litter_super,}; /* struct cftype: * * The files in the cpuset filesystem mostly have a very simple read/write * handling, some common function will take care of it. Nevertheless some cases * (read tasks) are special and therefore I define this structure for every * kind of file. * * * When reading/writing to a file: *	- the cpuset to use in file->f_dentry->d_parent->d_fsdata *	- the 'cftype' of the file is file->f_dentry->d_fsdata */ struct cftype {	char *name;	int private;	int (*open) (struct inode *inode, struct file *file);	ssize_t (*read) (struct file *file, char __user *buf, size_t nbytes,							loff_t *ppos);	int (*write) (struct file *file, const char __user *buf, size_t nbytes,							loff_t *ppos);	int (*release) (struct inode *inode, struct file *file);}; static inline struct cpuset *__d_cs(struct dentry *dentry){	return dentry->d_fsdata;} static inline struct cftype *__d_cft(struct dentry *dentry){	return dentry->d_fsdata;} /* * Call with cpuset_sem held.  Writes path of cpuset into buf. * Returns 0 on success, -errno on error. */ static int cpuset_path(const struct cpuset *cs, char *buf, int buflen){	char *start; 	start = buf + buflen; 	*--start = '\0';	for (;;) {		int len = cs->dentry->d_name.len;		if ((start -= len) < buf)			return -ENAMETOOLONG;		memcpy(start, cs->dentry->d_name.name, len);		cs = cs->parent;		if (!cs)			break;		if (!cs->parent)			continue;		if (--start < buf)			return -ENAMETOOLONG;		*start = '/';	}	memmove(buf, start, buf + buflen - start);	return 0;} /* * Notify userspace when a cpuset is released, by running * /sbin/cpuset_release_agent with the name of the cpuset (path * relative to the root of cpuset file system) as the argument. * * Most likely, this user command will try to rmdir this cpuset. * * This races with the possibility that some other task will be * attached to this cpuset before it is removed, or that some other * user task will 'mkdir' a child cpuset of this cpuset.  That's ok. * The presumed 'rmdir' will fail quietly if this cpuset is no longer * unused, and this cpuset will be reprieved from its death sentence, * to continue to serve a useful existence.  Next time it's released, * we will get notified again, if it still has 'notify_on_release' set. * * The final arg to call_usermodehelper() is 0, which means don't * wait.  The separate /sbin/cpuset_release_agent task is forked by * call_usermodehelper(), then control in this thread returns here, * without waiting for the release agent task.  We don't bother to * wait because the caller of this routine has no use for the exit * status of the /sbin/cpuset_release_agent task, so no sense holding * our caller up for that. * * The simple act of forking that task might require more memory, * which might need cpuset_sem.  So this routine must be called while * cpuset_sem is not held, to avoid a possible deadlock.  See also * comments for check_for_release(), below. */ static void cpuset_release_agent(const char *pathbuf){	char *argv[3], *envp[3];	int i; 	if (!pathbuf)		return; 	i = 0;	argv[i++] = "/sbin/cpuset_release_agent";	argv[i++] = (char *)pathbuf;	argv[i] = NULL; 	i = 0;	/* minimal command environment */	envp[i++] = "HOME=/";	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";	envp[i] = NULL; 	call_usermodehelper(argv[0], argv, envp, 0);	kfree(pathbuf);} /* * Either cs->count of using tasks transitioned to zero, or the * cs->children list of child cpusets just became empty.  If this * cs is notify_on_release() and now both the user count is zero and * the list of children is empty, prepare cpuset path in a kmalloc'd * buffer, to be returned via ppathbuf, so that the caller can invoke * cpuset_release_agent() with it later on, once cpuset_sem is dropped. * Call here with cpuset_sem held. * * This check_for_release() routine is responsible for kmalloc'ing * pathbuf.  The above cpuset_release_agent() is responsible for * kfree'ing pathbuf.  The caller of these routines is responsible * for providing a pathbuf pointer, initialized to NULL, then * calling check_for_release() with cpuset_sem held and the address * of the pathbuf pointer, then dropping cpuset_sem, then calling * cpuset_release_agent() with pathbuf, as set by check_for_release(). */ static void check_for_release(struct cpuset *cs, char **ppathbuf){	if (notify_on_release(cs) && atomic_read(&cs->count) == 0 &&	    list_empty(&cs->children)) {		char *buf; 		buf = kmalloc(PAGE_SIZE, GFP_KERNEL);		if (!buf)			return;		if (cpuset_path(cs, buf, PAGE_SIZE) < 0)			kfree(buf);		else			*ppathbuf = buf;	}} /* * Return in *pmask the portion of a cpusets's cpus_allowed that * are online.  If none are online, walk up the cpuset hierarchy * until we find one that does have some online cpus.  If we get * all the way to the top and still haven't found any online cpus, * return cpu_online_map.  Or if passed a NULL cs from an exit'ing * task, return cpu_online_map. * * One way or another, we guarantee to return some non-empty subset * of cpu_online_map. * * Call with cpuset_sem held. */ static void guarantee_online_cpus(const struct cpuset *cs, cpumask_t *pmask){	while (cs && !cpus_intersects(cs->cpus_allowed, cpu_online_map))		cs = cs->parent;	if (cs)		cpus_and(*pmask, cs->cpus_allowed, cpu_online_map);	else		*pmask = cpu_online_map;	BUG_ON(!cpus_intersects(*pmask, cpu_online_map));} /* * Return in *pmask the portion of a cpusets's mems_allowed that * are online.  If none are online, walk up the cpuset hierarchy * until we find one that does have some online mems.  If we get

Lines 1–500 of 1688.