res_counter.c revision 0eea10301708c64a6b793894c156e21ddd15eb64
1/* 2 * resource cgroups 3 * 4 * Copyright 2007 OpenVZ SWsoft Inc 5 * 6 * Author: Pavel Emelianov <xemul@openvz.org> 7 * 8 */ 9 10#include <linux/types.h> 11#include <linux/parser.h> 12#include <linux/fs.h> 13#include <linux/res_counter.h> 14#include <linux/uaccess.h> 15 16void res_counter_init(struct res_counter *counter) 17{ 18 spin_lock_init(&counter->lock); 19 counter->limit = (unsigned long long)LLONG_MAX; 20} 21 22int res_counter_charge_locked(struct res_counter *counter, unsigned long val) 23{ 24 if (counter->usage + val > counter->limit) { 25 counter->failcnt++; 26 return -ENOMEM; 27 } 28 29 counter->usage += val; 30 return 0; 31} 32 33int res_counter_charge(struct res_counter *counter, unsigned long val) 34{ 35 int ret; 36 unsigned long flags; 37 38 spin_lock_irqsave(&counter->lock, flags); 39 ret = res_counter_charge_locked(counter, val); 40 spin_unlock_irqrestore(&counter->lock, flags); 41 return ret; 42} 43 44void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val) 45{ 46 if (WARN_ON(counter->usage < val)) 47 val = counter->usage; 48 49 counter->usage -= val; 50} 51 52void res_counter_uncharge(struct res_counter *counter, unsigned long val) 53{ 54 unsigned long flags; 55 56 spin_lock_irqsave(&counter->lock, flags); 57 res_counter_uncharge_locked(counter, val); 58 spin_unlock_irqrestore(&counter->lock, flags); 59} 60 61 62static inline unsigned long long * 63res_counter_member(struct res_counter *counter, int member) 64{ 65 switch (member) { 66 case RES_USAGE: 67 return &counter->usage; 68 case RES_LIMIT: 69 return &counter->limit; 70 case RES_FAILCNT: 71 return &counter->failcnt; 72 }; 73 74 BUG(); 75 return NULL; 76} 77 78ssize_t res_counter_read(struct res_counter *counter, int member, 79 const char __user *userbuf, size_t nbytes, loff_t *pos, 80 int (*read_strategy)(unsigned long long val, char *st_buf)) 81{ 82 unsigned long long *val; 83 char buf[64], *s; 84 85 s = buf; 86 val = res_counter_member(counter, member); 87 if (read_strategy) 88 s += read_strategy(*val, s); 89 else 90 s += sprintf(s, "%llu\n", *val); 91 return simple_read_from_buffer((void __user *)userbuf, nbytes, 92 pos, buf, s - buf); 93} 94 95ssize_t res_counter_write(struct res_counter *counter, int member, 96 const char __user *userbuf, size_t nbytes, loff_t *pos, 97 int (*write_strategy)(char *st_buf, unsigned long long *val)) 98{ 99 int ret; 100 char *buf, *end; 101 unsigned long flags; 102 unsigned long long tmp, *val; 103 104 buf = kmalloc(nbytes + 1, GFP_KERNEL); 105 ret = -ENOMEM; 106 if (buf == NULL) 107 goto out; 108 109 buf[nbytes] = '\0'; 110 ret = -EFAULT; 111 if (copy_from_user(buf, userbuf, nbytes)) 112 goto out_free; 113 114 ret = -EINVAL; 115 116 if (write_strategy) { 117 if (write_strategy(buf, &tmp)) { 118 goto out_free; 119 } 120 } else { 121 tmp = simple_strtoull(buf, &end, 10); 122 if (*end != '\0') 123 goto out_free; 124 } 125 spin_lock_irqsave(&counter->lock, flags); 126 val = res_counter_member(counter, member); 127 *val = tmp; 128 spin_unlock_irqrestore(&counter->lock, flags); 129 ret = nbytes; 130out_free: 131 kfree(buf); 132out: 133 return ret; 134} 135