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
= RES_COUNTER_MAX
;
21 counter
->soft_limit
= RES_COUNTER_MAX
;
22 counter
->parent
= parent
;
25 static u64
res_counter_uncharge_locked(struct res_counter
*counter
,
28 if (WARN_ON(counter
->usage
< val
))
31 counter
->usage
-= val
;
32 return counter
->usage
;
35 static int res_counter_charge_locked(struct res_counter
*counter
,
36 unsigned long val
, bool force
)
40 if (counter
->usage
+ val
> counter
->limit
) {
47 counter
->usage
+= val
;
48 if (counter
->usage
> counter
->max_usage
)
49 counter
->max_usage
= counter
->usage
;
53 static int __res_counter_charge(struct res_counter
*counter
, unsigned long val
,
54 struct res_counter
**limit_fail_at
, bool force
)
58 struct res_counter
*c
, *u
;
61 *limit_fail_at
= NULL
;
62 local_irq_save(flags
);
63 for (c
= counter
; c
!= NULL
; c
= c
->parent
) {
65 r
= res_counter_charge_locked(c
, val
, force
);
66 spin_unlock(&c
->lock
);
75 if (ret
< 0 && !force
) {
76 for (u
= counter
; u
!= c
; u
= u
->parent
) {
78 res_counter_uncharge_locked(u
, val
);
79 spin_unlock(&u
->lock
);
82 local_irq_restore(flags
);
87 int res_counter_charge(struct res_counter
*counter
, unsigned long val
,
88 struct res_counter
**limit_fail_at
)
90 return __res_counter_charge(counter
, val
, limit_fail_at
, false);
93 int res_counter_charge_nofail(struct res_counter
*counter
, unsigned long val
,
94 struct res_counter
**limit_fail_at
)
96 return __res_counter_charge(counter
, val
, limit_fail_at
, true);
99 u64
res_counter_uncharge_until(struct res_counter
*counter
,
100 struct res_counter
*top
,
104 struct res_counter
*c
;
107 local_irq_save(flags
);
108 for (c
= counter
; c
!= top
; c
= c
->parent
) {
111 r
= res_counter_uncharge_locked(c
, val
);
114 spin_unlock(&c
->lock
);
116 local_irq_restore(flags
);
120 u64
res_counter_uncharge(struct res_counter
*counter
, unsigned long val
)
122 return res_counter_uncharge_until(counter
, NULL
, val
);
125 static inline unsigned long long *
126 res_counter_member(struct res_counter
*counter
, int member
)
130 return &counter
->usage
;
132 return &counter
->max_usage
;
134 return &counter
->limit
;
136 return &counter
->failcnt
;
138 return &counter
->soft_limit
;
145 ssize_t
res_counter_read(struct res_counter
*counter
, int member
,
146 const char __user
*userbuf
, size_t nbytes
, loff_t
*pos
,
147 int (*read_strategy
)(unsigned long long val
, char *st_buf
))
149 unsigned long long *val
;
153 val
= res_counter_member(counter
, member
);
155 s
+= read_strategy(*val
, s
);
157 s
+= sprintf(s
, "%llu\n", *val
);
158 return simple_read_from_buffer((void __user
*)userbuf
, nbytes
,
162 #if BITS_PER_LONG == 32
163 u64
res_counter_read_u64(struct res_counter
*counter
, int member
)
168 spin_lock_irqsave(&counter
->lock
, flags
);
169 ret
= *res_counter_member(counter
, member
);
170 spin_unlock_irqrestore(&counter
->lock
, flags
);
175 u64
res_counter_read_u64(struct res_counter
*counter
, int member
)
177 return *res_counter_member(counter
, member
);
181 int res_counter_memparse_write_strategy(const char *buf
,
182 unsigned long long *resp
)
185 unsigned long long res
;
187 /* return RES_COUNTER_MAX(unlimited) if "-1" is specified */
189 res
= simple_strtoull(buf
+ 1, &end
, 10);
190 if (res
!= 1 || *end
!= '\0')
192 *resp
= RES_COUNTER_MAX
;
196 res
= memparse(buf
, &end
);
200 if (PAGE_ALIGN(res
) >= res
)
201 res
= PAGE_ALIGN(res
);
203 res
= RES_COUNTER_MAX
;