cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

health.c (7298B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Copyright (c) 2019 Mellanox Technologies. All rights reserved */
      3
      4#include <linux/debugfs.h>
      5#include <linux/err.h>
      6#include <linux/kernel.h>
      7#include <linux/slab.h>
      8
      9#include "netdevsim.h"
     10
     11static int
     12nsim_dev_empty_reporter_dump(struct devlink_health_reporter *reporter,
     13			     struct devlink_fmsg *fmsg, void *priv_ctx,
     14			     struct netlink_ext_ack *extack)
     15{
     16	return 0;
     17}
     18
     19static int
     20nsim_dev_empty_reporter_diagnose(struct devlink_health_reporter *reporter,
     21				 struct devlink_fmsg *fmsg,
     22				 struct netlink_ext_ack *extack)
     23{
     24	return 0;
     25}
     26
     27static const
     28struct devlink_health_reporter_ops nsim_dev_empty_reporter_ops = {
     29	.name = "empty",
     30	.dump = nsim_dev_empty_reporter_dump,
     31	.diagnose = nsim_dev_empty_reporter_diagnose,
     32};
     33
     34struct nsim_dev_dummy_reporter_ctx {
     35	char *break_msg;
     36};
     37
     38static int
     39nsim_dev_dummy_reporter_recover(struct devlink_health_reporter *reporter,
     40				void *priv_ctx,
     41				struct netlink_ext_ack *extack)
     42{
     43	struct nsim_dev_health *health = devlink_health_reporter_priv(reporter);
     44	struct nsim_dev_dummy_reporter_ctx *ctx = priv_ctx;
     45
     46	if (health->fail_recover) {
     47		/* For testing purposes, user set debugfs fail_recover
     48		 * value to true. Fail right away.
     49		 */
     50		NL_SET_ERR_MSG_MOD(extack, "User setup the recover to fail for testing purposes");
     51		return -EINVAL;
     52	}
     53	if (ctx) {
     54		kfree(health->recovered_break_msg);
     55		health->recovered_break_msg = kstrdup(ctx->break_msg,
     56						      GFP_KERNEL);
     57		if (!health->recovered_break_msg)
     58			return -ENOMEM;
     59	}
     60	return 0;
     61}
     62
     63static int nsim_dev_dummy_fmsg_put(struct devlink_fmsg *fmsg, u32 binary_len)
     64{
     65	char *binary;
     66	int err;
     67	int i;
     68
     69	err = devlink_fmsg_bool_pair_put(fmsg, "test_bool", true);
     70	if (err)
     71		return err;
     72	err = devlink_fmsg_u8_pair_put(fmsg, "test_u8", 1);
     73	if (err)
     74		return err;
     75	err = devlink_fmsg_u32_pair_put(fmsg, "test_u32", 3);
     76	if (err)
     77		return err;
     78	err = devlink_fmsg_u64_pair_put(fmsg, "test_u64", 4);
     79	if (err)
     80		return err;
     81	err = devlink_fmsg_string_pair_put(fmsg, "test_string", "somestring");
     82	if (err)
     83		return err;
     84
     85	binary = kmalloc(binary_len, GFP_KERNEL | __GFP_NOWARN);
     86	if (!binary)
     87		return -ENOMEM;
     88	get_random_bytes(binary, binary_len);
     89	err = devlink_fmsg_binary_pair_put(fmsg, "test_binary", binary, binary_len);
     90	kfree(binary);
     91	if (err)
     92		return err;
     93
     94	err = devlink_fmsg_pair_nest_start(fmsg, "test_nest");
     95	if (err)
     96		return err;
     97	err = devlink_fmsg_obj_nest_start(fmsg);
     98	if (err)
     99		return err;
    100	err = devlink_fmsg_bool_pair_put(fmsg, "nested_test_bool", false);
    101	if (err)
    102		return err;
    103	err = devlink_fmsg_u8_pair_put(fmsg, "nested_test_u8", false);
    104	if (err)
    105		return err;
    106	err = devlink_fmsg_obj_nest_end(fmsg);
    107	if (err)
    108		return err;
    109	err = devlink_fmsg_pair_nest_end(fmsg);
    110	if (err)
    111		return err;
    112
    113	err = devlink_fmsg_arr_pair_nest_end(fmsg);
    114	if (err)
    115		return err;
    116
    117	err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_u32_array");
    118	if (err)
    119		return err;
    120	for (i = 0; i < 10; i++) {
    121		err = devlink_fmsg_u32_put(fmsg, i);
    122		if (err)
    123			return err;
    124	}
    125	err = devlink_fmsg_arr_pair_nest_end(fmsg);
    126	if (err)
    127		return err;
    128
    129	err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_array_of_objects");
    130	if (err)
    131		return err;
    132	for (i = 0; i < 10; i++) {
    133		err = devlink_fmsg_obj_nest_start(fmsg);
    134		if (err)
    135			return err;
    136		err = devlink_fmsg_bool_pair_put(fmsg,
    137						 "in_array_nested_test_bool",
    138						 false);
    139		if (err)
    140			return err;
    141		err = devlink_fmsg_u8_pair_put(fmsg,
    142					       "in_array_nested_test_u8",
    143					       i);
    144		if (err)
    145			return err;
    146		err = devlink_fmsg_obj_nest_end(fmsg);
    147		if (err)
    148			return err;
    149	}
    150	return devlink_fmsg_arr_pair_nest_end(fmsg);
    151}
    152
    153static int
    154nsim_dev_dummy_reporter_dump(struct devlink_health_reporter *reporter,
    155			     struct devlink_fmsg *fmsg, void *priv_ctx,
    156			     struct netlink_ext_ack *extack)
    157{
    158	struct nsim_dev_health *health = devlink_health_reporter_priv(reporter);
    159	struct nsim_dev_dummy_reporter_ctx *ctx = priv_ctx;
    160	int err;
    161
    162	if (ctx) {
    163		err = devlink_fmsg_string_pair_put(fmsg, "break_message",
    164						   ctx->break_msg);
    165		if (err)
    166			return err;
    167	}
    168	return nsim_dev_dummy_fmsg_put(fmsg, health->binary_len);
    169}
    170
    171static int
    172nsim_dev_dummy_reporter_diagnose(struct devlink_health_reporter *reporter,
    173				 struct devlink_fmsg *fmsg,
    174				 struct netlink_ext_ack *extack)
    175{
    176	struct nsim_dev_health *health = devlink_health_reporter_priv(reporter);
    177	int err;
    178
    179	if (health->recovered_break_msg) {
    180		err = devlink_fmsg_string_pair_put(fmsg,
    181						   "recovered_break_message",
    182						   health->recovered_break_msg);
    183		if (err)
    184			return err;
    185	}
    186	return nsim_dev_dummy_fmsg_put(fmsg, health->binary_len);
    187}
    188
    189static const
    190struct devlink_health_reporter_ops nsim_dev_dummy_reporter_ops = {
    191	.name = "dummy",
    192	.recover = nsim_dev_dummy_reporter_recover,
    193	.dump = nsim_dev_dummy_reporter_dump,
    194	.diagnose = nsim_dev_dummy_reporter_diagnose,
    195};
    196
    197static ssize_t nsim_dev_health_break_write(struct file *file,
    198					   const char __user *data,
    199					   size_t count, loff_t *ppos)
    200{
    201	struct nsim_dev_health *health = file->private_data;
    202	struct nsim_dev_dummy_reporter_ctx ctx;
    203	char *break_msg;
    204	int err;
    205
    206	break_msg = memdup_user_nul(data, count);
    207	if (IS_ERR(break_msg))
    208		return PTR_ERR(break_msg);
    209
    210	if (break_msg[count - 1] == '\n')
    211		break_msg[count - 1] = '\0';
    212
    213	ctx.break_msg = break_msg;
    214	err = devlink_health_report(health->dummy_reporter, break_msg, &ctx);
    215	if (err)
    216		goto out;
    217
    218out:
    219	kfree(break_msg);
    220	return err ?: count;
    221}
    222
    223static const struct file_operations nsim_dev_health_break_fops = {
    224	.open = simple_open,
    225	.write = nsim_dev_health_break_write,
    226	.llseek = generic_file_llseek,
    227	.owner = THIS_MODULE,
    228};
    229
    230int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink)
    231{
    232	struct nsim_dev_health *health = &nsim_dev->health;
    233	int err;
    234
    235	health->empty_reporter =
    236		devlink_health_reporter_create(devlink,
    237					       &nsim_dev_empty_reporter_ops,
    238					       0, health);
    239	if (IS_ERR(health->empty_reporter))
    240		return PTR_ERR(health->empty_reporter);
    241
    242	health->dummy_reporter =
    243		devlink_health_reporter_create(devlink,
    244					       &nsim_dev_dummy_reporter_ops,
    245					       0, health);
    246	if (IS_ERR(health->dummy_reporter)) {
    247		err = PTR_ERR(health->dummy_reporter);
    248		goto err_empty_reporter_destroy;
    249	}
    250
    251	health->ddir = debugfs_create_dir("health", nsim_dev->ddir);
    252	if (IS_ERR(health->ddir)) {
    253		err = PTR_ERR(health->ddir);
    254		goto err_dummy_reporter_destroy;
    255	}
    256
    257	health->recovered_break_msg = NULL;
    258	debugfs_create_file("break_health", 0200, health->ddir, health,
    259			    &nsim_dev_health_break_fops);
    260	health->binary_len = 16;
    261	debugfs_create_u32("binary_len", 0600, health->ddir,
    262			   &health->binary_len);
    263	health->fail_recover = false;
    264	debugfs_create_bool("fail_recover", 0600, health->ddir,
    265			    &health->fail_recover);
    266	return 0;
    267
    268err_dummy_reporter_destroy:
    269	devlink_health_reporter_destroy(health->dummy_reporter);
    270err_empty_reporter_destroy:
    271	devlink_health_reporter_destroy(health->empty_reporter);
    272	return err;
    273}
    274
    275void nsim_dev_health_exit(struct nsim_dev *nsim_dev)
    276{
    277	struct nsim_dev_health *health = &nsim_dev->health;
    278
    279	debugfs_remove_recursive(health->ddir);
    280	kfree(health->recovered_break_msg);
    281	devlink_health_reporter_destroy(health->dummy_reporter);
    282	devlink_health_reporter_destroy(health->empty_reporter);
    283}