at v3.13 5.8 kB view raw
1#ifndef __RES_COUNTER_H__ 2#define __RES_COUNTER_H__ 3 4/* 5 * Resource Counters 6 * Contain common data types and routines for resource accounting 7 * 8 * Copyright 2007 OpenVZ SWsoft Inc 9 * 10 * Author: Pavel Emelianov <xemul@openvz.org> 11 * 12 * See Documentation/cgroups/resource_counter.txt for more 13 * info about what this counter is. 14 */ 15 16#include <linux/spinlock.h> 17#include <linux/errno.h> 18 19/* 20 * The core object. the cgroup that wishes to account for some 21 * resource may include this counter into its structures and use 22 * the helpers described beyond 23 */ 24 25struct res_counter { 26 /* 27 * the current resource consumption level 28 */ 29 unsigned long long usage; 30 /* 31 * the maximal value of the usage from the counter creation 32 */ 33 unsigned long long max_usage; 34 /* 35 * the limit that usage cannot exceed 36 */ 37 unsigned long long limit; 38 /* 39 * the limit that usage can be exceed 40 */ 41 unsigned long long soft_limit; 42 /* 43 * the number of unsuccessful attempts to consume the resource 44 */ 45 unsigned long long failcnt; 46 /* 47 * the lock to protect all of the above. 48 * the routines below consider this to be IRQ-safe 49 */ 50 spinlock_t lock; 51 /* 52 * Parent counter, used for hierarchial resource accounting 53 */ 54 struct res_counter *parent; 55}; 56 57#define RES_COUNTER_MAX ULLONG_MAX 58 59/** 60 * Helpers to interact with userspace 61 * res_counter_read_u64() - returns the value of the specified member. 62 * res_counter_read/_write - put/get the specified fields from the 63 * res_counter struct to/from the user 64 * 65 * @counter: the counter in question 66 * @member: the field to work with (see RES_xxx below) 67 * @buf: the buffer to opeate on,... 68 * @nbytes: its size... 69 * @pos: and the offset. 70 */ 71 72u64 res_counter_read_u64(struct res_counter *counter, int member); 73 74ssize_t res_counter_read(struct res_counter *counter, int member, 75 const char __user *buf, size_t nbytes, loff_t *pos, 76 int (*read_strategy)(unsigned long long val, char *s)); 77 78int res_counter_memparse_write_strategy(const char *buf, 79 unsigned long long *res); 80 81/* 82 * the field descriptors. one for each member of res_counter 83 */ 84 85enum { 86 RES_USAGE, 87 RES_MAX_USAGE, 88 RES_LIMIT, 89 RES_FAILCNT, 90 RES_SOFT_LIMIT, 91}; 92 93/* 94 * helpers for accounting 95 */ 96 97void res_counter_init(struct res_counter *counter, struct res_counter *parent); 98 99/* 100 * charge - try to consume more resource. 101 * 102 * @counter: the counter 103 * @val: the amount of the resource. each controller defines its own 104 * units, e.g. numbers, bytes, Kbytes, etc 105 * 106 * returns 0 on success and <0 if the counter->usage will exceed the 107 * counter->limit _locked call expects the counter->lock to be taken 108 * 109 * charge_nofail works the same, except that it charges the resource 110 * counter unconditionally, and returns < 0 if the after the current 111 * charge we are over limit. 112 */ 113 114int __must_check res_counter_charge_locked(struct res_counter *counter, 115 unsigned long val, bool force); 116int __must_check res_counter_charge(struct res_counter *counter, 117 unsigned long val, struct res_counter **limit_fail_at); 118int res_counter_charge_nofail(struct res_counter *counter, 119 unsigned long val, struct res_counter **limit_fail_at); 120 121/* 122 * uncharge - tell that some portion of the resource is released 123 * 124 * @counter: the counter 125 * @val: the amount of the resource 126 * 127 * these calls check for usage underflow and show a warning on the console 128 * _locked call expects the counter->lock to be taken 129 * 130 * returns the total charges still present in @counter. 131 */ 132 133u64 res_counter_uncharge_locked(struct res_counter *counter, unsigned long val); 134u64 res_counter_uncharge(struct res_counter *counter, unsigned long val); 135 136u64 res_counter_uncharge_until(struct res_counter *counter, 137 struct res_counter *top, 138 unsigned long val); 139/** 140 * res_counter_margin - calculate chargeable space of a counter 141 * @cnt: the counter 142 * 143 * Returns the difference between the hard limit and the current usage 144 * of resource counter @cnt. 145 */ 146static inline unsigned long long res_counter_margin(struct res_counter *cnt) 147{ 148 unsigned long long margin; 149 unsigned long flags; 150 151 spin_lock_irqsave(&cnt->lock, flags); 152 if (cnt->limit > cnt->usage) 153 margin = cnt->limit - cnt->usage; 154 else 155 margin = 0; 156 spin_unlock_irqrestore(&cnt->lock, flags); 157 return margin; 158} 159 160/** 161 * Get the difference between the usage and the soft limit 162 * @cnt: The counter 163 * 164 * Returns 0 if usage is less than or equal to soft limit 165 * The difference between usage and soft limit, otherwise. 166 */ 167static inline unsigned long long 168res_counter_soft_limit_excess(struct res_counter *cnt) 169{ 170 unsigned long long excess; 171 unsigned long flags; 172 173 spin_lock_irqsave(&cnt->lock, flags); 174 if (cnt->usage <= cnt->soft_limit) 175 excess = 0; 176 else 177 excess = cnt->usage - cnt->soft_limit; 178 spin_unlock_irqrestore(&cnt->lock, flags); 179 return excess; 180} 181 182static inline void res_counter_reset_max(struct res_counter *cnt) 183{ 184 unsigned long flags; 185 186 spin_lock_irqsave(&cnt->lock, flags); 187 cnt->max_usage = cnt->usage; 188 spin_unlock_irqrestore(&cnt->lock, flags); 189} 190 191static inline void res_counter_reset_failcnt(struct res_counter *cnt) 192{ 193 unsigned long flags; 194 195 spin_lock_irqsave(&cnt->lock, flags); 196 cnt->failcnt = 0; 197 spin_unlock_irqrestore(&cnt->lock, flags); 198} 199 200static inline int res_counter_set_limit(struct res_counter *cnt, 201 unsigned long long limit) 202{ 203 unsigned long flags; 204 int ret = -EBUSY; 205 206 spin_lock_irqsave(&cnt->lock, flags); 207 if (cnt->usage <= limit) { 208 cnt->limit = limit; 209 ret = 0; 210 } 211 spin_unlock_irqrestore(&cnt->lock, flags); 212 return ret; 213} 214 215static inline int 216res_counter_set_soft_limit(struct res_counter *cnt, 217 unsigned long long soft_limit) 218{ 219 unsigned long flags; 220 221 spin_lock_irqsave(&cnt->lock, flags); 222 cnt->soft_limit = soft_limit; 223 spin_unlock_irqrestore(&cnt->lock, flags); 224 return 0; 225} 226 227#endif