Commit 55e585b4 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Nathan Scott

[XFS] use generic XFS stats and sysctl infrastructure in pagebuf

SGI Modid: xfs-linux:xfs-kern:166505a
parent bf47e0c2
...@@ -59,14 +59,8 @@ ...@@ -59,14 +59,8 @@
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <support/ktrace.h> #include "xfs_linux.h"
#include <support/debug.h>
#include "kmem.h"
#include "xfs_types.h"
#include "xfs_cred.h"
#include "xfs_lrw.h"
#include "xfs_buf.h"
#define BBSHIFT 9 #define BBSHIFT 9
#define BN_ALIGN_MASK ((1 << (PAGE_CACHE_SHIFT - BBSHIFT)) - 1) #define BN_ALIGN_MASK ((1 << (PAGE_CACHE_SHIFT - BBSHIFT)) - 1)
...@@ -85,60 +79,6 @@ STATIC void pagebuf_delwri_queue(page_buf_t *, int); ...@@ -85,60 +79,6 @@ STATIC void pagebuf_delwri_queue(page_buf_t *, int);
STATIC struct workqueue_struct *pagebuf_logio_workqueue; STATIC struct workqueue_struct *pagebuf_logio_workqueue;
STATIC struct workqueue_struct *pagebuf_dataio_workqueue; STATIC struct workqueue_struct *pagebuf_dataio_workqueue;
/*
* Pagebuf module configuration parameters, exported via
* /proc/sys/vm/pagebuf
*/
typedef struct pb_sysctl_val {
int min;
int val;
int max;
} pb_sysctl_val_t;
struct {
pb_sysctl_val_t flush_interval; /* interval between runs of the
* delwri flush daemon. */
pb_sysctl_val_t age_buffer; /* time for buffer to age before
* we flush it. */
pb_sysctl_val_t stats_clear; /* clear the pagebuf stats */
pb_sysctl_val_t debug; /* debug tracing on or off */
} pb_params = {
/* MIN DFLT MAX */
.flush_interval = { HZ/2, HZ, 30*HZ },
.age_buffer = { 1*HZ, 15*HZ, 300*HZ },
.stats_clear = { 0, 0, 1 },
.debug = { 0, 0, 1 },
};
enum {
PB_FLUSH_INT = 1,
PB_FLUSH_AGE = 2,
PB_STATS_CLEAR = 3,
PB_DEBUG = 4,
};
/*
* Pagebuf statistics variables
*/
struct pbstats {
u_int32_t pb_get;
u_int32_t pb_create;
u_int32_t pb_get_locked;
u_int32_t pb_get_locked_waited;
u_int32_t pb_busy_locked;
u_int32_t pb_miss_locked;
u_int32_t pb_page_retries;
u_int32_t pb_page_found;
u_int32_t pb_get_read;
} pbstats;
DEFINE_PER_CPU(struct pbstats, pbstats);
/* We don't disable preempt, not too worried about poking the
* wrong cpu's stat for now */
#define PB_STATS_INC(count) (__get_cpu_var(pbstats).count++)
/* /*
* Pagebuf debugging * Pagebuf debugging
*/ */
...@@ -151,8 +91,6 @@ pagebuf_trace( ...@@ -151,8 +91,6 @@ pagebuf_trace(
void *data, void *data,
void *ra) void *ra)
{ {
if (!pb_params.debug.val)
return;
ktrace_enter(pagebuf_trace_buf, ktrace_enter(pagebuf_trace_buf,
pb, id, pb, id,
(void *)(unsigned long)pb->pb_flags, (void *)(unsigned long)pb->pb_flags,
...@@ -326,7 +264,7 @@ _pagebuf_initialize( ...@@ -326,7 +264,7 @@ _pagebuf_initialize(
atomic_set(&pb->pb_pin_count, 0); atomic_set(&pb->pb_pin_count, 0);
init_waitqueue_head(&pb->pb_waiters); init_waitqueue_head(&pb->pb_waiters);
PB_STATS_INC(pb_create); XFS_STATS_INC(pb_create);
PB_TRACE(pb, "initialize", target); PB_TRACE(pb, "initialize", target);
} }
...@@ -513,13 +451,13 @@ _pagebuf_lookup_pages( ...@@ -513,13 +451,13 @@ _pagebuf_lookup_pages(
"possibly deadlocking in %s\n", "possibly deadlocking in %s\n",
__FUNCTION__); __FUNCTION__);
} }
PB_STATS_INC(pb_page_retries); XFS_STATS_INC(pb_page_retries);
pagebuf_daemon_wakeup(); pagebuf_daemon_wakeup();
current->state = TASK_UNINTERRUPTIBLE; current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(10); schedule_timeout(10);
goto retry; goto retry;
} }
PB_STATS_INC(pb_page_found); XFS_STATS_INC(pb_page_found);
mark_page_accessed(page); mark_page_accessed(page);
pb->pb_pages[pi] = page; pb->pb_pages[pi] = page;
} else { } else {
...@@ -667,7 +605,7 @@ _pagebuf_find( /* find buffer for block */ ...@@ -667,7 +605,7 @@ _pagebuf_find( /* find buffer for block */
new_pb->pb_hash_index = hval; new_pb->pb_hash_index = hval;
list_add(&new_pb->pb_hash_list, &h->pb_hash); list_add(&new_pb->pb_hash_list, &h->pb_hash);
} else { } else {
PB_STATS_INC(pb_miss_locked); XFS_STATS_INC(pb_miss_locked);
} }
spin_unlock(&h->pb_hash_lock); spin_unlock(&h->pb_hash_lock);
...@@ -686,7 +624,7 @@ _pagebuf_find( /* find buffer for block */ ...@@ -686,7 +624,7 @@ _pagebuf_find( /* find buffer for block */
/* wait for buffer ownership */ /* wait for buffer ownership */
PB_TRACE(pb, "get_lock", 0); PB_TRACE(pb, "get_lock", 0);
pagebuf_lock(pb); pagebuf_lock(pb);
PB_STATS_INC(pb_get_locked_waited); XFS_STATS_INC(pb_get_locked_waited);
} else { } else {
/* We asked for a trylock and failed, no need /* We asked for a trylock and failed, no need
* to look at file offset and length here, we * to look at file offset and length here, we
...@@ -696,7 +634,7 @@ _pagebuf_find( /* find buffer for block */ ...@@ -696,7 +634,7 @@ _pagebuf_find( /* find buffer for block */
*/ */
pagebuf_rele(pb); pagebuf_rele(pb);
PB_STATS_INC(pb_busy_locked); XFS_STATS_INC(pb_busy_locked);
return (NULL); return (NULL);
} }
} else { } else {
...@@ -711,7 +649,7 @@ _pagebuf_find( /* find buffer for block */ ...@@ -711,7 +649,7 @@ _pagebuf_find( /* find buffer for block */
_PBF_MEM_ALLOCATED | \ _PBF_MEM_ALLOCATED | \
_PBF_MEM_SLAB; _PBF_MEM_SLAB;
PB_TRACE(pb, "got_lock", 0); PB_TRACE(pb, "got_lock", 0);
PB_STATS_INC(pb_get_locked); XFS_STATS_INC(pb_get_locked);
return (pb); return (pb);
} }
...@@ -767,7 +705,7 @@ pagebuf_get( /* allocate a buffer */ ...@@ -767,7 +705,7 @@ pagebuf_get( /* allocate a buffer */
return (NULL); return (NULL);
} }
PB_STATS_INC(pb_get); XFS_STATS_INC(pb_get);
/* fill in any missing pages */ /* fill in any missing pages */
error = _pagebuf_lookup_pages(pb, pb->pb_target->pbr_mapping, flags); error = _pagebuf_lookup_pages(pb, pb->pb_target->pbr_mapping, flags);
...@@ -787,7 +725,7 @@ pagebuf_get( /* allocate a buffer */ ...@@ -787,7 +725,7 @@ pagebuf_get( /* allocate a buffer */
if (flags & PBF_READ) { if (flags & PBF_READ) {
if (PBF_NOT_DONE(pb)) { if (PBF_NOT_DONE(pb)) {
PB_TRACE(pb, "get_read", (unsigned long)flags); PB_TRACE(pb, "get_read", (unsigned long)flags);
PB_STATS_INC(pb_get_read); XFS_STATS_INC(pb_get_read);
pagebuf_iostart(pb, flags); pagebuf_iostart(pb, flags);
} else if (flags & PBF_ASYNC) { } else if (flags & PBF_ASYNC) {
PB_TRACE(pb, "get_read_async", (unsigned long)flags); PB_TRACE(pb, "get_read_async", (unsigned long)flags);
...@@ -1655,7 +1593,7 @@ pagebuf_delwri_queue( ...@@ -1655,7 +1593,7 @@ pagebuf_delwri_queue(
} }
list_add_tail(&pb->pb_list, &pbd_delwrite_queue); list_add_tail(&pb->pb_list, &pbd_delwrite_queue);
pb->pb_flushtime = jiffies + pb_params.age_buffer.val; pb->pb_flushtime = jiffies + xfs_age_buffer;
spin_unlock(&pbd_delwrite_lock); spin_unlock(&pbd_delwrite_lock);
if (unlock) if (unlock)
...@@ -1717,7 +1655,7 @@ pagebuf_daemon( ...@@ -1717,7 +1655,7 @@ pagebuf_daemon(
refrigerator(PF_IOTHREAD); refrigerator(PF_IOTHREAD);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(pb_params.flush_interval.val); schedule_timeout(xfs_flush_interval);
spin_lock(&pbd_delwrite_lock); spin_lock(&pbd_delwrite_lock);
...@@ -1876,112 +1814,6 @@ pagebuf_daemon_stop(void) ...@@ -1876,112 +1814,6 @@ pagebuf_daemon_stop(void)
destroy_workqueue(pagebuf_dataio_workqueue); destroy_workqueue(pagebuf_dataio_workqueue);
} }
/*
* Pagebuf sysctl interface
*/
STATIC int
pb_stats_clear_handler(
ctl_table *ctl,
int write,
struct file *filp,
void *buffer,
size_t *lenp)
{
int c, ret;
int *valp = ctl->data;
ret = proc_dointvec_minmax(ctl, write, filp, buffer, lenp);
if (!ret && write && *valp) {
printk("XFS Clearing pbstats\n");
for (c = 0; c < NR_CPUS; c++) {
if (!cpu_possible(c)) continue;
memset(&per_cpu(pbstats, c), 0,
sizeof(struct pbstats));
}
pb_params.stats_clear.val = 0;
}
return ret;
}
STATIC struct ctl_table_header *pagebuf_table_header;
STATIC ctl_table pagebuf_table[] = {
{PB_FLUSH_INT, "flush_int", &pb_params.flush_interval.val,
sizeof(int), 0644, NULL, &proc_dointvec_minmax,
&sysctl_intvec, NULL,
&pb_params.flush_interval.min, &pb_params.flush_interval.max},
{PB_FLUSH_AGE, "flush_age", &pb_params.age_buffer.val,
sizeof(int), 0644, NULL, &proc_dointvec_minmax,
&sysctl_intvec, NULL,
&pb_params.age_buffer.min, &pb_params.age_buffer.max},
{PB_STATS_CLEAR, "stats_clear", &pb_params.stats_clear.val,
sizeof(int), 0644, NULL, &pb_stats_clear_handler,
&sysctl_intvec, NULL,
&pb_params.stats_clear.min, &pb_params.stats_clear.max},
#ifdef PAGEBUF_TRACE
{PB_DEBUG, "debug", &pb_params.debug.val,
sizeof(int), 0644, NULL, &proc_dointvec_minmax,
&sysctl_intvec, NULL,
&pb_params.debug.min, &pb_params.debug.max},
#endif
{0}
};
STATIC ctl_table pagebuf_dir_table[] = {
{VM_PAGEBUF, "pagebuf", NULL, 0, 0555, pagebuf_table},
{0}
};
STATIC ctl_table pagebuf_root_table[] = {
{CTL_VM, "vm", NULL, 0, 0555, pagebuf_dir_table},
{0}
};
#ifdef CONFIG_PROC_FS
STATIC int
pagebuf_readstats(
char *buffer,
char **start,
off_t offset,
int count,
int *eof,
void *data)
{
int c, i, len, val;
len = 0;
len += sprintf(buffer + len, "pagebuf");
for (i = 0; i < sizeof(struct pbstats) / sizeof(u_int32_t); i++) {
val = 0;
for (c = 0 ; c < NR_CPUS; c++) {
if (!cpu_possible(c)) continue;
val += *(((u_int32_t*)&per_cpu(pbstats, c) + i));
}
len += sprintf(buffer + len, " %u", val);
}
buffer[len++] = '\n';
if (offset >= len) {
*start = buffer;
*eof = 1;
return 0;
}
*start = buffer + offset;
if ((len -= offset) > count)
return count;
*eof = 1;
return len;
}
#endif /* CONFIG_PROC_FS */
/* /*
* Initialization and Termination * Initialization and Termination
*/ */
...@@ -1991,14 +1823,6 @@ pagebuf_init(void) ...@@ -1991,14 +1823,6 @@ pagebuf_init(void)
{ {
int i; int i;
pagebuf_table_header = register_sysctl_table(pagebuf_root_table, 1);
#ifdef CONFIG_PROC_FS
if (proc_mkdir("fs/pagebuf", 0))
create_proc_read_entry(
"fs/pagebuf/stat", 0, 0, pagebuf_readstats, NULL);
#endif
pagebuf_cache = kmem_cache_create("page_buf_t", sizeof(page_buf_t), 0, pagebuf_cache = kmem_cache_create("page_buf_t", sizeof(page_buf_t), 0,
SLAB_HWCACHE_ALIGN, NULL, NULL); SLAB_HWCACHE_ALIGN, NULL, NULL);
if (pagebuf_cache == NULL) { if (pagebuf_cache == NULL) {
...@@ -2036,10 +1860,4 @@ pagebuf_terminate(void) ...@@ -2036,10 +1860,4 @@ pagebuf_terminate(void)
#endif #endif
kmem_cache_destroy(pagebuf_cache); kmem_cache_destroy(pagebuf_cache);
unregister_sysctl_table(pagebuf_table_header);
#ifdef CONFIG_PROC_FS
remove_proc_entry("fs/pagebuf/stat", NULL);
remove_proc_entry("fs/pagebuf", NULL);
#endif
} }
...@@ -61,6 +61,8 @@ xfs_param_t xfs_params = { ...@@ -61,6 +61,8 @@ xfs_param_t xfs_params = {
.inherit_sync = { 0, 1, 1 }, .inherit_sync = { 0, 1, 1 },
.inherit_nodump = { 0, 1, 1 }, .inherit_nodump = { 0, 1, 1 },
.inherit_noatim = { 0, 1, 1 }, .inherit_noatim = { 0, 1, 1 },
.flush_interval = { HZ/2, HZ, 30*HZ },
.age_buffer = { 1*HZ, 15*HZ, 300*HZ },
}; };
/* /*
......
...@@ -138,6 +138,8 @@ static inline void set_buffer_unwritten_io(struct buffer_head *bh) ...@@ -138,6 +138,8 @@ static inline void set_buffer_unwritten_io(struct buffer_head *bh)
#define xfs_inherit_sync xfs_params.inherit_sync.val #define xfs_inherit_sync xfs_params.inherit_sync.val
#define xfs_inherit_nodump xfs_params.inherit_nodump.val #define xfs_inherit_nodump xfs_params.inherit_nodump.val
#define xfs_inherit_noatime xfs_params.inherit_noatim.val #define xfs_inherit_noatime xfs_params.inherit_noatim.val
#define xfs_flush_interval xfs_params.flush_interval.val
#define xfs_age_buffer xfs_params.age_buffer.val
#define current_cpu() smp_processor_id() #define current_cpu() smp_processor_id()
#define current_pid() (current->pid) #define current_pid() (current->pid)
......
...@@ -67,6 +67,7 @@ xfs_read_xfsstats( ...@@ -67,6 +67,7 @@ xfs_read_xfsstats(
{ "attr", XFSSTAT_END_ATTRIBUTE_OPS }, { "attr", XFSSTAT_END_ATTRIBUTE_OPS },
{ "icluster", XFSSTAT_END_INODE_CLUSTER }, { "icluster", XFSSTAT_END_INODE_CLUSTER },
{ "vnodes", XFSSTAT_END_VNODE_OPS }, { "vnodes", XFSSTAT_END_VNODE_OPS },
{ "buf", XFSSTAT_END_BUF },
}; };
/* Loop over all stats groups */ /* Loop over all stats groups */
......
...@@ -122,6 +122,16 @@ struct xfsstats { ...@@ -122,6 +122,16 @@ struct xfsstats {
__uint32_t vn_reclaim; /* # times vn_reclaim called */ __uint32_t vn_reclaim; /* # times vn_reclaim called */
__uint32_t vn_remove; /* # times vn_remove called */ __uint32_t vn_remove; /* # times vn_remove called */
__uint32_t vn_free; /* # times vn_free called */ __uint32_t vn_free; /* # times vn_free called */
#define XFSSTAT_END_BUF (XFSSTAT_END_VNODE_OPS+9)
__uint32_t pb_get;
__uint32_t pb_create;
__uint32_t pb_get_locked;
__uint32_t pb_get_locked_waited;
__uint32_t pb_busy_locked;
__uint32_t pb_miss_locked;
__uint32_t pb_page_retries;
__uint32_t pb_page_found;
__uint32_t pb_get_read;
/* Extra precision counters */ /* Extra precision counters */
__uint64_t xs_xstrat_bytes; __uint64_t xs_xstrat_bytes;
__uint64_t xs_write_bytes; __uint64_t xs_write_bytes;
......
...@@ -117,6 +117,16 @@ STATIC ctl_table xfs_table[] = { ...@@ -117,6 +117,16 @@ STATIC ctl_table xfs_table[] = {
sizeof(int), 0644, NULL, &proc_dointvec_minmax, sizeof(int), 0644, NULL, &proc_dointvec_minmax,
&sysctl_intvec, NULL, &sysctl_intvec, NULL,
&xfs_params.inherit_noatim.min, &xfs_params.inherit_noatim.max}, &xfs_params.inherit_noatim.min, &xfs_params.inherit_noatim.max},
{XFS_FLUSH_INTERVAL, "flush_interval", &xfs_params.flush_interval.val,
sizeof(int), 0644, NULL, &proc_dointvec_minmax,
&sysctl_intvec, NULL,
&xfs_params.flush_interval.min, &xfs_params.flush_interval.max},
{XFS_AGE_BUFFER, "age_buffer", &xfs_params.age_buffer.val,
sizeof(int), 0644, NULL, &proc_dointvec_minmax,
&sysctl_intvec, NULL,
&xfs_params.age_buffer.min, &xfs_params.age_buffer.max},
/* please keep this the last entry */ /* please keep this the last entry */
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
......
...@@ -58,6 +58,10 @@ typedef struct xfs_param { ...@@ -58,6 +58,10 @@ typedef struct xfs_param {
xfs_sysctl_val_t inherit_sync; /* Inherit the "sync" inode flag. */ xfs_sysctl_val_t inherit_sync; /* Inherit the "sync" inode flag. */
xfs_sysctl_val_t inherit_nodump;/* Inherit the "nodump" inode flag. */ xfs_sysctl_val_t inherit_nodump;/* Inherit the "nodump" inode flag. */
xfs_sysctl_val_t inherit_noatim;/* Inherit the "noatime" inode flag. */ xfs_sysctl_val_t inherit_noatim;/* Inherit the "noatime" inode flag. */
xfs_sysctl_val_t flush_interval;/* interval between runs of the
* delwri flush daemon. */
xfs_sysctl_val_t age_buffer; /* time for buffer to age before
* we flush it. */
} xfs_param_t; } xfs_param_t;
/* /*
...@@ -86,6 +90,8 @@ enum { ...@@ -86,6 +90,8 @@ enum {
XFS_INHERIT_SYNC = 13, XFS_INHERIT_SYNC = 13,
XFS_INHERIT_NODUMP = 14, XFS_INHERIT_NODUMP = 14,
XFS_INHERIT_NOATIME = 15, XFS_INHERIT_NOATIME = 15,
XFS_FLUSH_INTERVAL = 16,
XFS_AGE_BUFFER = 17,
}; };
extern xfs_param_t xfs_params; extern xfs_param_t xfs_params;
......
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