diff options
author | Sunil Mushran <sunil.mushran@oracle.com> | 2008-12-17 17:17:43 -0500 |
---|---|---|
committer | Mark Fasheh <mfasheh@suse.com> | 2009-04-03 14:39:15 -0400 |
commit | 50397507e856455b3f5cb3d5c7c482209f9e46a0 (patch) | |
tree | 537d1aa6aec9108aa080a2b58f68fac767420416 /fs | |
parent | 96a6c64b5354b804b3ccfd1b31306565a01ebcb1 (diff) |
ocfs2: Expose the file system state via debugfs
This patch creates a per mount debugfs file, fs_state, which exposes
information like, cluster stack in use, states of the downconvert, recovery
and commit threads, number of journal txns, some allocation stats, list of
all slots, etc.
Signed-off-by: Sunil Mushran <sunil.mushran@oracle.com>
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/ocfs2.h | 1 | ||||
-rw-r--r-- | fs/ocfs2/super.c | 176 |
2 files changed, 177 insertions, 0 deletions
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 946d3c34b90b..18d8542a615e 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h | |||
@@ -308,6 +308,7 @@ struct ocfs2_super | |||
308 | struct ocfs2_dlm_debug *osb_dlm_debug; | 308 | struct ocfs2_dlm_debug *osb_dlm_debug; |
309 | 309 | ||
310 | struct dentry *osb_debug_root; | 310 | struct dentry *osb_debug_root; |
311 | struct dentry *osb_ctxt; | ||
311 | 312 | ||
312 | wait_queue_head_t recovery_event; | 313 | wait_queue_head_t recovery_event; |
313 | 314 | ||
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 7ac83a81ee55..4eaf0e602bd0 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
@@ -201,6 +201,170 @@ static const match_table_t tokens = { | |||
201 | {Opt_err, NULL} | 201 | {Opt_err, NULL} |
202 | }; | 202 | }; |
203 | 203 | ||
204 | #ifdef CONFIG_DEBUG_FS | ||
205 | static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) | ||
206 | { | ||
207 | int out = 0; | ||
208 | int i; | ||
209 | struct ocfs2_cluster_connection *cconn = osb->cconn; | ||
210 | struct ocfs2_recovery_map *rm = osb->recovery_map; | ||
211 | |||
212 | out += snprintf(buf + out, len - out, | ||
213 | "%10s => Id: %-s Uuid: %-s Gen: 0x%X Label: %-s\n", | ||
214 | "Device", osb->dev_str, osb->uuid_str, | ||
215 | osb->fs_generation, osb->vol_label); | ||
216 | |||
217 | out += snprintf(buf + out, len - out, | ||
218 | "%10s => State: %d Flags: 0x%lX\n", "Volume", | ||
219 | atomic_read(&osb->vol_state), osb->osb_flags); | ||
220 | |||
221 | out += snprintf(buf + out, len - out, | ||
222 | "%10s => Block: %lu Cluster: %d\n", "Sizes", | ||
223 | osb->sb->s_blocksize, osb->s_clustersize); | ||
224 | |||
225 | out += snprintf(buf + out, len - out, | ||
226 | "%10s => Compat: 0x%X Incompat: 0x%X " | ||
227 | "ROcompat: 0x%X\n", | ||
228 | "Features", osb->s_feature_compat, | ||
229 | osb->s_feature_incompat, osb->s_feature_ro_compat); | ||
230 | |||
231 | out += snprintf(buf + out, len - out, | ||
232 | "%10s => Opts: 0x%lX AtimeQuanta: %u\n", "Mount", | ||
233 | osb->s_mount_opt, osb->s_atime_quantum); | ||
234 | |||
235 | out += snprintf(buf + out, len - out, | ||
236 | "%10s => Stack: %s Name: %*s Version: %d.%d\n", | ||
237 | "Cluster", | ||
238 | (*osb->osb_cluster_stack == '\0' ? | ||
239 | "o2cb" : osb->osb_cluster_stack), | ||
240 | cconn->cc_namelen, cconn->cc_name, | ||
241 | cconn->cc_version.pv_major, cconn->cc_version.pv_minor); | ||
242 | |||
243 | spin_lock(&osb->dc_task_lock); | ||
244 | out += snprintf(buf + out, len - out, | ||
245 | "%10s => Pid: %d Count: %lu WakeSeq: %lu " | ||
246 | "WorkSeq: %lu\n", "DownCnvt", | ||
247 | task_pid_nr(osb->dc_task), osb->blocked_lock_count, | ||
248 | osb->dc_wake_sequence, osb->dc_work_sequence); | ||
249 | spin_unlock(&osb->dc_task_lock); | ||
250 | |||
251 | spin_lock(&osb->osb_lock); | ||
252 | out += snprintf(buf + out, len - out, "%10s => Pid: %d Nodes:", | ||
253 | "Recovery", | ||
254 | (osb->recovery_thread_task ? | ||
255 | task_pid_nr(osb->recovery_thread_task) : -1)); | ||
256 | if (rm->rm_used == 0) | ||
257 | out += snprintf(buf + out, len - out, " None\n"); | ||
258 | else { | ||
259 | for (i = 0; i < rm->rm_used; i++) | ||
260 | out += snprintf(buf + out, len - out, " %d", | ||
261 | rm->rm_entries[i]); | ||
262 | out += snprintf(buf + out, len - out, "\n"); | ||
263 | } | ||
264 | spin_unlock(&osb->osb_lock); | ||
265 | |||
266 | out += snprintf(buf + out, len - out, | ||
267 | "%10s => Pid: %d Interval: %lu Needs: %d\n", "Commit", | ||
268 | task_pid_nr(osb->commit_task), osb->osb_commit_interval, | ||
269 | atomic_read(&osb->needs_checkpoint)); | ||
270 | |||
271 | out += snprintf(buf + out, len - out, | ||
272 | "%10s => State: %d NumTxns: %d TxnId: %lu\n", | ||
273 | "Journal", osb->journal->j_state, | ||
274 | atomic_read(&osb->journal->j_num_trans), | ||
275 | osb->journal->j_trans_id); | ||
276 | |||
277 | out += snprintf(buf + out, len - out, | ||
278 | "%10s => GlobalAllocs: %d LocalAllocs: %d " | ||
279 | "SubAllocs: %d LAWinMoves: %d SAExtends: %d\n", | ||
280 | "Stats", | ||
281 | atomic_read(&osb->alloc_stats.bitmap_data), | ||
282 | atomic_read(&osb->alloc_stats.local_data), | ||
283 | atomic_read(&osb->alloc_stats.bg_allocs), | ||
284 | atomic_read(&osb->alloc_stats.moves), | ||
285 | atomic_read(&osb->alloc_stats.bg_extends)); | ||
286 | |||
287 | out += snprintf(buf + out, len - out, | ||
288 | "%10s => State: %u Descriptor: %llu Size: %u bits " | ||
289 | "Default: %u bits\n", | ||
290 | "LocalAlloc", osb->local_alloc_state, | ||
291 | (unsigned long long)osb->la_last_gd, | ||
292 | osb->local_alloc_bits, osb->local_alloc_default_bits); | ||
293 | |||
294 | spin_lock(&osb->osb_lock); | ||
295 | out += snprintf(buf + out, len - out, | ||
296 | "%10s => Slot: %d NumStolen: %d\n", "Steal", | ||
297 | osb->s_inode_steal_slot, | ||
298 | atomic_read(&osb->s_num_inodes_stolen)); | ||
299 | spin_unlock(&osb->osb_lock); | ||
300 | |||
301 | out += snprintf(buf + out, len - out, "%10s => %3s %10s\n", | ||
302 | "Slots", "Num", "RecoGen"); | ||
303 | |||
304 | for (i = 0; i < osb->max_slots; ++i) { | ||
305 | out += snprintf(buf + out, len - out, | ||
306 | "%10s %c %3d %10d\n", | ||
307 | " ", | ||
308 | (i == osb->slot_num ? '*' : ' '), | ||
309 | i, osb->slot_recovery_generations[i]); | ||
310 | } | ||
311 | |||
312 | return out; | ||
313 | } | ||
314 | |||
315 | static int ocfs2_osb_debug_open(struct inode *inode, struct file *file) | ||
316 | { | ||
317 | struct ocfs2_super *osb = inode->i_private; | ||
318 | char *buf = NULL; | ||
319 | |||
320 | buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
321 | if (!buf) | ||
322 | goto bail; | ||
323 | |||
324 | i_size_write(inode, ocfs2_osb_dump(osb, buf, PAGE_SIZE)); | ||
325 | |||
326 | file->private_data = buf; | ||
327 | |||
328 | return 0; | ||
329 | bail: | ||
330 | return -ENOMEM; | ||
331 | } | ||
332 | |||
333 | static int ocfs2_debug_release(struct inode *inode, struct file *file) | ||
334 | { | ||
335 | kfree(file->private_data); | ||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | static ssize_t ocfs2_debug_read(struct file *file, char __user *buf, | ||
340 | size_t nbytes, loff_t *ppos) | ||
341 | { | ||
342 | return simple_read_from_buffer(buf, nbytes, ppos, file->private_data, | ||
343 | i_size_read(file->f_mapping->host)); | ||
344 | } | ||
345 | #else | ||
346 | static int ocfs2_osb_debug_open(struct inode *inode, struct file *file) | ||
347 | { | ||
348 | return 0; | ||
349 | } | ||
350 | static int ocfs2_debug_release(struct inode *inode, struct file *file) | ||
351 | { | ||
352 | return 0; | ||
353 | } | ||
354 | static ssize_t ocfs2_debug_read(struct file *file, char __user *buf, | ||
355 | size_t nbytes, loff_t *ppos) | ||
356 | { | ||
357 | return 0; | ||
358 | } | ||
359 | #endif /* CONFIG_DEBUG_FS */ | ||
360 | |||
361 | static struct file_operations ocfs2_osb_debug_fops = { | ||
362 | .open = ocfs2_osb_debug_open, | ||
363 | .release = ocfs2_debug_release, | ||
364 | .read = ocfs2_debug_read, | ||
365 | .llseek = generic_file_llseek, | ||
366 | }; | ||
367 | |||
204 | /* | 368 | /* |
205 | * write_super and sync_fs ripped right out of ext3. | 369 | * write_super and sync_fs ripped right out of ext3. |
206 | */ | 370 | */ |
@@ -926,6 +1090,16 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) | |||
926 | goto read_super_error; | 1090 | goto read_super_error; |
927 | } | 1091 | } |
928 | 1092 | ||
1093 | osb->osb_ctxt = debugfs_create_file("fs_state", S_IFREG|S_IRUSR, | ||
1094 | osb->osb_debug_root, | ||
1095 | osb, | ||
1096 | &ocfs2_osb_debug_fops); | ||
1097 | if (!osb->osb_ctxt) { | ||
1098 | status = -EINVAL; | ||
1099 | mlog_errno(status); | ||
1100 | goto read_super_error; | ||
1101 | } | ||
1102 | |||
929 | status = ocfs2_mount_volume(sb); | 1103 | status = ocfs2_mount_volume(sb); |
930 | if (osb->root_inode) | 1104 | if (osb->root_inode) |
931 | inode = igrab(osb->root_inode); | 1105 | inode = igrab(osb->root_inode); |
@@ -1620,6 +1794,8 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) | |||
1620 | osb = OCFS2_SB(sb); | 1794 | osb = OCFS2_SB(sb); |
1621 | BUG_ON(!osb); | 1795 | BUG_ON(!osb); |
1622 | 1796 | ||
1797 | debugfs_remove(osb->osb_ctxt); | ||
1798 | |||
1623 | ocfs2_disable_quotas(osb); | 1799 | ocfs2_disable_quotas(osb); |
1624 | 1800 | ||
1625 | ocfs2_shutdown_local_alloc(osb); | 1801 | ocfs2_shutdown_local_alloc(osb); |