1 From: Mark Fasheh <mfasheh@suse.com>
2 Subject: ocfs2: track local alloc state via debugfs
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.
11 Signed-off-by: Mark Fasheh <mfasheh@suse.com>
13 fs/ocfs2/localalloc.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++
14 fs/ocfs2/ocfs2.h | 5 ++
15 2 files changed, 92 insertions(+)
17 --- a/fs/ocfs2/localalloc.c
18 +++ b/fs/ocfs2/localalloc.c
20 #include <linux/slab.h>
21 #include <linux/highmem.h>
22 #include <linux/bitops.h>
23 +#include <linux/debugfs.h>
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);
31 +#ifdef CONFIG_OCFS2_FS_STATS
33 +DEFINE_MUTEX(la_debug_mutex);
35 +static int ocfs2_la_debug_open(struct inode *inode, struct file *file)
37 + file->private_data = inode->i_private;
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)
46 + struct ocfs2_super *osb = file->private_data;
48 + char *buf = osb->local_alloc_debug_buf;
50 + mutex_lock(&la_debug_mutex);
51 + memset(buf, 0, LA_DEBUG_BUF_SZ);
53 + written = snprintf(buf, LA_DEBUG_BUF_SZ,
54 + "0x%x\t0x%llx\t%u\t%u\t0x%x\n",
56 + (unsigned long long)osb->la_last_gd,
57 + osb->local_alloc_default_bits,
58 + osb->local_alloc_bits, osb->local_alloc_state);
60 + ret = simple_read_from_buffer(userbuf, count, ppos, buf, written);
62 + mutex_unlock(&la_debug_mutex);
66 +static const struct file_operations ocfs2_la_debug_fops = {
67 + .open = ocfs2_la_debug_open,
68 + .read = ocfs2_la_debug_read,
71 +static void ocfs2_init_la_debug(struct ocfs2_super *osb)
73 + osb->local_alloc_debug_buf = kmalloc(LA_DEBUG_BUF_SZ, GFP_NOFS);
74 + if (!osb->local_alloc_debug_buf)
77 + osb->local_alloc_debug = debugfs_create_file("local_alloc_stats",
79 + osb->osb_debug_root,
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;
88 +static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb)
90 + if (osb->local_alloc_debug)
91 + debugfs_remove(osb->local_alloc_debug);
93 + if (osb->local_alloc_debug_buf)
94 + kfree(osb->local_alloc_debug_buf);
96 + osb->local_alloc_debug_buf = NULL;
97 + osb->local_alloc_debug = NULL;
99 +#else /* CONFIG_OCFS2_FS_STATS */
100 +static void ocfs2_init_la_debug(struct ocfs2_super *osb)
104 +static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb)
110 static inline int ocfs2_la_state_enabled(struct ocfs2_super *osb)
112 return (osb->local_alloc_state == OCFS2_LA_THROTTLED ||
113 @@ -146,6 +226,8 @@ int ocfs2_load_local_alloc(struct ocfs2_
117 + ocfs2_init_la_debug(osb);
119 if (osb->local_alloc_bits == 0)
122 @@ -218,6 +300,9 @@ bail:
127 + ocfs2_shutdown_la_debug(osb);
129 mlog(0, "Local alloc window bits = %d\n", osb->local_alloc_bits);
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);
136 + ocfs2_shutdown_la_debug(osb);
138 if (osb->local_alloc_state == OCFS2_LA_UNUSED)
141 --- a/fs/ocfs2/ocfs2.h
142 +++ b/fs/ocfs2/ocfs2.h
143 @@ -281,6 +281,11 @@ struct ocfs2_super
147 +#ifdef CONFIG_OCFS2_FS_STATS
148 + struct dentry *local_alloc_debug;
149 + char *local_alloc_debug_buf;
152 /* Next two fields are for local node slot recovery during