linux-nfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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

  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).