linux/kernel/res_counter.c
<<
>>
Prefs
   1/*
   2 * resource cgroups
   3 *
   4 * Copyright 2007 OpenVZ SWsoft Inc
   5 *
   6 * Author: Pavel Emelianov <xemul@openvz.org>
   7 *
   8 */
   9
  10#include <linux/types.h>
  11#include <linux/parser.h>
  12#include <linux/fs.h>
  13#include <linux/slab.h>
  14#include <linux/res_counter.h>
  15#include <linux/uaccess.h>
  16
  17void res_counter_init(struct res_counter *counter)
  18{
  19        spin_lock_init(&counter->lock);
  20        counter->limit = (unsigned long long)LLONG_MAX;
  21}
  22
  23int res_counter_charge_locked(struct res_counter *counter, unsigned long val)
  24{
  25        if (counter->usage + val > counter->limit) {
  26                counter->failcnt++;
  27                return -ENOMEM;
  28        }
  29
  30        counter->usage += val;
  31        if (counter->usage > counter->max_usage)
  32                counter->max_usage = counter->usage;
  33        return 0;
  34}
  35
  36int res_counter_charge(struct res_counter *counter, unsigned long val)
  37{
  38        int ret;
  39        unsigned long flags;
  40
  41        spin_lock_irqsave(&counter->lock, flags);
  42        ret = res_counter_charge_locked(counter, val);
  43        spin_unlock_irqrestore(&counter->lock, flags);
  44        return ret;
  45}
  46
  47void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val)
  48{
  49        if (WARN_ON(counter->usage < val))
  50                val = counter->usage;
  51
  52        counter->usage -= val;
  53}
  54
  55void res_counter_uncharge(struct res_counter *counter, unsigned long val)
  56{
  57        unsigned long flags;
  58
  59        spin_lock_irqsave(&counter->lock, flags);
  60        res_counter_uncharge_locked(counter, val);
  61        spin_unlock_irqrestore(&counter->lock, flags);
  62}
  63
  64
  65static inline unsigned long long *
  66res_counter_member(struct res_counter *counter, int member)
  67{
  68        switch (member) {
  69        case RES_USAGE:
  70                return &counter->usage;
  71        case RES_MAX_USAGE:
  72                return &counter->max_usage;
  73        case RES_LIMIT:
  74                return &counter->limit;
  75        case RES_FAILCNT:
  76                return &counter->failcnt;
  77        };
  78
  79        BUG();
  80        return NULL;
  81}
  82
  83ssize_t res_counter_read(struct res_counter *counter, int member,
  84                const char __user *userbuf, size_t nbytes, loff_t *pos,
  85                int (*read_strategy)(unsigned long long val, char *st_buf))
  86{
  87        unsigned long long *val;
  88        char buf[64], *s;
  89
  90        s = buf;
  91        val = res_counter_member(counter, member);
  92        if (read_strategy)
  93                s += read_strategy(*val, s);
  94        else
  95                s += sprintf(s, "%llu\n", *val);
  96        return simple_read_from_buffer((void __user *)userbuf, nbytes,
  97                        pos, buf, s - buf);
  98}
  99
 100u64 res_counter_read_u64(struct res_counter *counter, int member)
 101{
 102        return *res_counter_member(counter, member);
 103}
 104
 105ssize_t res_counter_write(struct res_counter *counter, int member,
 106                const char __user *userbuf, size_t nbytes, loff_t *pos,
 107                int (*write_strategy)(char *st_buf, unsigned long long *val))
 108{
 109        int ret;
 110        char *buf, *end;
 111        unsigned long flags;
 112        unsigned long long tmp, *val;
 113
 114        buf = kmalloc(nbytes + 1, GFP_KERNEL);
 115        ret = -ENOMEM;
 116        if (buf == NULL)
 117                goto out;
 118
 119        buf[nbytes] = '\0';
 120        ret = -EFAULT;
 121        if (copy_from_user(buf, userbuf, nbytes))
 122                goto out_free;
 123
 124        ret = -EINVAL;
 125
 126        strstrip(buf);
 127        if (write_strategy) {
 128                if (write_strategy(buf, &tmp)) {
 129                        goto out_free;
 130                }
 131        } else {
 132                tmp = simple_strtoull(buf, &end, 10);
 133                if (*end != '\0')
 134                        goto out_free;
 135        }
 136        spin_lock_irqsave(&counter->lock, flags);
 137        val = res_counter_member(counter, member);
 138        *val = tmp;
 139        spin_unlock_irqrestore(&counter->lock, flags);
 140        ret = nbytes;
 141out_free:
 142        kfree(buf);
 143out:
 144        return ret;
 145}
 146
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.