178 lines · 4.4 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * Authors: *   Branden Bonaby <brandonbonaby94@gmail.com> */ #include <linux/hyperv.h>#include <linux/debugfs.h>#include <linux/delay.h>#include <linux/err.h> #include "hyperv_vmbus.h" static struct dentry *hv_debug_root; static int hv_debugfs_delay_get(void *data, u64 *val){	*val = *(u32 *)data;	return 0;} static int hv_debugfs_delay_set(void *data, u64 val){	if (val > 1000)		return -EINVAL;	*(u32 *)data = val;	return 0;} DEFINE_DEBUGFS_ATTRIBUTE(hv_debugfs_delay_fops, hv_debugfs_delay_get,			 hv_debugfs_delay_set, "%llu\n"); static int hv_debugfs_state_get(void *data, u64 *val){	*val = *(bool *)data;	return 0;} static int hv_debugfs_state_set(void *data, u64 val){	if (val == 1)		*(bool *)data = true;	else if (val == 0)		*(bool *)data = false;	else		return -EINVAL;	return 0;} DEFINE_DEBUGFS_ATTRIBUTE(hv_debugfs_state_fops, hv_debugfs_state_get,			 hv_debugfs_state_set, "%llu\n"); /* Setup delay files to store test values */static int hv_debug_delay_files(struct hv_device *dev, struct dentry *root){	struct vmbus_channel *channel = dev->channel;	char *buffer = "fuzz_test_buffer_interrupt_delay";	char *message = "fuzz_test_message_delay";	int *buffer_val = &channel->fuzz_testing_interrupt_delay;	int *message_val = &channel->fuzz_testing_message_delay;	struct dentry *buffer_file, *message_file; 	buffer_file = debugfs_create_file(buffer, 0644, root,					  buffer_val,					  &hv_debugfs_delay_fops);	if (IS_ERR(buffer_file)) {		pr_debug("debugfs_hyperv: file %s not created\n", buffer);		return PTR_ERR(buffer_file);	} 	message_file = debugfs_create_file(message, 0644, root,					   message_val,					   &hv_debugfs_delay_fops);	if (IS_ERR(message_file)) {		pr_debug("debugfs_hyperv: file %s not created\n", message);		return PTR_ERR(message_file);	} 	return 0;} /* Setup test state value for vmbus device */static int hv_debug_set_test_state(struct hv_device *dev, struct dentry *root){	struct vmbus_channel *channel = dev->channel;	bool *state = &channel->fuzz_testing_state;	char *status = "fuzz_test_state";	struct dentry *test_state; 	test_state = debugfs_create_file(status, 0644, root,					 state,					 &hv_debugfs_state_fops);	if (IS_ERR(test_state)) {		pr_debug("debugfs_hyperv: file %s not created\n", status);		return PTR_ERR(test_state);	} 	return 0;} /* Bind hv device to a dentry for debugfs */static void hv_debug_set_dir_dentry(struct hv_device *dev, struct dentry *root){	if (hv_debug_root)		dev->debug_dir = root;} /* Create all test dentry's and names for fuzz testing */int hv_debug_add_dev_dir(struct hv_device *dev){	const char *device = dev_name(&dev->device);	char *delay_name = "delay";	struct dentry *delay, *dev_root;	int ret; 	if (!IS_ERR(hv_debug_root)) {		dev_root = debugfs_create_dir(device, hv_debug_root);		if (IS_ERR(dev_root)) {			pr_debug("debugfs_hyperv: hyperv/%s/ not created\n",				 device);			return PTR_ERR(dev_root);		}		hv_debug_set_test_state(dev, dev_root);		hv_debug_set_dir_dentry(dev, dev_root);		delay = debugfs_create_dir(delay_name, dev_root); 		if (IS_ERR(delay)) {			pr_debug("debugfs_hyperv: hyperv/%s/%s/ not created\n",				 device, delay_name);			return PTR_ERR(delay);		}		ret = hv_debug_delay_files(dev, delay); 		return ret;	}	pr_debug("debugfs_hyperv: hyperv/ not in root debugfs path\n");	return PTR_ERR(hv_debug_root);} /* Remove dentry associated with released hv device */void hv_debug_rm_dev_dir(struct hv_device *dev){	if (!IS_ERR(hv_debug_root))		debugfs_remove_recursive(dev->debug_dir);} /* Remove all dentrys associated with vmbus testing */void hv_debug_rm_all_dir(void){	debugfs_remove_recursive(hv_debug_root);} /* Delay buffer/message reads on a vmbus channel */void hv_debug_delay_test(struct vmbus_channel *channel, enum delay delay_type){	struct vmbus_channel *test_channel =    channel->primary_channel ?						channel->primary_channel :						channel;	bool state = test_channel->fuzz_testing_state; 	if (state) {		if (delay_type == 0)			udelay(test_channel->fuzz_testing_interrupt_delay);		else			udelay(test_channel->fuzz_testing_message_delay);	}} /* Initialize top dentry for vmbus testing */int hv_debug_init(void){	hv_debug_root = debugfs_create_dir("hyperv", NULL);	if (IS_ERR(hv_debug_root)) {		pr_debug("debugfs_hyperv: hyperv/ not created\n");		return PTR_ERR(hv_debug_root);	}	return 0;}