return 0;
 }
 
-static int tg_set_conf(struct cgroup_subsys_state *css, struct cftype *cft,
-                      const char *buf, bool is_u64)
+static ssize_t tg_set_conf(struct kernfs_open_file *of,
+                          char *buf, size_t nbytes, loff_t off, bool is_u64)
 {
-       struct blkcg *blkcg = css_to_blkcg(css);
+       struct blkcg *blkcg = css_to_blkcg(of_css(of));
        struct blkg_conf_ctx ctx;
        struct throtl_grp *tg;
        struct throtl_service_queue *sq;
                ctx.v = -1;
 
        if (is_u64)
-               *(u64 *)((void *)tg + cft->private) = ctx.v;
+               *(u64 *)((void *)tg + of_cft(of)->private) = ctx.v;
        else
-               *(unsigned int *)((void *)tg + cft->private) = ctx.v;
+               *(unsigned int *)((void *)tg + of_cft(of)->private) = ctx.v;
 
        throtl_log(&tg->service_queue,
                   "limit change rbps=%llu wbps=%llu riops=%u wiops=%u",
        }
 
        blkg_conf_finish(&ctx);
-       return 0;
+       return nbytes;
 }
 
-static int tg_set_conf_u64(struct cgroup_subsys_state *css, struct cftype *cft,
-                          char *buf)
+static ssize_t tg_set_conf_u64(struct kernfs_open_file *of,
+                              char *buf, size_t nbytes, loff_t off)
 {
-       return tg_set_conf(css, cft, buf, true);
+       return tg_set_conf(of, buf, nbytes, off, true);
 }
 
-static int tg_set_conf_uint(struct cgroup_subsys_state *css, struct cftype *cft,
-                           char *buf)
+static ssize_t tg_set_conf_uint(struct kernfs_open_file *of,
+                               char *buf, size_t nbytes, loff_t off)
 {
-       return tg_set_conf(css, cft, buf, false);
+       return tg_set_conf(of, buf, nbytes, off, false);
 }
 
 static struct cftype throtl_files[] = {
                .name = "throttle.read_bps_device",
                .private = offsetof(struct throtl_grp, bps[READ]),
                .seq_show = tg_print_conf_u64,
-               .write_string = tg_set_conf_u64,
+               .write = tg_set_conf_u64,
        },
        {
                .name = "throttle.write_bps_device",
                .private = offsetof(struct throtl_grp, bps[WRITE]),
                .seq_show = tg_print_conf_u64,
-               .write_string = tg_set_conf_u64,
+               .write = tg_set_conf_u64,
        },
        {
                .name = "throttle.read_iops_device",
                .private = offsetof(struct throtl_grp, iops[READ]),
                .seq_show = tg_print_conf_uint,
-               .write_string = tg_set_conf_uint,
+               .write = tg_set_conf_uint,
        },
        {
                .name = "throttle.write_iops_device",
                .private = offsetof(struct throtl_grp, iops[WRITE]),
                .seq_show = tg_print_conf_uint,
-               .write_string = tg_set_conf_uint,
+               .write = tg_set_conf_uint,
        },
        {
                .name = "throttle.io_service_bytes",
 
        return 0;
 }
 
-static int __cfqg_set_weight_device(struct cgroup_subsys_state *css,
-                                   struct cftype *cft, const char *buf,
-                                   bool is_leaf_weight)
+static ssize_t __cfqg_set_weight_device(struct kernfs_open_file *of,
+                                       char *buf, size_t nbytes, loff_t off,
+                                       bool is_leaf_weight)
 {
-       struct blkcg *blkcg = css_to_blkcg(css);
+       struct blkcg *blkcg = css_to_blkcg(of_css(of));
        struct blkg_conf_ctx ctx;
        struct cfq_group *cfqg;
        int ret;
        }
 
        blkg_conf_finish(&ctx);
-       return ret;
+       return ret ?: nbytes;
 }
 
