mirror of
				https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
				synced 2025-10-31 18:28:19 +00:00 
			
		
		
		
	 856c13aa1f
			
		
	
	
		856c13aa1f
		
	
	
	
	
		
			
			Currently res_counter_write() is a raw file handler even though it's ultimately taking a number, since in some cases it wants to pre-process the string when converting it to a number. This patch converts res_counter_write() from a raw file handler to a write_string() handler; this allows some of the boilerplate copying/locking/checking to be removed, and simplies the cleanup path, since these functions are now performed by the cgroups framework. [lizf@cn.fujitsu.com: build fix] Signed-off-by: Paul Menage <menage@google.com> Cc: Paul Jackson <pj@sgi.com> Cc: Pavel Emelyanov <xemul@openvz.org> Cc: Balbir Singh <balbir@in.ibm.com> Cc: Serge Hallyn <serue@us.ibm.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
		
			
				
	
	
		
			140 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			140 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * resource cgroups
 | |
|  *
 | |
|  * Copyright 2007 OpenVZ SWsoft Inc
 | |
|  *
 | |
|  * Author: Pavel Emelianov <xemul@openvz.org>
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include <linux/types.h>
 | |
| #include <linux/parser.h>
 | |
| #include <linux/fs.h>
 | |
| #include <linux/slab.h>
 | |
| #include <linux/res_counter.h>
 | |
| #include <linux/uaccess.h>
 | |
| #include <linux/mm.h>
 | |
| 
 | |
| void res_counter_init(struct res_counter *counter)
 | |
| {
 | |
| 	spin_lock_init(&counter->lock);
 | |
| 	counter->limit = (unsigned long long)LLONG_MAX;
 | |
| }
 | |
| 
 | |
| int res_counter_charge_locked(struct res_counter *counter, unsigned long val)
 | |
| {
 | |
| 	if (counter->usage + val > counter->limit) {
 | |
| 		counter->failcnt++;
 | |
| 		return -ENOMEM;
 | |
| 	}
 | |
| 
 | |
| 	counter->usage += val;
 | |
| 	if (counter->usage > counter->max_usage)
 | |
| 		counter->max_usage = counter->usage;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int res_counter_charge(struct res_counter *counter, unsigned long val)
 | |
| {
 | |
| 	int ret;
 | |
| 	unsigned long flags;
 | |
| 
 | |
| 	spin_lock_irqsave(&counter->lock, flags);
 | |
| 	ret = res_counter_charge_locked(counter, val);
 | |
| 	spin_unlock_irqrestore(&counter->lock, flags);
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val)
 | |
| {
 | |
| 	if (WARN_ON(counter->usage < val))
 | |
| 		val = counter->usage;
 | |
| 
 | |
| 	counter->usage -= val;
 | |
| }
 | |
| 
 | |
| void res_counter_uncharge(struct res_counter *counter, unsigned long val)
 | |
| {
 | |
| 	unsigned long flags;
 | |
| 
 | |
| 	spin_lock_irqsave(&counter->lock, flags);
 | |
| 	res_counter_uncharge_locked(counter, val);
 | |
| 	spin_unlock_irqrestore(&counter->lock, flags);
 | |
| }
 | |
| 
 | |
| 
 | |
| static inline unsigned long long *
 | |
| res_counter_member(struct res_counter *counter, int member)
 | |
| {
 | |
| 	switch (member) {
 | |
| 	case RES_USAGE:
 | |
| 		return &counter->usage;
 | |
| 	case RES_MAX_USAGE:
 | |
| 		return &counter->max_usage;
 | |
| 	case RES_LIMIT:
 | |
| 		return &counter->limit;
 | |
| 	case RES_FAILCNT:
 | |
| 		return &counter->failcnt;
 | |
| 	};
 | |
| 
 | |
| 	BUG();
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| ssize_t res_counter_read(struct res_counter *counter, int member,
 | |
| 		const char __user *userbuf, size_t nbytes, loff_t *pos,
 | |
| 		int (*read_strategy)(unsigned long long val, char *st_buf))
 | |
| {
 | |
| 	unsigned long long *val;
 | |
| 	char buf[64], *s;
 | |
| 
 | |
| 	s = buf;
 | |
| 	val = res_counter_member(counter, member);
 | |
| 	if (read_strategy)
 | |
| 		s += read_strategy(*val, s);
 | |
| 	else
 | |
| 		s += sprintf(s, "%llu\n", *val);
 | |
| 	return simple_read_from_buffer((void __user *)userbuf, nbytes,
 | |
| 			pos, buf, s - buf);
 | |
| }
 | |
| 
 | |
| u64 res_counter_read_u64(struct res_counter *counter, int member)
 | |
| {
 | |
| 	return *res_counter_member(counter, member);
 | |
| }
 | |
| 
 | |
| int res_counter_memparse_write_strategy(const char *buf,
 | |
| 					unsigned long long *res)
 | |
| {
 | |
| 	char *end;
 | |
| 	/* FIXME - make memparse() take const char* args */
 | |
| 	*res = memparse((char *)buf, &end);
 | |
| 	if (*end != '\0')
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	*res = PAGE_ALIGN(*res);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int res_counter_write(struct res_counter *counter, int member,
 | |
| 		      const char *buf, write_strategy_fn write_strategy)
 | |
| {
 | |
| 	char *end;
 | |
| 	unsigned long flags;
 | |
| 	unsigned long long tmp, *val;
 | |
| 
 | |
| 	if (write_strategy) {
 | |
| 		if (write_strategy(buf, &tmp))
 | |
| 			return -EINVAL;
 | |
| 	} else {
 | |
| 		tmp = simple_strtoull(buf, &end, 10);
 | |
| 		if (*end != '\0')
 | |
| 			return -EINVAL;
 | |
| 	}
 | |
| 	spin_lock_irqsave(&counter->lock, flags);
 | |
| 	val = res_counter_member(counter, member);
 | |
| 	*val = tmp;
 | |
| 	spin_unlock_irqrestore(&counter->lock, flags);
 | |
| 	return 0;
 | |
| }
 |