ipc_logging_debug.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2012-2022 Qualcomm Innovation Center, Inc. All rights reserved.
  4. */
  5. #include <linux/slab.h>
  6. #include <linux/uaccess.h>
  7. #include <linux/module.h>
  8. #include <linux/fs.h>
  9. #include <linux/kernel.h>
  10. #include <linux/errno.h>
  11. #include <linux/jiffies.h>
  12. #include <linux/debugfs.h>
  13. #include <linux/io.h>
  14. #include <linux/idr.h>
  15. #include <linux/string.h>
  16. #include <linux/sched.h>
  17. #include <linux/wait.h>
  18. #include <linux/delay.h>
  19. #include <linux/completion.h>
  20. #include <linux/ipc_logging.h>
  21. #include "ipc_logging_private.h"
  22. static DEFINE_MUTEX(ipc_log_debugfs_init_lock);
  23. static struct dentry *root_dent;
  24. static int debug_log(struct ipc_log_context *ilctxt,
  25. char *buff, int size, int cont)
  26. {
  27. int i = 0;
  28. int ret;
  29. if (size < MAX_MSG_DECODED_SIZE) {
  30. pr_err("%s: buffer size %d < %d\n", __func__, size,
  31. MAX_MSG_DECODED_SIZE);
  32. return -ENOMEM;
  33. }
  34. do {
  35. i = ipc_log_extract(ilctxt, buff, size - 1);
  36. if (cont && i == 0) {
  37. ret = wait_for_completion_interruptible(
  38. &ilctxt->read_avail);
  39. if (ret < 0)
  40. return ret;
  41. }
  42. } while (cont && i == 0);
  43. return i;
  44. }
  45. /*
  46. * VFS Read operation helper which dispatches the call to the debugfs
  47. * read command stored in file->private_data.
  48. *
  49. * @file File structure
  50. * @buff user buffer
  51. * @count size of user buffer
  52. * @ppos file position to read from (only a value of 0 is accepted)
  53. * @cont 1 = continuous mode (don't return 0 to signal end-of-file)
  54. *
  55. * @returns ==0 end of file
  56. * >0 number of bytes read
  57. * <0 error
  58. */
  59. static ssize_t debug_read_helper(struct file *file, char __user *buff,
  60. size_t count, loff_t *ppos, int cont)
  61. {
  62. struct ipc_log_context *ilctxt;
  63. struct dentry *d = file->f_path.dentry;
  64. char *buffer;
  65. int bsize;
  66. int r;
  67. r = debugfs_file_get(d);
  68. if (r)
  69. return r;
  70. ilctxt = file->private_data;
  71. r = kref_get_unless_zero(&ilctxt->refcount) ? 0 : -EIO;
  72. if (r) {
  73. debugfs_file_put(d);
  74. return r;
  75. }
  76. buffer = kmalloc(count, GFP_KERNEL);
  77. if (!buffer) {
  78. bsize = -ENOMEM;
  79. goto done;
  80. }
  81. bsize = debug_log(ilctxt, buffer, count, cont);
  82. if (bsize > 0) {
  83. if (copy_to_user(buff, buffer, bsize)) {
  84. bsize = -EFAULT;
  85. kfree(buffer);
  86. goto done;
  87. }
  88. *ppos += bsize;
  89. }
  90. kfree(buffer);
  91. done:
  92. ipc_log_context_put(ilctxt);
  93. debugfs_file_put(d);
  94. return bsize;
  95. }
  96. static ssize_t debug_read(struct file *file, char __user *buff,
  97. size_t count, loff_t *ppos)
  98. {
  99. return debug_read_helper(file, buff, count, ppos, 0);
  100. }
  101. static ssize_t debug_read_cont(struct file *file, char __user *buff,
  102. size_t count, loff_t *ppos)
  103. {
  104. return debug_read_helper(file, buff, count, ppos, 1);
  105. }
  106. static const struct file_operations debug_ops = {
  107. .read = debug_read,
  108. .open = simple_open,
  109. };
  110. static const struct file_operations debug_ops_cont = {
  111. .read = debug_read_cont,
  112. .open = simple_open,
  113. };
  114. static void debug_create(const char *name, mode_t mode,
  115. struct dentry *dent,
  116. struct ipc_log_context *ilctxt,
  117. const struct file_operations *fops)
  118. {
  119. debugfs_create_file_unsafe(name, mode, dent, ilctxt, fops);
  120. }
  121. static void dfunc_string(struct encode_context *ectxt,
  122. struct decode_context *dctxt)
  123. {
  124. tsv_timestamp_read(ectxt, dctxt, "");
  125. tsv_qtimer_read(ectxt, dctxt, " ");
  126. tsv_byte_array_read(ectxt, dctxt, "");
  127. /* add trailing \n if necessary */
  128. if (*(dctxt->buff - 1) != '\n') {
  129. if (dctxt->size) {
  130. ++dctxt->buff;
  131. --dctxt->size;
  132. }
  133. *(dctxt->buff - 1) = '\n';
  134. }
  135. }
  136. void check_and_create_debugfs(void)
  137. {
  138. mutex_lock(&ipc_log_debugfs_init_lock);
  139. if (!root_dent) {
  140. root_dent = debugfs_create_dir("ipc_logging", 0);
  141. if (IS_ERR(root_dent)) {
  142. pr_err("%s: unable to create debugfs %ld\n",
  143. __func__, PTR_ERR(root_dent));
  144. root_dent = NULL;
  145. }
  146. }
  147. mutex_unlock(&ipc_log_debugfs_init_lock);
  148. }
  149. EXPORT_SYMBOL(check_and_create_debugfs);
  150. void create_ctx_debugfs(struct ipc_log_context *ctxt,
  151. const char *mod_name)
  152. {
  153. if (!root_dent)
  154. check_and_create_debugfs();
  155. if (root_dent) {
  156. ctxt->dent = debugfs_create_dir(mod_name, root_dent);
  157. if (!IS_ERR(ctxt->dent)) {
  158. debug_create("log", 0444, ctxt->dent,
  159. ctxt, &debug_ops);
  160. debug_create("log_cont", 0444, ctxt->dent,
  161. ctxt, &debug_ops_cont);
  162. }
  163. }
  164. add_deserialization_func((void *)ctxt,
  165. TSV_TYPE_STRING, dfunc_string);
  166. }
  167. EXPORT_SYMBOL(create_ctx_debugfs);