X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=kernel%2Fres_counter.c;h=c7eaa37a768b785cf69cd2eb64ab3fb75c052124;hb=fa9dc265ace9774e62f0e31108e5f47911124bda;hp=722c484b068bc855c65813f3082a10c6d7fb72b3;hpb=e552b6617067ab785256dcec5ca29eeea981aacb;p=safe%2Fjmp%2Flinux-2.6 diff --git a/kernel/res_counter.c b/kernel/res_counter.c index 722c484..c7eaa37 100644 --- a/kernel/res_counter.c +++ b/kernel/res_counter.c @@ -12,11 +12,14 @@ #include #include #include +#include -void res_counter_init(struct res_counter *counter) +void res_counter_init(struct res_counter *counter, struct res_counter *parent) { spin_lock_init(&counter->lock); - counter->limit = (unsigned long)LONG_MAX; + counter->limit = RESOURCE_MAX; + counter->soft_limit = RESOURCE_MAX; + counter->parent = parent; } int res_counter_charge_locked(struct res_counter *counter, unsigned long val) @@ -27,17 +30,39 @@ int res_counter_charge_locked(struct res_counter *counter, unsigned long val) } counter->usage += val; + if (counter->usage > counter->max_usage) + counter->max_usage = counter->usage; return 0; } -int res_counter_charge(struct res_counter *counter, unsigned long val) +int res_counter_charge(struct res_counter *counter, unsigned long val, + struct res_counter **limit_fail_at) { int ret; unsigned long flags; - - spin_lock_irqsave(&counter->lock, flags); - ret = res_counter_charge_locked(counter, val); - spin_unlock_irqrestore(&counter->lock, flags); + struct res_counter *c, *u; + + *limit_fail_at = NULL; + local_irq_save(flags); + for (c = counter; c != NULL; c = c->parent) { + spin_lock(&c->lock); + ret = res_counter_charge_locked(c, val); + spin_unlock(&c->lock); + if (ret < 0) { + *limit_fail_at = c; + goto undo; + } + } + ret = 0; + goto done; +undo: + for (u = counter; u != c; u = u->parent) { + spin_lock(&u->lock); + res_counter_uncharge_locked(u, val); + spin_unlock(&u->lock); + } +done: + local_irq_restore(flags); return ret; } @@ -52,23 +77,32 @@ void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val) void res_counter_uncharge(struct res_counter *counter, unsigned long val) { unsigned long flags; + struct res_counter *c; - spin_lock_irqsave(&counter->lock, flags); - res_counter_uncharge_locked(counter, val); - spin_unlock_irqrestore(&counter->lock, flags); + local_irq_save(flags); + for (c = counter; c != NULL; c = c->parent) { + spin_lock(&c->lock); + res_counter_uncharge_locked(c, val); + spin_unlock(&c->lock); + } + local_irq_restore(flags); } -static inline unsigned long *res_counter_member(struct res_counter *counter, - int member) +static inline unsigned long long * +res_counter_member(struct res_counter *counter, int member) { switch (member) { case RES_USAGE: return &counter->usage; + case RES_MAX_USAGE: + return &counter->max_usage; case RES_LIMIT: return &counter->limit; case RES_FAILCNT: return &counter->failcnt; + case RES_SOFT_LIMIT: + return &counter->soft_limit; }; BUG(); @@ -76,45 +110,68 @@ static inline unsigned long *res_counter_member(struct res_counter *counter, } ssize_t res_counter_read(struct res_counter *counter, int member, - const char __user *userbuf, size_t nbytes, loff_t *pos) + const char __user *userbuf, size_t nbytes, loff_t *pos, + int (*read_strategy)(unsigned long long val, char *st_buf)) { - unsigned long *val; + unsigned long long *val; char buf[64], *s; s = buf; val = res_counter_member(counter, member); - s += sprintf(s, "%lu\n", *val); + if (read_strategy) + s += read_strategy(*val, s); + else + s += sprintf(s, "%llu\n", *val); return simple_read_from_buffer((void __user *)userbuf, nbytes, pos, buf, s - buf); } -ssize_t res_counter_write(struct res_counter *counter, int member, - const char __user *userbuf, size_t nbytes, loff_t *pos) +u64 res_counter_read_u64(struct res_counter *counter, int member) { - int ret; - char *buf, *end; - unsigned long tmp, *val; - - buf = kmalloc(nbytes + 1, GFP_KERNEL); - ret = -ENOMEM; - if (buf == NULL) - goto out; + return *res_counter_member(counter, member); +} - buf[nbytes] = '\0'; - ret = -EFAULT; - if (copy_from_user(buf, userbuf, nbytes)) - goto out_free; +int res_counter_memparse_write_strategy(const char *buf, + unsigned long long *res) +{ + char *end; + + /* return RESOURCE_MAX(unlimited) if "-1" is specified */ + if (*buf == '-') { + *res = simple_strtoull(buf + 1, &end, 10); + if (*res != 1 || *end != '\0') + return -EINVAL; + *res = RESOURCE_MAX; + return 0; + } - ret = -EINVAL; - tmp = simple_strtoul(buf, &end, 10); + /* FIXME - make memparse() take const char* args */ + *res = memparse((char *)buf, &end); if (*end != '\0') - goto out_free; + return -EINVAL; + + *res = PAGE_ALIGN(*res); + return 0; +} +int res_counter_write(struct res_counter *counter, int member, + const char *buf, write_strategy_fn write_strategy) +{ + char *end; + unsigned long flags; + unsigned long long tmp, *val; + + if (write_strategy) { + if (write_strategy(buf, &tmp)) + return -EINVAL; + } else { + tmp = simple_strtoull(buf, &end, 10); + if (*end != '\0') + return -EINVAL; + } + spin_lock_irqsave(&counter->lock, flags); val = res_counter_member(counter, member); *val = tmp; - ret = nbytes; -out_free: - kfree(buf); -out: - return ret; + spin_unlock_irqrestore(&counter->lock, flags); + return 0; }