diff options
Diffstat (limited to 'kernel/cpuset.c')
| -rw-r--r-- | kernel/cpuset.c | 70 | 
1 files changed, 54 insertions, 16 deletions
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 8da627d3380..9fceb97e989 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -797,8 +797,10 @@ static int update_cpumask(struct cpuset *cs, char *buf)  		retval = cpulist_parse(buf, trialcs.cpus_allowed);  		if (retval < 0)  			return retval; + +		if (!cpus_subset(trialcs.cpus_allowed, cpu_online_map)) +			return -EINVAL;  	} -	cpus_and(trialcs.cpus_allowed, trialcs.cpus_allowed, cpu_online_map);  	retval = validate_change(cs, &trialcs);  	if (retval < 0)  		return retval; @@ -932,9 +934,11 @@ static int update_nodemask(struct cpuset *cs, char *buf)  		retval = nodelist_parse(buf, trialcs.mems_allowed);  		if (retval < 0)  			goto done; + +		if (!nodes_subset(trialcs.mems_allowed, +				node_states[N_HIGH_MEMORY])) +			return -EINVAL;  	} -	nodes_and(trialcs.mems_allowed, trialcs.mems_allowed, -						node_states[N_HIGH_MEMORY]);  	oldmem = cs->mems_allowed;  	if (nodes_equal(oldmem, trialcs.mems_allowed)) {  		retval = 0;		/* Too easy - nothing to do */ @@ -1031,12 +1035,10 @@ int current_cpuset_is_being_rebound(void)  	return task_cs(current) == cpuset_being_rebound;  } -static int update_relax_domain_level(struct cpuset *cs, char *buf) +static int update_relax_domain_level(struct cpuset *cs, s64 val)  { -	int val = simple_strtol(buf, NULL, 10); - -	if (val < 0) -		val = -1; +	if (val < -1 || val >= SD_LV_MAX) +		return -EINVAL;  	if (val != cs->relax_domain_level) {  		cs->relax_domain_level = val; @@ -1280,9 +1282,6 @@ static ssize_t cpuset_common_file_write(struct cgroup *cont,  	case FILE_MEMLIST:  		retval = update_nodemask(cs, buffer);  		break; -	case FILE_SCHED_RELAX_DOMAIN_LEVEL: -		retval = update_relax_domain_level(cs, buffer); -		break;  	default:  		retval = -EINVAL;  		goto out2; @@ -1348,6 +1347,30 @@ static int cpuset_write_u64(struct cgroup *cgrp, struct cftype *cft, u64 val)  	return retval;  } +static int cpuset_write_s64(struct cgroup *cgrp, struct cftype *cft, s64 val) +{ +	int retval = 0; +	struct cpuset *cs = cgroup_cs(cgrp); +	cpuset_filetype_t type = cft->private; + +	cgroup_lock(); + +	if (cgroup_is_removed(cgrp)) { +		cgroup_unlock(); +		return -ENODEV; +	} +	switch (type) { +	case FILE_SCHED_RELAX_DOMAIN_LEVEL: +		retval = update_relax_domain_level(cs, val); +		break; +	default: +		retval = -EINVAL; +		break; +	} +	cgroup_unlock(); +	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 @@ -1406,9 +1429,6 @@ static ssize_t cpuset_common_file_read(struct cgroup *cont,  	case FILE_MEMLIST:  		s += cpuset_sprintf_memlist(s, cs);  		break; -	case FILE_SCHED_RELAX_DOMAIN_LEVEL: -		s += sprintf(s, "%d", cs->relax_domain_level); -		break;  	default:  		retval = -EINVAL;  		goto out; @@ -1449,6 +1469,18 @@ static u64 cpuset_read_u64(struct cgroup *cont, struct cftype *cft)  	}  } +static s64 cpuset_read_s64(struct cgroup *cont, struct cftype *cft) +{ +	struct cpuset *cs = cgroup_cs(cont); +	cpuset_filetype_t type = cft->private; +	switch (type) { +	case FILE_SCHED_RELAX_DOMAIN_LEVEL: +		return cs->relax_domain_level; +	default: +		BUG(); +	} +} +  /*   * for the common functions, 'private' gives the type of file @@ -1499,8 +1531,8 @@ static struct cftype files[] = {  	{  		.name = "sched_relax_domain_level", -		.read_u64 = cpuset_read_u64, -		.write_u64 = cpuset_write_u64, +		.read_s64 = cpuset_read_s64, +		.write_s64 = cpuset_write_s64,  		.private = FILE_SCHED_RELAX_DOMAIN_LEVEL,  	}, @@ -1858,6 +1890,12 @@ static void common_cpu_mem_hotplug_unplug(void)  	top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];  	scan_for_empty_cpusets(&top_cpuset); +	/* +	 * Scheduler destroys domains on hotplug events. +	 * Rebuild them based on the current settings. +	 */ +	rebuild_sched_domains(); +  	cgroup_unlock();  }  |