cachefiles: Add some error injection support
authorDavid Howells <dhowells@redhat.com>
Thu, 21 Oct 2021 07:15:26 +0000 (08:15 +0100)
committerDavid Howells <dhowells@redhat.com>
Fri, 7 Jan 2022 13:40:56 +0000 (13:40 +0000)
Add support for injecting ENOSPC or EIO errors.  This needs to be enabled
by CONFIG_CACHEFILES_ERROR_INJECTION=y.  Once enabled, ENOSPC on things
like write and mkdir can be triggered by:

        echo 1 >/proc/sys/cachefiles/error_injection

and EIO can be triggered on most operations by:

        echo 2 >/proc/sys/cachefiles/error_injection

Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
cc: linux-cachefs@redhat.com
Link: https://lore.kernel.org/r/163819624706.215744.6911916249119962943.stgit@warthog.procyon.org.uk/
Link: https://lore.kernel.org/r/163906925343.143852.5465695512984025812.stgit@warthog.procyon.org.uk/
Link: https://lore.kernel.org/r/163967134412.1823006.7354285948280296595.stgit@warthog.procyon.org.uk/
Link: https://lore.kernel.org/r/164021532340.640689.18209494225772443698.stgit@warthog.procyon.org.uk/
fs/cachefiles/Kconfig
fs/cachefiles/Makefile
fs/cachefiles/error_inject.c [new file with mode: 0644]
fs/cachefiles/internal.h
fs/cachefiles/main.c

index 6827b40f7ddc37ba03bcfe3a6e9146504b6dd442..719faeeda168812326c0c10a6f77ece8e639b95a 100644 (file)
@@ -19,3 +19,10 @@ config CACHEFILES_DEBUG
          caching on files module.  If this is set, the debugging output may be
          enabled by setting bits in /sys/modules/cachefiles/parameter/debug or
          by including a debugging specifier in /etc/cachefilesd.conf.
+
+config CACHEFILES_ERROR_INJECTION
+       bool "Provide error injection for cachefiles"
+       depends on CACHEFILES && SYSCTL
+       help
+         This permits error injection to be enabled in cachefiles whilst a
+         cache is in service.
index a7f3e982e249ace1fb78df8bf6c6007a5c22950f..183fb5f3b8b17f00e339507cd78725fa5e91c31c 100644 (file)
@@ -6,4 +6,6 @@
 cachefiles-y := \
        main.o
 
+cachefiles-$(CONFIG_CACHEFILES_ERROR_INJECTION) += error_inject.o
+
 obj-$(CONFIG_CACHEFILES) := cachefiles.o
diff --git a/fs/cachefiles/error_inject.c b/fs/cachefiles/error_inject.c
new file mode 100644 (file)
index 0000000..58f8aec
--- /dev/null
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Error injection handling.
+ *
+ * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#include <linux/sysctl.h>
+#include "internal.h"
+
+unsigned int cachefiles_error_injection_state;
+
+static struct ctl_table_header *cachefiles_sysctl;
+static struct ctl_table cachefiles_sysctls[] = {
+       {
+               .procname       = "error_injection",
+               .data           = &cachefiles_error_injection_state,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = proc_douintvec,
+       },
+       {}
+};
+
+static struct ctl_table cachefiles_sysctls_root[] = {
+       {
+               .procname       = "cachefiles",
+               .mode           = 0555,
+               .child          = cachefiles_sysctls,
+       },
+       {}
+};
+
+int __init cachefiles_register_error_injection(void)
+{
+       cachefiles_sysctl = register_sysctl_table(cachefiles_sysctls_root);
+       if (!cachefiles_sysctl)
+               return -ENOMEM;
+       return 0;
+
+}
+
+void cachefiles_unregister_error_injection(void)
+{
+       unregister_sysctl_table(cachefiles_sysctl);
+}
index cff4b2a5f9284fd16c858c222739bdf851a9f23a..1f2fea902d3ea6e749a0b67a5a3e8b5d521fd8f0 100644 (file)
@@ -64,7 +64,47 @@ struct cachefiles_cache {
 
 
 /*
- * Debug tracing.
+ * error_inject.c
+ */
+#ifdef CONFIG_CACHEFILES_ERROR_INJECTION
+extern unsigned int cachefiles_error_injection_state;
+extern int cachefiles_register_error_injection(void);
+extern void cachefiles_unregister_error_injection(void);
+
+#else
+#define cachefiles_error_injection_state 0
+
+static inline int cachefiles_register_error_injection(void)
+{
+       return 0;
+}
+
+static inline void cachefiles_unregister_error_injection(void)
+{
+}
+#endif
+
+
+static inline int cachefiles_inject_read_error(void)
+{
+       return cachefiles_error_injection_state & 2 ? -EIO : 0;
+}
+
+static inline int cachefiles_inject_write_error(void)
+{
+       return cachefiles_error_injection_state & 2 ? -EIO :
+               cachefiles_error_injection_state & 1 ? -ENOSPC :
+               0;
+}
+
+static inline int cachefiles_inject_remove_error(void)
+{
+       return cachefiles_error_injection_state & 2 ? -EIO : 0;
+}
+
+
+/*
+ * Debug tracing
  */
 extern unsigned cachefiles_debug;
 #define CACHEFILES_DEBUG_KENTER        1
index 47bc1cc078de8cab2451cf0fe62ea62a2df050e4..387d42c7185f288da4169508a6e0739db702b2f5 100644 (file)
@@ -36,8 +36,18 @@ MODULE_LICENSE("GPL");
  */
 static int __init cachefiles_init(void)
 {
+       int ret;
+
+       ret = cachefiles_register_error_injection();
+       if (ret < 0)
+               goto error_einj;
+
        pr_info("Loaded\n");
        return 0;
+
+error_einj:
+       pr_err("failed to register: %d\n", ret);
+       return ret;
 }
 
 fs_initcall(cachefiles_init);
@@ -48,6 +58,8 @@ fs_initcall(cachefiles_init);
 static void __exit cachefiles_exit(void)
 {
        pr_info("Unloading\n");
+
+       cachefiles_unregister_error_injection();
 }
 
 module_exit(cachefiles_exit);