forked from Minki/linux
s390/cio: add CRW inject functionality
This patch introduces the mechanism to inject artificial events to the CIO layer. One of the main-event type which triggers the CommonIO operations are Channel Report events. When a malfunction or other condition affecting channel-subsystem operation is recognized, a Channel Report Word (consisting of one or more CRWs) describing the condition is made pending for retrieval and analysis by the program. The CRW contains information concerning the identity and state of a facility following the detection of the malfunction or other condition. The patch introduces two debugfs interfaces which can be used to inject 'artificial' events from the userspace. It is intended to provide an easy means to increase the test coverage for CIO code. And this functionality can be enabled via a new configuration option CONFIG_CIO_INJECT. The newly introduces debugfs interfaces can be used as mentioned below to generate different fake-events. To use the crw_inject, first we should enable it by using enable_inject interface. i.e echo 1 > /sys/kernel/debug/s390/cio/enable_inject After the first step, user can simulate CRW as follows: echo <solicited> <overflow> <chaining> <rsc> <ancillary> <erc> <rsid> \ > /sys/kernel/debug/s390/cio/crw_inject Example: A permanent error ERC on CHPID 0x60 would look like this: echo 0 0 0 4 0 6 0x60 > /sys/kernel/debug/s390/cio/crw_inject and an initialized ERC on the same CHPID: echo 0 0 0 4 0 2 0x60 > /sys/kernel/debug/s390/cio/crw_inject Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
This commit is contained in:
parent
64a715ab4e
commit
a4f17cc726
@ -15,3 +15,11 @@ config DEBUG_ENTRY
|
||||
exits or otherwise impact performance.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config CIO_INJECT
|
||||
bool "CIO Inject interfaces"
|
||||
depends on DEBUG_KERNEL && DEBUG_FS
|
||||
help
|
||||
This option provides a debugging facility to inject certain artificial events
|
||||
and instruction responses to the CIO layer of Linux kernel. The newly created
|
||||
debugfs user-interfaces will be at /sys/kernel/debug/s390/cio/*
|
||||
|
@ -829,6 +829,7 @@ CONFIG_HIST_TRIGGERS=y
|
||||
CONFIG_FTRACE_STARTUP_TEST=y
|
||||
# CONFIG_EVENT_TRACE_STARTUP_TEST is not set
|
||||
CONFIG_DEBUG_ENTRY=y
|
||||
CONFIG_CIO_INJECT=y
|
||||
CONFIG_NOTIFIER_ERROR_INJECTION=m
|
||||
CONFIG_NETDEV_NOTIFIER_ERROR_INJECT=m
|
||||
CONFIG_FAULT_INJECTION=y
|
||||
|
@ -23,3 +23,5 @@ obj-$(CONFIG_QDIO) += qdio.o
|
||||
vfio_ccw-objs += vfio_ccw_drv.o vfio_ccw_cp.o vfio_ccw_ops.o vfio_ccw_fsm.o \
|
||||
vfio_ccw_async.o vfio_ccw_trace.o vfio_ccw_chp.o
|
||||
obj-$(CONFIG_VFIO_CCW) += vfio_ccw.o
|
||||
|
||||
obj-$(CONFIG_CIO_INJECT) += cio_inject.o
|
||||
|
171
drivers/s390/cio/cio_inject.c
Normal file
171
drivers/s390/cio/cio_inject.c
Normal file
@ -0,0 +1,171 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* CIO inject interface
|
||||
*
|
||||
* Copyright IBM Corp. 2021
|
||||
* Author(s): Vineeth Vijayan <vneethv@linux.ibm.com>
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "cio"
|
||||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <asm/chpid.h>
|
||||
|
||||
#include "cio_inject.h"
|
||||
#include "cio_debug.h"
|
||||
|
||||
static DEFINE_SPINLOCK(crw_inject_lock);
|
||||
DEFINE_STATIC_KEY_FALSE(cio_inject_enabled);
|
||||
static struct crw *crw_inject_data;
|
||||
|
||||
/**
|
||||
* crw_inject : Initiate the artificial CRW inject
|
||||
* @crw: The data which needs to be injected as new CRW.
|
||||
*
|
||||
* The CRW handler is called, which will use the provided artificial
|
||||
* data instead of the CRW from the underlying hardware.
|
||||
*
|
||||
* Return: 0 on success
|
||||
*/
|
||||
static int crw_inject(struct crw *crw)
|
||||
{
|
||||
int rc = 0;
|
||||
struct crw *copy;
|
||||
unsigned long flags;
|
||||
|
||||
copy = kmemdup(crw, sizeof(*crw), GFP_KERNEL);
|
||||
if (!copy)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_irqsave(&crw_inject_lock, flags);
|
||||
if (crw_inject_data) {
|
||||
kfree(copy);
|
||||
rc = -EBUSY;
|
||||
} else {
|
||||
crw_inject_data = copy;
|
||||
}
|
||||
spin_unlock_irqrestore(&crw_inject_lock, flags);
|
||||
|
||||
if (!rc)
|
||||
crw_handle_channel_report();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* stcrw_get_injected: Copy the artificial CRW data to CRW struct.
|
||||
* @crw: The target CRW pointer.
|
||||
*
|
||||
* Retrieve an injected CRW data. Return 0 on success, 1 if no
|
||||
* injected-CRW is available. The function reproduces the return
|
||||
* code of the actual STCRW function.
|
||||
*/
|
||||
int stcrw_get_injected(struct crw *crw)
|
||||
{
|
||||
int rc = 1;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&crw_inject_lock, flags);
|
||||
if (crw_inject_data) {
|
||||
memcpy(crw, crw_inject_data, sizeof(*crw));
|
||||
kfree(crw_inject_data);
|
||||
crw_inject_data = NULL;
|
||||
rc = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&crw_inject_lock, flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* The debugfs write handler for crw_inject nodes operation */
|
||||
static ssize_t crw_inject_write(struct file *file, const char __user *buf,
|
||||
size_t lbuf, loff_t *ppos)
|
||||
{
|
||||
u32 slct, oflw, chn, rsc, anc, erc, rsid;
|
||||
struct crw crw;
|
||||
char *buffer;
|
||||
int rc;
|
||||
|
||||
if (!static_branch_likely(&cio_inject_enabled)) {
|
||||
pr_warn("CIO inject is not enabled - ignoring CRW inject\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
buffer = vmemdup_user(buf, lbuf);
|
||||
if (IS_ERR(buffer))
|
||||
return -ENOMEM;
|
||||
|
||||
rc = sscanf(buffer, "%x %x %x %x %x %x %x", &slct, &oflw, &chn, &rsc, &anc,
|
||||
&erc, &rsid);
|
||||
|
||||
kvfree(buffer);
|
||||
if (rc != 7) {
|
||||
pr_warn("crw_inject: Invalid format (need <solicited> <overflow> <chaining> <rsc> <ancillary> <erc> <rsid>)\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&crw, 0, sizeof(crw));
|
||||
crw.slct = slct;
|
||||
crw.oflw = oflw;
|
||||
crw.chn = chn;
|
||||
crw.rsc = rsc;
|
||||
crw.anc = anc;
|
||||
crw.erc = erc;
|
||||
crw.rsid = rsid;
|
||||
|
||||
rc = crw_inject(&crw);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return lbuf;
|
||||
}
|
||||
|
||||
/* Debugfs write handler for inject_enable node*/
|
||||
static ssize_t enable_inject_write(struct file *file, const char __user *buf,
|
||||
size_t lbuf, loff_t *ppos)
|
||||
{
|
||||
unsigned long en = 0;
|
||||
int rc;
|
||||
|
||||
rc = kstrtoul_from_user(buf, lbuf, 10, &en);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
switch (en) {
|
||||
case 0:
|
||||
static_branch_disable(&cio_inject_enabled);
|
||||
break;
|
||||
case 1:
|
||||
static_branch_enable(&cio_inject_enabled);
|
||||
break;
|
||||
}
|
||||
|
||||
return lbuf;
|
||||
}
|
||||
|
||||
static const struct file_operations crw_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.write = crw_inject_write,
|
||||
};
|
||||
|
||||
static const struct file_operations cio_en_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.write = enable_inject_write,
|
||||
};
|
||||
|
||||
static int __init cio_inject_init(void)
|
||||
{
|
||||
/* enable_inject node enables the static branching */
|
||||
debugfs_create_file("enable_inject", 0200, cio_debugfs_dir,
|
||||
NULL, &cio_en_fops);
|
||||
|
||||
debugfs_create_file("crw_inject", 0200, cio_debugfs_dir,
|
||||
NULL, &crw_fops);
|
||||
return 0;
|
||||
}
|
||||
|
||||
device_initcall(cio_inject_init);
|
18
drivers/s390/cio/cio_inject.h
Normal file
18
drivers/s390/cio/cio_inject.h
Normal file
@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright IBM Corp. 2021
|
||||
* Author(s): Vineeth Vijayan <vneethv@linux.ibm.com>
|
||||
*/
|
||||
|
||||
#ifndef CIO_CRW_INJECT_H
|
||||
#define CIO_CRW_INJECT_H
|
||||
|
||||
#ifdef CONFIG_CIO_INJECT
|
||||
|
||||
#include <asm/crw.h>
|
||||
|
||||
DECLARE_STATIC_KEY_FALSE(cio_inject_enabled);
|
||||
int stcrw_get_injected(struct crw *crw);
|
||||
|
||||
#endif
|
||||
#endif
|
@ -12,6 +12,7 @@
|
||||
#include "ioasm.h"
|
||||
#include "orb.h"
|
||||
#include "cio.h"
|
||||
#include "cio_inject.h"
|
||||
|
||||
static inline int __stsch(struct subchannel_id schid, struct schib *addr)
|
||||
{
|
||||
@ -260,7 +261,7 @@ int xsch(struct subchannel_id schid)
|
||||
return ccode;
|
||||
}
|
||||
|
||||
int stcrw(struct crw *crw)
|
||||
static inline int __stcrw(struct crw *crw)
|
||||
{
|
||||
int ccode;
|
||||
|
||||
@ -271,6 +272,26 @@ int stcrw(struct crw *crw)
|
||||
: "=d" (ccode), "=m" (*crw)
|
||||
: "a" (crw)
|
||||
: "cc");
|
||||
return ccode;
|
||||
}
|
||||
|
||||
static inline int _stcrw(struct crw *crw)
|
||||
{
|
||||
#ifdef CONFIG_CIO_INJECT
|
||||
if (static_branch_unlikely(&cio_inject_enabled)) {
|
||||
if (stcrw_get_injected(crw) == 0)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return __stcrw(crw);
|
||||
}
|
||||
|
||||
int stcrw(struct crw *crw)
|
||||
{
|
||||
int ccode;
|
||||
|
||||
ccode = _stcrw(crw);
|
||||
trace_s390_cio_stcrw(crw, ccode);
|
||||
|
||||
return ccode;
|
||||
|
Loading…
Reference in New Issue
Block a user