const struct kernfs_ops *ops;
        char *buf;
 
-       buf = kmalloc(len, GFP_KERNEL);
+       buf = of->prealloc_buf;
+       if (!buf)
+               buf = kmalloc(len, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
 
        /*
-        * @of->mutex nests outside active ref and is primarily to ensure that
-        * the ops aren't called concurrently for the same open file.
+        * @of->mutex nests outside active ref and is used both to ensure that
+        * the ops aren't called concurrently for the same open file, and
+        * to provide exclusive access to ->prealloc_buf (when that exists).
         */
        mutex_lock(&of->mutex);
        if (!kernfs_get_active(of->kn)) {
        else
                len = -EINVAL;
 
-       kernfs_put_active(of->kn);
-       mutex_unlock(&of->mutex);
-
        if (len < 0)
-               goto out_free;
+               goto out_unlock;
 
        if (copy_to_user(user_buf, buf, len)) {
                len = -EFAULT;
-               goto out_free;
+               goto out_unlock;
        }
 
        *ppos += len;
 
+ out_unlock:
+       kernfs_put_active(of->kn);
+       mutex_unlock(&of->mutex);
  out_free:
-       kfree(buf);
+       if (buf != of->prealloc_buf)
+               kfree(buf);
        return len;
 }
 
         */
        of->atomic_write_len = ops->atomic_write_len;
 
+       error = -EINVAL;
+       /*
+        * ->seq_show is incompatible with ->prealloc,
+        * as seq_read does its own allocation.
+        * ->read must be used instead.
+        */
+       if (ops->prealloc && ops->seq_show)
+               goto err_free;
        if (ops->prealloc) {
                int len = of->atomic_write_len ?: PAGE_SIZE;
                of->prealloc_buf = kmalloc(len + 1, GFP_KERNEL);
 
        return battr->read(of->file, kobj, battr, buf, pos, count);
 }
 
+/* kernfs read callback for regular sysfs files with pre-alloc */
+static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,
+                            size_t count, loff_t pos)
+{
+       const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
+       struct kobject *kobj = of->kn->parent->priv;
+
+       /*
+        * If buf != of->prealloc_buf, we don't know how
+        * large it is, so cannot safely pass it to ->show
+        */
+       if (pos || WARN_ON_ONCE(buf != of->prealloc_buf))
+               return 0;
+       return ops->show(kobj, of->kn->priv, buf);
+}
+
 /* kernfs write callback for regular sysfs files */
 static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf,
                              size_t count, loff_t pos)
        .write          = sysfs_kf_write,
 };
 
+static const struct kernfs_ops sysfs_prealloc_kfops_ro = {
+       .read           = sysfs_kf_read,
+       .prealloc       = true,
+};
+
 static const struct kernfs_ops sysfs_prealloc_kfops_wo = {
        .write          = sysfs_kf_write,
        .prealloc       = true,
 };
 
 static const struct kernfs_ops sysfs_prealloc_kfops_rw = {
-       .seq_show       = sysfs_kf_seq_show,
+       .read           = sysfs_kf_read,
        .write          = sysfs_kf_write,
        .prealloc       = true,
 };
                                ops = &sysfs_prealloc_kfops_rw;
                        else
                                ops = &sysfs_file_kfops_rw;
-               } else if (sysfs_ops->show)
-                       ops = &sysfs_file_kfops_ro;
-               else if (sysfs_ops->store) {
+               } else if (sysfs_ops->show) {
+                       if (mode & SYSFS_PREALLOC)
+                               ops = &sysfs_prealloc_kfops_ro;
+                       else
+                               ops = &sysfs_file_kfops_ro;
+               } else if (sysfs_ops->store) {
                        if (mode & SYSFS_PREALLOC)
                                ops = &sysfs_prealloc_kfops_wo;
                        else