1/*
2 * Sysctl operations for Coda filesystem
3 * Original version: (C) 1996 P. Braam and M. Callahan
4 * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
5 *
6 * Carnegie Mellon encourages users to contribute improvements to
7 * the Coda project. Contact Peter Braam (coda@cs.cmu.edu).
8 *
9 * CODA operation statistics
10 * (c) March, 1998 Zhanyong Wan <zhanyong.wan@yale.edu>
11 *
12 */
13
14#include <linux/time.h>
15#include <linux/mm.h>
16#include <linux/sysctl.h>
17#include <linux/proc_fs.h>
18#include <linux/seq_file.h>
19#include <linux/slab.h>
20#include <linux/stat.h>
21#include <linux/ctype.h>
22#include <linux/bitops.h>
23#include <asm/uaccess.h>
24#include <linux/utsname.h>
25#include <linux/module.h>
26
27#include <linux/coda.h>
28#include <linux/coda_linux.h>
29#include <linux/coda_fs_i.h>
30#include <linux/coda_psdev.h>
31#include <linux/coda_cache.h>
32#include <linux/coda_proc.h>
33
34static struct ctl_table_header *fs_table_header;
35
36#define CODA_TIMEOUT    3       /* timeout on upcalls to become intrble */
37#define CODA_HARD       5       /* mount type "hard" or "soft" */
38#define CODA_VFS 	 6       /* vfs statistics */
39#define CODA_CACHE_INV 	 9       /* cache invalidation statistics */
40#define CODA_FAKE_STATFS 10	 /* don't query venus for actual cache usage */
41
42struct coda_vfs_stats		coda_vfs_stat;
43static struct coda_cache_inv_stats	coda_cache_inv_stat;
44
45static void reset_coda_vfs_stats( void )
46{
47	memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) );
48}
49
50static void reset_coda_cache_inv_stats( void )
51{
52	memset( &coda_cache_inv_stat, 0, sizeof( coda_cache_inv_stat ) );
53}
54
55static int do_reset_coda_vfs_stats( ctl_table * table, int write,
56				    struct file * filp, void __user * buffer,
57				    size_t * lenp, loff_t * ppos )
58{
59	if ( write ) {
60		reset_coda_vfs_stats();
61
62		*ppos += *lenp;
63	} else {
64		*lenp = 0;
65	}
66
67	return 0;
68}
69
70static int do_reset_coda_cache_inv_stats( ctl_table * table, int write,
71					  struct file * filp,
72					  void __user * buffer,
73					  size_t * lenp, loff_t * ppos )
74{
75	if ( write ) {
76		reset_coda_cache_inv_stats();
77
78		*ppos += *lenp;
79	} else {
80		*lenp = 0;
81	}
82
83	return 0;
84}
85
86static int proc_vfs_stats_show(struct seq_file *m, void *v)
87{
88	struct coda_vfs_stats * ps = & coda_vfs_stat;
89
90	seq_printf(m,
91			"Coda VFS statistics\n"
92			"===================\n\n"
93			"File Operations:\n"
94			"\topen\t\t%9d\n"
95			"\tflush\t\t%9d\n"
96			"\trelease\t\t%9d\n"
97			"\tfsync\t\t%9d\n\n"
98			"Dir Operations:\n"
99			"\treaddir\t\t%9d\n\n"
100			"Inode Operations\n"
101			"\tcreate\t\t%9d\n"
102			"\tlookup\t\t%9d\n"
103			"\tlink\t\t%9d\n"
104			"\tunlink\t\t%9d\n"
105			"\tsymlink\t\t%9d\n"
106			"\tmkdir\t\t%9d\n"
107			"\trmdir\t\t%9d\n"
108			"\trename\t\t%9d\n"
109			"\tpermission\t%9d\n",
110
111			/* file operations */
112			ps->open,
113			ps->flush,
114			ps->release,
115			ps->fsync,
116
117			/* dir operations */
118			ps->readdir,
119
120			/* inode operations */
121			ps->create,
122			ps->lookup,
123			ps->link,
124			ps->unlink,
125			ps->symlink,
126			ps->mkdir,
127			ps->rmdir,
128			ps->rename,
129			ps->permission);
130	return 0;
131}
132
133static int proc_cache_inv_stats_show(struct seq_file *m, void *v)
134{
135	struct coda_cache_inv_stats * ps = & coda_cache_inv_stat;
136
137	seq_printf(m,
138			"Coda cache invalidation statistics\n"
139			"==================================\n\n"
140			"flush\t\t%9d\n"
141			"purge user\t%9d\n"
142			"zap_dir\t\t%9d\n"
143			"zap_file\t%9d\n"
144			"zap_vnode\t%9d\n"
145			"purge_fid\t%9d\n"
146			"replace\t\t%9d\n",
147			ps->flush,
148			ps->purge_user,
149			ps->zap_dir,
150			ps->zap_file,
151			ps->zap_vnode,
152			ps->purge_fid,
153			ps->replace );
154	return 0;
155}
156
157static int proc_vfs_stats_open(struct inode *inode, struct file *file)
158{
159	return single_open(file, proc_vfs_stats_show, NULL);
160}
161
162static int proc_cache_inv_stats_open(struct inode *inode, struct file *file)
163{
164	return single_open(file, proc_cache_inv_stats_show, NULL);
165}
166
167static const struct file_operations proc_vfs_stats_fops = {
168	.owner		= THIS_MODULE,
169	.open		= proc_vfs_stats_open,
170	.read		= seq_read,
171	.llseek		= seq_lseek,
172	.release	= single_release,
173};
174
175static const struct file_operations proc_cache_inv_stats_fops = {
176	.owner		= THIS_MODULE,
177	.open		= proc_cache_inv_stats_open,
178	.read		= seq_read,
179	.llseek		= seq_lseek,
180	.release	= single_release,
181};
182
183static ctl_table coda_table[] = {
184	{
185		.ctl_name	= CTL_UNNUMBERED,
186		.procname	= "timeout",
187		.data		= &coda_timeout,
188		.maxlen		= sizeof(int),
189		.mode		= 0644,
190		.proc_handler	= &proc_dointvec
191	},
192	{
193		.ctl_name	= CTL_UNNUMBERED,
194		.procname	= "hard",
195		.data		= &coda_hard,
196		.maxlen		= sizeof(int),
197		.mode		= 0644,
198		.proc_handler	= &proc_dointvec
199	},
200	{
201		.ctl_name	= CTL_UNNUMBERED,
202		.procname	= "vfs_stats",
203		.data		= NULL,
204		.maxlen		= 0,
205		.mode		= 0644,
206		.proc_handler	= &do_reset_coda_vfs_stats
207	},
208	{
209		.ctl_name	= CTL_UNNUMBERED,
210		.procname	= "cache_inv_stats",
211		.data		= NULL,
212		.maxlen		= 0,
213		.mode		= 0644,
214		.proc_handler	= &do_reset_coda_cache_inv_stats
215	},
216	{
217		.ctl_name	= CTL_UNNUMBERED,
218		.procname	= "fake_statfs",
219		.data		= &coda_fake_statfs,
220		.maxlen		= sizeof(int),
221		.mode		= 0600,
222		.proc_handler	= &proc_dointvec
223	},
224	{}
225};
226
227static ctl_table fs_table[] = {
228	{
229		.ctl_name	= CTL_UNNUMBERED,
230		.procname	= "coda",
231		.mode		= 0555,
232		.child		= coda_table
233	},
234	{}
235};
236
237
238#ifdef CONFIG_PROC_FS
239
240/*
241 target directory structure:
242   /proc/fs  (see linux/fs/proc/root.c)
243   /proc/fs/coda
244   /proc/fs/coda/{vfs_stats,
245
246*/
247
248static struct proc_dir_entry* proc_fs_coda;
249
250#endif
251
252void coda_sysctl_init(void)
253{
254	reset_coda_vfs_stats();
255	reset_coda_cache_inv_stats();
256
257#ifdef CONFIG_PROC_FS
258	proc_fs_coda = proc_mkdir("coda", proc_root_fs);
259	if (proc_fs_coda) {
260		struct proc_dir_entry *pde;
261
262		proc_fs_coda->owner = THIS_MODULE;
263		pde = create_proc_entry("vfs_stats", 0, proc_fs_coda);
264		if (pde)
265			pde->proc_fops = &proc_vfs_stats_fops;
266		pde = create_proc_entry("cache_inv_stats", 0, proc_fs_coda);
267		if (pde)
268			pde->proc_fops = &proc_cache_inv_stats_fops;
269	}
270#endif
271
272#ifdef CONFIG_SYSCTL
273	if ( !fs_table_header )
274		fs_table_header = register_sysctl_table(fs_table);
275#endif
276}
277
278void coda_sysctl_clean(void)
279{
280
281#ifdef CONFIG_SYSCTL
282	if ( fs_table_header ) {
283		unregister_sysctl_table(fs_table_header);
284		fs_table_header = NULL;
285	}
286#endif
287
288#ifdef CONFIG_PROC_FS
289        remove_proc_entry("cache_inv_stats", proc_fs_coda);
290        remove_proc_entry("vfs_stats", proc_fs_coda);
291	remove_proc_entry("coda", proc_root_fs);
292#endif
293}
294