linux/drivers/hv/hv_debugfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Authors:
   4 *   Branden Bonaby <brandonbonaby94@gmail.com>
   5 */
   6
   7#include <linux/hyperv.h>
   8#include <linux/debugfs.h>
   9#include <linux/delay.h>
  10#include <linux/err.h>
  11
  12#include "hyperv_vmbus.h"
  13
  14static struct dentry *hv_debug_root;
  15
  16static int hv_debugfs_delay_get(void *data, u64 *val)
  17{
  18        *val = *(u32 *)data;
  19        return 0;
  20}
  21
  22static int hv_debugfs_delay_set(void *data, u64 val)
  23{
  24        if (val > 1000)
  25                return -EINVAL;
  26        *(u32 *)data = val;
  27        return 0;
  28}
  29
  30DEFINE_DEBUGFS_ATTRIBUTE(hv_debugfs_delay_fops, hv_debugfs_delay_get,
  31                         hv_debugfs_delay_set, "%llu\n");
  32
  33static int hv_debugfs_state_get(void *data, u64 *val)
  34{
  35        *val = *(bool *)data;
  36        return 0;
  37}
  38
  39static int hv_debugfs_state_set(void *data, u64 val)
  40{
  41        if (val == 1)
  42                *(bool *)data = true;
  43        else if (val == 0)
  44                *(bool *)data = false;
  45        else
  46                return -EINVAL;
  47        return 0;
  48}
  49
  50DEFINE_DEBUGFS_ATTRIBUTE(hv_debugfs_state_fops, hv_debugfs_state_get,
  51                         hv_debugfs_state_set, "%llu\n");
  52
  53/* Setup delay files to store test values */
  54static int hv_debug_delay_files(struct hv_device *dev, struct dentry *root)
  55{
  56        struct vmbus_channel *channel = dev->channel;
  57        char *buffer = "fuzz_test_buffer_interrupt_delay";
  58        char *message = "fuzz_test_message_delay";
  59        int *buffer_val = &channel->fuzz_testing_interrupt_delay;
  60        int *message_val = &channel->fuzz_testing_message_delay;
  61        struct dentry *buffer_file, *message_file;
  62
  63        buffer_file = debugfs_create_file(buffer, 0644, root,
  64                                          buffer_val,
  65                                          &hv_debugfs_delay_fops);
  66        if (IS_ERR(buffer_file)) {
  67                pr_debug("debugfs_hyperv: file %s not created\n", buffer);
  68                return PTR_ERR(buffer_file);
  69        }
  70
  71        message_file = debugfs_create_file(message, 0644, root,
  72                                           message_val,
  73                                           &hv_debugfs_delay_fops);
  74        if (IS_ERR(message_file)) {
  75                pr_debug("debugfs_hyperv: file %s not created\n", message);
  76                return PTR_ERR(message_file);
  77        }
  78
  79        return 0;
  80}
  81
  82/* Setup test state value for vmbus device */
  83static int hv_debug_set_test_state(struct hv_device *dev, struct dentry *root)
  84{
  85        struct vmbus_channel *channel = dev->channel;
  86        bool *state = &channel->fuzz_testing_state;
  87        char *status = "fuzz_test_state";
  88        struct dentry *test_state;
  89
  90        test_state = debugfs_create_file(status, 0644, root,
  91                                         state,
  92                                         &hv_debugfs_state_fops);
  93        if (IS_ERR(test_state)) {
  94                pr_debug("debugfs_hyperv: file %s not created\n", status);
  95                return PTR_ERR(test_state);
  96        }
  97
  98        return 0;
  99}
 100
 101/* Bind hv device to a dentry for debugfs */
 102static void hv_debug_set_dir_dentry(struct hv_device *dev, struct dentry *root)
 103{
 104        if (hv_debug_root)
 105                dev->debug_dir = root;
 106}
 107
 108/* Create all test dentry's and names for fuzz testing */
 109int hv_debug_add_dev_dir(struct hv_device *dev)
 110{
 111        const char *device = dev_name(&dev->device);
 112        char *delay_name = "delay";
 113        struct dentry *delay, *dev_root;
 114        int ret;
 115
 116        if (!IS_ERR(hv_debug_root)) {
 117                dev_root = debugfs_create_dir(device, hv_debug_root);
 118                if (IS_ERR(dev_root)) {
 119                        pr_debug("debugfs_hyperv: hyperv/%s/ not created\n",
 120                                 device);
 121                        return PTR_ERR(dev_root);
 122                }
 123                hv_debug_set_test_state(dev, dev_root);
 124                hv_debug_set_dir_dentry(dev, dev_root);
 125                delay = debugfs_create_dir(delay_name, dev_root);
 126
 127                if (IS_ERR(delay)) {
 128                        pr_debug("debugfs_hyperv: hyperv/%s/%s/ not created\n",
 129                                 device, delay_name);
 130                        return PTR_ERR(delay);
 131                }
 132                ret = hv_debug_delay_files(dev, delay);
 133
 134                return ret;
 135        }
 136        pr_debug("debugfs_hyperv: hyperv/ not in root debugfs path\n");
 137        return PTR_ERR(hv_debug_root);
 138}
 139
 140/* Remove dentry associated with released hv device */
 141void hv_debug_rm_dev_dir(struct hv_device *dev)
 142{
 143        if (!IS_ERR(hv_debug_root))
 144                debugfs_remove_recursive(dev->debug_dir);
 145}
 146
 147/* Remove all dentrys associated with vmbus testing */
 148void hv_debug_rm_all_dir(void)
 149{
 150        debugfs_remove_recursive(hv_debug_root);
 151}
 152
 153/* Delay buffer/message reads on a vmbus channel */
 154void hv_debug_delay_test(struct vmbus_channel *channel, enum delay delay_type)
 155{
 156        struct vmbus_channel *test_channel =    channel->primary_channel ?
 157                                                channel->primary_channel :
 158                                                channel;
 159        bool state = test_channel->fuzz_testing_state;
 160
 161        if (state) {
 162                if (delay_type == 0)
 163                        udelay(test_channel->fuzz_testing_interrupt_delay);
 164                else
 165                        udelay(test_channel->fuzz_testing_message_delay);
 166        }
 167}
 168
 169/* Initialize top dentry for vmbus testing */
 170int hv_debug_init(void)
 171{
 172        hv_debug_root = debugfs_create_dir("hyperv", NULL);
 173        if (IS_ERR(hv_debug_root)) {
 174                pr_debug("debugfs_hyperv: hyperv/ not created\n");
 175                return PTR_ERR(hv_debug_root);
 176        }
 177        return 0;
 178}
 179