monwriter.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Character device driver for writing z/VM *MONITOR service records.
  4. *
  5. * Copyright IBM Corp. 2006, 2009
  6. *
  7. * Author(s): Melissa Howland <Melissa.Howland@us.ibm.com>
  8. */
  9. #define KMSG_COMPONENT "monwriter"
  10. #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  11. #include <linux/module.h>
  12. #include <linux/moduleparam.h>
  13. #include <linux/init.h>
  14. #include <linux/errno.h>
  15. #include <linux/types.h>
  16. #include <linux/kernel.h>
  17. #include <linux/miscdevice.h>
  18. #include <linux/ctype.h>
  19. #include <linux/poll.h>
  20. #include <linux/mutex.h>
  21. #include <linux/slab.h>
  22. #include <linux/uaccess.h>
  23. #include <linux/io.h>
  24. #include <asm/ebcdic.h>
  25. #include <asm/appldata.h>
  26. #include <asm/monwriter.h>
  27. #define MONWRITE_MAX_DATALEN 4010
  28. static int mon_max_bufs = 255;
  29. static int mon_buf_count;
  30. struct mon_buf {
  31. struct list_head list;
  32. struct monwrite_hdr hdr;
  33. int diag_done;
  34. char *data;
  35. };
  36. struct mon_private {
  37. struct list_head list;
  38. struct monwrite_hdr hdr;
  39. size_t hdr_to_read;
  40. size_t data_to_read;
  41. struct mon_buf *current_buf;
  42. struct mutex thread_mutex;
  43. };
  44. /*
  45. * helper functions
  46. */
  47. static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
  48. {
  49. struct appldata_parameter_list *parm_list;
  50. struct appldata_product_id *id;
  51. int rc;
  52. id = kmalloc(sizeof(*id), GFP_KERNEL);
  53. parm_list = kmalloc(sizeof(*parm_list), GFP_KERNEL);
  54. rc = -ENOMEM;
  55. if (!id || !parm_list)
  56. goto out;
  57. memcpy(id->prod_nr, "LNXAPPL", 7);
  58. id->prod_fn = myhdr->applid;
  59. id->record_nr = myhdr->record_num;
  60. id->version_nr = myhdr->version;
  61. id->release_nr = myhdr->release;
  62. id->mod_lvl = myhdr->mod_level;
  63. rc = appldata_asm(parm_list, id, fcn,
  64. (void *) buffer, myhdr->datalen);
  65. if (rc <= 0)
  66. goto out;
  67. pr_err("Writing monitor data failed with rc=%i\n", rc);
  68. rc = (rc == 5) ? -EPERM : -EINVAL;
  69. out:
  70. kfree(id);
  71. kfree(parm_list);
  72. return rc;
  73. }
  74. static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
  75. struct monwrite_hdr *monhdr)
  76. {
  77. struct mon_buf *entry, *next;
  78. list_for_each_entry_safe(entry, next, &monpriv->list, list)
  79. if ((entry->hdr.mon_function == monhdr->mon_function ||
  80. monhdr->mon_function == MONWRITE_STOP_INTERVAL) &&
  81. entry->hdr.applid == monhdr->applid &&
  82. entry->hdr.record_num == monhdr->record_num &&
  83. entry->hdr.version == monhdr->version &&
  84. entry->hdr.release == monhdr->release &&
  85. entry->hdr.mod_level == monhdr->mod_level)
  86. return entry;
  87. return NULL;
  88. }
  89. static int monwrite_new_hdr(struct mon_private *monpriv)
  90. {
  91. struct monwrite_hdr *monhdr = &monpriv->hdr;
  92. struct mon_buf *monbuf;
  93. int rc = 0;
  94. if (monhdr->datalen > MONWRITE_MAX_DATALEN ||
  95. monhdr->mon_function > MONWRITE_START_CONFIG ||
  96. monhdr->hdrlen != sizeof(struct monwrite_hdr))
  97. return -EINVAL;
  98. monbuf = NULL;
  99. if (monhdr->mon_function != MONWRITE_GEN_EVENT)
  100. monbuf = monwrite_find_hdr(monpriv, monhdr);
  101. if (monbuf) {
  102. if (monhdr->mon_function == MONWRITE_STOP_INTERVAL) {
  103. monhdr->datalen = monbuf->hdr.datalen;
  104. rc = monwrite_diag(monhdr, monbuf->data,
  105. APPLDATA_STOP_REC);
  106. list_del(&monbuf->list);
  107. mon_buf_count--;
  108. kfree(monbuf->data);
  109. kfree(monbuf);
  110. monbuf = NULL;
  111. }
  112. } else if (monhdr->mon_function != MONWRITE_STOP_INTERVAL) {
  113. if (mon_buf_count >= mon_max_bufs)
  114. return -ENOSPC;
  115. monbuf = kzalloc(sizeof(struct mon_buf), GFP_KERNEL);
  116. if (!monbuf)
  117. return -ENOMEM;
  118. monbuf->data = kzalloc(monhdr->datalen,
  119. GFP_KERNEL | GFP_DMA);
  120. if (!monbuf->data) {
  121. kfree(monbuf);
  122. return -ENOMEM;
  123. }
  124. monbuf->hdr = *monhdr;
  125. list_add_tail(&monbuf->list, &monpriv->list);
  126. if (monhdr->mon_function != MONWRITE_GEN_EVENT)
  127. mon_buf_count++;
  128. }
  129. monpriv->current_buf = monbuf;
  130. return rc;
  131. }
  132. static int monwrite_new_data(struct mon_private *monpriv)
  133. {
  134. struct monwrite_hdr *monhdr = &monpriv->hdr;
  135. struct mon_buf *monbuf = monpriv->current_buf;
  136. int rc = 0;
  137. switch (monhdr->mon_function) {
  138. case MONWRITE_START_INTERVAL:
  139. if (!monbuf->diag_done) {
  140. rc = monwrite_diag(monhdr, monbuf->data,
  141. APPLDATA_START_INTERVAL_REC);
  142. monbuf->diag_done = 1;
  143. }
  144. break;
  145. case MONWRITE_START_CONFIG:
  146. if (!monbuf->diag_done) {
  147. rc = monwrite_diag(monhdr, monbuf->data,
  148. APPLDATA_START_CONFIG_REC);
  149. monbuf->diag_done = 1;
  150. }
  151. break;
  152. case MONWRITE_GEN_EVENT:
  153. rc = monwrite_diag(monhdr, monbuf->data,
  154. APPLDATA_GEN_EVENT_REC);
  155. list_del(&monpriv->current_buf->list);
  156. kfree(monpriv->current_buf->data);
  157. kfree(monpriv->current_buf);
  158. monpriv->current_buf = NULL;
  159. break;
  160. default:
  161. /* monhdr->mon_function is checked in monwrite_new_hdr */
  162. BUG();
  163. }
  164. return rc;
  165. }
  166. /*
  167. * file operations
  168. */
  169. static int monwrite_open(struct inode *inode, struct file *filp)
  170. {
  171. struct mon_private *monpriv;
  172. monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL);
  173. if (!monpriv)
  174. return -ENOMEM;
  175. INIT_LIST_HEAD(&monpriv->list);
  176. monpriv->hdr_to_read = sizeof(monpriv->hdr);
  177. mutex_init(&monpriv->thread_mutex);
  178. filp->private_data = monpriv;
  179. return nonseekable_open(inode, filp);
  180. }
  181. static int monwrite_close(struct inode *inode, struct file *filp)
  182. {
  183. struct mon_private *monpriv = filp->private_data;
  184. struct mon_buf *entry, *next;
  185. list_for_each_entry_safe(entry, next, &monpriv->list, list) {
  186. if (entry->hdr.mon_function != MONWRITE_GEN_EVENT)
  187. monwrite_diag(&entry->hdr, entry->data,
  188. APPLDATA_STOP_REC);
  189. mon_buf_count--;
  190. list_del(&entry->list);
  191. kfree(entry->data);
  192. kfree(entry);
  193. }
  194. kfree(monpriv);
  195. return 0;
  196. }
  197. static ssize_t monwrite_write(struct file *filp, const char __user *data,
  198. size_t count, loff_t *ppos)
  199. {
  200. struct mon_private *monpriv = filp->private_data;
  201. size_t len, written;
  202. void *to;
  203. int rc;
  204. mutex_lock(&monpriv->thread_mutex);
  205. for (written = 0; written < count; ) {
  206. if (monpriv->hdr_to_read) {
  207. len = min(count - written, monpriv->hdr_to_read);
  208. to = (char *) &monpriv->hdr +
  209. sizeof(monpriv->hdr) - monpriv->hdr_to_read;
  210. if (copy_from_user(to, data + written, len)) {
  211. rc = -EFAULT;
  212. goto out_error;
  213. }
  214. monpriv->hdr_to_read -= len;
  215. written += len;
  216. if (monpriv->hdr_to_read > 0)
  217. continue;
  218. rc = monwrite_new_hdr(monpriv);
  219. if (rc)
  220. goto out_error;
  221. monpriv->data_to_read = monpriv->current_buf ?
  222. monpriv->current_buf->hdr.datalen : 0;
  223. }
  224. if (monpriv->data_to_read) {
  225. len = min(count - written, monpriv->data_to_read);
  226. to = monpriv->current_buf->data +
  227. monpriv->hdr.datalen - monpriv->data_to_read;
  228. if (copy_from_user(to, data + written, len)) {
  229. rc = -EFAULT;
  230. goto out_error;
  231. }
  232. monpriv->data_to_read -= len;
  233. written += len;
  234. if (monpriv->data_to_read > 0)
  235. continue;
  236. rc = monwrite_new_data(monpriv);
  237. if (rc)
  238. goto out_error;
  239. }
  240. monpriv->hdr_to_read = sizeof(monpriv->hdr);
  241. }
  242. mutex_unlock(&monpriv->thread_mutex);
  243. return written;
  244. out_error:
  245. monpriv->data_to_read = 0;
  246. monpriv->hdr_to_read = sizeof(struct monwrite_hdr);
  247. mutex_unlock(&monpriv->thread_mutex);
  248. return rc;
  249. }
  250. static const struct file_operations monwrite_fops = {
  251. .owner = THIS_MODULE,
  252. .open = &monwrite_open,
  253. .release = &monwrite_close,
  254. .write = &monwrite_write,
  255. .llseek = noop_llseek,
  256. };
  257. static struct miscdevice mon_dev = {
  258. .name = "monwriter",
  259. .fops = &monwrite_fops,
  260. .minor = MISC_DYNAMIC_MINOR,
  261. };
  262. /*
  263. * module init/exit
  264. */
  265. static int __init mon_init(void)
  266. {
  267. if (!MACHINE_IS_VM)
  268. return -ENODEV;
  269. /*
  270. * misc_register() has to be the last action in module_init(), because
  271. * file operations will be available right after this.
  272. */
  273. return misc_register(&mon_dev);
  274. }
  275. static void __exit mon_exit(void)
  276. {
  277. misc_deregister(&mon_dev);
  278. }
  279. module_init(mon_init);
  280. module_exit(mon_exit);
  281. module_param_named(max_bufs, mon_max_bufs, int, 0644);
  282. MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers "
  283. "that can be active at one time");
  284. MODULE_AUTHOR("Melissa Howland <Melissa.Howland@us.ibm.com>");
  285. MODULE_DESCRIPTION("Character device driver for writing z/VM "
  286. "APPLDATA monitor records.");
  287. MODULE_LICENSE("GPL");