mt_fuse.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. /*
  2. FUSE: file io log
  3. Copyright (C) 2015 Perry Hsu <perry.hsu@mediatek.com>
  4. This program can be distributed under the terms of the GNU GPL.
  5. See the file COPYING.
  6. */
  7. #define DEBUG 1
  8. #include "fuse_i.h"
  9. #include "mt_fuse.h"
  10. #include <linux/debugfs.h>
  11. #include <linux/slab.h>
  12. #include <linux/time.h>
  13. /* kerel log buffer and ring buffer for debugfs */
  14. struct fuse_proc_info *fuse_iolog = NULL;
  15. struct fuse_proc_log *fuse_ringbuf = NULL;
  16. int fuse_ringbuf_index = 0;
  17. /* kernel print buffer */
  18. static char *fuse_iolog_buf;
  19. /* mutex used to protect the buffers */
  20. struct mutex fuse_iolog_lock;
  21. /* kernel log thread */
  22. struct task_struct *fuse_iolog_thread = NULL;
  23. /* debugfs dentries */
  24. struct dentry *fuseio_droot = NULL;
  25. struct dentry *fuseio_dklog = NULL;
  26. struct dentry *fuseio_dlog = NULL;
  27. /* kernel log enable */
  28. unsigned int fuseio_klog_enable = 0;
  29. void fuse_time_diff(struct timespec *start, struct timespec *end, struct timespec *diff)
  30. {
  31. if ((end->tv_nsec-start->tv_nsec) < 0) {
  32. diff->tv_sec = end->tv_sec-start->tv_sec-1;
  33. diff->tv_nsec = 1000000000+end->tv_nsec-start->tv_nsec;
  34. } else {
  35. diff->tv_sec = end->tv_sec-start->tv_sec;
  36. diff->tv_nsec = end->tv_nsec-start->tv_nsec;
  37. }
  38. }
  39. /* type code translation table */
  40. struct fuse_ioiog_type_map {
  41. int type;
  42. const char *str;
  43. };
  44. #define FUSE_IOLOG_TYPE_MAX 46
  45. static const char *fuse_iolog_type[FUSE_IOLOG_TYPE_MAX] = {
  46. "unknown", /*0*/
  47. "lookup", /*1*/
  48. "forget", /*2*/
  49. "getattr", /*3*/
  50. "setattr", /*4*/
  51. "readlink", /*5*/
  52. "symlink", /*6*/
  53. "", /*7*/
  54. "mknod", /*8*/
  55. "mkdir", /*9*/
  56. "unlink", /*10*/
  57. "rmdir", /*11*/
  58. "rename", /*12*/
  59. "link", /*13*/
  60. "open", /*14*/
  61. "read", /*15*/
  62. "write", /*16*/
  63. "statfs", /*17*/
  64. "release", /*18*/
  65. "", /*19*/
  66. "fsync", /*20*/
  67. "setxattr", /*21*/
  68. "getxattr", /*22*/
  69. "listxattr", /*23*/
  70. "removexattr", /*24*/
  71. "flush", /*25*/
  72. "init", /*26*/
  73. "opendir", /*27*/
  74. "readdir", /*28*/
  75. "releasedir", /*29*/
  76. "fsyncdir", /*30*/
  77. "getlk", /*31*/
  78. "setlk", /*32*/
  79. "setlkw", /*33*/
  80. "access", /*34*/
  81. "create", /*35*/
  82. "interrupt", /*36*/
  83. "bmap", /*37*/
  84. "destroy", /*38*/
  85. "ioctl", /*39*/
  86. "poll", /*40*/
  87. "notify_reply", /*41*/
  88. "batch_forget", /*42*/
  89. "fallocate", /*43*/
  90. "readdirplus", /*44*/
  91. "cuse"
  92. };
  93. /* convert type code to string */
  94. static const char *fuse_iolog_type2str(int type)
  95. {
  96. if (type >= 0 && type < FUSE_IOLOG_TYPE_MAX)
  97. goto out;
  98. else if (type == CUSE_INIT)
  99. type = FUSE_IOLOG_TYPE_MAX-1;
  100. else
  101. type = 0;
  102. out:
  103. return fuse_iolog_type[type];
  104. }
  105. int fuse_iolog_print(void)
  106. {
  107. int i, len, n;
  108. char *ptr;
  109. len = FUSE_IOLOG_BUFLEN-1;
  110. ptr = &fuse_iolog_buf[0];
  111. for (i = 0; i < FUSE_IOLOG_MAX && fuse_iolog[i].valid; i++) {
  112. if (fuse_iolog[i].read.count || fuse_iolog[i].write.count) {
  113. n = snprintf(ptr, len, "{%d:R(%d,%d,%d),W(%d,%d,%d)}",
  114. fuse_iolog[i].pid,
  115. fuse_iolog[i].read.bytes,
  116. fuse_iolog[i].read.count,
  117. fuse_iolog[i].read.us,
  118. fuse_iolog[i].write.bytes,
  119. fuse_iolog[i].write.count,
  120. fuse_iolog[i].write.us);
  121. len -= n;
  122. ptr += n;
  123. if (len < 0)
  124. goto overflow;
  125. }
  126. if (fuse_iolog[i].misc_type) {
  127. n = snprintf(ptr, len, "{%d:%s(%d,%d,%d)}",
  128. fuse_iolog[i].pid,
  129. fuse_iolog_type2str(fuse_iolog[i].misc_type),
  130. fuse_iolog[i].misc.bytes,
  131. fuse_iolog[i].misc.count,
  132. fuse_iolog[i].misc.us);
  133. len -= n;
  134. ptr += n;
  135. if (len < 0)
  136. goto overflow;
  137. }
  138. }
  139. if (i > 0) {
  140. if (fuseio_klog_enable)
  141. pr_debug("[BLOCK_TAG] FUSEIO %s\n", &fuse_iolog_buf[0]);
  142. memcpy(fuse_ringbuf[fuse_ringbuf_index].info, fuse_iolog, FUSE_IOLOG_MAX*sizeof(struct fuse_proc_info));
  143. fuse_ringbuf[fuse_ringbuf_index].time = sched_clock();
  144. fuse_ringbuf_index++;
  145. if (fuse_ringbuf_index >= FUSE_IOLOG_RINGBUF_MAX)
  146. fuse_ringbuf_index = 0;
  147. }
  148. return ptr - &fuse_iolog_buf[0];
  149. overflow:
  150. pr_debug("[BLOCK_TAG] FUSEIO log buffer overflow\n");
  151. return -1;
  152. }
  153. static void fuse_iolog_seq_entry_time(struct seq_file *seq, uint64_t time)
  154. {
  155. uint32_t nsec;
  156. if (time > 0) {
  157. nsec = do_div(time, 1000000000);
  158. seq_printf(seq, "[%5lu.%06lu] FUSEIO ", (unsigned long)time, (unsigned long)nsec/1000);
  159. }
  160. }
  161. static int fuse_iolog_seq_entry(struct seq_file *seq, int index)
  162. {
  163. int i;
  164. if (index < 0 || index >= FUSE_IOLOG_RINGBUF_MAX)
  165. pr_warn("fuseio: fuse_iolog_seq_entry, index %d out of range (0-%d).\n",
  166. index, FUSE_IOLOG_RINGBUF_MAX-1);
  167. fuse_iolog_seq_entry_time(seq, fuse_ringbuf[index].time);
  168. for (i = 0; i < FUSE_IOLOG_MAX && fuse_ringbuf[index].info[i].valid; i++) {
  169. struct fuse_proc_info *info = &fuse_ringbuf[index].info[i];
  170. if (info->read.count || info->write.count) {
  171. seq_printf(seq, "{%d:R(%d,%d,%d),W(%d,%d,%d)}",
  172. info->pid,
  173. info->read.bytes,
  174. info->read.count,
  175. info->read.us,
  176. info->write.bytes,
  177. info->write.count,
  178. info->write.us);
  179. }
  180. if (info->misc_type) {
  181. seq_printf(seq, "{%d:%s(%d,%d,%d)}",
  182. info->pid,
  183. fuse_iolog_type2str(info->misc_type),
  184. info->misc.bytes,
  185. info->misc.count,
  186. info->misc.us);
  187. }
  188. }
  189. if (i > 0)
  190. seq_puts(seq, "\n");
  191. return i;
  192. }
  193. static void fuse_iolog_clear(void)
  194. {
  195. memset(&fuse_iolog[0], 0, sizeof(struct fuse_proc_info)*FUSE_IOLOG_MAX);
  196. }
  197. static void fuse_ringbuf_clear(void)
  198. {
  199. memset(&fuse_ringbuf[0], 0, sizeof(struct fuse_proc_log)*FUSE_IOLOG_RINGBUF_MAX);
  200. }
  201. inline __u32 fuse_iolog_timeus(struct timespec *t)
  202. {
  203. __u32 _t;
  204. long us;
  205. us = t->tv_nsec;
  206. do_div(us, 1000);
  207. if (t->tv_sec > 3600)
  208. return 0xD693A400; /* 3600000000 */
  209. _t = t->tv_sec * 1000000 + us;
  210. if (_t)
  211. return _t;
  212. return 1;
  213. }
  214. __u32 fuse_iolog_timeus_diff(struct timespec *start, struct timespec *end)
  215. {
  216. struct timespec diff;
  217. fuse_time_diff(start, end, &diff);
  218. return fuse_iolog_timeus(&diff);
  219. }
  220. inline int fuse_iolog_proc_update(struct fuse_proc_info *info,
  221. __u32 io_bytes, int type, struct timespec *diff)
  222. {
  223. struct fuse_rw_info *rwi;
  224. __u32 _t;
  225. _t = fuse_iolog_timeus(diff);
  226. if (type == FUSE_READ)
  227. rwi = &info->read;
  228. else if (type == FUSE_WRITE)
  229. rwi = &info->write;
  230. else {
  231. if (info->misc_type == 0)
  232. info->misc_type = type;
  233. else if (info->misc_type != type) /* misc type mismatch => continue */
  234. return -1;
  235. rwi = &info->misc;
  236. }
  237. rwi->bytes += io_bytes;
  238. rwi->us += _t;
  239. rwi->count++;
  240. return 0;
  241. }
  242. static int fuse_iolog_watch(void *arg)
  243. {
  244. unsigned int timeout;
  245. int n;
  246. int empty = 0; /* how many seconds that log is empty */
  247. while (1) {
  248. if (kthread_should_stop())
  249. break;
  250. /* log is empty for last 1 seconds => sleep till next io coming */
  251. if (empty > 1) {
  252. set_current_state(TASK_INTERRUPTIBLE);
  253. schedule();
  254. } else { /* otherwise, check 1 seconds later */
  255. do {
  256. set_current_state(TASK_INTERRUPTIBLE);
  257. timeout = schedule_timeout(FUSE_IOLOG_LATENCY*HZ);
  258. } while (timeout);
  259. }
  260. mutex_lock(&fuse_iolog_lock);
  261. n = fuse_iolog_print();
  262. if (n > 0) {
  263. fuse_iolog_clear();
  264. empty = 0;
  265. } else {
  266. empty++;
  267. }
  268. mutex_unlock(&fuse_iolog_lock);
  269. }
  270. return 0;
  271. }
  272. static ssize_t fuseio_debug_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos)
  273. {
  274. return count;
  275. }
  276. /* seq file operations */
  277. static void *fuseio_seq_debug_start(struct seq_file *seq, loff_t *pos)
  278. {
  279. unsigned int idx;
  280. if (*pos < 0 || *pos >= 1)
  281. return NULL;
  282. idx = *pos + 1;
  283. return (void *) ((unsigned long) idx);
  284. }
  285. static void *fuseio_seq_debug_next(struct seq_file *seq, void *v, loff_t *pos)
  286. {
  287. unsigned int idx;
  288. ++*pos;
  289. if (*pos < 0 || *pos >= 1)
  290. return NULL;
  291. idx = *pos + 1;
  292. return (void *) ((unsigned long) idx);
  293. }
  294. static int fuseio_seq_debug_show(struct seq_file *seq, void *v)
  295. {
  296. int i, end;
  297. mutex_lock(&fuse_iolog_lock);
  298. end = (fuse_ringbuf_index > 0) ? fuse_ringbuf_index-1 : FUSE_IOLOG_RINGBUF_MAX-1;
  299. for (i = fuse_ringbuf_index; ;) {
  300. fuse_iolog_seq_entry(seq, i);
  301. if (i == end)
  302. break;
  303. i = (i == FUSE_IOLOG_RINGBUF_MAX-1) ? 0 : i+1;
  304. };
  305. mutex_unlock(&fuse_iolog_lock);
  306. return 0;
  307. }
  308. static void fuseio_seq_debug_stop(struct seq_file *seq, void *v)
  309. {
  310. }
  311. static const struct seq_operations fuseio_seq_debug_ops = {
  312. .start = fuseio_seq_debug_start,
  313. .next = fuseio_seq_debug_next,
  314. .stop = fuseio_seq_debug_stop,
  315. .show = fuseio_seq_debug_show,
  316. };
  317. static int fuseio_seq_debug_open(struct inode *inode, struct file *file)
  318. {
  319. int rc;
  320. rc = seq_open(file, &fuseio_seq_debug_ops);
  321. if (rc == 0) {
  322. struct seq_file *m = file->private_data;
  323. m->private = &fuse_ringbuf_index;
  324. }
  325. return rc;
  326. }
  327. static const struct file_operations fuseio_seq_debug_fops = {
  328. .owner = THIS_MODULE,
  329. .open = fuseio_seq_debug_open,
  330. .read = seq_read,
  331. .llseek = seq_lseek,
  332. .release = seq_release,
  333. .write = fuseio_debug_write,
  334. };
  335. void fuse_iolog_init(void)
  336. {
  337. int ret;
  338. fuse_iolog_buf = kmalloc(FUSE_IOLOG_BUFLEN, GFP_NOFS);
  339. fuse_iolog = kmalloc_array(FUSE_IOLOG_MAX, sizeof(struct fuse_proc_info), GFP_NOFS);
  340. fuse_ringbuf = kmalloc_array(FUSE_IOLOG_RINGBUF_MAX, sizeof(struct fuse_proc_log), GFP_NOFS);
  341. if (!fuse_iolog_buf || !fuse_iolog || !fuse_ringbuf)
  342. goto error_out;
  343. mutex_init(&fuse_iolog_lock);
  344. mutex_lock(&fuse_iolog_lock);
  345. fuse_iolog_clear();
  346. fuse_ringbuf_clear();
  347. mutex_unlock(&fuse_iolog_lock);
  348. fuse_iolog_thread = kthread_create(fuse_iolog_watch, NULL, "fuse_log");
  349. if (IS_ERR(fuse_iolog_thread)) {
  350. ret = PTR_ERR(fuse_iolog_thread);
  351. pr_warn("[BLOCK_TAG] fuse: fail to create fuse_log thread %d\n", ret);
  352. fuse_iolog_thread = NULL;
  353. goto error_out;
  354. }
  355. fuseio_droot = debugfs_create_dir("fuseio", NULL);
  356. if (IS_ERR(fuseio_droot)) {
  357. pr_warn("[BLOCK_TAG] fuse: fail to create debugfs root\n");
  358. goto out;
  359. }
  360. fuseio_dklog = debugfs_create_u32("klog_enable", 0660, fuseio_droot, &fuseio_klog_enable);
  361. if (IS_ERR(fuseio_dklog)) {
  362. pr_warn("[BLOCK_TAG] fuse: fail to create klog_enable at debugfs\n");
  363. goto out;
  364. }
  365. fuseio_dlog = debugfs_create_file("log", S_IFREG | S_IRUGO, fuseio_droot, (void *)0, &fuseio_seq_debug_fops);
  366. if (IS_ERR(fuseio_dlog)) {
  367. pr_warn("[BLOCK_TAG] fuse: fail to create log at debugfs\n");
  368. goto out;
  369. }
  370. out:
  371. return;
  372. error_out:
  373. kfree(fuse_iolog_buf);
  374. kfree(fuse_iolog);
  375. kfree(fuse_ringbuf);
  376. }
  377. void fuse_iolog_exit(void)
  378. {
  379. kthread_stop(fuse_iolog_thread);
  380. kfree(fuse_iolog_buf);
  381. kfree(fuse_iolog);
  382. kfree(fuse_ringbuf);
  383. }
  384. void fuse_iolog_add(__u32 io_bytes, int type,
  385. struct timespec *start,
  386. struct timespec *end)
  387. {
  388. struct fuse_proc_info *info;
  389. struct timespec diff;
  390. pid_t pid;
  391. int i;
  392. pid = task_pid_nr(current);
  393. fuse_time_diff(start, end, &diff);
  394. mutex_lock(&fuse_iolog_lock);
  395. for (i = 0; i < FUSE_IOLOG_MAX; i++) {
  396. info = &fuse_iolog[i];
  397. if (info->valid) {
  398. if (info->pid == pid) {
  399. if (fuse_iolog_proc_update(info, io_bytes, type, &diff))
  400. continue; /* ops mismatch */
  401. else
  402. goto out;
  403. } else {
  404. continue;
  405. }
  406. } else {
  407. info->valid = 1;
  408. info->pid = pid;
  409. fuse_iolog_proc_update(info, io_bytes, type, &diff);
  410. if (i == 0) { /* this is the first entry, wake up the handler */
  411. if (fuse_iolog_thread)
  412. wake_up_process(fuse_iolog_thread);
  413. }
  414. goto out;
  415. }
  416. }
  417. if (i == FUSE_IOLOG_MAX) {
  418. fuse_iolog_print();
  419. fuse_iolog_clear();
  420. info = &fuse_iolog[0];
  421. info->valid = 1;
  422. info->pid = pid;
  423. fuse_iolog_proc_update(info, io_bytes, type, &diff);
  424. }
  425. out:
  426. mutex_unlock(&fuse_iolog_lock);
  427. }