X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=kernel%2Fvserver%2Flimit.c;h=2739c1d4c6cab4c6ec1e76302839c19657b0750a;hb=refs%2Fheads%2Fvserver;hp=4af1ee567d20ef5a6fd4cc5450fe6aa058ec7bf2;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/kernel/vserver/limit.c b/kernel/vserver/limit.c index 4af1ee567..2739c1d4c 100644 --- a/kernel/vserver/limit.c +++ b/kernel/vserver/limit.c @@ -3,20 +3,19 @@ * * Virtual Server: Context Limits * - * Copyright (C) 2004 Herbert Pötzl + * Copyright (C) 2004-2007 Herbert Pötzl * * V0.01 broken out from vcontext V0.05 + * V0.02 changed vcmds to vxi arg * */ -#include #include -#include -#include -#include -#include #include #include +#include +#include +#include #include #include @@ -26,108 +25,226 @@ const char *vlimit_name[NUM_LIMITS] = { [RLIMIT_CPU] = "CPU", [RLIMIT_RSS] = "RSS", [RLIMIT_NPROC] = "NPROC", - [RLIMIT_NOFILE] = "NOFILE", + [RLIMIT_NOFILE] = "NOFILE", [RLIMIT_MEMLOCK] = "VML", [RLIMIT_AS] = "VM", [RLIMIT_LOCKS] = "LOCKS", + [RLIMIT_SIGPENDING] = "SIGP", [RLIMIT_MSGQUEUE] = "MSGQ", + [VLIMIT_NSOCK] = "NSOCK", + [VLIMIT_OPENFD] = "OPENFD", + [VLIMIT_ANON] = "ANON", + [VLIMIT_SHMEM] = "SHMEM", + [VLIMIT_DENTRY] = "DENTRY", }; EXPORT_SYMBOL_GPL(vlimit_name); +#define MASK_ENTRY(x) (1 << (x)) + +const struct vcmd_ctx_rlimit_mask_v0 vlimit_mask = { + /* minimum */ + 0 + , /* softlimit */ + MASK_ENTRY( RLIMIT_RSS ) | + MASK_ENTRY( VLIMIT_ANON ) | + 0 + , /* maximum */ + MASK_ENTRY( RLIMIT_RSS ) | + MASK_ENTRY( RLIMIT_NPROC ) | + MASK_ENTRY( RLIMIT_NOFILE ) | + MASK_ENTRY( RLIMIT_MEMLOCK ) | + MASK_ENTRY( RLIMIT_AS ) | + MASK_ENTRY( RLIMIT_LOCKS ) | + MASK_ENTRY( RLIMIT_MSGQUEUE ) | -static int is_valid_rlimit(int id) + MASK_ENTRY( VLIMIT_NSOCK ) | + MASK_ENTRY( VLIMIT_OPENFD ) | + MASK_ENTRY( VLIMIT_ANON ) | + MASK_ENTRY( VLIMIT_SHMEM ) | + MASK_ENTRY( VLIMIT_DENTRY ) | + 0 +}; + /* accounting only */ +uint32_t account_mask = + MASK_ENTRY( VLIMIT_SEMARY ) | + MASK_ENTRY( VLIMIT_NSEMS ) | + MASK_ENTRY( VLIMIT_MAPPED ) | + 0; + + +static int is_valid_vlimit(int id) { - int valid = 0; + uint32_t mask = vlimit_mask.minimum | + vlimit_mask.softlimit | vlimit_mask.maximum; + return mask & (1 << id); +} - switch (id) { - case RLIMIT_NPROC: - case RLIMIT_AS: - case RLIMIT_RSS: - case RLIMIT_MEMLOCK: - case RLIMIT_NOFILE: - valid = 1; - break; - } - return valid; +static int is_accounted_vlimit(int id) +{ + if (is_valid_vlimit(id)) + return 1; + return account_mask & (1 << id); } -static inline uint64_t vc_get_rlim(struct vx_info *vxi, int id) + +static inline uint64_t vc_get_soft(struct vx_info *vxi, int id) { - unsigned long limit; + rlim_t limit = __rlim_soft(&vxi->limit, id); + return VX_VLIM(limit); +} - limit = vxi->limit.rlim[id]; - if (limit == RLIM_INFINITY) - return CRLIM_INFINITY; - return limit; +static inline uint64_t vc_get_hard(struct vx_info *vxi, int id) +{ + rlim_t limit = __rlim_hard(&vxi->limit, id); + return VX_VLIM(limit); } -int vc_get_rlimit(uint32_t id, void __user *data) +static int do_get_rlimit(struct vx_info *vxi, uint32_t id, + uint64_t *minimum, uint64_t *softlimit, uint64_t *maximum) +{ + if (!is_valid_vlimit(id)) + return -EINVAL; + + if (minimum) + *minimum = CRLIM_UNSET; + if (softlimit) + *softlimit = vc_get_soft(vxi, id); + if (maximum) + *maximum = vc_get_hard(vxi, id); + return 0; +} + +int vc_get_rlimit(struct vx_info *vxi, void __user *data) { - struct vx_info *vxi; struct vcmd_ctx_rlimit_v0 vc_data; + int ret; if (copy_from_user (&vc_data, data, sizeof(vc_data))) return -EFAULT; - if (!is_valid_rlimit(vc_data.id)) - return -ENOTSUPP; - - vxi = locate_vx_info(id); - if (!vxi) - return -ESRCH; - vc_data.maximum = vc_get_rlim(vxi, vc_data.id); - vc_data.minimum = CRLIM_UNSET; - vc_data.softlimit = CRLIM_UNSET; - put_vx_info(vxi); + ret = do_get_rlimit(vxi, vc_data.id, + &vc_data.minimum, &vc_data.softlimit, &vc_data.maximum); + if (ret) + return ret; if (copy_to_user (data, &vc_data, sizeof(vc_data))) return -EFAULT; return 0; } -int vc_set_rlimit(uint32_t id, void __user *data) +static int do_set_rlimit(struct vx_info *vxi, uint32_t id, + uint64_t minimum, uint64_t softlimit, uint64_t maximum) +{ + if (!is_valid_vlimit(id)) + return -EINVAL; + + if (maximum != CRLIM_KEEP) + __rlim_hard(&vxi->limit, id) = VX_RLIM(maximum); + if (softlimit != CRLIM_KEEP) + __rlim_soft(&vxi->limit, id) = VX_RLIM(softlimit); + + /* clamp soft limit */ + if (__rlim_soft(&vxi->limit, id) > __rlim_hard(&vxi->limit, id)) + __rlim_soft(&vxi->limit, id) = __rlim_hard(&vxi->limit, id); + + return 0; +} + +int vc_set_rlimit(struct vx_info *vxi, void __user *data) { - struct vx_info *vxi; struct vcmd_ctx_rlimit_v0 vc_data; - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE)) - return -EPERM; if (copy_from_user (&vc_data, data, sizeof(vc_data))) return -EFAULT; - if (!is_valid_rlimit(vc_data.id)) - return -ENOTSUPP; - vxi = locate_vx_info(id); - if (!vxi) - return -ESRCH; + return do_set_rlimit(vxi, vc_data.id, + vc_data.minimum, vc_data.softlimit, vc_data.maximum); +} + +#ifdef CONFIG_IA32_EMULATION + +int vc_set_rlimit_x32(struct vx_info *vxi, void __user *data) +{ + struct vcmd_ctx_rlimit_v0_x32 vc_data; + + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_set_rlimit(vxi, vc_data.id, + vc_data.minimum, vc_data.softlimit, vc_data.maximum); +} + +int vc_get_rlimit_x32(struct vx_info *vxi, void __user *data) +{ + struct vcmd_ctx_rlimit_v0_x32 vc_data; + int ret; + + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; - if (vc_data.maximum != CRLIM_KEEP) - vxi->limit.rlim[vc_data.id] = vc_data.maximum; - put_vx_info(vxi); + ret = do_get_rlimit(vxi, vc_data.id, + &vc_data.minimum, &vc_data.softlimit, &vc_data.maximum); + if (ret) + return ret; + if (copy_to_user (data, &vc_data, sizeof(vc_data))) + return -EFAULT; return 0; } +#endif /* CONFIG_IA32_EMULATION */ + + int vc_get_rlimit_mask(uint32_t id, void __user *data) { - static struct vcmd_ctx_rlimit_mask_v0 mask = { - /* minimum */ - 0 - , /* softlimit */ - 0 - , /* maximum */ - (1 << RLIMIT_NPROC) | - (1 << RLIMIT_NOFILE) | - (1 << RLIMIT_MEMLOCK) | - (1 << RLIMIT_AS) | - (1 << RLIMIT_RSS) - }; - - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE)) - return -EPERM; - if (copy_to_user(data, &mask, sizeof(mask))) + if (copy_to_user(data, &vlimit_mask, sizeof(vlimit_mask))) + return -EFAULT; + return 0; +} + + +static inline void vx_reset_minmax(struct _vx_limit *limit) +{ + rlim_t value; + int lim; + + for (lim=0; limlimit); + return 0; +} + + +int vc_rlimit_stat(struct vx_info *vxi, void __user *data) +{ + struct vcmd_rlimit_stat_v0 vc_data; + struct _vx_limit *limit = &vxi->limit; + int id; + + if (copy_from_user (&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + id = vc_data.id; + if (!is_accounted_vlimit(id)) + return -EINVAL; + + vx_limit_fixup(limit, id); + vc_data.hits = atomic_read(&__rlim_lhit(limit, id)); + vc_data.value = __rlim_get(limit, id); + vc_data.minimum = __rlim_rmin(limit, id); + vc_data.maximum = __rlim_rmax(limit, id); + + if (copy_to_user (data, &vc_data, sizeof(vc_data))) return -EFAULT; return 0; } @@ -136,13 +253,19 @@ int vc_get_rlimit_mask(uint32_t id, void __user *data) void vx_vsi_meminfo(struct sysinfo *val) { struct vx_info *vxi = current->vx_info; - unsigned long v; + unsigned long totalram, freeram; + rlim_t v; - v = vxi->limit.rlim[RLIMIT_RSS]; - if (v != RLIM_INFINITY) - val->totalram = min(val->totalram, v); - v = atomic_read(&vxi->limit.rcur[RLIMIT_RSS]); - val->freeram = (v < val->totalram) ? val->totalram - v : 0; + /* we blindly accept the max */ + v = __rlim_soft(&vxi->limit, RLIMIT_RSS); + totalram = (v != RLIM_INFINITY) ? v : val->totalram; + + /* total minus used equals free */ + v = __vx_cres_array_fixup(&vxi->limit, VLA_RSS); + freeram = (v < totalram) ? totalram - v : 0; + + val->totalram = totalram; + val->freeram = freeram; val->bufferram = 0; val->totalhigh = 0; val->freehigh = 0; @@ -152,15 +275,45 @@ void vx_vsi_meminfo(struct sysinfo *val) void vx_vsi_swapinfo(struct sysinfo *val) { struct vx_info *vxi = current->vx_info; - unsigned long v, w; - - v = vxi->limit.rlim[RLIMIT_RSS]; - w = vxi->limit.rlim[RLIMIT_AS]; - if (w != RLIM_INFINITY) - val->totalswap = min(val->totalswap, w - - ((v != RLIM_INFINITY) ? v : 0)); - w = atomic_read(&vxi->limit.rcur[RLIMIT_AS]); - val->freeswap = (w < val->totalswap) ? val->totalswap - w : 0; + unsigned long totalswap, freeswap; + rlim_t v, w; + + v = __rlim_soft(&vxi->limit, RLIMIT_RSS); + if (v == RLIM_INFINITY) { + val->freeswap = val->totalswap; + return; + } + + /* we blindly accept the max */ + w = __rlim_hard(&vxi->limit, RLIMIT_RSS); + totalswap = (w != RLIM_INFINITY) ? (w - v) : val->totalswap; + + /* currently 'used' swap */ + w = __vx_cres_array_fixup(&vxi->limit, VLA_RSS); + w -= (w > v) ? v : w; + + /* total minus used equals free */ + freeswap = (w < totalswap) ? totalswap - w : 0; + + val->totalswap = totalswap; + val->freeswap = freeswap; return; } + +unsigned long vx_badness(struct task_struct *task, struct mm_struct *mm) +{ + struct vx_info *vxi = mm->mm_vx_info; + unsigned long points; + rlim_t v, w; + + if (!vxi) + return 0; + + v = __vx_cres_array_fixup(&vxi->limit, VLA_RSS); + w = __rlim_soft(&vxi->limit, RLIMIT_RSS); + points = (v > w) ? (v - w) : 0; + + return points; +} +