From: Greg Banks <gnb@sgi.com>
To: "J. Bruce Fields" <bfields@fieldses.org>
Cc: Linux NFS ML <linux-nfs@vger.kernel.org>
Subject: [patch 06/29] knfsd: Gather per-export stats
Date: Wed, 01 Apr 2009 07:28:06 +1100 [thread overview]
Message-ID: <20090331202940.087008000@sgi.com> (raw)
In-Reply-To: 20090331202800.739621000@sgi.com
Uses the new stats infrastructure to record and export NFS statistics
on a per-export basis. The export is chosen according to the first
filehandle presented in the incoming call. If an NFSv4 call references
filehandles on multiple exports, all statistics will be recorded
against the first one. If the call does not reference any filehandles
(e.g. NFSv3 NULL call), it will not be counted in the per-export stats
(although later it will be counted in the per-client stats).
A file /proc/fs/nfsd/export_stats is provided to allow userspace
programs to read the statistics.
To avoid a hash lookup in a locked global table on every operation,
the stats entry is cached on the struct svc_export.
Contains code based on a patch from Harshula Jayasuriya <harshula@sgi.com>.
Signed-off-by: Greg Banks <gnb@sgi.com>
---
fs/nfsd/export.c | 33 +++++++++++++++++++++++++++++++
fs/nfsd/nfsctl.c | 15 ++++++++++++++
fs/nfsd/stats.c | 35 +++++++++++++++++++++++++++++++--
include/linux/nfsd/export.h | 1
include/linux/nfsd/stats.h | 1
include/linux/sunrpc/svc.h | 1
6 files changed, 84 insertions(+), 2 deletions(-)
Index: bfields/fs/nfsd/export.c
===================================================================
--- bfields.orig/fs/nfsd/export.c
+++ bfields/fs/nfsd/export.c
@@ -27,6 +27,7 @@
#include <linux/hash.h>
#include <linux/module.h>
#include <linux/exportfs.h>
+#include <linux/list.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
@@ -44,6 +45,7 @@ typedef struct svc_export svc_export;
static void exp_do_unexport(svc_export *unexp);
static int exp_verify_string(char *cp, int max);
+static nfsd_stats_hentry_t *exp_stats_find(struct path *);
/*
* We have two caches.
@@ -333,6 +335,8 @@ static void svc_export_put(struct kref *
auth_domain_put(exp->ex_client);
kfree(exp->ex_pathname);
nfsd4_fslocs_free(&exp->ex_fslocs);
+ if (exp->ex_stats)
+ nfsd_stats_put(exp->ex_stats);
kfree(exp);
}
@@ -673,6 +677,34 @@ static int svc_export_match(struct cache
orig->ex_path.mnt == new->ex_path.mnt;
}
+/*
+ * Find and return a stats hentry in the export stats hash,
+ * given the mount+dentry for the export, creating it if
+ * necessary. Will return NULL on OOM or if stats disabled.
+ */
+static nfsd_stats_hentry_t *exp_stats_find(struct path *pp)
+{
+ char *buf, *pathname;
+ int len;
+ nfsd_stats_hentry_t *se = NULL;
+
+ dprintk("exp_stats_find: mnt %p dentry %p\n", pp->mnt, pp->dentry);
+
+ /* construct the export's path in a temporary page */
+ buf = (char *)__get_free_page(GFP_KERNEL);
+ if (buf == NULL)
+ return NULL;
+
+ pathname = d_path(pp, buf, PAGE_SIZE);
+ if (!IS_ERR(pathname)) {
+ len = buf + PAGE_SIZE - 1 - pathname;
+ se = nfsd_stats_find(&nfsd_export_stats_hash, pathname, len);
+ }
+
+ free_page((unsigned long)buf);
+ return se;
+}
+
static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
{
struct svc_export *new = container_of(cnew, struct svc_export, h);
@@ -686,6 +718,7 @@ static void svc_export_init(struct cache
new->ex_fslocs.locations = NULL;
new->ex_fslocs.locations_count = 0;
new->ex_fslocs.migrated = 0;
+ new->ex_stats = exp_stats_find(&new->ex_path);
}
static void export_update(struct cache_head *cnew, struct cache_head *citem)
Index: bfields/fs/nfsd/stats.c
===================================================================
--- bfields.orig/fs/nfsd/stats.c
+++ bfields/fs/nfsd/stats.c
@@ -49,6 +49,7 @@ struct svc_stat nfsd_svcstats = {
.program = &nfsd_program,
};
+nfsd_stats_hash_t nfsd_export_stats_hash;
int nfsd_stats_enabled = 1;
int nfsd_stats_prune_period = 2*86400;
@@ -384,15 +385,34 @@ static void __nfsd_stats_op(struct svc_r
void nfsd_stats_update_op(struct svc_rqst *rqstp, struct svc_fh *fh,
int rbucket, int wbucket, int op)
{
+ nfsd_stats_hentry_t *se;
+
if (!nfsd_stats_enabled)
return;
- /* interesting things happen here 2 patches hence */
+ /* first op in the call: find and cache per-export stats */
+ if (fh != NULL &&
+ fh->fh_export != NULL &&
+ (se = fh->fh_export->ex_stats) != NULL &&
+ rqstp->rq_export_stats == NULL) {
+ /*
+ * We want the stats to survive fh_put() of the filehandle
+ * so we can update os_bytes_out and service time in
+ * nfsd_stats_post(). So grab a reference here.
+ */
+ nfsd_stats_get(se);
+ rqstp->rq_export_stats = se;
+ __nfsd_stats_begin_call(rqstp, se);
+ }
+ /* all ops in the call: update per-export stats */
+ if (rqstp->rq_export_stats)
+ __nfsd_stats_op(rqstp, rqstp->rq_export_stats, rbucket, wbucket, op);
}
void nfsd_stats_pre(struct svc_rqst *rqstp)
{
svc_time_mark(&rqstp->rq_start_time);
+ rqstp->rq_export_stats = NULL;
}
static inline int time_bucket(const struct timespec *ts)
@@ -418,11 +438,18 @@ void nfsd_stats_post(struct svc_rqst *rq
int tb = -1;
struct timespec svctime;
+ if (rqstp->rq_export_stats == NULL)
+ return;
+
/* calculate service time and update the stats */
if (svc_time_elapsed(&rqstp->rq_start_time, &svctime) == 0)
tb = time_bucket(&svctime);
- /* interesting things happen here 2 patches hence */
+ if (rqstp->rq_export_stats != NULL) {
+ __nfsd_stats_end_call(rqstp, rqstp->rq_export_stats, tb);
+ nfsd_stats_put(rqstp->rq_export_stats);
+ rqstp->rq_export_stats = NULL;
+ }
}
@@ -603,10 +630,14 @@ void
nfsd_stat_init(void)
{
svc_proc_register(&nfsd_svcstats, &nfsd_proc_fops);
+
+ nfsd_stats_hash_init(&nfsd_export_stats_hash, "export");
}
void
nfsd_stat_shutdown(void)
{
svc_proc_unregister("nfsd");
+
+ nfsd_stats_hash_destroy(&nfsd_export_stats_hash);
}
Index: bfields/include/linux/nfsd/export.h
===================================================================
--- bfields.orig/include/linux/nfsd/export.h
+++ bfields/include/linux/nfsd/export.h
@@ -92,6 +92,7 @@ struct svc_export {
struct nfsd4_fs_locations ex_fslocs;
int ex_nflavors;
struct exp_flavor_info ex_flavors[MAX_SECINFO_LIST];
+ struct nfsd_stats_hentry *ex_stats;
};
/* an "export key" (expkey) maps a filehandlefragement to an
Index: bfields/include/linux/nfsd/stats.h
===================================================================
--- bfields.orig/include/linux/nfsd/stats.h
+++ bfields/include/linux/nfsd/stats.h
@@ -135,6 +135,7 @@ struct nfsd_stats_hiter {
extern struct nfsd_stats nfsdstats;
extern struct svc_stat nfsd_svcstats;
+extern nfsd_stats_hash_t nfsd_export_stats_hash;
void nfsd_stat_init(void);
void nfsd_stat_shutdown(void);
Index: bfields/fs/nfsd/nfsctl.c
===================================================================
--- bfields.orig/fs/nfsd/nfsctl.c
+++ bfields/fs/nfsd/nfsctl.c
@@ -66,6 +66,7 @@ enum {
NFSD_MaxBlkSize,
NFSD_Stats_Enabled,
NFSD_Stats_Prune_Period,
+ NFSD_Export_Stats,
/*
* The below MUST come last. Otherwise we leave a hole in nfsd_files[]
* with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
@@ -179,6 +180,19 @@ static const struct file_operations expo
.owner = THIS_MODULE,
};
+static int export_stats_open(struct inode *inode, struct file *file)
+{
+ return nfsd_stats_open(file, &nfsd_export_stats_hash);
+}
+
+static struct file_operations export_stats_operations = {
+ .open = export_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private,
+ .owner = THIS_MODULE,
+};
+
extern int nfsd_pool_stats_open(struct inode *inode, struct file *file);
static struct file_operations pool_stats_operations = {
@@ -1362,6 +1376,7 @@ static int nfsd_fill_super(struct super_
[NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
[NFSD_Stats_Enabled] = {"stats_enabled", &transaction_ops, S_IWUSR|S_IRUGO},
[NFSD_Stats_Prune_Period] = {"stats_prune_period", &transaction_ops, S_IWUSR|S_IRUGO},
+ [NFSD_Export_Stats] = {"export_stats", &export_stats_operations, S_IRUGO},
#ifdef CONFIG_NFSD_V4
[NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
Index: bfields/include/linux/sunrpc/svc.h
===================================================================
--- bfields.orig/include/linux/sunrpc/svc.h
+++ bfields/include/linux/sunrpc/svc.h
@@ -291,6 +291,7 @@ struct svc_rqst {
struct task_struct *rq_task; /* service thread */
int rq_waking; /* 1 if thread is being woken */
struct svc_time rq_start_time;
+ struct nfsd_stats_hentry *rq_export_stats;
};
/*
--
Greg
next prev parent reply other threads:[~2009-03-31 21:02 UTC|newest]
Thread overview: 63+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-03-31 20:28 [patch 00/29] SGI enhancedNFS patches Greg Banks
2009-03-31 20:28 ` [patch 01/29] knfsd: Add infrastructure for measuring RPC service times Greg Banks
2009-04-25 2:13 ` J. Bruce Fields
2009-04-25 2:14 ` J. Bruce Fields
2009-04-25 2:52 ` Greg Banks
2009-03-31 20:28 ` [patch 02/29] knfsd: Add stats table infrastructure Greg Banks
2009-04-25 3:56 ` J. Bruce Fields
2009-04-26 4:12 ` Greg Banks
2009-03-31 20:28 ` [patch 03/29] knfsd: add userspace controls for stats tables Greg Banks
2009-04-25 21:57 ` J. Bruce Fields
2009-04-25 22:03 ` J. Bruce Fields
2009-04-27 16:06 ` Chuck Lever
2009-04-27 23:22 ` J. Bruce Fields
2009-04-28 15:37 ` Chuck Lever
2009-04-28 15:57 ` J. Bruce Fields
2009-04-28 16:03 ` Chuck Lever
2009-04-28 16:26 ` J. Bruce Fields
2009-04-29 1:45 ` Greg Banks
[not found] ` <ac442c870904271827w6041a67ew82fe36a843beeac3@mail.gmail.com>
[not found] ` <ac442c870904271827w6041a67ew82fe36a843beeac3-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2009-04-28 1:31 ` Greg Banks
2009-04-26 4:14 ` Greg Banks
2009-03-31 20:28 ` [patch 04/29] knfsd: Add stats updating API Greg Banks
2009-03-31 20:28 ` [patch 05/29] knfsd: Infrastructure for providing stats to userspace Greg Banks
2009-04-01 0:28 ` J. Bruce Fields
2009-04-01 3:43 ` Greg Banks
2009-03-31 20:28 ` Greg Banks [this message]
2009-03-31 20:28 ` [patch 07/29] knfsd: Prefetch the per-export stats entry Greg Banks
2009-03-31 20:28 ` [patch 08/29] knfsd: Gather per-client stats Greg Banks
2009-03-31 20:28 ` [patch 09/29] knfsd: Cache per-client stats entry on TCP transports Greg Banks
2009-03-31 20:28 ` [patch 10/29] knfsd: Update per-client & per-export stats from NFSv3 Greg Banks
2009-03-31 20:28 ` [patch 11/29] knfsd: Update per-client & per-export stats from NFSv2 Greg Banks
2009-03-31 20:28 ` [patch 12/29] knfsd: Update per-client & per-export stats from NFSv4 Greg Banks
2009-03-31 20:28 ` [patch 13/29] knfsd: reply cache cleanups Greg Banks
2009-05-12 19:54 ` J. Bruce Fields
2009-03-31 20:28 ` [patch 14/29] knfsd: better hashing in the reply cache Greg Banks
2009-05-08 22:01 ` J. Bruce Fields
2009-03-31 20:28 ` [patch 15/29] knfsd: fix reply cache memory corruption Greg Banks
2009-05-12 19:55 ` J. Bruce Fields
2009-03-31 20:28 ` [patch 16/29] knfsd: use client IPv4 address in reply cache hash Greg Banks
2009-05-11 21:48 ` J. Bruce Fields
2009-03-31 20:28 ` [patch 17/29] knfsd: make the reply cache SMP-friendly Greg Banks
2009-03-31 20:28 ` [patch 18/29] knfsd: dynamically expand the reply cache Greg Banks
2009-05-26 18:57 ` J. Bruce Fields
2009-05-26 19:04 ` J. Bruce Fields
2009-05-26 21:24 ` Rob Gardner
2009-05-26 21:52 ` J. Bruce Fields
2009-05-27 0:28 ` Greg Banks
2009-03-31 20:28 ` [patch 19/29] knfsd: faster probing in " Greg Banks
2009-03-31 20:28 ` [patch 20/29] knfsd: add extended reply cache stats Greg Banks
2009-03-31 20:28 ` [patch 21/29] knfsd: remove unreported filehandle stats counters Greg Banks
2009-05-12 20:00 ` J. Bruce Fields
2009-03-31 20:28 ` [patch 22/29] knfsd: make svc_authenticate() scale Greg Banks
2009-05-12 21:24 ` J. Bruce Fields
2009-03-31 20:28 ` [patch 23/29] knfsd: introduce SVC_INC_STAT Greg Banks
2009-03-31 20:28 ` [patch 24/29] knfsd: remove the program field from struct svc_stat Greg Banks
2009-03-31 20:28 ` [patch 25/29] knfsd: allocate svc_serv.sv_stats dynamically Greg Banks
2009-03-31 20:28 ` [patch 26/29] knfsd: make svc_serv.sv_stats per-CPU Greg Banks
2009-03-31 20:28 ` [patch 27/29] knfsd: move hot procedure count field out of svc_procedure Greg Banks
2009-03-31 20:28 ` [patch 28/29] knfsd: introduce NFSD_INC_STAT() Greg Banks
2009-03-31 20:28 ` [patch 29/29] knfsd: make nfsdstats per-CPU Greg Banks
2009-04-01 0:23 ` [patch 00/29] SGI enhancedNFS patches J. Bruce Fields
2009-04-01 3:32 ` Greg Banks
[not found] ` <ac442c870903312032t34630c6dvdbb644cb510f8079-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2009-04-01 6:34 ` Jeff Garzik
2009-04-01 6:41 ` Greg Banks
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090331202940.087008000@sgi.com \
--to=gnb@sgi.com \
--cc=bfields@fieldses.org \
--cc=linux-nfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).