Merge to Fedora kernel-2.6.18-1.2255_FC5 patched with stable patch-2.6.18.5-vs2.0...
[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         0
51         ,       /* maximum */
52         MASK_ENTRY( RLIMIT_RSS          ) |
53         MASK_ENTRY( RLIMIT_NPROC        ) |
54         MASK_ENTRY( RLIMIT_NOFILE       ) |
55         MASK_ENTRY( RLIMIT_MEMLOCK      ) |
56         MASK_ENTRY( RLIMIT_AS           ) |
57         MASK_ENTRY( RLIMIT_LOCKS        ) |
58         MASK_ENTRY( RLIMIT_MSGQUEUE     ) |
59
60         MASK_ENTRY( VLIMIT_ANON         ) |
61         MASK_ENTRY( VLIMIT_SHMEM        ) |
62         0
63 };
64
65
66 static int is_valid_vlimit(int id)
67 {
68         uint32_t mask = vlimit_mask.minimum |
69                 vlimit_mask.softlimit | vlimit_mask.maximum;
70         return mask & (1 << id);
71 }
72
73 static inline uint64_t vc_get_rlim(struct vx_info *vxi, int id)
74 {
75         unsigned long limit;
76
77         limit = vxi->limit.rlim[id];
78         if (limit == RLIM_INFINITY)
79                 return CRLIM_INFINITY;
80         return limit;
81 }
82
83 static int do_get_rlimit(xid_t xid, uint32_t id,
84         uint64_t *minimum, uint64_t *softlimit, uint64_t *maximum)
85 {
86         struct vx_info *vxi;
87
88         if (!is_valid_vlimit(id))
89                 return -EINVAL;
90
91         vxi = lookup_vx_info(xid);
92         if (!vxi)
93                 return -ESRCH;
94
95         if (minimum)
96                 *minimum = CRLIM_UNSET;
97         if (softlimit)
98                 *softlimit = CRLIM_UNSET;
99         if (maximum)
100                 *maximum = vc_get_rlim(vxi, id);
101         put_vx_info(vxi);
102         return 0;
103 }
104
105 int vc_get_rlimit(uint32_t id, void __user *data)
106 {
107         struct vcmd_ctx_rlimit_v0 vc_data;
108         int ret;
109
110         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
111                 return -EFAULT;
112
113         ret = do_get_rlimit(id, vc_data.id,
114                 &vc_data.minimum, &vc_data.softlimit, &vc_data.maximum);
115         if (ret)
116                 return ret;
117
118         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
119                 return -EFAULT;
120         return 0;
121 }
122
123 static int do_set_rlimit(xid_t xid, uint32_t id,
124         uint64_t minimum, uint64_t softlimit, uint64_t maximum)
125 {
126         struct vx_info *vxi;
127
128         if (!is_valid_vlimit(id))
129                 return -EINVAL;
130
131         vxi = lookup_vx_info(xid);
132         if (!vxi)
133                 return -ESRCH;
134
135         if (maximum != CRLIM_KEEP)
136                 vxi->limit.rlim[id] = maximum;
137
138         put_vx_info(vxi);
139         return 0;
140 }
141
142 int vc_set_rlimit(uint32_t id, void __user *data)
143 {
144         struct vcmd_ctx_rlimit_v0 vc_data;
145
146         if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE))
147                 return -EPERM;
148         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
149                 return -EFAULT;
150
151         return do_set_rlimit(id, vc_data.id,
152                 vc_data.minimum, vc_data.softlimit, vc_data.maximum);
153 }
154
155 #ifdef  CONFIG_IA32_EMULATION
156
157 int vc_set_rlimit_x32(uint32_t id, void __user *data)
158 {
159         struct vcmd_ctx_rlimit_v0_x32 vc_data;
160
161         if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE))
162                 return -EPERM;
163         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
164                 return -EFAULT;
165
166         return do_set_rlimit(id, vc_data.id,
167                 vc_data.minimum, vc_data.softlimit, vc_data.maximum);
168 }
169
170 int vc_get_rlimit_x32(uint32_t id, void __user *data)
171 {
172         struct vcmd_ctx_rlimit_v0_x32 vc_data;
173         int ret;
174
175         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
176                 return -EFAULT;
177
178         ret = do_get_rlimit(id, vc_data.id,
179                 &vc_data.minimum, &vc_data.softlimit, &vc_data.maximum);
180         if (ret)
181                 return ret;
182
183         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
184                 return -EFAULT;
185         return 0;
186 }
187
188 #endif  /* CONFIG_IA32_EMULATION */
189
190
191 int vc_get_rlimit_mask(uint32_t id, void __user *data)
192 {
193         if (copy_to_user(data, &vlimit_mask, sizeof(vlimit_mask)))
194                 return -EFAULT;
195         return 0;
196 }
197
198
199 void vx_vsi_meminfo(struct sysinfo *val)
200 {
201         struct vx_info *vxi = current->vx_info;
202         unsigned long v;
203
204         v = vxi->limit.rlim[RLIMIT_RSS];
205         if (v != RLIM_INFINITY)
206                 val->totalram = min(val->totalram, v);
207         v = atomic_read(&vxi->limit.rcur[RLIMIT_RSS]);
208         val->freeram = (v < val->totalram) ? val->totalram - v : 0;
209         val->bufferram = 0;
210         val->totalhigh = 0;
211         val->freehigh = 0;
212         return;
213 }
214
215 void vx_vsi_swapinfo(struct sysinfo *val)
216 {
217         struct vx_info *vxi = current->vx_info;
218         unsigned long v, w;
219
220         v = vxi->limit.rlim[RLIMIT_RSS];
221         w = vxi->limit.rlim[RLIMIT_AS];
222         if (w != RLIM_INFINITY)
223                 val->totalswap = min(val->totalswap, w -
224                 ((v != RLIM_INFINITY) ? v : 0));
225         w = atomic_read(&vxi->limit.rcur[RLIMIT_AS]);
226         val->freeswap = (w < val->totalswap) ? val->totalswap - w : 0;
227         return;
228 }
229