File: /usr/src/linux/fs/nfsd/stats.c

1     /*
2      * linux/fs/nfsd/stats.c
3      *
4      * procfs-based user access to knfsd statistics
5      *
6      * /proc/net/rpc/nfsd
7      *
8      * Format:
9      *	rc <hits> <misses> <nocache>
10      *			Statistsics for the reply cache
11      *	fh <stale> <total-lookups> <anonlookups> <dir-not-in-dcache> <nondir-not-in-dcache>
12      *			statistics for filehandle lookup
13      *	io <bytes-read> <bytes-writtten>
14      *			statistics for IO throughput
15      *	th <threads> <fullcnt> <10%-20%> <20%-30%> ... <90%-100%> <100%> 
16      *			time (seconds) when nfsd thread usage above thresholds
17      *			and number of times that all threads were in use
18      *	ra cache-size  <10%  <20%  <30% ... <100% not-found
19      *			number of times that read-ahead entry was found that deep in
20      *			the cache.
21      *	plus generic RPC stats (see net/sunrpc/stats.c)
22      *
23      * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
24      */
25     
26     #include <linux/kernel.h>
27     #include <linux/sched.h>
28     #include <linux/proc_fs.h>
29     #include <linux/stat.h>
30     #define __NO_VERSION__
31     #include <linux/module.h>
32     
33     #include <linux/sunrpc/svc.h>
34     #include <linux/sunrpc/stats.h>
35     #include <linux/nfsd/nfsd.h>
36     #include <linux/nfsd/stats.h>
37     
38     struct nfsd_stats	nfsdstats;
39     struct svc_stat		nfsd_svcstats = { &nfsd_program, };
40     
41     static int
42     nfsd_proc_read(char *buffer, char **start, off_t offset, int count,
43     				int *eof, void *data)
44     {
45     	int	len;
46     	int	i;
47     
48     	len = sprintf(buffer, "rc %u %u %u\nfh %u %u %u %u %u\nio %u %u\n",
49     		      nfsdstats.rchits,
50     		      nfsdstats.rcmisses,
51     		      nfsdstats.rcnocache,
52     		      nfsdstats.fh_stale,
53     		      nfsdstats.fh_lookup,
54     		      nfsdstats.fh_anon,
55     		      nfsdstats.fh_nocache_dir,
56     		      nfsdstats.fh_nocache_nondir,
57     		      nfsdstats.io_read,
58     		      nfsdstats.io_write);
59     	/* thread usage: */
60     	len += sprintf(buffer+len, "th %u %u", nfsdstats.th_cnt, nfsdstats.th_fullcnt);
61     	for (i=0; i<10; i++) {
62     		unsigned int jifs = nfsdstats.th_usage[i];
63     		unsigned int sec = jifs / HZ, msec = (jifs % HZ)*1000/HZ;
64     		len += sprintf(buffer+len, " %u.%03u", sec, msec);
65     	}
66     
67     	/* newline and ra-cache */
68     	len += sprintf(buffer+len, "\nra %u", nfsdstats.ra_size);
69     	for (i=0; i<11; i++)
70     		len += sprintf(buffer+len, " %u", nfsdstats.ra_depth[i]);
71     	len += sprintf(buffer+len, "\n");
72     	
73     
74     	/* Assume we haven't hit EOF yet. Will be set by svc_proc_read. */
75     	*eof = 0;
76     
77     	/*
78     	 * Append generic nfsd RPC statistics if there's room for it.
79     	 */
80     	if (len <= offset) {
81     		len = svc_proc_read(buffer, start, offset - len, count,
82     				    eof, data);
83     		return len;
84     	}
85     
86     	if (len < count) {
87     		len += svc_proc_read(buffer + len, start, 0, count - len,
88     				     eof, data);
89     	}
90     
91     	if (offset >= len) {
92     		*start = buffer;
93     		return 0;
94     	}
95     
96     	*start = buffer + offset;
97     	if ((len -= offset) > count)
98     		return count;
99     	return len;
100     }
101     
102     void
103     nfsd_stat_init(void)
104     {
105     	struct proc_dir_entry	*ent;
106     
107     	if ((ent = svc_proc_register(&nfsd_svcstats)) != 0) {
108     		ent->read_proc = nfsd_proc_read;
109     		ent->owner = THIS_MODULE;
110     	}
111     }
112     
113     void
114     nfsd_stat_shutdown(void)
115     {
116     	svc_proc_unregister("nfsd");
117     }
118