Sometimes it is helpful to be able to access firmware variables as
file, like efivarfs, but not all firmware is EFI. Create a framework
that allows generic access to firmware variables exposed by a
implementations of a simple backend API.

Add a demonstration memory-based backend.

Signed-off-by: Daniel Axtens <d...@axtens.net>
---
 Documentation/filesystems/fwvarfs.txt | 146 +++++++++++++
 fs/Kconfig                            |   1 +
 fs/Makefile                           |   1 +
 fs/fwvarfs/Kconfig                    |  25 +++
 fs/fwvarfs/Makefile                   |   8 +
 fs/fwvarfs/fwvarfs.c                  | 289 ++++++++++++++++++++++++++
 fs/fwvarfs/fwvarfs.h                  | 116 +++++++++++
 fs/fwvarfs/mem.c                      | 113 ++++++++++
 fs/kernfs/dir.c                       |   1 -
 include/uapi/linux/magic.h            |   1 +
 10 files changed, 700 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/filesystems/fwvarfs.txt
 create mode 100644 fs/fwvarfs/Kconfig
 create mode 100644 fs/fwvarfs/Makefile
 create mode 100644 fs/fwvarfs/fwvarfs.c
 create mode 100644 fs/fwvarfs/fwvarfs.h
 create mode 100644 fs/fwvarfs/mem.c

diff --git a/Documentation/filesystems/fwvarfs.txt 
b/Documentation/filesystems/fwvarfs.txt
new file mode 100644
index 000000000000..bf1bccba6ab9
--- /dev/null
+++ b/Documentation/filesystems/fwvarfs.txt
@@ -0,0 +1,146 @@
+fwvarfs
+=======
+
+fwvarfs is a generic firmware variable file-system. A platform
+provides a backend implementing a few very simple callbacks, and
+fwvarfs handles all the details required to present the variables as a
+filesystem.
+
+The minimum functionality for a backend is the ability to enumerate
+existing variables. Backends can optionally also allow:
+ - reading of variables
+ - writing of variables
+ - creation of variables
+ - deletion of variables
+
+Key assumptions
+---------------
+
+ * Variables for each backend live in a single, flat directory -
+   there's no concept of subdirectories.
+
+ * Files are created with mode 600 if the backend provides a write
+   hook, and 400 otherwise, and are owned by root:root.
+
+ * The set of variables stored can be determined at boot time, and
+   nothing outside of fwvarfs creates new variables after boot.
+
+Supported backends
+------------------
+
+ * mem - a memory-backed example filesystem supporting all
+   operations. Files created persist across mount/unmount but as no
+   hardware is involved they do not persist across reboots.
+
+Usage
+-----
+
+mount -t fwvarfs <backend> <dir>
+
+For example:
+
+mount -t fwvarfs mem /fw/mem/
+
+API
+---
+
+A backend is installed by creating a fwvarfs_backend struct,
+containing the name of the backend and various callbacks. The backend
+must be registered by adding it to the list at the top of
+fs/fwvarfs/fwvarfs.c
+
+The fwvarfs infrastructure provides the following function to backends:
+
+  int fwvarfs_register_var(struct fwvarfs_backend *backend, const char *name, 
void *variable, size_t size);
+
+  Register a variable with fwvarfs to allow it to be seen by users.
+
+  backend: the backend to which to add this variable
+
+  name: the name of file representing the variable. Must be a valid
+        filename, so no nulls or slashes.
+
+  variable: data private to the backend representing the variable -
+            will be passed back to every callback
+
+  size: the initial size of the variable
+
+
+The backend must then provide the following functions:
+
+    int (*enumerate)(void);
+
+       Mandatory and called at init time, a backend must call
+       fwvarfs_register_var for all variables it wants to expose to
+       the user.
+
+    void (*destroy)(void *variable);
+
+       Mandatory if you provide a create or unlink hook, and may
+       become mandatory in the future for cleanup.
+
+       Free backend data associated with variable. It will not be
+       referenced after this point by fwvarfs.
+
+
+    ssize_t (*read)(void *variable, char *dest, size_t bytes, loff_t off);
+
+       Read from variable into the a kernel buffer. Similar semantics
+       to a usual read operation, except that off is not a pointer
+       (unlike the usual ppos).
+
+       variable: the variable to read
+       dest: kernel buffer to read into
+       bytes: maximum number of bytes to read
+       off: offset to read from
+
+       Returns the number of bytes read or an error.
+       If this hook is not provided, all reads will fail with -EPERM.
+
+    ssize_t (*write)(void *variable, const char *src, size_t bytes, loff_t 
off);
+
+       Write into the variable from the given kernel buffer.
+
+       variable: the variable to write
+       src: kernel buffer with contents
+       bytes: write at most this many bytes
+       off: offset into the file to write at.
+
+       Returns the number of bytes written or an error.
+       If this hook is not provided, all writes will fail with -EPERM.
+
+
+    void* (*create)(const char *name);
+
+       Create a variable with the supplied name, and return the
+       associated private data or an error pointer. Do not return
+       NULL on failure.
+
+       If the variable created cannot be registered for any reason,
+       destroy() will be called on the variable returned.
+
+       If the hook is not provided, all attempts to create a file will
+       fail with -EPERM.
+
+    int (*unlink)(void *variable);
+
+       Delete the variable supplied from the backing store. Do not
+       free it yet, if you return success destroy() will be called on
+       the variable.
+
+       If an error is returned, the unlink will be aborted and the file
+       will still be present in the filesystem.
+
+       If the hook is not provided, all attempts to unlink a file will
+       fail with -EPERM.
+
+TODOs
+-----
+
+Perhaps a different registration scheme?
+Currently size is not updated after write
+Should standardise on whether writes must cover the whole file if partial 
writes are supported.
+Various TODOs in the code
+Convert API documentation to kerndoc
+perhaps better cleanup/removal, although kernfs doesn't seem to provide 
anything for this so difficult to do with out leaking memory
+check error handling with kernfs create and O_EXCL
diff --git a/fs/Kconfig b/fs/Kconfig
index cbbffc8b9ef5..6fb6e6cbd7b6 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -219,6 +219,7 @@ config ARCH_HAS_GIGANTIC_PAGE
 
 source "fs/configfs/Kconfig"
 source "fs/efivarfs/Kconfig"
+source "fs/fwvarfs/Kconfig"
 
 endmenu
 
diff --git a/fs/Makefile b/fs/Makefile
index c9aea23aba56..2a0c593dfc0f 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -130,3 +130,4 @@ obj-$(CONFIG_F2FS_FS)               += f2fs/
 obj-$(CONFIG_CEPH_FS)          += ceph/
 obj-$(CONFIG_PSTORE)           += pstore/
 obj-$(CONFIG_EFIVAR_FS)                += efivarfs/
+obj-$(CONFIG_FWVAR_FS)         += fwvarfs/
diff --git a/fs/fwvarfs/Kconfig b/fs/fwvarfs/Kconfig
new file mode 100644
index 000000000000..62a47cddd4b5
--- /dev/null
+++ b/fs/fwvarfs/Kconfig
@@ -0,0 +1,25 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config FWVAR_FS
+       bool "Generic Firmware Variable Filesystem"
+       help
+         fwvarfs is a generic file system for access to firmware
+         variables.
+
+         It is pluggable: you will need to select a backend below in
+         order to actually access anything.
+
+         This cannot currently be built as a module. (TODO: see if
+         kernfs can be exported or if there are technical obstacles.)
+
+         If unsure, say N.
+
+config FWVAR_FS_MEM_BACKEND
+       bool "In-memory testing backend"
+       depends on FWVAR_FS
+       help
+         Include a backend where firmware variables are just
+         elements of an in-memory list. This is helpful mostly as a
+         demonstration of fwvarfs.
+
+         You can safely say N here unless you're exploring fwvarfs.
diff --git a/fs/fwvarfs/Makefile b/fs/fwvarfs/Makefile
new file mode 100644
index 000000000000..f1585baccabe
--- /dev/null
+++ b/fs/fwvarfs/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the fwvarfs filesytem
+#
+
+obj-$(CONFIG_FWVAR_FS)         += fwvarfs.o
+
+obj-$(CONFIG_FWVAR_FS_MEM_BACKEND)             += mem.o
diff --git a/fs/fwvarfs/fwvarfs.c b/fs/fwvarfs/fwvarfs.c
new file mode 100644
index 000000000000..99b7f2fd0f14
--- /dev/null
+++ b/fs/fwvarfs/fwvarfs.c
@@ -0,0 +1,289 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Daniel Axtens
+ *
+ * Thanks to efivarfs, rdt, and cgroupfs for the kernfs example.
+ */
+
+#include <linux/fs.h>
+#include <linux/fs_context.h>
+#include <linux/kernfs.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/user_namespace.h>
+#include <uapi/linux/magic.h>
+#include "fwvarfs.h"
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
+static struct fwvarfs_backend *fwvarfs_backends[] = {
+#if CONFIG_FWVAR_FS_MEM_BACKEND
+       &fwvarfs_mem_backend,
+#endif
+
+       NULL,
+};
+
+struct fwvarfs_file {
+       struct kernfs_node *kn;
+       struct fwvarfs_backend *backend;
+       void *backend_data;
+};
+
+static ssize_t fwvarfs_file_read(struct kernfs_open_file *of, char *buf,
+                                size_t bytes, loff_t off)
+{
+       struct fwvarfs_file *file_data = of->kn->priv;
+
+       if (file_data->backend->read)
+               return file_data->backend->read(file_data->backend_data, buf,
+                                               bytes, off);
+       else
+               return -EPERM;
+}
+
+static ssize_t fwvarfs_file_write(struct kernfs_open_file *of, char *buf,
+                                 size_t bytes, loff_t off)
+{
+       struct fwvarfs_file *file_data = of->kn->priv;
+
+       if (file_data->backend->write)
+               return file_data->backend->write(file_data->backend_data, buf,
+                                                bytes, off);
+       else
+               return -EPERM;
+}
+
+
+static struct kernfs_ops fwvarfs_kf_ops = {
+       .atomic_write_len       = PAGE_SIZE,
+       .read                   = fwvarfs_file_read,
+       .write                  = fwvarfs_file_write,
+};
+
+struct kernfs_node *fwvarfs_create(struct kernfs_node *parent,
+                                  const char *name, umode_t mode)
+{
+       struct kernfs_node *kn;
+       struct fwvarfs_file *parent_file = parent->priv;
+       struct fwvarfs_file *file_data;
+       void *backend_data;
+
+       if (!parent_file->backend->create)
+               return ERR_PTR(-EPERM);
+
+       file_data = kzalloc(sizeof(struct fwvarfs_file), GFP_KERNEL);
+       if (!file_data)
+               return ERR_PTR(-ENOMEM);
+
+       file_data->backend = parent_file->backend;
+
+       backend_data = parent_file->backend->create(name);
+
+       if (IS_ERR(backend_data)) {
+               kfree(file_data);
+               return backend_data;
+       }
+
+       file_data->backend_data = backend_data;
+
+       kn = kernfs_create_file(parent, name,
+               (!!parent_file->backend->write ? 0600 : 0400), 0,
+               &fwvarfs_kf_ops, file_data);
+
+       if (IS_ERR(kn)) {
+               parent_file->backend->destroy(backend_data);
+               kfree(file_data);
+               return kn;
+       }
+
+       file_data->kn = kn;
+
+       return kn;
+}
+
+int fwvarfs_unlink(struct kernfs_node *kn)
+{
+
+       struct fwvarfs_file *file_data = kn->priv;
+       int ret;
+
+       if (!file_data->backend->unlink)
+               return -EPERM;
+
+       ret = file_data->backend->unlink(file_data->backend_data);
+
+       if (ret)
+               return ret;
+
+       kernfs_remove(file_data->kn);
+
+       file_data->backend->destroy(file_data->backend_data);
+
+       kfree(file_data);
+       return 0;
+}
+
+static struct kernfs_syscall_ops fwvarfs_scops = {
+       .create = fwvarfs_create,
+       .unlink = fwvarfs_unlink,
+};
+
+int fwvarfs_register_var(struct fwvarfs_backend *backend, const char *name,
+                        void *variable, size_t size)
+{
+       struct fwvarfs_file *file_data;
+       struct kernfs_node *kn;
+
+       file_data = kzalloc(sizeof(struct fwvarfs_file), GFP_KERNEL);
+       if (!file_data)
+               return -ENOMEM;
+
+       file_data->backend = backend;
+       file_data->backend_data = variable;
+
+       kn = kernfs_create_file(backend->kf_root->kn, name,
+               (!!backend->write ? 0600 : 0400), size,
+               &fwvarfs_kf_ops, file_data);
+
+       if (IS_ERR(kn)) {
+               kfree(file_data);
+               return PTR_ERR(kn);
+       }
+
+       file_data->kn = kn;
+
+       return 0;
+
+}
+
+static int fwvarfs_get_tree(struct fs_context *fc)
+{
+       int ret = -ENODEV;
+       struct fwvarfs_backend *backend;
+       struct kernfs_fs_context *kfc = fc->fs_private;
+       int i;
+
+       for (i = 0; (backend = fwvarfs_backends[i]); i++) {
+               if (!backend->is_active)
+                       continue;
+
+               if (strcasecmp(fc->source, backend->name) == 0) {
+                       kfc->root = backend->kf_root;
+                       ret = 0;
+               }
+       }
+       if (ret)
+               return ret;
+
+       return kernfs_get_tree(fc);
+}
+
+static void fwvarfs_free_fs_context(struct fs_context *fc)
+{
+       kernfs_free_fs_context(fc);
+       kfree(fc->fs_private);
+}
+
+static const struct fs_context_operations fwvarfs_fs_context_ops = {
+       .get_tree       = fwvarfs_get_tree,
+       .free           = fwvarfs_free_fs_context,
+};
+
+static int fwvarfs_init_fs_context(struct fs_context *fc)
+{
+       struct kernfs_fs_context *ctx;
+
+       ctx = kzalloc(sizeof(struct kernfs_fs_context), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       ctx->magic = FWVARFS_SUPER_MAGIC;
+       fc->fs_private = ctx;
+
+       fc->ops = &fwvarfs_fs_context_ops;
+       if (fc->user_ns)
+               put_user_ns(fc->user_ns);
+       fc->user_ns = get_user_ns(&init_user_ns);
+       fc->global = true;
+       return 0;
+}
+
+static struct file_system_type fwvarfs_type = {
+       .owner   = THIS_MODULE,
+       .name    = "fwvarfs",
+       .init_fs_context = fwvarfs_init_fs_context,
+       .kill_sb = kernfs_kill_sb,
+};
+
+static __init int fwvarfs_init(void)
+{
+       struct fwvarfs_backend *backend;
+       struct fwvarfs_file *file_data;
+       int ret, i;
+
+       for (i = 0; (backend = fwvarfs_backends[i]); i++) {
+               file_data = kzalloc(sizeof(struct fwvarfs_file), GFP_KERNEL);
+               if (!file_data)
+                       return -ENOMEM;
+
+               file_data->backend = backend;
+
+               backend->kf_root = kernfs_create_root(&fwvarfs_scops,
+                                       KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK,
+                                       file_data);
+
+               if (IS_ERR(backend->kf_root)) {
+                       pr_err("kernfs_create_root failed for %s: %ld",
+                               backend->name, PTR_ERR(backend->kf_root));
+                       kfree(file_data);
+                       continue;
+               }
+
+               file_data->kn = backend->kf_root->kn;
+
+               ret = backend->enumerate();
+               if (ret) {
+                       pr_err("enumerate failed for %s: %d",
+                              backend->name, ret);
+
+                       /*
+                        * TODO: we make no attempt to clean up partially
+                        * created files at this point
+                        */
+                       kernfs_destroy_root(backend->kf_root);
+                       kfree(file_data);
+                       continue;
+               }
+
+               backend->is_active = true;
+       }
+
+       return register_filesystem(&fwvarfs_type);
+}
+
+
+/*
+ * kernfs doesn't support being called from a module atm
+ * and we also have no obvious way to remove all the created variables, so
+ * atm even if you did this you would leak memory. TODO
+ * static __exit void fwvarfs_exit(void)
+ * {
+ *     unregister_filesystem(&fwvarfs_type);
+ * }
+ */
+
+
+/*
+ * again, kernfs blocks module-ising this atm but it's still a neat way
+ * to handle initialisation
+ */
+MODULE_AUTHOR("Daniel Axtens");
+MODULE_DESCRIPTION("Generic Firmware Variable Filesystem");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_FS("fwvarfs");
+
+module_init(fwvarfs_init);
+/* module_exit(fwvarfs_exit); */
diff --git a/fs/fwvarfs/fwvarfs.h b/fs/fwvarfs/fwvarfs.h
new file mode 100644
index 000000000000..b2944a3baaf7
--- /dev/null
+++ b/fs/fwvarfs/fwvarfs.h
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Daniel Axtens
+ */
+
+
+#ifndef FWVARFS_H
+#define FWVARFS_H
+
+#include <linux/kernfs.h>
+
+struct fwvarfs_backend {
+       /* name of backend */
+       const char *name;
+
+       /*
+        * Mandatory and called at init time, a backend must call
+        * fwvarfs_register_var for all variables it wants to expose to
+        * the user.
+        */
+       int (*enumerate)(void);
+
+       /*
+        * Mandatory if you provide a create or unlink hook, and may
+        * become mandatory in the future for cleanup.
+        *
+        * Free backend data associated with variable. It will not be
+        * referenced after this point by fwvarfs.
+        */
+       void (*destroy)(void *variable);
+
+       /*
+        * Read from variable into the a kernel buffer. Similar semantics
+        * to a usual read operation, except that off is not a pointer
+        * (unlike the usual ppos).
+        *
+        * variable: the variable to read
+        * dest: kernel buffer to read into
+        * bytes: maximum number of bytes to read
+        * off: offset to read from
+        *
+        * Returns the number of bytes read or an error.
+        * If this hook is not provided, all reads will fail with -EPERM.
+        */
+       ssize_t (*read)(void *variable, char *dest, size_t bytes, loff_t off);
+
+       /*
+        * Write into the variable from the given kernel buffer.
+        *
+        * variable: the variable to write
+        * src: kernel buffer with contents
+        * bytes: write at most this many bytes
+        * off: offset into the file to write at.
+        *
+        * Returns the number of bytes written or an error.
+        * If this hook is not provided, all writes will fail with -EPERM.
+        */
+       ssize_t (*write)(void *variable, const char *src, size_t bytes,
+                        loff_t off);
+
+       /*
+        * Create a variable with the supplied name, and return the
+        * associated private data or an error pointer. Do not return
+        * NULL on failure.
+        *
+        * If the variable created cannot be registered for any reason,
+        * destroy() will be called on the variable returned.
+        *
+        * If the hook is not provided, all attempts to create a file will
+        * fail with -EPERM.
+        */
+       void* (*create)(const char *name);
+
+       /*
+        * Delete the variable supplied from the backing store. Do not
+        * free it yet, if you return success destroy() will be called on
+        * the variable.
+        *
+        * If an error is returned, the unlink will be aborted and the file
+        * will still be present in the filesystem.
+        *
+        * If the hook is not provided, all attempts to unlink a file will
+        * fail with -EPERM.
+        */
+       int (*unlink)(void *variable);
+
+       /* private to fwvarfs generic code */
+       struct kernfs_root *kf_root;
+       /* did enumerate succeed? */
+       bool is_active;
+};
+
+/*
+ * Register a variable with fwvarfs to allow it to be seen by users.
+ *
+ * backend: the backend to which to add this variable
+ *
+ * name: the name of file representing the variable. Must be a valid
+ *       filename, so no nulls or slashes.
+ *
+ * variable: data private to the backend representing the variable -
+ *           will be passed back to every callback
+ *
+ * size: the initial size of the variable
+ */
+int fwvarfs_register_var(struct fwvarfs_backend *backend, const char *name,
+                        void *variable, size_t size);
+
+
+/* Backends go here */
+#if defined(CONFIG_FWVAR_FS_MEM_BACKEND)
+extern struct fwvarfs_backend fwvarfs_mem_backend;
+#endif
+
+#endif /* FWVARFS_H */
diff --git a/fs/fwvarfs/mem.c b/fs/fwvarfs/mem.c
new file mode 100644
index 000000000000..5c90ea856f8e
--- /dev/null
+++ b/fs/fwvarfs/mem.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Daniel Axtens
+ *
+ * Thanks to efivarfs, and cgroupfs for the kernfs example.
+ */
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include "fwvarfs.h"
+
+static LIST_HEAD(mem_file_list);
+
+struct fwvarfs_mem_file {
+       size_t length;
+       char data[PAGE_SIZE];
+       struct list_head list;
+};
+
+static ssize_t fwvarfs_mem_file_read(void *var, char *buf, size_t bytes,
+                                    loff_t off)
+{
+       struct fwvarfs_mem_file *file_data = var;
+       loff_t ppos = off;
+
+       return memory_read_from_buffer(buf, bytes, &ppos, file_data->data,
+                                      file_data->length);
+}
+
+static ssize_t simple_write_to_kernel_buffer(void *to, size_t available,
+                                            loff_t *ppos, const void *from,
+                                            size_t count)
+{
+       loff_t pos = *ppos;
+
+       if (pos < 0)
+               return -EINVAL;
+       if (pos >= available)
+               return -ENOSPC;
+       if (!count)
+               return 0;
+       if (count > available - pos)
+               count = available - pos;
+       memcpy(to, from, count);
+       *ppos = pos + count;
+       return count;
+}
+
+static ssize_t fwvarfs_mem_file_write(void *var, const char *buf,
+                                     size_t bytes, loff_t off)
+{
+       struct fwvarfs_mem_file *file_data = var;
+       loff_t ppos = off;
+       int rc;
+
+       // todo - update size of file
+       rc = simple_write_to_kernel_buffer(file_data->data, PAGE_SIZE, &ppos,
+                                          buf, bytes);
+       if (rc)
+               file_data->length = ppos;
+       return rc;
+}
+
+
+static void *fwvarfs_mem_create(const char *name)
+{
+       struct fwvarfs_mem_file *file_data;
+
+       file_data = kzalloc(sizeof(struct fwvarfs_mem_file), GFP_KERNEL);
+       if (!file_data)
+               return ERR_PTR(-ENOMEM);
+
+       INIT_LIST_HEAD(&file_data->list);
+       list_add(&mem_file_list, &file_data->list);
+
+       return file_data;
+}
+
+static void fwvarfs_mem_destroy(void *var)
+{
+       struct fwvarfs_mem_file *file_data = var;
+
+       list_del(&file_data->list);
+       kfree(file_data);
+}
+
+static int fwvarfs_mem_unlink(void *var)
+{
+       /*
+        * This always succeeds and there's nothing we need to do.
+        * We free the memory in destroy() which is called after
+        * this by fwvarfs.
+        */
+       return 0;
+}
+
+static int fwvarfs_mem_enumerate(void)
+{
+       /* Nothing to do, we always start from a blank slate */
+       return 0;
+}
+
+struct fwvarfs_backend fwvarfs_mem_backend = {
+       .name = "mem",
+       .read = fwvarfs_mem_file_read,
+       .write = fwvarfs_mem_file_write,
+       .create = fwvarfs_mem_create,
+       .destroy = fwvarfs_mem_destroy,
+       .unlink = fwvarfs_mem_unlink,
+       .enumerate = fwvarfs_mem_enumerate,
+};
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 74fe51dbd027..211366ecf5a8 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -1201,7 +1201,6 @@ static int kernfs_iop_create(struct inode *dir, struct 
dentry *dentry,
                return PTR_ERR(kn);
 
        d_instantiate(dentry, kernfs_get_inode(dir->i_sb, kn));
-
        return 0;
 }
 
diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h
index f8c00045d537..61f2f5532366 100644
--- a/include/uapi/linux/magic.h
+++ b/include/uapi/linux/magic.h
@@ -34,6 +34,7 @@
 #define EFIVARFS_MAGIC         0xde5e81e4
 #define HOSTFS_SUPER_MAGIC     0x00c0ffee
 #define OVERLAYFS_SUPER_MAGIC  0x794c7630
+#define FWVARFS_SUPER_MAGIC    0x66777672      /* "fwvr" */
 
 #define MINIX_SUPER_MAGIC      0x137F          /* minix v1 fs, 14 char names */
 #define MINIX_SUPER_MAGIC2     0x138F          /* minix v1 fs, 30 char names */
-- 
2.19.1

Reply via email to