appldata_base.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Base infrastructure for Linux-z/VM Monitor Stream, Stage 1.
  4. * Exports appldata_register_ops() and appldata_unregister_ops() for the
  5. * data gathering modules.
  6. *
  7. * Copyright IBM Corp. 2003, 2009
  8. *
  9. * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  10. */
  11. #define pr_fmt(fmt) "appldata: " fmt
  12. #include <linux/export.h>
  13. #include <linux/module.h>
  14. #include <linux/sched/stat.h>
  15. #include <linux/init.h>
  16. #include <linux/slab.h>
  17. #include <linux/errno.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/proc_fs.h>
  20. #include <linux/mm.h>
  21. #include <linux/swap.h>
  22. #include <linux/pagemap.h>
  23. #include <linux/sysctl.h>
  24. #include <linux/notifier.h>
  25. #include <linux/cpu.h>
  26. #include <linux/workqueue.h>
  27. #include <linux/uaccess.h>
  28. #include <linux/io.h>
  29. #include <asm/appldata.h>
  30. #include <asm/vtimer.h>
  31. #include <asm/smp.h>
  32. #include "appldata.h"
  33. #define APPLDATA_CPU_INTERVAL 10000 /* default (CPU) time for
  34. sampling interval in
  35. milliseconds */
  36. #define TOD_MICRO 0x01000 /* nr. of TOD clock units
  37. for 1 microsecond */
  38. /*
  39. * /proc entries (sysctl)
  40. */
  41. static const char appldata_proc_name[APPLDATA_PROC_NAME_LENGTH] = "appldata";
  42. static int appldata_timer_handler(const struct ctl_table *ctl, int write,
  43. void *buffer, size_t *lenp, loff_t *ppos);
  44. static int appldata_interval_handler(const struct ctl_table *ctl, int write,
  45. void *buffer, size_t *lenp, loff_t *ppos);
  46. static struct ctl_table_header *appldata_sysctl_header;
  47. static const struct ctl_table appldata_table[] = {
  48. {
  49. .procname = "timer",
  50. .mode = S_IRUGO | S_IWUSR,
  51. .proc_handler = appldata_timer_handler,
  52. },
  53. {
  54. .procname = "interval",
  55. .mode = S_IRUGO | S_IWUSR,
  56. .proc_handler = appldata_interval_handler,
  57. },
  58. };
  59. /*
  60. * Timer
  61. */
  62. static struct vtimer_list appldata_timer;
  63. static DEFINE_SPINLOCK(appldata_timer_lock);
  64. static int appldata_interval = APPLDATA_CPU_INTERVAL;
  65. static int appldata_timer_active;
  66. /*
  67. * Work queue
  68. */
  69. static struct workqueue_struct *appldata_wq;
  70. static void appldata_work_fn(struct work_struct *work);
  71. static DECLARE_WORK(appldata_work, appldata_work_fn);
  72. /*
  73. * Ops list
  74. */
  75. static DEFINE_MUTEX(appldata_ops_mutex);
  76. static LIST_HEAD(appldata_ops_list);
  77. /*************************** timer, work, DIAG *******************************/
  78. /*
  79. * appldata_timer_function()
  80. *
  81. * schedule work and reschedule timer
  82. */
  83. static void appldata_timer_function(unsigned long data)
  84. {
  85. queue_work(appldata_wq, (struct work_struct *) data);
  86. }
  87. /*
  88. * appldata_work_fn()
  89. *
  90. * call data gathering function for each (active) module
  91. */
  92. static void appldata_work_fn(struct work_struct *work)
  93. {
  94. struct list_head *lh;
  95. struct appldata_ops *ops;
  96. mutex_lock(&appldata_ops_mutex);
  97. list_for_each(lh, &appldata_ops_list) {
  98. ops = list_entry(lh, struct appldata_ops, list);
  99. if (ops->active == 1) {
  100. ops->callback(ops->data);
  101. }
  102. }
  103. mutex_unlock(&appldata_ops_mutex);
  104. }
  105. static struct appldata_product_id appldata_id = {
  106. .prod_nr = {0xD3, 0xC9, 0xD5, 0xE4,
  107. 0xE7, 0xD2, 0xD9}, /* "LINUXKR" */
  108. .prod_fn = 0xD5D3, /* "NL" */
  109. .version_nr = 0xF2F6, /* "26" */
  110. .release_nr = 0xF0F1, /* "01" */
  111. };
  112. /*
  113. * appldata_diag()
  114. *
  115. * prepare parameter list, issue DIAG 0xDC
  116. */
  117. int appldata_diag(char record_nr, u16 function, unsigned long buffer,
  118. u16 length, char *mod_lvl)
  119. {
  120. struct appldata_parameter_list *parm_list;
  121. struct appldata_product_id *id;
  122. int rc;
  123. parm_list = kmalloc_obj(*parm_list);
  124. id = kmemdup(&appldata_id, sizeof(appldata_id), GFP_KERNEL);
  125. rc = -ENOMEM;
  126. if (parm_list && id) {
  127. id->record_nr = record_nr;
  128. id->mod_lvl = (mod_lvl[0]) << 8 | mod_lvl[1];
  129. rc = appldata_asm(parm_list, id, function,
  130. (void *) buffer, length);
  131. }
  132. kfree(id);
  133. kfree(parm_list);
  134. return rc;
  135. }
  136. /************************ timer, work, DIAG <END> ****************************/
  137. /****************************** /proc stuff **********************************/
  138. #define APPLDATA_ADD_TIMER 0
  139. #define APPLDATA_DEL_TIMER 1
  140. #define APPLDATA_MOD_TIMER 2
  141. /*
  142. * __appldata_vtimer_setup()
  143. *
  144. * Add, delete or modify virtual timers on all online cpus.
  145. * The caller needs to get the appldata_timer_lock spinlock.
  146. */
  147. static void __appldata_vtimer_setup(int cmd)
  148. {
  149. u64 timer_interval = (u64) appldata_interval * 1000 * TOD_MICRO;
  150. switch (cmd) {
  151. case APPLDATA_ADD_TIMER:
  152. if (appldata_timer_active)
  153. break;
  154. appldata_timer.expires = timer_interval;
  155. add_virt_timer_periodic(&appldata_timer);
  156. appldata_timer_active = 1;
  157. break;
  158. case APPLDATA_DEL_TIMER:
  159. del_virt_timer(&appldata_timer);
  160. if (!appldata_timer_active)
  161. break;
  162. appldata_timer_active = 0;
  163. break;
  164. case APPLDATA_MOD_TIMER:
  165. if (!appldata_timer_active)
  166. break;
  167. mod_virt_timer_periodic(&appldata_timer, timer_interval);
  168. }
  169. }
  170. /*
  171. * appldata_timer_handler()
  172. *
  173. * Start/Stop timer, show status of timer (0 = not active, 1 = active)
  174. */
  175. static int
  176. appldata_timer_handler(const struct ctl_table *ctl, int write,
  177. void *buffer, size_t *lenp, loff_t *ppos)
  178. {
  179. int timer_active = appldata_timer_active;
  180. int rc;
  181. struct ctl_table ctl_entry = {
  182. .procname = ctl->procname,
  183. .data = &timer_active,
  184. .maxlen = sizeof(int),
  185. .extra1 = SYSCTL_ZERO,
  186. .extra2 = SYSCTL_ONE,
  187. };
  188. rc = proc_douintvec_minmax(&ctl_entry, write, buffer, lenp, ppos);
  189. if (rc < 0 || !write)
  190. return rc;
  191. spin_lock(&appldata_timer_lock);
  192. if (timer_active)
  193. __appldata_vtimer_setup(APPLDATA_ADD_TIMER);
  194. else
  195. __appldata_vtimer_setup(APPLDATA_DEL_TIMER);
  196. spin_unlock(&appldata_timer_lock);
  197. return 0;
  198. }
  199. /*
  200. * appldata_interval_handler()
  201. *
  202. * Set (CPU) timer interval for collection of data (in milliseconds), show
  203. * current timer interval.
  204. */
  205. static int
  206. appldata_interval_handler(const struct ctl_table *ctl, int write,
  207. void *buffer, size_t *lenp, loff_t *ppos)
  208. {
  209. int interval = appldata_interval;
  210. int rc;
  211. struct ctl_table ctl_entry = {
  212. .procname = ctl->procname,
  213. .data = &interval,
  214. .maxlen = sizeof(int),
  215. .extra1 = SYSCTL_ONE,
  216. };
  217. rc = proc_dointvec_minmax(&ctl_entry, write, buffer, lenp, ppos);
  218. if (rc < 0 || !write)
  219. return rc;
  220. spin_lock(&appldata_timer_lock);
  221. appldata_interval = interval;
  222. __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
  223. spin_unlock(&appldata_timer_lock);
  224. return 0;
  225. }
  226. /*
  227. * appldata_generic_handler()
  228. *
  229. * Generic start/stop monitoring and DIAG, show status of
  230. * monitoring (0 = not in process, 1 = in process)
  231. */
  232. static int
  233. appldata_generic_handler(const struct ctl_table *ctl, int write,
  234. void *buffer, size_t *lenp, loff_t *ppos)
  235. {
  236. struct appldata_ops *ops = NULL, *tmp_ops;
  237. struct list_head *lh;
  238. int rc, found;
  239. int active;
  240. struct ctl_table ctl_entry = {
  241. .data = &active,
  242. .maxlen = sizeof(int),
  243. .extra1 = SYSCTL_ZERO,
  244. .extra2 = SYSCTL_ONE,
  245. };
  246. found = 0;
  247. mutex_lock(&appldata_ops_mutex);
  248. list_for_each(lh, &appldata_ops_list) {
  249. tmp_ops = list_entry(lh, struct appldata_ops, list);
  250. if (&tmp_ops->ctl_table[0] == ctl) {
  251. found = 1;
  252. }
  253. }
  254. if (!found) {
  255. mutex_unlock(&appldata_ops_mutex);
  256. return -ENODEV;
  257. }
  258. ops = ctl->data;
  259. if (!try_module_get(ops->owner)) { // protect this function
  260. mutex_unlock(&appldata_ops_mutex);
  261. return -ENODEV;
  262. }
  263. mutex_unlock(&appldata_ops_mutex);
  264. active = ops->active;
  265. rc = proc_douintvec_minmax(&ctl_entry, write, buffer, lenp, ppos);
  266. if (rc < 0 || !write) {
  267. module_put(ops->owner);
  268. return rc;
  269. }
  270. mutex_lock(&appldata_ops_mutex);
  271. if (active && (ops->active == 0)) {
  272. // protect work queue callback
  273. if (!try_module_get(ops->owner)) {
  274. mutex_unlock(&appldata_ops_mutex);
  275. module_put(ops->owner);
  276. return -ENODEV;
  277. }
  278. ops->callback(ops->data); // init record
  279. rc = appldata_diag(ops->record_nr,
  280. APPLDATA_START_INTERVAL_REC,
  281. (unsigned long) ops->data, ops->size,
  282. ops->mod_lvl);
  283. if (rc != 0) {
  284. pr_err("Starting the data collection for %s "
  285. "failed with rc=%d\n", ops->name, rc);
  286. module_put(ops->owner);
  287. } else
  288. ops->active = 1;
  289. } else if (!active && (ops->active == 1)) {
  290. ops->active = 0;
  291. rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
  292. (unsigned long) ops->data, ops->size,
  293. ops->mod_lvl);
  294. if (rc != 0)
  295. pr_err("Stopping the data collection for %s "
  296. "failed with rc=%d\n", ops->name, rc);
  297. module_put(ops->owner);
  298. }
  299. mutex_unlock(&appldata_ops_mutex);
  300. module_put(ops->owner);
  301. return 0;
  302. }
  303. /*************************** /proc stuff <END> *******************************/
  304. /************************* module-ops management *****************************/
  305. /*
  306. * appldata_register_ops()
  307. *
  308. * update ops list, register /proc/sys entries
  309. */
  310. int appldata_register_ops(struct appldata_ops *ops)
  311. {
  312. if (ops->size > APPLDATA_MAX_REC_SIZE)
  313. return -EINVAL;
  314. ops->ctl_table = kzalloc_objs(struct ctl_table, 1);
  315. if (!ops->ctl_table)
  316. return -ENOMEM;
  317. mutex_lock(&appldata_ops_mutex);
  318. list_add(&ops->list, &appldata_ops_list);
  319. mutex_unlock(&appldata_ops_mutex);
  320. ops->ctl_table[0].procname = ops->name;
  321. ops->ctl_table[0].mode = S_IRUGO | S_IWUSR;
  322. ops->ctl_table[0].proc_handler = appldata_generic_handler;
  323. ops->ctl_table[0].data = ops;
  324. ops->sysctl_header = register_sysctl_sz(appldata_proc_name, ops->ctl_table, 1);
  325. if (!ops->sysctl_header)
  326. goto out;
  327. return 0;
  328. out:
  329. mutex_lock(&appldata_ops_mutex);
  330. list_del(&ops->list);
  331. mutex_unlock(&appldata_ops_mutex);
  332. kfree(ops->ctl_table);
  333. return -ENOMEM;
  334. }
  335. /*
  336. * appldata_unregister_ops()
  337. *
  338. * update ops list, unregister /proc entries, stop DIAG if necessary
  339. */
  340. void appldata_unregister_ops(struct appldata_ops *ops)
  341. {
  342. mutex_lock(&appldata_ops_mutex);
  343. list_del(&ops->list);
  344. mutex_unlock(&appldata_ops_mutex);
  345. unregister_sysctl_table(ops->sysctl_header);
  346. kfree(ops->ctl_table);
  347. }
  348. /********************** module-ops management <END> **************************/
  349. /******************************* init / exit *********************************/
  350. /*
  351. * appldata_init()
  352. *
  353. * init timer, register /proc entries
  354. */
  355. static int __init appldata_init(void)
  356. {
  357. init_virt_timer(&appldata_timer);
  358. appldata_timer.function = appldata_timer_function;
  359. appldata_timer.data = (unsigned long) &appldata_work;
  360. appldata_wq = alloc_ordered_workqueue("appldata", 0);
  361. if (!appldata_wq)
  362. return -ENOMEM;
  363. appldata_sysctl_header = register_sysctl(appldata_proc_name, appldata_table);
  364. return 0;
  365. }
  366. __initcall(appldata_init);
  367. /**************************** init / exit <END> ******************************/
  368. EXPORT_SYMBOL_GPL(appldata_register_ops);
  369. EXPORT_SYMBOL_GPL(appldata_unregister_ops);
  370. EXPORT_SYMBOL_GPL(appldata_diag);
  371. #ifdef CONFIG_SWAP
  372. EXPORT_SYMBOL_GPL(si_swapinfo);
  373. #endif
  374. EXPORT_SYMBOL_GPL(nr_threads);
  375. EXPORT_SYMBOL_GPL(nr_running);
  376. EXPORT_SYMBOL_GPL(nr_iowait);