hv_debugfs.c 4.4 KB

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