]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Mark Fasheh <mfasheh@suse.com> |
2 | Subject: ocfs2: track local alloc state via debugfs | |
3 | Patch-mainline: 2.6.28 | |
4 | ||
5 | A per-mount debugfs file, "local_alloc" is created which when read will | |
6 | expose live state of the nodes local alloc file. Performance impact is | |
7 | minimal, only a bit of memory overhead per mount point. Still, the code is | |
8 | hidden behind CONFIG_OCFS2_FS_STATS. This feature will help us debug | |
9 | local alloc performance problems on a live system. | |
10 | ||
11 | Signed-off-by: Mark Fasheh <mfasheh@suse.com> | |
12 | --- | |
13 | fs/ocfs2/localalloc.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++ | |
14 | fs/ocfs2/ocfs2.h | 5 ++ | |
15 | 2 files changed, 92 insertions(+) | |
16 | ||
17 | --- a/fs/ocfs2/localalloc.c | |
18 | +++ b/fs/ocfs2/localalloc.c | |
19 | @@ -28,6 +28,7 @@ | |
20 | #include <linux/slab.h> | |
21 | #include <linux/highmem.h> | |
22 | #include <linux/bitops.h> | |
23 | +#include <linux/debugfs.h> | |
24 | ||
25 | #define MLOG_MASK_PREFIX ML_DISK_ALLOC | |
26 | #include <cluster/masklog.h> | |
27 | @@ -73,6 +74,85 @@ static int ocfs2_local_alloc_new_window( | |
28 | static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb, | |
29 | struct inode *local_alloc_inode); | |
30 | ||
31 | +#ifdef CONFIG_OCFS2_FS_STATS | |
32 | + | |
33 | +DEFINE_MUTEX(la_debug_mutex); | |
34 | + | |
35 | +static int ocfs2_la_debug_open(struct inode *inode, struct file *file) | |
36 | +{ | |
37 | + file->private_data = inode->i_private; | |
38 | + return 0; | |
39 | +} | |
40 | + | |
41 | +#define LA_DEBUG_BUF_SZ PAGE_CACHE_SIZE | |
42 | +#define LA_DEBUG_VER 1 | |
43 | +static ssize_t ocfs2_la_debug_read(struct file *file, char __user *userbuf, | |
44 | + size_t count, loff_t *ppos) | |
45 | +{ | |
46 | + struct ocfs2_super *osb = file->private_data; | |
47 | + int written, ret; | |
48 | + char *buf = osb->local_alloc_debug_buf; | |
49 | + | |
50 | + mutex_lock(&la_debug_mutex); | |
51 | + memset(buf, 0, LA_DEBUG_BUF_SZ); | |
52 | + | |
53 | + written = snprintf(buf, LA_DEBUG_BUF_SZ, | |
54 | + "0x%x\t0x%llx\t%u\t%u\t0x%x\n", | |
55 | + LA_DEBUG_VER, | |
56 | + (unsigned long long)osb->la_last_gd, | |
57 | + osb->local_alloc_default_bits, | |
58 | + osb->local_alloc_bits, osb->local_alloc_state); | |
59 | + | |
60 | + ret = simple_read_from_buffer(userbuf, count, ppos, buf, written); | |
61 | + | |
62 | + mutex_unlock(&la_debug_mutex); | |
63 | + return ret; | |
64 | +} | |
65 | + | |
66 | +static const struct file_operations ocfs2_la_debug_fops = { | |
67 | + .open = ocfs2_la_debug_open, | |
68 | + .read = ocfs2_la_debug_read, | |
69 | +}; | |
70 | + | |
71 | +static void ocfs2_init_la_debug(struct ocfs2_super *osb) | |
72 | +{ | |
73 | + osb->local_alloc_debug_buf = kmalloc(LA_DEBUG_BUF_SZ, GFP_NOFS); | |
74 | + if (!osb->local_alloc_debug_buf) | |
75 | + return; | |
76 | + | |
77 | + osb->local_alloc_debug = debugfs_create_file("local_alloc_stats", | |
78 | + S_IFREG|S_IRUSR, | |
79 | + osb->osb_debug_root, | |
80 | + osb, | |
81 | + &ocfs2_la_debug_fops); | |
82 | + if (!osb->local_alloc_debug) { | |
83 | + kfree(osb->local_alloc_debug_buf); | |
84 | + osb->local_alloc_debug_buf = NULL; | |
85 | + } | |
86 | +} | |
87 | + | |
88 | +static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb) | |
89 | +{ | |
90 | + if (osb->local_alloc_debug) | |
91 | + debugfs_remove(osb->local_alloc_debug); | |
92 | + | |
93 | + if (osb->local_alloc_debug_buf) | |
94 | + kfree(osb->local_alloc_debug_buf); | |
95 | + | |
96 | + osb->local_alloc_debug_buf = NULL; | |
97 | + osb->local_alloc_debug = NULL; | |
98 | +} | |
99 | +#else /* CONFIG_OCFS2_FS_STATS */ | |
100 | +static void ocfs2_init_la_debug(struct ocfs2_super *osb) | |
101 | +{ | |
102 | + return; | |
103 | +} | |
104 | +static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb) | |
105 | +{ | |
106 | + return; | |
107 | +} | |
108 | +#endif | |
109 | + | |
110 | static inline int ocfs2_la_state_enabled(struct ocfs2_super *osb) | |
111 | { | |
112 | return (osb->local_alloc_state == OCFS2_LA_THROTTLED || | |
113 | @@ -146,6 +226,8 @@ int ocfs2_load_local_alloc(struct ocfs2_ | |
114 | ||
115 | mlog_entry_void(); | |
116 | ||
117 | + ocfs2_init_la_debug(osb); | |
118 | + | |
119 | if (osb->local_alloc_bits == 0) | |
120 | goto bail; | |
121 | ||
122 | @@ -218,6 +300,9 @@ bail: | |
123 | if (inode) | |
124 | iput(inode); | |
125 | ||
126 | + if (status < 0) | |
127 | + ocfs2_shutdown_la_debug(osb); | |
128 | + | |
129 | mlog(0, "Local alloc window bits = %d\n", osb->local_alloc_bits); | |
130 | ||
131 | mlog_exit(status); | |
132 | @@ -247,6 +332,8 @@ void ocfs2_shutdown_local_alloc(struct o | |
133 | cancel_delayed_work(&osb->la_enable_wq); | |
134 | flush_workqueue(ocfs2_wq); | |
135 | ||
136 | + ocfs2_shutdown_la_debug(osb); | |
137 | + | |
138 | if (osb->local_alloc_state == OCFS2_LA_UNUSED) | |
139 | goto out; | |
140 | ||
141 | --- a/fs/ocfs2/ocfs2.h | |
142 | +++ b/fs/ocfs2/ocfs2.h | |
143 | @@ -281,6 +281,11 @@ struct ocfs2_super | |
144 | ||
145 | u64 la_last_gd; | |
146 | ||
147 | +#ifdef CONFIG_OCFS2_FS_STATS | |
148 | + struct dentry *local_alloc_debug; | |
149 | + char *local_alloc_debug_buf; | |
150 | +#endif | |
151 | + | |
152 | /* Next two fields are for local node slot recovery during | |
153 | * mount. */ | |
154 | int dirty; |