cgroup files: convert res_counter_write() to be a cgroups write_string() handler
Paul Menage [Fri, 25 Jul 2008 08:47:04 +0000 (01:47 -0700)]
Currently res_counter_write() is a raw file handler even though it's
ultimately taking a number, since in some cases it wants to
pre-process the string when converting it to a number.

This patch converts res_counter_write() from a raw file handler to a
write_string() handler; this allows some of the boilerplate
copying/locking/checking to be removed, and simplies the cleanup path,
since these functions are now performed by the cgroups framework.

[lizf@cn.fujitsu.com: build fix]
Signed-off-by: Paul Menage <menage@google.com>
Cc: Paul Jackson <pj@sgi.com>
Cc: Pavel Emelyanov <xemul@openvz.org>
Cc: Balbir Singh <balbir@in.ibm.com>
Cc: Serge Hallyn <serue@us.ibm.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

include/linux/res_counter.h
kernel/res_counter.c
mm/memcontrol.c

index 125660e..290205d 100644 (file)
@@ -63,9 +63,14 @@ u64 res_counter_read_u64(struct res_counter *counter, int member);
 ssize_t res_counter_read(struct res_counter *counter, int member,
                const char __user *buf, size_t nbytes, loff_t *pos,
                int (*read_strategy)(unsigned long long val, char *s));
-ssize_t res_counter_write(struct res_counter *counter, int member,
-               const char __user *buf, size_t nbytes, loff_t *pos,
-               int (*write_strategy)(char *buf, unsigned long long *val));
+
+typedef int (*write_strategy_fn)(const char *buf, unsigned long long *val);
+
+int res_counter_memparse_write_strategy(const char *buf,
+                                       unsigned long long *res);
+
+int res_counter_write(struct res_counter *counter, int member,
+                     const char *buffer, write_strategy_fn write_strategy);
 
 /*
  * the field descriptors. one for each member of res_counter
index d3c61b4..f275c8e 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/res_counter.h>
 #include <linux/uaccess.h>
+#include <linux/mm.h>
 
 void res_counter_init(struct res_counter *counter)
 {
@@ -102,44 +103,37 @@ u64 res_counter_read_u64(struct res_counter *counter, int member)
        return *res_counter_member(counter, member);
 }
 
-ssize_t res_counter_write(struct res_counter *counter, int member,
-               const char __user *userbuf, size_t nbytes, loff_t *pos,
-               int (*write_strategy)(char *st_buf, unsigned long long *val))
+int res_counter_memparse_write_strategy(const char *buf,
+                                       unsigned long long *res)
 {
-       int ret;
-       char *buf, *end;
-       unsigned long flags;
-       unsigned long long tmp, *val;
-
-       buf = kmalloc(nbytes + 1, GFP_KERNEL);
-       ret = -ENOMEM;
-       if (buf == NULL)
-               goto out;
+       char *end;
+       /* FIXME - make memparse() take const char* args */
+       *res = memparse((char *)buf, &end);
+       if (*end != '\0')
+               return -EINVAL;
 
-       buf[nbytes] = '\0';
-       ret = -EFAULT;
-       if (copy_from_user(buf, userbuf, nbytes))
-               goto out_free;
+       *res = PAGE_ALIGN(*res);
+       return 0;
+}
 
-       ret = -EINVAL;
+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;
 
-       strstrip(buf);
        if (write_strategy) {
-               if (write_strategy(buf, &tmp)) {
-                       goto out_free;
-               }
+               if (write_strategy(buf, &tmp))
+                       return -EINVAL;
        } else {
                tmp = simple_strtoull(buf, &end, 10);
                if (*end != '\0')
-                       goto out_free;
+                       return -EINVAL;
        }
        spin_lock_irqsave(&counter->lock, flags);
        val = res_counter_member(counter, member);
        *val = tmp;
        spin_unlock_irqrestore(&counter->lock, flags);
-       ret = nbytes;
-out_free:
-       kfree(buf);
-out:
-       return ret;
+       return 0;
 }
index e46451e..7385d58 100644 (file)
@@ -838,32 +838,18 @@ out:
        return ret;
 }
 
-static int mem_cgroup_write_strategy(char *buf, unsigned long long *tmp)
-{
-       *tmp = memparse(buf, &buf);
-       if (*buf != '\0')
-               return -EINVAL;
-
-       /*
-        * Round up the value to the closest page size
-        */
-       *tmp = ((*tmp + PAGE_SIZE - 1) >> PAGE_SHIFT) << PAGE_SHIFT;
-       return 0;
-}
-
 static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft)
 {
        return res_counter_read_u64(&mem_cgroup_from_cont(cont)->res,
                                    cft->private);
 }
 
-static ssize_t mem_cgroup_write(struct cgroup *cont, struct cftype *cft,
-                               struct file *file, const char __user *userbuf,
-                               size_t nbytes, loff_t *ppos)
+static int mem_cgroup_write(struct cgroup *cont, struct cftype *cft,
+                           const char *buffer)
 {
        return res_counter_write(&mem_cgroup_from_cont(cont)->res,
-                               cft->private, userbuf, nbytes, ppos,
-                               mem_cgroup_write_strategy);
+                                cft->private, buffer,
+                                res_counter_memparse_write_strategy);
 }
 
 static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
@@ -940,7 +926,7 @@ static struct cftype mem_cgroup_files[] = {
        {
                .name = "limit_in_bytes",
                .private = RES_LIMIT,
-               .write = mem_cgroup_write,
+               .write_string = mem_cgroup_write,
                .read_u64 = mem_cgroup_read,
        },
        {