vserver 1.9.5.x5
[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/config.h>
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 static int is_valid_rlimit(int id)
45 {
46         int valid = 0;
47
48         switch (id) {
49                 case RLIMIT_RSS:
50                 case RLIMIT_NPROC:
51                 case RLIMIT_NOFILE:
52                 case RLIMIT_MEMLOCK:
53                 case RLIMIT_AS:
54
55                 case VLIMIT_NSOCK:
56                 case VLIMIT_OPENFD:
57                 case VLIMIT_ANON:
58                 case VLIMIT_SHMEM:
59                         valid = 1;
60                         break;
61         }
62         return valid;
63 }
64
65 static inline uint64_t vc_get_rlim(struct vx_info *vxi, int id)
66 {
67         unsigned long limit;
68
69         limit = vxi->limit.rlim[id];
70         if (limit == RLIM_INFINITY)
71                 return CRLIM_INFINITY;
72         return limit;
73 }
74
75 int vc_get_rlimit(uint32_t id, void __user *data)
76 {
77         struct vx_info *vxi;
78         struct vcmd_ctx_rlimit_v0 vc_data;
79
80         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
81                 return -EFAULT;
82         if (!is_valid_rlimit(vc_data.id))
83                 return -ENOTSUPP;
84
85         vxi = locate_vx_info(id);
86         if (!vxi)
87                 return -ESRCH;
88
89         vc_data.maximum = vc_get_rlim(vxi, vc_data.id);
90         vc_data.minimum = CRLIM_UNSET;
91         vc_data.softlimit = CRLIM_UNSET;
92         put_vx_info(vxi);
93
94         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
95                 return -EFAULT;
96         return 0;
97 }
98
99 int vc_set_rlimit(uint32_t id, void __user *data)
100 {
101         struct vx_info *vxi;
102         struct vcmd_ctx_rlimit_v0 vc_data;
103
104         if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE))
105                 return -EPERM;
106         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
107                 return -EFAULT;
108         if (!is_valid_rlimit(vc_data.id))
109                 return -ENOTSUPP;
110
111         vxi = locate_vx_info(id);
112         if (!vxi)
113                 return -ESRCH;
114
115         if (vc_data.maximum != CRLIM_KEEP)
116                 vxi->limit.rlim[vc_data.id] = vc_data.maximum;
117         put_vx_info(vxi);
118
119         return 0;
120 }
121
122 int vc_get_rlimit_mask(uint32_t id, void __user *data)
123 {
124         static struct vcmd_ctx_rlimit_mask_v0 mask = {
125                         /* minimum */
126                 0
127                 ,       /* softlimit */
128                 0
129                 ,       /* maximum */
130                 (1 << RLIMIT_RSS) |
131                 (1 << RLIMIT_NPROC) |
132                 (1 << RLIMIT_NOFILE) |
133                 (1 << RLIMIT_MEMLOCK) |
134                 (1 << RLIMIT_LOCKS) |
135                 (1 << RLIMIT_AS) |
136                 (1 << VLIMIT_ANON) |
137                 0
138                 };
139
140         if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE))
141                 return -EPERM;
142         if (copy_to_user(data, &mask, sizeof(mask)))
143                 return -EFAULT;
144         return 0;
145 }
146
147
148 void vx_vsi_meminfo(struct sysinfo *val)
149 {
150         struct vx_info *vxi = current->vx_info;
151         unsigned long v;
152
153         v = vxi->limit.rlim[RLIMIT_RSS];
154         if (v != RLIM_INFINITY)
155                 val->totalram = min(val->totalram, v);
156         v = atomic_read(&vxi->limit.rcur[RLIMIT_RSS]);
157         val->freeram = (v < val->totalram) ? val->totalram - v : 0;
158         val->bufferram = 0;
159         val->totalhigh = 0;
160         val->freehigh = 0;
161         return;
162 }
163
164 void vx_vsi_swapinfo(struct sysinfo *val)
165 {
166         struct vx_info *vxi = current->vx_info;
167         unsigned long v, w;
168
169         v = vxi->limit.rlim[RLIMIT_RSS];
170         w = vxi->limit.rlim[RLIMIT_AS];
171         if (w != RLIM_INFINITY)
172                 val->totalswap = min(val->totalswap, w -
173                 ((v != RLIM_INFINITY) ? v : 0));
174         w = atomic_read(&vxi->limit.rcur[RLIMIT_AS]);
175         val->freeswap = (w < val->totalswap) ? val->totalswap - w : 0;
176         return;
177 }
178