f2fs: add spin_lock to cover radix operations in IO tracer
[firefly-linux-kernel-4.4.55.git] / fs / f2fs / trace.c
1 /*
2  * f2fs IO tracer
3  *
4  * Copyright (c) 2014 Motorola Mobility
5  * Copyright (c) 2014 Jaegeuk Kim <jaegeuk@kernel.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 #include <linux/fs.h>
12 #include <linux/f2fs_fs.h>
13 #include <linux/sched.h>
14
15 #include "f2fs.h"
16 #include "trace.h"
17
18 RADIX_TREE(pids, GFP_ATOMIC);
19 spinlock_t pids_lock;
20 struct last_io_info last_io;
21
22 static inline void __print_last_io(void)
23 {
24         if (!last_io.len)
25                 return;
26
27         trace_printk("%3x:%3x %4x %-16s %2x %5x %12x %4x\n",
28                         last_io.major, last_io.minor,
29                         last_io.pid, "----------------",
30                         last_io.type,
31                         last_io.fio.rw, last_io.fio.blk_addr,
32                         last_io.len);
33         memset(&last_io, 0, sizeof(last_io));
34 }
35
36 static int __file_type(struct inode *inode, pid_t pid)
37 {
38         if (f2fs_is_atomic_file(inode))
39                 return __ATOMIC_FILE;
40         else if (f2fs_is_volatile_file(inode))
41                 return __VOLATILE_FILE;
42         else if (S_ISDIR(inode->i_mode))
43                 return __DIR_FILE;
44         else if (inode->i_ino == F2FS_NODE_INO(F2FS_I_SB(inode)))
45                 return __NODE_FILE;
46         else if (inode->i_ino == F2FS_META_INO(F2FS_I_SB(inode)))
47                 return __META_FILE;
48         else if (pid)
49                 return __NORMAL_FILE;
50         else
51                 return __MISC_FILE;
52 }
53
54 void f2fs_trace_pid(struct page *page)
55 {
56         struct inode *inode = page->mapping->host;
57         pid_t pid = task_pid_nr(current);
58         void *p;
59
60         page->private = pid;
61
62         if (radix_tree_preload(GFP_NOFS))
63                 return;
64
65         spin_lock(&pids_lock);
66         p = radix_tree_lookup(&pids, pid);
67         if (p == current)
68                 goto out;
69         if (p)
70                 radix_tree_delete(&pids, pid);
71
72         f2fs_radix_tree_insert(&pids, pid, current);
73
74         trace_printk("%3x:%3x %4x %-16s\n",
75                         MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev),
76                         pid, current->comm);
77 out:
78         spin_unlock(&pids_lock);
79         radix_tree_preload_end();
80 }
81
82 void f2fs_trace_ios(struct page *page, struct f2fs_io_info *fio, int flush)
83 {
84         struct inode *inode;
85         pid_t pid;
86         int major, minor;
87
88         if (flush) {
89                 __print_last_io();
90                 return;
91         }
92
93         inode = page->mapping->host;
94         pid = page_private(page);
95
96         major = MAJOR(inode->i_sb->s_dev);
97         minor = MINOR(inode->i_sb->s_dev);
98
99         if (last_io.major == major && last_io.minor == minor &&
100                         last_io.pid == pid &&
101                         last_io.type == __file_type(inode, pid) &&
102                         last_io.fio.rw == fio->rw &&
103                         last_io.fio.blk_addr + last_io.len == fio->blk_addr) {
104                 last_io.len++;
105                 return;
106         }
107
108         __print_last_io();
109
110         last_io.major = major;
111         last_io.minor = minor;
112         last_io.pid = pid;
113         last_io.type = __file_type(inode, pid);
114         last_io.fio = *fio;
115         last_io.len = 1;
116         return;
117 }
118
119 void f2fs_build_trace_ios(void)
120 {
121         spin_lock_init(&pids_lock);
122 }