diff options
author | Mark Fasheh <mfasheh@suse.com> | 2008-07-29 21:29:18 -0400 |
---|---|---|
committer | Mark Fasheh <mfasheh@suse.com> | 2008-10-13 16:57:58 -0400 |
commit | 9a8ff578fb430a8816dfbc73c77e5e09c6d9c343 (patch) | |
tree | be97f570b59a4af8fbf0c4c054619193155aaaa6 /fs/ocfs2/localalloc.c | |
parent | 9c7af40b210e87f8fddd97b0badc0a352862234a (diff) |
ocfs2: track local alloc state via debugfs
A per-mount debugfs file, "local_alloc" is created which when read will
expose live state of the nodes local alloc file. Performance impact is
minimal, only a bit of memory overhead per mount point. Still, the code is
hidden behind CONFIG_OCFS2_FS_STATS. This feature will help us debug
local alloc performance problems on a live system.
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/ocfs2/localalloc.c')
-rw-r--r-- | fs/ocfs2/localalloc.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c index f71658adddb5..b889f10d8090 100644 --- a/fs/ocfs2/localalloc.c +++ b/fs/ocfs2/localalloc.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/highmem.h> | 29 | #include <linux/highmem.h> |
30 | #include <linux/bitops.h> | 30 | #include <linux/bitops.h> |
31 | #include <linux/debugfs.h> | ||
31 | 32 | ||
32 | #define MLOG_MASK_PREFIX ML_DISK_ALLOC | 33 | #define MLOG_MASK_PREFIX ML_DISK_ALLOC |
33 | #include <cluster/masklog.h> | 34 | #include <cluster/masklog.h> |
@@ -73,6 +74,85 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb, | |||
73 | static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb, | 74 | static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb, |
74 | struct inode *local_alloc_inode); | 75 | struct inode *local_alloc_inode); |
75 | 76 | ||
77 | #ifdef CONFIG_OCFS2_FS_STATS | ||
78 | |||
79 | DEFINE_MUTEX(la_debug_mutex); | ||
80 | |||
81 | static int ocfs2_la_debug_open(struct inode *inode, struct file *file) | ||
82 | { | ||
83 | file->private_data = inode->i_private; | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | #define LA_DEBUG_BUF_SZ PAGE_CACHE_SIZE | ||
88 | #define LA_DEBUG_VER 1 | ||
89 | static ssize_t ocfs2_la_debug_read(struct file *file, char __user *userbuf, | ||
90 | size_t count, loff_t *ppos) | ||
91 | { | ||
92 | struct ocfs2_super *osb = file->private_data; | ||
93 | int written, ret; | ||
94 | char *buf = osb->local_alloc_debug_buf; | ||
95 | |||
96 | mutex_lock(&la_debug_mutex); | ||
97 | memset(buf, 0, LA_DEBUG_BUF_SZ); | ||
98 | |||
99 | written = snprintf(buf, LA_DEBUG_BUF_SZ, | ||
100 | "0x%x\t0x%llx\t%u\t%u\t0x%x\n", | ||
101 | LA_DEBUG_VER, | ||
102 | (unsigned long long)osb->la_last_gd, | ||
103 | osb->local_alloc_default_bits, | ||
104 | osb->local_alloc_bits, osb->local_alloc_state); | ||
105 | |||
106 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, written); | ||
107 | |||
108 | mutex_unlock(&la_debug_mutex); | ||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | static const struct file_operations ocfs2_la_debug_fops = { | ||
113 | .open = ocfs2_la_debug_open, | ||
114 | .read = ocfs2_la_debug_read, | ||
115 | }; | ||
116 | |||
117 | static void ocfs2_init_la_debug(struct ocfs2_super *osb) | ||
118 | { | ||
119 | osb->local_alloc_debug_buf = kmalloc(LA_DEBUG_BUF_SZ, GFP_NOFS); | ||
120 | if (!osb->local_alloc_debug_buf) | ||
121 | return; | ||
122 | |||
123 | osb->local_alloc_debug = debugfs_create_file("local_alloc_stats", | ||
124 | S_IFREG|S_IRUSR, | ||
125 | osb->osb_debug_root, | ||
126 | osb, | ||
127 | &ocfs2_la_debug_fops); | ||
128 | if (!osb->local_alloc_debug) { | ||
129 | kfree(osb->local_alloc_debug_buf); | ||
130 | osb->local_alloc_debug_buf = NULL; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb) | ||
135 | { | ||
136 | if (osb->local_alloc_debug) | ||
137 | debugfs_remove(osb->local_alloc_debug); | ||
138 | |||
139 | if (osb->local_alloc_debug_buf) | ||
140 | kfree(osb->local_alloc_debug_buf); | ||
141 | |||
142 | osb->local_alloc_debug_buf = NULL; | ||
143 | osb->local_alloc_debug = NULL; | ||
144 | } | ||
145 | #else /* CONFIG_OCFS2_FS_STATS */ | ||
146 | static void ocfs2_init_la_debug(struct ocfs2_super *osb) | ||
147 | { | ||
148 | return; | ||
149 | } | ||
150 | static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb) | ||
151 | { | ||
152 | return; | ||
153 | } | ||
154 | #endif | ||
155 | |||
76 | static inline int ocfs2_la_state_enabled(struct ocfs2_super *osb) | 156 | static inline int ocfs2_la_state_enabled(struct ocfs2_super *osb) |
77 | { | 157 | { |
78 | return (osb->local_alloc_state == OCFS2_LA_THROTTLED || | 158 | return (osb->local_alloc_state == OCFS2_LA_THROTTLED || |
@@ -146,6 +226,8 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb) | |||
146 | 226 | ||
147 | mlog_entry_void(); | 227 | mlog_entry_void(); |
148 | 228 | ||
229 | ocfs2_init_la_debug(osb); | ||
230 | |||
149 | if (osb->local_alloc_bits == 0) | 231 | if (osb->local_alloc_bits == 0) |
150 | goto bail; | 232 | goto bail; |
151 | 233 | ||
@@ -218,6 +300,9 @@ bail: | |||
218 | if (inode) | 300 | if (inode) |
219 | iput(inode); | 301 | iput(inode); |
220 | 302 | ||
303 | if (status < 0) | ||
304 | ocfs2_shutdown_la_debug(osb); | ||
305 | |||
221 | mlog(0, "Local alloc window bits = %d\n", osb->local_alloc_bits); | 306 | mlog(0, "Local alloc window bits = %d\n", osb->local_alloc_bits); |
222 | 307 | ||
223 | mlog_exit(status); | 308 | mlog_exit(status); |
@@ -247,6 +332,8 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb) | |||
247 | cancel_delayed_work(&osb->la_enable_wq); | 332 | cancel_delayed_work(&osb->la_enable_wq); |
248 | flush_workqueue(ocfs2_wq); | 333 | flush_workqueue(ocfs2_wq); |
249 | 334 | ||
335 | ocfs2_shutdown_la_debug(osb); | ||
336 | |||
250 | if (osb->local_alloc_state == OCFS2_LA_UNUSED) | 337 | if (osb->local_alloc_state == OCFS2_LA_UNUSED) |
251 | goto out; | 338 | goto out; |
252 | 339 | ||