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