4 * Copyright 2007 OpenVZ SWsoft Inc
6 * Author: Pavel Emelianov <xemul@openvz.org>
10 #include <linux/types.h>
11 #include <linux/parser.h>
13 #include <linux/res_counter.h>
14 #include <linux/uaccess.h>
17 void res_counter_init(struct res_counter
*counter
, struct res_counter
*parent
)
19 spin_lock_init(&counter
->lock
);
20 counter
->limit
= RESOURCE_MAX
;
21 counter
->soft_limit
= RESOURCE_MAX
;
22 counter
->parent
= parent
;
25 int res_counter_charge_locked(struct res_counter
*counter
, unsigned long val
)
27 if (counter
->usage
+ val
> counter
->limit
) {
32 counter
->usage
+= val
;
33 if (counter
->usage
> counter
->max_usage
)
34 counter
->max_usage
= counter
->usage
;
38 int res_counter_charge(struct res_counter
*counter
, unsigned long val
,
39 struct res_counter
**limit_fail_at
)
43 struct res_counter
*c
, *u
;
45 *limit_fail_at
= NULL
;
46 local_irq_save(flags
);
47 for (c
= counter
; c
!= NULL
; c
= c
->parent
) {
49 ret
= res_counter_charge_locked(c
, val
);
50 spin_unlock(&c
->lock
);
59 for (u
= counter
; u
!= c
; u
= u
->parent
) {
61 res_counter_uncharge_locked(u
, val
);
62 spin_unlock(&u
->lock
);
65 local_irq_restore(flags
);
69 int res_counter_charge_nofail(struct res_counter
*counter
, unsigned long val
,
70 struct res_counter
**limit_fail_at
)
74 struct res_counter
*c
;
77 *limit_fail_at
= NULL
;
78 local_irq_save(flags
);
79 for (c
= counter
; c
!= NULL
; c
= c
->parent
) {
81 r
= res_counter_charge_locked(c
, val
);
84 spin_unlock(&c
->lock
);
85 if (r
< 0 && ret
== 0) {
90 local_irq_restore(flags
);
94 void res_counter_uncharge_locked(struct res_counter
*counter
, unsigned long val
)
96 if (WARN_ON(counter
->usage
< val
))
99 counter
->usage
-= val
;
102 void res_counter_uncharge(struct res_counter
*counter
, unsigned long val
)
105 struct res_counter
*c
;
107 local_irq_save(flags
);
108 for (c
= counter
; c
!= NULL
; c
= c
->parent
) {
110 res_counter_uncharge_locked(c
, val
);
111 spin_unlock(&c
->lock
);
113 local_irq_restore(flags
);
117 static inline unsigned long long *
118 res_counter_member(struct res_counter
*counter
, int member
)
122 return &counter
->usage
;
124 return &counter
->max_usage
;
126 return &counter
->limit
;
128 return &counter
->failcnt
;
130 return &counter
->soft_limit
;
137 ssize_t
res_counter_read(struct res_counter
*counter
, int member
,
138 const char __user
*userbuf
, size_t nbytes
, loff_t
*pos
,
139 int (*read_strategy
)(unsigned long long val
, char *st_buf
))
141 unsigned long long *val
;
145 val
= res_counter_member(counter
, member
);
147 s
+= read_strategy(*val
, s
);
149 s
+= sprintf(s
, "%llu\n", *val
);
150 return simple_read_from_buffer((void __user
*)userbuf
, nbytes
,
154 #if BITS_PER_LONG == 32
155 u64
res_counter_read_u64(struct res_counter
*counter
, int member
)
160 spin_lock_irqsave(&counter
->lock
, flags
);
161 ret
= *res_counter_member(counter
, member
);
162 spin_unlock_irqrestore(&counter
->lock
, flags
);
167 u64
res_counter_read_u64(struct res_counter
*counter
, int member
)
169 return *res_counter_member(counter
, member
);
173 int res_counter_memparse_write_strategy(const char *buf
,
174 unsigned long long *res
)
178 /* return RESOURCE_MAX(unlimited) if "-1" is specified */
180 *res
= simple_strtoull(buf
+ 1, &end
, 10);
181 if (*res
!= 1 || *end
!= '\0')
187 *res
= memparse(buf
, &end
);
191 *res
= PAGE_ALIGN(*res
);
195 int res_counter_write(struct res_counter
*counter
, int member
,
196 const char *buf
, write_strategy_fn write_strategy
)
200 unsigned long long tmp
, *val
;
202 if (write_strategy
) {
203 if (write_strategy(buf
, &tmp
))
206 tmp
= simple_strtoull(buf
, &end
, 10);
210 spin_lock_irqsave(&counter
->lock
, flags
);
211 val
= res_counter_member(counter
, member
);
213 spin_unlock_irqrestore(&counter
->lock
, flags
);