Merge to Fedora kernel-2.6.18-1.2255_FC5-vs2.0.2.2-rc9 patched with stable patch...
[linux-2.6.git] / kernel / vserver / limit.c
1 /*
2  *  linux/kernel/vserver/limit.c
3  *
4  *  Virtual Server: Context Limits
5  *
6  *  Copyright (C) 2004-2006  Herbert Pƶtzl
7  *
8  *  V0.01  broken out from vcontext V0.05
9  *  V0.02  sync to valid limit check from 2.1.1
10  *
11  */
12
13 #include <linux/module.h>
14 #include <linux/vs_context.h>
15 #include <linux/vs_limit.h>
16 #include <linux/vserver/limit.h>
17 #include <linux/vserver/switch.h>
18 #include <linux/vserver/limit_cmd.h>
19
20 #include <asm/errno.h>
21 #include <asm/uaccess.h>
22
23
24 const char *vlimit_name[NUM_LIMITS] = {
25         [RLIMIT_CPU]            = "CPU",
26         [RLIMIT_RSS]            = "RSS",
27         [RLIMIT_NPROC]          = "NPROC",
28         [RLIMIT_NOFILE]         = "NOFILE",
29         [RLIMIT_MEMLOCK]        = "VML",
30         [RLIMIT_AS]             = "VM",
31         [RLIMIT_LOCKS]          = "LOCKS",
32         [RLIMIT_SIGPENDING]     = "SIGP",
33         [RLIMIT_MSGQUEUE]       = "MSGQ",
34
35         [VLIMIT_NSOCK]          = "NSOCK",
36         [VLIMIT_OPENFD]         = "OPENFD",
37         [VLIMIT_ANON]           = "ANON",
38         [VLIMIT_SHMEM]          = "SHMEM",
39 };
40
41 EXPORT_SYMBOL_GPL(vlimit_name);
42
43
44 #define MASK_ENTRY(x)   (1 << (x))
45
46 const struct vcmd_ctx_rlimit_mask_v0 vlimit_mask = {
47                 /* minimum */
48         0
49         ,       /* softlimit */
50         MASK_ENTRY( RLIMIT_RSS          ) |
51         MASK_ENTRY( VLIMIT_ANON         ) |
52         0
53         ,       /* maximum */
54         MASK_ENTRY( RLIMIT_RSS          ) |
55         MASK_ENTRY( RLIMIT_NPROC        ) |
56         MASK_ENTRY( RLIMIT_NOFILE       ) |
57         MASK_ENTRY( RLIMIT_MEMLOCK      ) |
58         MASK_ENTRY( RLIMIT_AS           ) |
59         MASK_ENTRY( RLIMIT_LOCKS        ) |
60         MASK_ENTRY( RLIMIT_MSGQUEUE     ) |
61
62         MASK_ENTRY( VLIMIT_NSOCK        ) |
63         MASK_ENTRY( VLIMIT_OPENFD       ) |
64         MASK_ENTRY( VLIMIT_ANON         ) |
65         MASK_ENTRY( VLIMIT_SHMEM        ) |
66         0
67 };
68
69
70 static int is_valid_vlimit(int id)
71 {
72         uint32_t mask = vlimit_mask.minimum |
73                 vlimit_mask.softlimit | vlimit_mask.maximum;
74         return mask & (1 << id);
75 }
76
77 static inline uint64_t vc_get_rlim(struct vx_info *vxi, int id)
78 {
79         unsigned long limit;
80
81         limit = vxi->limit.rlim[id];
82         if (limit == RLIM_INFINITY)
83                 return CRLIM_INFINITY;
84         return limit;
85 }
86
87 static int do_get_rlimit(xid_t xid, uint32_t id,
88         uint64_t *minimum, uint64_t *softlimit, uint64_t *maximum)
89 {
90         struct vx_info *vxi;
91
92         if (!is_valid_vlimit(id))
93                 return -EINVAL;
94
95         vxi = lookup_vx_info(xid);
96         if (!vxi)
97                 return -ESRCH;
98
99         if (minimum)
100                 *minimum = CRLIM_UNSET;
101         if (softlimit)
102                 *softlimit = CRLIM_UNSET;
103         if (maximum)
104                 *maximum = vc_get_rlim(vxi, id);
105         put_vx_info(vxi);
106         return 0;
107 }
108
109 int vc_get_rlimit(uint32_t id, void __user *data)
110 {
111         struct vcmd_ctx_rlimit_v0 vc_data;
112         int ret;
113
114         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
115                 return -EFAULT;
116
117         ret = do_get_rlimit(id, vc_data.id,
118                 &vc_data.minimum, &vc_data.softlimit, &vc_data.maximum);
119         if (ret)
120                 return ret;
121
122         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
123                 return -EFAULT;
124         return 0;
125 }
126
127 static int do_set_rlimit(xid_t xid, uint32_t id,
128         uint64_t minimum, uint64_t softlimit, uint64_t maximum)
129 {
130         struct vx_info *vxi;
131
132         if (!is_valid_vlimit(id))
133                 return -EINVAL;
134
135         vxi = lookup_vx_info(xid);
136         if (!vxi)
137                 return -ESRCH;
138
139         if (maximum != CRLIM_KEEP)
140                 vxi->limit.rlim[id] = maximum;
141
142         put_vx_info(vxi);
143         return 0;
144 }
145
146 int vc_set_rlimit(uint32_t id, void __user *data)
147 {
148         struct vcmd_ctx_rlimit_v0 vc_data;
149
150         if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE))
151                 return -EPERM;
152         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
153                 return -EFAULT;
154
155         return do_set_rlimit(id, vc_data.id,
156                 vc_data.minimum, vc_data.softlimit, vc_data.maximum);
157 }
158
159 #ifdef  CONFIG_IA32_EMULATION
160
161 int vc_set_rlimit_x32(uint32_t id, void __user *data)
162 {
163         struct vcmd_ctx_rlimit_v0_x32 vc_data;
164
165         if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE))
166                 return -EPERM;
167         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
168                 return -EFAULT;
169
170         return do_set_rlimit(id, vc_data.id,
171                 vc_data.minimum, vc_data.softlimit, vc_data.maximum);
172 }
173
174 int vc_get_rlimit_x32(uint32_t id, void __user *data)
175 {
176         struct vcmd_ctx_rlimit_v0_x32 vc_data;
177         int ret;
178
179         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
180                 return -EFAULT;
181
182         ret = do_get_rlimit(id, vc_data.id,
183                 &vc_data.minimum, &vc_data.softlimit, &vc_data.maximum);
184         if (ret)
185                 return ret;
186
187         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
188                 return -EFAULT;
189         return 0;
190 }
191
192 #endif  /* CONFIG_IA32_EMULATION */
193
194
195 int vc_get_rlimit_mask(uint32_t id, void __user *data)
196 {
197         if (copy_to_user(data, &vlimit_mask, sizeof(vlimit_mask)))
198                 return -EFAULT;
199         return 0;
200 }
201
202
203 void vx_vsi_meminfo(struct sysinfo *val)
204 {
205         struct vx_info *vxi = current->vx_info;
206         unsigned long v;
207
208         v = vxi->limit.rlim[RLIMIT_RSS];
209         if (v != RLIM_INFINITY)
210                 val->totalram = min(val->totalram, v);
211         v = atomic_read(&vxi->limit.rcur[RLIMIT_RSS]);
212         val->freeram = (v < val->totalram) ? val->totalram - v : 0;
213         val->bufferram = 0;
214         val->totalhigh = 0;
215         val->freehigh = 0;
216         return;
217 }
218
219 void vx_vsi_swapinfo(struct sysinfo *val)
220 {
221         struct vx_info *vxi = current->vx_info;
222         unsigned long v, w;
223
224         v = vxi->limit.rlim[RLIMIT_RSS];
225         w = vxi->limit.rlim[RLIMIT_AS];
226         if (w != RLIM_INFINITY)
227                 val->totalswap = min(val->totalswap, w -
228                 ((v != RLIM_INFINITY) ? v : 0));
229         w = atomic_read(&vxi->limit.rcur[RLIMIT_AS]);
230         val->freeswap = (w < val->totalswap) ? val->totalswap - w : 0;
231         return;
232 }
233