-static int cfqg_set_weight_device(struct cgroup_subsys_state *css,
-                                 struct cftype *cft, char *buf)
+static ssize_t cfqg_set_weight_device(struct kernfs_open_file *of,
+                                     char *buf, size_t nbytes, loff_t off)
 {
-       return __cfqg_set_weight_device(css, cft, buf, false);
+       return __cfqg_set_weight_device(of, buf, nbytes, off, false);
 }
 
-static int cfqg_set_leaf_weight_device(struct cgroup_subsys_state *css,
-                                      struct cftype *cft, char *buf)
+static ssize_t cfqg_set_leaf_weight_device(struct kernfs_open_file *of,
+                                          char *buf, size_t nbytes, loff_t off)
 {
-       return __cfqg_set_weight_device(css, cft, buf, true);
+       return __cfqg_set_weight_device(of, buf, nbytes, off, true);
 }
 
 static int __cfq_set_weight(struct cgroup_subsys_state *css, struct cftype *cft,
                .name = "weight_device",
                .flags = CFTYPE_ONLY_ON_ROOT,
                .seq_show = cfqg_print_leaf_weight_device,
-               .write_string = cfqg_set_leaf_weight_device,
+               .write = cfqg_set_leaf_weight_device,
        },
        {
                .name = "weight",
                .name = "weight_device",
                .flags = CFTYPE_NOT_ON_ROOT,
                .seq_show = cfqg_print_weight_device,
-               .write_string = cfqg_set_weight_device,
+               .write = cfqg_set_weight_device,
        },
        {
                .name = "weight",
        {
                .name = "leaf_weight_device",
                .seq_show = cfqg_print_leaf_weight_device,
-               .write_string = cfqg_set_leaf_weight_device,
+               .write = cfqg_set_leaf_weight_device,
        },
        {
                .name = "leaf_weight",
 
 
        /*
         * The maximum length of string, excluding trailing nul, that can
-        * be passed to write_string.  If < PAGE_SIZE-1, PAGE_SIZE-1 is
-        * assumed.
+        * be passed to write.  If < PAGE_SIZE-1, PAGE_SIZE-1 is assumed.
         */
        size_t max_write_len;
 
        int (*write_s64)(struct cgroup_subsys_state *css, struct cftype *cft,
                         s64 val);
 
-       /*
-        * write_string() is passed a nul-terminated kernelspace
-        * buffer of maximum length determined by max_write_len.
-        * Returns 0 or -ve error code.
-        */
-       int (*write_string)(struct cgroup_subsys_state *css, struct cftype *cft,
-                           char *buffer);
        /*
         * trigger() callback can be used to get some kick from the
         * userspace, when the actual string written is not important
 
                mode |= S_IRUGO;
 
        if (cft->write_u64 || cft->write_s64 || cft->write ||
-           cft->write_string || cft->trigger)
+           cft->trigger)
                mode |= S_IWUSR;
 
        return mode;
        return attach_task_by_pid(css->cgroup, tgid, true);
 }
 
-static int cgroup_release_agent_write(struct cgroup_subsys_state *css,
-                                     struct cftype *cft, char *buffer)
+static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of,
+                                         char *buf, size_t nbytes, loff_t off)
 {
-       struct cgroup_root *root = css->cgroup->root;
+       struct cgroup *cgrp = of_css(of)->cgroup;
+       struct cgroup_root *root = cgrp->root;
 
        BUILD_BUG_ON(sizeof(root->release_agent_path) < PATH_MAX);
-       if (!cgroup_lock_live_group(css->cgroup))
+       if (!cgroup_lock_live_group(cgrp))
                return -ENODEV;
        spin_lock(&release_agent_path_lock);
-       strlcpy(root->release_agent_path, buffer,
+       strlcpy(root->release_agent_path, strstrip(buf),
                sizeof(root->release_agent_path));
        spin_unlock(&release_agent_path_lock);
        mutex_unlock(&cgroup_mutex);
-       return 0;
+       return nbytes;
 }
 
 static int cgroup_release_agent_show(struct seq_file *seq, void *v)
 }
 
 /* change the enabled child controllers for a cgroup in the default hierarchy */
-static int cgroup_subtree_control_write(struct cgroup_subsys_state *dummy_css,
-                                       struct cftype *cft, char *buffer)
+static ssize_t cgroup_subtree_control_write(struct kernfs_open_file *of,
+                                           char *buf, size_t nbytes,
+                                           loff_t off)
 {
        unsigned int enable = 0, disable = 0;
-       struct cgroup *cgrp = dummy_css->cgroup, *child;
+       struct cgroup *cgrp = of_css(of)->cgroup, *child;
        struct cgroup_subsys *ss;
-       char *tok, *p;
+       char *tok;
        int ssid, ret;
 
        /*
         * Parse input - space separated list of subsystem names prefixed
         * with either + or -.
         */
-       p = buffer;
-       while ((tok = strsep(&p, " "))) {
+       buf = strstrip(buf);
+       while ((tok = strsep(&buf, " "))) {
                if (tok[0] == '\0')
                        continue;
                for_each_subsys(ss, ssid) {
 out_unbreak:
        kernfs_unbreak_active_protection(cgrp->control_kn);
        cgroup_put(cgrp);
-       return ret;
+       return ret ?: nbytes;
 
 err_undo_css:
        cgrp->child_subsys_mask &= ~enable;
        css = cgroup_css(cgrp, cft->ss);
        rcu_read_unlock();
 
-       if (cft->write_string) {
-               ret = cft->write_string(css, cft, strstrip(buf));
-       } else if (cft->write_u64) {
+       if (cft->write_u64) {
                unsigned long long v;
                ret = kstrtoull(buf, 0, &v);
                if (!ret)
                .name = "cgroup.subtree_control",
                .flags = CFTYPE_ONLY_ON_DFL,
                .seq_show = cgroup_subtree_control_show,
-               .write_string = cgroup_subtree_control_write,
+               .write = cgroup_subtree_control_write,
        },
        {
                .name = "cgroup.populated",
                .name = "release_agent",
                .flags = CFTYPE_INSANE | CFTYPE_ONLY_ON_ROOT,
                .seq_show = cgroup_release_agent_show,
-               .write_string = cgroup_release_agent_write,
+               .write = cgroup_release_agent_write,
                .max_write_len = PATH_MAX - 1,
        },
        { }     /* terminate */
 
        return ret;
 }
 
-/*
- * cgroups_write_string() limits the size of freezer state strings to
- * CGROUP_LOCAL_BUFFER_SIZE
- */
 static const char *freezer_state_strs(unsigned int state)
 {
        if (state & CGROUP_FROZEN)
        mutex_unlock(&freezer_mutex);
 }
 
-static int freezer_write(struct cgroup_subsys_state *css, struct cftype *cft,
-                        char *buffer)
+static ssize_t freezer_write(struct kernfs_open_file *of,
+                            char *buf, size_t nbytes, loff_t off)
 {
        bool freeze;
 
-       if (strcmp(buffer, freezer_state_strs(0)) == 0)
+       buf = strstrip(buf);
+
+       if (strcmp(buf, freezer_state_strs(0)) == 0)
                freeze = false;
-       else if (strcmp(buffer, freezer_state_strs(CGROUP_FROZEN)) == 0)
+       else if (strcmp(buf, freezer_state_strs(CGROUP_FROZEN)) == 0)
                freeze = true;
        else
                return -EINVAL;
 
-       freezer_change_state(css_freezer(css), freeze);
-       return 0;
+       freezer_change_state(css_freezer(of_css(of)), freeze);
+       return nbytes;
 }
 
 static u64 freezer_self_freezing_read(struct cgroup_subsys_state *css,
                .name = "state",
                .flags = CFTYPE_NOT_ON_ROOT,
                .seq_show = freezer_read,
-               .write_string = freezer_write,
+               .write = freezer_write,
        },
        {
                .name = "self_freezing",
 
 /*
  * Common handling for a write to a "cpus" or "mems" file.
  */
-static int cpuset_write_resmask(struct cgroup_subsys_state *css,
-                               struct cftype *cft, char *buf)
+static ssize_t cpuset_write_resmask(struct kernfs_open_file *of,
+                                   char *buf, size_t nbytes, loff_t off)
 {
-       struct cpuset *cs = css_cs(css);
+       struct cpuset *cs = css_cs(of_css(of));
        struct cpuset *trialcs;
        int retval = -ENODEV;
 
+       buf = strstrip(buf);
+
        /*
         * CPU or memory hotunplug may leave @cs w/o any execution
         * resources, in which case the hotplug code asynchronously updates
                goto out_unlock;
        }
 
-       switch (cft->private) {
+       switch (of_cft(of)->private) {
        case FILE_CPULIST:
                retval = update_cpumask(cs, trialcs, buf);
                break;
        free_trial_cpuset(trialcs);
 out_unlock:
        mutex_unlock(&cpuset_mutex);
-       return retval;
+       return retval ?: nbytes;
 }
 
 /*
        {
                .name = "cpus",
                .seq_show = cpuset_common_seq_show,
-               .write_string = cpuset_write_resmask,
+               .write = cpuset_write_resmask,
                .max_write_len = (100U + 6 * NR_CPUS),
                .private = FILE_CPULIST,
        },
        {
                .name = "mems",
                .seq_show = cpuset_common_seq_show,
-               .write_string = cpuset_write_resmask,
+               .write = cpuset_write_resmask,
                .max_write_len = (100U + 6 * MAX_NUMNODES),
                .private = FILE_MEMLIST,
        },
 
        return res_counter_read_u64(&h_cg->hugepage[idx], name);
 }
 
-static int hugetlb_cgroup_write(struct cgroup_subsys_state *css,
-                               struct cftype *cft, char *buffer)
+static ssize_t hugetlb_cgroup_write(struct kernfs_open_file *of,
+                                   char *buf, size_t nbytes, loff_t off)
 {
        int idx, name, ret;
        unsigned long long val;
-       struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(css);
+       struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(of_css(of));
 
-       idx = MEMFILE_IDX(cft->private);
-       name = MEMFILE_ATTR(cft->private);
+       buf = strstrip(buf);
+       idx = MEMFILE_IDX(of_cft(of)->private);
+       name = MEMFILE_ATTR(of_cft(of)->private);
 
        switch (name) {
        case RES_LIMIT:
                        break;
                }
                /* This function does all necessary parse...reuse it */
-               ret = res_counter_memparse_write_strategy(buffer, &val);
+               ret = res_counter_memparse_write_strategy(buf, &val);
                if (ret)
                        break;
                ret = res_counter_set_limit(&h_cg->hugepage[idx], val);
                ret = -EINVAL;
                break;
        }
-       return ret;
+       return ret ?: nbytes;
 }
 
 static int hugetlb_cgroup_reset(struct cgroup_subsys_state *css,
        snprintf(cft->name, MAX_CFTYPE_NAME, "%s.limit_in_bytes", buf);
        cft->private = MEMFILE_PRIVATE(idx, RES_LIMIT);
        cft->read_u64 = hugetlb_cgroup_read_u64;
-       cft->write_string = hugetlb_cgroup_write;
+       cft->write = hugetlb_cgroup_write;
 
        /* Add the usage file */
        cft = &h->cgroup_files[1];
 
  * The user of this function is...
  * RES_LIMIT.
  */
-static int mem_cgroup_write(struct cgroup_subsys_state *css, struct cftype *cft,
-                           char *buffer)
+static ssize_t mem_cgroup_write(struct kernfs_open_file *of,
+                               char *buf, size_t nbytes, loff_t off)
 {
-       struct mem_cgroup *memcg = mem_cgroup_from_css(css);
+       struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
        enum res_type type;
        int name;
        unsigned long long val;
        int ret;
 
-       type = MEMFILE_TYPE(cft->private);
-       name = MEMFILE_ATTR(cft->private);
+       buf = strstrip(buf);
+       type = MEMFILE_TYPE(of_cft(of)->private);
+       name = MEMFILE_ATTR(of_cft(of)->private);
 
        switch (name) {
        case RES_LIMIT:
                        break;
                }
                /* This function does all necessary parse...reuse it */
-               ret = res_counter_memparse_write_strategy(buffer, &val);
+               ret = res_counter_memparse_write_strategy(buf, &val);
                if (ret)
                        break;
                if (type == _MEM)
                        return -EINVAL;
                break;
        case RES_SOFT_LIMIT:
-               ret = res_counter_memparse_write_strategy(buffer, &val);
+               ret = res_counter_memparse_write_strategy(buf, &val);
                if (ret)
                        break;
                /*
                ret = -EINVAL; /* should be BUG() ? */
                break;
        }
-       return ret;
+       return ret ?: nbytes;
 }
 
 static void memcg_get_hierarchical_limit(struct mem_cgroup *memcg,
  * Input must be in format '<event_fd> <control_fd> <args>'.
  * Interpretation of args is defined by control file implementation.
  */
-static int memcg_write_event_control(struct cgroup_subsys_state *css,
-                                    struct cftype *cft, char *buffer)
+static ssize_t memcg_write_event_control(struct kernfs_open_file *of,
+                                        char *buf, size_t nbytes, loff_t off)
 {
+       struct cgroup_subsys_state *css = of_css(of);
        struct mem_cgroup *memcg = mem_cgroup_from_css(css);
        struct mem_cgroup_event *event;
        struct cgroup_subsys_state *cfile_css;
        char *endp;
        int ret;
 
-       efd = simple_strtoul(buffer, &endp, 10);
+       buf = strstrip(buf);
+
+       efd = simple_strtoul(buf, &endp, 10);
        if (*endp != ' ')
                return -EINVAL;
-       buffer = endp + 1;
+       buf = endp + 1;
 
-       cfd = simple_strtoul(buffer, &endp, 10);
+       cfd = simple_strtoul(buf, &endp, 10);
        if ((*endp != ' ') && (*endp != '\0'))
                return -EINVAL;
-       buffer = endp + 1;
+       buf = endp + 1;
 
        event = kzalloc(sizeof(*event), GFP_KERNEL);
        if (!event)
                goto out_put_cfile;
        }
 
-       ret = event->register_event(memcg, event->eventfd, buffer);
+       ret = event->register_event(memcg, event->eventfd, buf);
        if (ret)
                goto out_put_css;
 
        fdput(cfile);
        fdput(efile);
 
-       return 0;
+       return nbytes;
 
 out_put_css:
        css_put(css);
        {
                .name = "limit_in_bytes",
                .private = MEMFILE_PRIVATE(_MEM, RES_LIMIT),
-               .write_string = mem_cgroup_write,
+               .write = mem_cgroup_write,
                .read_u64 = mem_cgroup_read_u64,
        },
        {
                .name = "soft_limit_in_bytes",
                .private = MEMFILE_PRIVATE(_MEM, RES_SOFT_LIMIT),
-               .write_string = mem_cgroup_write,
+               .write = mem_cgroup_write,
                .read_u64 = mem_cgroup_read_u64,
        },
        {
        },
        {
                .name = "cgroup.event_control",         /* XXX: for compat */
-               .write_string = memcg_write_event_control,
+               .write = memcg_write_event_control,
                .flags = CFTYPE_NO_PREFIX,
                .mode = S_IWUGO,
        },
        {
                .name = "kmem.limit_in_bytes",
                .private = MEMFILE_PRIVATE(_KMEM, RES_LIMIT),
-               .write_string = mem_cgroup_write,
+               .write = mem_cgroup_write,
                .read_u64 = mem_cgroup_read_u64,
        },
        {
        {
                .name = "memsw.limit_in_bytes",
                .private = MEMFILE_PRIVATE(_MEMSWAP, RES_LIMIT),
-               .write_string = mem_cgroup_write,
+               .write = mem_cgroup_write,
                .read_u64 = mem_cgroup_read_u64,
        },
        {
 
        return 0;
 }
 
-static int write_priomap(struct cgroup_subsys_state *css, struct cftype *cft,
-                        char *buffer)
+static ssize_t write_priomap(struct kernfs_open_file *of,
+                            char *buf, size_t nbytes, loff_t off)
 {
        char devname[IFNAMSIZ + 1];
        struct net_device *dev;
        u32 prio;
        int ret;
 
-       if (sscanf(buffer, "%"__stringify(IFNAMSIZ)"s %u", devname, &prio) != 2)
+       if (sscanf(buf, "%"__stringify(IFNAMSIZ)"s %u", devname, &prio) != 2)
                return -EINVAL;
 
        dev = dev_get_by_name(&init_net, devname);
 
        rtnl_lock();
 
-       ret = netprio_set_prio(css, dev, prio);
+       ret = netprio_set_prio(of_css(of), dev, prio);
 
        rtnl_unlock();
        dev_put(dev);
-       return ret;
+       return ret ?: nbytes;
 }
 
 static int update_netprio(const void *v, struct file *file, unsigned n)
        {
                .name = "ifpriomap",
                .seq_show = read_priomap,
-               .write_string = write_priomap,
+               .write = write_priomap,
        },
        { }     /* terminate */
 };
 
        return 0;
 }
 
-static int tcp_cgroup_write(struct cgroup_subsys_state *css, struct cftype *cft,
-                           char *buffer)
+static ssize_t tcp_cgroup_write(struct kernfs_open_file *of,
+                               char *buf, size_t nbytes, loff_t off)
 {
-       struct mem_cgroup *memcg = mem_cgroup_from_css(css);
+       struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
        unsigned long long val;
        int ret = 0;
 
-       switch (cft->private) {
+       buf = strstrip(buf);
+
+       switch (of_cft(of)->private) {
        case RES_LIMIT:
                /* see memcontrol.c */
-               ret = res_counter_memparse_write_strategy(buffer, &val);
+               ret = res_counter_memparse_write_strategy(buf, &val);
                if (ret)
                        break;
                ret = tcp_update_limit(memcg, val);
                ret = -EINVAL;
                break;
        }
-       return ret;
+       return ret ?: nbytes;
 }
 
 static u64 tcp_read_stat(struct mem_cgroup *memcg, int type, u64 default_val)
 static struct cftype tcp_files[] = {
        {
                .name = "kmem.tcp.limit_in_bytes",
-               .write_string = tcp_cgroup_write,
+               .write = tcp_cgroup_write,
                .read_u64 = tcp_cgroup_read,
                .private = RES_LIMIT,
        },
 
        return rc;
 }
 
-static int devcgroup_access_write(struct cgroup_subsys_state *css,
-                                 struct cftype *cft, char *buffer)
+static ssize_t devcgroup_access_write(struct kernfs_open_file *of,
+                                     char *buf, size_t nbytes, loff_t off)
 {
        int retval;
 
        mutex_lock(&devcgroup_mutex);
-       retval = devcgroup_update_access(css_to_devcgroup(css),
-                                        cft->private, buffer);
+       retval = devcgroup_update_access(css_to_devcgroup(of_css(of)),
+                                        of_cft(of)->private, strstrip(buf));
        mutex_unlock(&devcgroup_mutex);
-       return retval;
+       return retval ?: nbytes;
 }
 
 static struct cftype dev_cgroup_files[] = {
        {
                .name = "allow",
-               .write_string  = devcgroup_access_write,
+               .write = devcgroup_access_write,
                .private = DEVCG_ALLOW,
        },
        {
                .name = "deny",
-               .write_string = devcgroup_access_write,
+               .write = devcgroup_access_write,
                .private = DEVCG_DENY,
        },
        {