Commit 9a8ff578 authored by Mark Fasheh's avatar Mark Fasheh

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: default avatarMark Fasheh <mfasheh@suse.com>
parent 9c7af40b
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/debugfs.h>
#define MLOG_MASK_PREFIX ML_DISK_ALLOC #define MLOG_MASK_PREFIX ML_DISK_ALLOC
#include <cluster/masklog.h> #include <cluster/masklog.h>
...@@ -73,6 +74,85 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb, ...@@ -73,6 +74,85 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb, static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
struct inode *local_alloc_inode); struct inode *local_alloc_inode);
#ifdef CONFIG_OCFS2_FS_STATS
DEFINE_MUTEX(la_debug_mutex);
static int ocfs2_la_debug_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
#define LA_DEBUG_BUF_SZ PAGE_CACHE_SIZE
#define LA_DEBUG_VER 1
static ssize_t ocfs2_la_debug_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct ocfs2_super *osb = file->private_data;
int written, ret;
char *buf = osb->local_alloc_debug_buf;
mutex_lock(&la_debug_mutex);
memset(buf, 0, LA_DEBUG_BUF_SZ);
written = snprintf(buf, LA_DEBUG_BUF_SZ,
"0x%x\t0x%llx\t%u\t%u\t0x%x\n",
LA_DEBUG_VER,
(unsigned long long)osb->la_last_gd,
osb->local_alloc_default_bits,
osb->local_alloc_bits, osb->local_alloc_state);
ret = simple_read_from_buffer(userbuf, count, ppos, buf, written);
mutex_unlock(&la_debug_mutex);
return ret;
}
static const struct file_operations ocfs2_la_debug_fops = {
.open = ocfs2_la_debug_open,
.read = ocfs2_la_debug_read,
};
static void ocfs2_init_la_debug(struct ocfs2_super *osb)
{
osb->local_alloc_debug_buf = kmalloc(LA_DEBUG_BUF_SZ, GFP_NOFS);
if (!osb->local_alloc_debug_buf)
return;
osb->local_alloc_debug = debugfs_create_file("local_alloc_stats",
S_IFREG|S_IRUSR,
osb->osb_debug_root,
osb,
&ocfs2_la_debug_fops);
if (!osb->local_alloc_debug) {
kfree(osb->local_alloc_debug_buf);
osb->local_alloc_debug_buf = NULL;
}
}
static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb)
{
if (osb->local_alloc_debug)
debugfs_remove(osb->local_alloc_debug);
if (osb->local_alloc_debug_buf)
kfree(osb->local_alloc_debug_buf);
osb->local_alloc_debug_buf = NULL;
osb->local_alloc_debug = NULL;
}
#else /* CONFIG_OCFS2_FS_STATS */
static void ocfs2_init_la_debug(struct ocfs2_super *osb)
{
return;
}
static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb)
{
return;
}
#endif
static inline int ocfs2_la_state_enabled(struct ocfs2_super *osb) static inline int ocfs2_la_state_enabled(struct ocfs2_super *osb)
{ {
return (osb->local_alloc_state == OCFS2_LA_THROTTLED || return (osb->local_alloc_state == OCFS2_LA_THROTTLED ||
...@@ -146,6 +226,8 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb) ...@@ -146,6 +226,8 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb)
mlog_entry_void(); mlog_entry_void();
ocfs2_init_la_debug(osb);
if (osb->local_alloc_bits == 0) if (osb->local_alloc_bits == 0)
goto bail; goto bail;
...@@ -218,6 +300,9 @@ bail: ...@@ -218,6 +300,9 @@ bail:
if (inode) if (inode)
iput(inode); iput(inode);
if (status < 0)
ocfs2_shutdown_la_debug(osb);
mlog(0, "Local alloc window bits = %d\n", osb->local_alloc_bits); mlog(0, "Local alloc window bits = %d\n", osb->local_alloc_bits);
mlog_exit(status); mlog_exit(status);
...@@ -247,6 +332,8 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb) ...@@ -247,6 +332,8 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
cancel_delayed_work(&osb->la_enable_wq); cancel_delayed_work(&osb->la_enable_wq);
flush_workqueue(ocfs2_wq); flush_workqueue(ocfs2_wq);
ocfs2_shutdown_la_debug(osb);
if (osb->local_alloc_state == OCFS2_LA_UNUSED) if (osb->local_alloc_state == OCFS2_LA_UNUSED)
goto out; goto out;
......
...@@ -272,6 +272,11 @@ struct ocfs2_super ...@@ -272,6 +272,11 @@ struct ocfs2_super
u64 la_last_gd; u64 la_last_gd;
#ifdef CONFIG_OCFS2_FS_STATS
struct dentry *local_alloc_debug;
char *local_alloc_debug_buf;
#endif
/* Next two fields are for local node slot recovery during /* Next two fields are for local node slot recovery during
* mount. */ * mount. */
int dirty; int dirty;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment