Commit a70f6526 authored by David Howells's avatar David Howells
Browse files

cachefiles: Add some error injection support



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: default avatarDavid Howells <dhowells@redhat.com>
Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
cc: linux-cachefs@redhat.com
Link: https://lore.kernel.org/r/163819624706.215744.6911916249119962943.stgit@warthog.procyon.org.uk/ # v1
Link: https://lore.kernel.org/r/163906925343.143852.5465695512984025812.stgit@warthog.procyon.org.uk/ # v2
Link: https://lore.kernel.org/r/163967134412.1823006.7354285948280296595.stgit@warthog.procyon.org.uk/ # v3
Link: https://lore.kernel.org/r/164021532340.640689.18209494225772443698.stgit@warthog.procyon.org.uk/ # v4
parent 8390fbc4
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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.
+2 −0
Original line number Diff line number Diff line
@@ -6,4 +6,6 @@
cachefiles-y := \
	main.o

cachefiles-$(CONFIG_CACHEFILES_ERROR_INJECTION) += error_inject.o

obj-$(CONFIG_CACHEFILES) := cachefiles.o
+46 −0
Original line number Diff line number Diff line
// 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);
}
+41 −1
Original line number Diff line number Diff line
@@ -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
+12 −0
Original line number Diff line number Diff line
@@ -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);