Blame view

fs/nfsd/nfsctl.c 29.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
   * Syscall interface to knfsd.
   *
   * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
   */
5a0e3ad6a   Tejun Heo   include cleanup: ...
6
  #include <linux/slab.h>
3f8206d49   Al Viro   [PATCH] get rid o...
7
  #include <linux/namei.h>
b41b66d63   NeilBrown   [PATCH] knfsd: al...
8
  #include <linux/ctype.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9

80212d59e   NeilBrown   [PATCH] knfsd: de...
10
  #include <linux/sunrpc/svcsock.h>
4373ea84c   Wendy Cheng   lockd: unlock loc...
11
  #include <linux/lockd/lockd.h>
4116092b9   Chuck Lever   NFSD: Support IPv...
12
  #include <linux/sunrpc/clnt.h>
b0b0c0a26   Kevin Coffman   nfsd: add proc fi...
13
  #include <linux/sunrpc/gss_api.h>
b084f598d   J. Bruce Fields   nfsd: fix depende...
14
  #include <linux/sunrpc/gss_krb5_enctypes.h>
143cb494c   Paul Gortmaker   fs: add module.h ...
15
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16

2ca72e17e   J. Bruce Fields   nfsd4: move idmap...
17
  #include "idmap.h"
9a74af213   Boaz Harrosh   nfsd: Move privat...
18
19
  #include "nfsd.h"
  #include "cache.h"
65178db42   Bryan Schumaker   NFSD: Added fault...
20
  #include "fault_inject.h"
9a74af213   Boaz Harrosh   nfsd: Move privat...
21

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  /*
b0b0c0a26   Kevin Coffman   nfsd: add proc fi...
23
   *	We have a single directory with several nodes in it.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
   */
  enum {
  	NFSD_Root = 1,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
  	NFSD_List,
e8e8753f7   J. Bruce Fields   nfsd: new interfa...
28
  	NFSD_Export_features,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  	NFSD_Fh,
4373ea84c   Wendy Cheng   lockd: unlock loc...
30
  	NFSD_FO_UnlockIP,
17efa372c   Wendy Cheng   lockd: unlock loc...
31
  	NFSD_FO_UnlockFS,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  	NFSD_Threads,
eed2965af   Greg Banks   [PATCH] knfsd: al...
33
  	NFSD_Pool_Threads,
03cf6c9f4   Greg Banks   knfsd: add file t...
34
  	NFSD_Pool_Stats,
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
35
  	NFSD_Versions,
80212d59e   NeilBrown   [PATCH] knfsd: de...
36
  	NFSD_Ports,
596bbe53e   NeilBrown   [PATCH] knfsd: Al...
37
  	NFSD_MaxBlkSize,
b0b0c0a26   Kevin Coffman   nfsd: add proc fi...
38
  	NFSD_SupportedEnctypes,
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
39
40
41
42
43
  	/*
  	 * The below MUST come last.  Otherwise we leave a hole in nfsd_files[]
  	 * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
  	 */
  #ifdef CONFIG_NFSD_V4
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  	NFSD_Leasetime,
efc4bb4fd   J. Bruce Fields   nfsd4: allow sett...
45
  	NFSD_Gracetime,
0964a3d3f   NeilBrown   [PATCH] knfsd: nf...
46
  	NFSD_RecoveryDir,
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
47
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
51
52
  };
  
  /*
   * write() for these nodes.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
b046ccdc1   Chuck Lever   NFSD: clean up fa...
54
55
  static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
  static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  static ssize_t write_threads(struct file *file, char *buf, size_t size);
eed2965af   Greg Banks   [PATCH] knfsd: al...
57
  static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
58
  static ssize_t write_versions(struct file *file, char *buf, size_t size);
80212d59e   NeilBrown   [PATCH] knfsd: de...
59
  static ssize_t write_ports(struct file *file, char *buf, size_t size);
596bbe53e   NeilBrown   [PATCH] knfsd: Al...
60
  static ssize_t write_maxblksize(struct file *file, char *buf, size_t size);
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
61
  #ifdef CONFIG_NFSD_V4
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
efc4bb4fd   J. Bruce Fields   nfsd4: allow sett...
63
  static ssize_t write_gracetime(struct file *file, char *buf, size_t size);
0964a3d3f   NeilBrown   [PATCH] knfsd: nf...
64
  static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
65
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
  
  static ssize_t (*write_op[])(struct file *, char *, size_t) = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
  	[NFSD_Fh] = write_filehandle,
b046ccdc1   Chuck Lever   NFSD: clean up fa...
69
70
  	[NFSD_FO_UnlockIP] = write_unlock_ip,
  	[NFSD_FO_UnlockFS] = write_unlock_fs,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  	[NFSD_Threads] = write_threads,
eed2965af   Greg Banks   [PATCH] knfsd: al...
72
  	[NFSD_Pool_Threads] = write_pool_threads,
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
73
  	[NFSD_Versions] = write_versions,
80212d59e   NeilBrown   [PATCH] knfsd: de...
74
  	[NFSD_Ports] = write_ports,
596bbe53e   NeilBrown   [PATCH] knfsd: Al...
75
  	[NFSD_MaxBlkSize] = write_maxblksize,
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
76
  #ifdef CONFIG_NFSD_V4
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
  	[NFSD_Leasetime] = write_leasetime,
efc4bb4fd   J. Bruce Fields   nfsd4: allow sett...
78
  	[NFSD_Gracetime] = write_gracetime,
0964a3d3f   NeilBrown   [PATCH] knfsd: nf...
79
  	[NFSD_RecoveryDir] = write_recoverydir,
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
80
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
84
  };
  
  static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
  {
7eaa36e2d   Josef "Jeff" Sipek   [PATCH] nfsd: cha...
85
  	ino_t ino =  file->f_path.dentry->d_inode->i_ino;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
  	char *data;
  	ssize_t rv;
e8c96f8c2   Tobias Klauser   [PATCH] fs: Use A...
88
  	if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
91
92
93
94
95
  		return -EINVAL;
  
  	data = simple_transaction_get(file, buf, size);
  	if (IS_ERR(data))
  		return PTR_ERR(data);
  
  	rv =  write_op[ino](file, data, size);
8971a1016   NeilBrown   [PATCH] knfsd: fi...
96
  	if (rv >= 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
100
101
  		simple_transaction_set(file, rv);
  		rv = size;
  	}
  	return rv;
  }
7390022d6   NeilBrown   [PATCH] knfsd: Re...
102
103
104
105
106
107
108
109
110
111
112
113
114
  static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
  {
  	if (! file->private_data) {
  		/* An attempt to read a transaction file without writing
  		 * causes a 0-byte write so that the file can return
  		 * state information
  		 */
  		ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos);
  		if (rv < 0)
  			return rv;
  	}
  	return simple_transaction_read(file, buf, size, pos);
  }
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
115
  static const struct file_operations transaction_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
  	.write		= nfsctl_transaction_write,
7390022d6   NeilBrown   [PATCH] knfsd: Re...
117
  	.read		= nfsctl_transaction_read,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
  	.release	= simple_transaction_release,
6038f373a   Arnd Bergmann   llseek: automatic...
119
  	.llseek		= default_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
  static int exports_open(struct inode *inode, struct file *file)
  {
  	return seq_open(file, &nfs_exports_op);
  }
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
125
  static const struct file_operations exports_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
  	.open		= exports_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= seq_release,
9ef2db263   Denis V. Lunev   nfsd: use proc_cr...
130
  	.owner		= THIS_MODULE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  };
e8e8753f7   J. Bruce Fields   nfsd: new interfa...
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  static int export_features_show(struct seq_file *m, void *v)
  {
  	seq_printf(m, "0x%x 0x%x
  ", NFSEXP_ALLFLAGS, NFSEXP_SECINFO_FLAGS);
  	return 0;
  }
  
  static int export_features_open(struct inode *inode, struct file *file)
  {
  	return single_open(file, export_features_show, NULL);
  }
  
  static struct file_operations export_features_operations = {
  	.open		= export_features_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= single_release,
  };
b084f598d   J. Bruce Fields   nfsd: fix depende...
150
  #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
b0b0c0a26   Kevin Coffman   nfsd: add proc fi...
151
152
  static int supported_enctypes_show(struct seq_file *m, void *v)
  {
b084f598d   J. Bruce Fields   nfsd: fix depende...
153
  	seq_printf(m, KRB5_SUPPORTED_ENCTYPES);
b0b0c0a26   Kevin Coffman   nfsd: add proc fi...
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  	return 0;
  }
  
  static int supported_enctypes_open(struct inode *inode, struct file *file)
  {
  	return single_open(file, supported_enctypes_show, NULL);
  }
  
  static struct file_operations supported_enctypes_ops = {
  	.open		= supported_enctypes_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= single_release,
  };
b084f598d   J. Bruce Fields   nfsd: fix depende...
168
  #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
b0b0c0a26   Kevin Coffman   nfsd: add proc fi...
169

03cf6c9f4   Greg Banks   knfsd: add file t...
170
  extern int nfsd_pool_stats_open(struct inode *inode, struct file *file);
ed2d8aed5   Ryusei Yamaguchi   knfsd: Replace lo...
171
  extern int nfsd_pool_stats_release(struct inode *inode, struct file *file);
03cf6c9f4   Greg Banks   knfsd: add file t...
172

828c09509   Alexey Dobriyan   const: constify r...
173
  static const struct file_operations pool_stats_operations = {
03cf6c9f4   Greg Banks   knfsd: add file t...
174
175
176
  	.open		= nfsd_pool_stats_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
ed2d8aed5   Ryusei Yamaguchi   knfsd: Replace lo...
177
  	.release	= nfsd_pool_stats_release,
03cf6c9f4   Greg Banks   knfsd: add file t...
178
179
  	.owner		= THIS_MODULE,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
  /*----------------------------------------------------------------------------*/
  /*
   * payload - write methods
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184

262a09823   Chuck Lever   NFSD: Add documen...
185
186
187
188
189
190
191
192
  /**
   * write_unlock_ip - Release all locks used by a client
   *
   * Experimental.
   *
   * Input:
   *			buf:	'
  '-terminated C string containing a
4116092b9   Chuck Lever   NFSD: Support IPv...
193
   *				presentation format IP address
262a09823   Chuck Lever   NFSD: Add documen...
194
195
196
197
198
   *			size:	length of C string in @buf
   * Output:
   *	On success:	returns zero if all specified locks were released;
   *			returns one if one or more locks were not released
   *	On error:	return code is negative errno value
262a09823   Chuck Lever   NFSD: Add documen...
199
   */
b046ccdc1   Chuck Lever   NFSD: clean up fa...
200
  static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
4373ea84c   Wendy Cheng   lockd: unlock loc...
201
  {
4116092b9   Chuck Lever   NFSD: Support IPv...
202
203
204
  	struct sockaddr_storage address;
  	struct sockaddr *sap = (struct sockaddr *)&address;
  	size_t salen = sizeof(address);
367c8c7bd   Chuck Lever   lockd: Pass "stru...
205
  	char *fo_path;
4373ea84c   Wendy Cheng   lockd: unlock loc...
206
207
208
209
210
211
212
213
214
215
216
217
  
  	/* sanity check */
  	if (size == 0)
  		return -EINVAL;
  
  	if (buf[size-1] != '
  ')
  		return -EINVAL;
  
  	fo_path = buf;
  	if (qword_get(&buf, fo_path, size) < 0)
  		return -EINVAL;
4116092b9   Chuck Lever   NFSD: Support IPv...
218
  	if (rpc_pton(fo_path, size, sap, salen) == 0)
4373ea84c   Wendy Cheng   lockd: unlock loc...
219
  		return -EINVAL;
4373ea84c   Wendy Cheng   lockd: unlock loc...
220

4116092b9   Chuck Lever   NFSD: Support IPv...
221
  	return nlmsvc_unlock_all_by_ip(sap);
4373ea84c   Wendy Cheng   lockd: unlock loc...
222
  }
262a09823   Chuck Lever   NFSD: Add documen...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  /**
   * write_unlock_fs - Release all locks on a local file system
   *
   * Experimental.
   *
   * Input:
   *			buf:	'
  '-terminated C string containing the
   *				absolute pathname of a local file system
   *			size:	length of C string in @buf
   * Output:
   *	On success:	returns zero if all specified locks were released;
   *			returns one if one or more locks were not released
   *	On error:	return code is negative errno value
   */
b046ccdc1   Chuck Lever   NFSD: clean up fa...
238
  static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
17efa372c   Wendy Cheng   lockd: unlock loc...
239
  {
a63bb9966   Al Viro   [PATCH] switch nf...
240
  	struct path path;
17efa372c   Wendy Cheng   lockd: unlock loc...
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  	char *fo_path;
  	int error;
  
  	/* sanity check */
  	if (size == 0)
  		return -EINVAL;
  
  	if (buf[size-1] != '
  ')
  		return -EINVAL;
  
  	fo_path = buf;
  	if (qword_get(&buf, fo_path, size) < 0)
  		return -EINVAL;
a63bb9966   Al Viro   [PATCH] switch nf...
255
  	error = kern_path(fo_path, 0, &path);
17efa372c   Wendy Cheng   lockd: unlock loc...
256
257
  	if (error)
  		return error;
262a09823   Chuck Lever   NFSD: Add documen...
258
259
260
261
262
263
264
265
266
  	/*
  	 * XXX: Needs better sanity checking.  Otherwise we could end up
  	 * releasing locks on the wrong file system.
  	 *
  	 * For example:
  	 * 1.  Does the path refer to a directory?
  	 * 2.  Is that directory a mount point, or
  	 * 3.  Is that directory the root of an exported file system?
  	 */
d8c9584ea   Al Viro   vfs: prefer ->den...
267
  	error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb);
17efa372c   Wendy Cheng   lockd: unlock loc...
268

a63bb9966   Al Viro   [PATCH] switch nf...
269
  	path_put(&path);
17efa372c   Wendy Cheng   lockd: unlock loc...
270
271
  	return error;
  }
262a09823   Chuck Lever   NFSD: Add documen...
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
  /**
   * write_filehandle - Get a variable-length NFS file handle by path
   *
   * On input, the buffer contains a '
  '-terminated C string comprised of
   * three alphanumeric words separated by whitespace.  The string may
   * contain escape sequences.
   *
   * Input:
   *			buf:
   *				domain:		client domain name
   *				path:		export pathname
   *				maxsize:	numeric maximum size of
   *						@buf
   *			size:	length of C string in @buf
   * Output:
   *	On success:	passed-in buffer filled with '
  '-terminated C
   *			string containing a ASCII hex text version
   *			of the NFS file handle;
   *			return code is the size in bytes of the string
   *	On error:	return code is negative errno value
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
  static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
  	char *dname, *path;
246d95ba0   Andrew Morton   nfsd warning fix
298
  	int uninitialized_var(maxsize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
301
302
  	char *mesg = buf;
  	int len;
  	struct auth_domain *dom;
  	struct knfsd_fh fh;
87d26ea77   J. Bruce Fields   nfsd: more carefu...
303
304
  	if (size == 0)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
308
309
310
311
  	if (buf[size-1] != '
  ')
  		return -EINVAL;
  	buf[size-1] = 0;
  
  	dname = mesg;
  	len = qword_get(&mesg, dname, size);
54224f04a   Chuck Lever   NFSD: Fix a handf...
312
313
  	if (len <= 0)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
316
  	
  	path = dname+len+1;
  	len = qword_get(&mesg, path, size);
54224f04a   Chuck Lever   NFSD: Fix a handf...
317
318
  	if (len <= 0)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
  
  	len = get_int(&mesg, &maxsize);
  	if (len)
  		return len;
  
  	if (maxsize < NFS_FHSIZE)
  		return -EINVAL;
  	if (maxsize > NFS3_FHSIZE)
  		maxsize = NFS3_FHSIZE;
  
  	if (qword_get(&mesg, mesg, size)>0)
  		return -EINVAL;
  
  	/* we have all the words, they are in buf.. */
  	dom = unix_domain_find(dname);
  	if (!dom)
  		return -ENOMEM;
  
  	len = exp_rootfh(dom, path, &fh,  maxsize);
  	auth_domain_put(dom);
  	if (len)
  		return len;
  	
54224f04a   Chuck Lever   NFSD: Fix a handf...
342
343
  	mesg = buf;
  	len = SIMPLE_TRANSACTION_LIMIT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
  	qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size);
  	mesg[-1] = '
  ';
  	return mesg - buf;	
  }
262a09823   Chuck Lever   NFSD: Add documen...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  /**
   * write_threads - Start NFSD, or report the current number of running threads
   *
   * Input:
   *			buf:		ignored
   *			size:		zero
   * Output:
   *	On success:	passed-in buffer filled with '
  '-terminated C
   *			string numeric value representing the number of
   *			running NFSD threads;
   *			return code is the size in bytes of the string
   *	On error:	return code is zero
   *
   * OR
   *
   * Input:
   *			buf:		C string containing an unsigned
   *					integer value representing the
   *					number of NFSD threads to start
   *			size:		non-zero length of C string in @buf
   * Output:
   *	On success:	NFS service is started;
   *			passed-in buffer filled with '
  '-terminated C
   *			string numeric value representing the number of
   *			running NFSD threads;
   *			return code is the size in bytes of the string
   *	On error:	return code is zero or a negative errno value
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
  static ssize_t write_threads(struct file *file, char *buf, size_t size)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
384
385
386
387
  	char *mesg = buf;
  	int rv;
  	if (size > 0) {
  		int newthreads;
  		rv = get_int(&mesg, &newthreads);
  		if (rv)
  			return rv;
9e074856c   Chuck Lever   NFSD: Replace ope...
388
  		if (newthreads < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
  			return -EINVAL;
9e074856c   Chuck Lever   NFSD: Replace ope...
390
  		rv = nfsd_svc(NFS_PORT, newthreads);
82e12fe92   NeilBrown   nfsd: don't take ...
391
  		if (rv < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
  			return rv;
82e12fe92   NeilBrown   nfsd: don't take ...
393
394
  	} else
  		rv = nfsd_nrthreads();
e06b64050   Chuck Lever   NFSD: Stricter bu...
395

82e12fe92   NeilBrown   nfsd: don't take ...
396
397
  	return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d
  ", rv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  }
262a09823   Chuck Lever   NFSD: Add documen...
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
  /**
   * write_pool_threads - Set or report the current number of threads per pool
   *
   * Input:
   *			buf:		ignored
   *			size:		zero
   *
   * OR
   *
   * Input:
   * 			buf:		C string containing whitespace-
   * 					separated unsigned integer values
   *					representing the number of NFSD
   *					threads to start in each pool
   *			size:		non-zero length of C string in @buf
   * Output:
   *	On success:	passed-in buffer filled with '
  '-terminated C
   *			string containing integer values representing the
   *			number of NFSD threads in each pool;
   *			return code is the size in bytes of the string
   *	On error:	return code is zero or a negative errno value
   */
eed2965af   Greg Banks   [PATCH] knfsd: al...
422
423
424
425
426
427
428
429
430
  static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
  {
  	/* if size > 0, look for an array of number of threads per node
  	 * and apply them  then write out number of threads per node as reply
  	 */
  	char *mesg = buf;
  	int i;
  	int rv;
  	int len;
bedbdd8ba   Neil Brown   knfsd: Replace lo...
431
  	int npools;
eed2965af   Greg Banks   [PATCH] knfsd: al...
432
  	int *nthreads;
bedbdd8ba   Neil Brown   knfsd: Replace lo...
433
434
  	mutex_lock(&nfsd_mutex);
  	npools = nfsd_nrpools();
eed2965af   Greg Banks   [PATCH] knfsd: al...
435
436
437
438
439
440
  	if (npools == 0) {
  		/*
  		 * NFS is shut down.  The admin can start it by
  		 * writing to the threads file but NOT the pool_threads
  		 * file, sorry.  Report zero threads.
  		 */
bedbdd8ba   Neil Brown   knfsd: Replace lo...
441
  		mutex_unlock(&nfsd_mutex);
eed2965af   Greg Banks   [PATCH] knfsd: al...
442
443
444
445
446
447
  		strcpy(buf, "0
  ");
  		return strlen(buf);
  	}
  
  	nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL);
bedbdd8ba   Neil Brown   knfsd: Replace lo...
448
  	rv = -ENOMEM;
eed2965af   Greg Banks   [PATCH] knfsd: al...
449
  	if (nthreads == NULL)
bedbdd8ba   Neil Brown   knfsd: Replace lo...
450
  		goto out_free;
eed2965af   Greg Banks   [PATCH] knfsd: al...
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
  
  	if (size > 0) {
  		for (i = 0; i < npools; i++) {
  			rv = get_int(&mesg, &nthreads[i]);
  			if (rv == -ENOENT)
  				break;		/* fewer numbers than pools */
  			if (rv)
  				goto out_free;	/* syntax error */
  			rv = -EINVAL;
  			if (nthreads[i] < 0)
  				goto out_free;
  		}
  		rv = nfsd_set_nrthreads(i, nthreads);
  		if (rv)
  			goto out_free;
  	}
  
  	rv = nfsd_get_nrthreads(npools, nthreads);
  	if (rv)
  		goto out_free;
  
  	mesg = buf;
  	size = SIMPLE_TRANSACTION_LIMIT;
  	for (i = 0; i < npools && size > 0; i++) {
  		snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '
  ' : ' '));
  		len = strlen(mesg);
  		size -= len;
  		mesg += len;
  	}
413d63d71   J. Bruce Fields   nfsd: minor write...
481
  	rv = mesg - buf;
eed2965af   Greg Banks   [PATCH] knfsd: al...
482
483
  out_free:
  	kfree(nthreads);
bedbdd8ba   Neil Brown   knfsd: Replace lo...
484
  	mutex_unlock(&nfsd_mutex);
eed2965af   Greg Banks   [PATCH] knfsd: al...
485
486
  	return rv;
  }
3dd98a3bc   Jeff Layton   knfsd: clean up n...
487
  static ssize_t __write_versions(struct file *file, char *buf, size_t size)
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
488
  {
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
489
  	char *mesg = buf;
8daf220a6   Benny Halevy   nfsd41: control n...
490
  	char *vers, *minorp, sign;
261758b5c   Chuck Lever   NFSD: Stricter bu...
491
  	int len, num, remaining;
8daf220a6   Benny Halevy   nfsd41: control n...
492
  	unsigned minor;
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
493
494
495
496
497
  	ssize_t tlen = 0;
  	char *sep;
  
  	if (size>0) {
  		if (nfsd_serv)
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
498
499
500
501
  			/* Cannot change versions without updating
  			 * nfsd_serv->sv_xdrsize, and reallocing
  			 * rq_argp and rq_resp
  			 */
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
502
503
504
505
506
507
508
509
510
511
512
513
  			return -EBUSY;
  		if (buf[size-1] != '
  ')
  			return -EINVAL;
  		buf[size-1] = 0;
  
  		vers = mesg;
  		len = qword_get(&mesg, vers, size);
  		if (len <= 0) return -EINVAL;
  		do {
  			sign = *vers;
  			if (sign == '+' || sign == '-')
8daf220a6   Benny Halevy   nfsd41: control n...
514
  				num = simple_strtol((vers+1), &minorp, 0);
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
515
  			else
8daf220a6   Benny Halevy   nfsd41: control n...
516
517
518
519
520
521
522
523
524
525
526
527
  				num = simple_strtol(vers, &minorp, 0);
  			if (*minorp == '.') {
  				if (num < 4)
  					return -EINVAL;
  				minor = simple_strtoul(minorp+1, NULL, 0);
  				if (minor == 0)
  					return -EINVAL;
  				if (nfsd_minorversion(minor, sign == '-' ?
  						     NFSD_CLEAR : NFSD_SET) < 0)
  					return -EINVAL;
  				goto next;
  			}
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
528
529
530
531
  			switch(num) {
  			case 2:
  			case 3:
  			case 4:
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
532
  				nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET);
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
533
534
535
536
  				break;
  			default:
  				return -EINVAL;
  			}
8daf220a6   Benny Halevy   nfsd41: control n...
537
  		next:
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
538
  			vers += len + 1;
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
539
540
541
542
  		} while ((len = qword_get(&mesg, vers, size)) > 0);
  		/* If all get turned off, turn them back on, as
  		 * having no versions is BAD
  		 */
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
543
  		nfsd_reset_versions();
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
544
  	}
261758b5c   Chuck Lever   NFSD: Stricter bu...
545

70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
546
547
548
  	/* Now write current state into reply buffer */
  	len = 0;
  	sep = "";
261758b5c   Chuck Lever   NFSD: Stricter bu...
549
  	remaining = SIMPLE_TRANSACTION_LIMIT;
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
550
  	for (num=2 ; num <= 4 ; num++)
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
551
  		if (nfsd_vers(num, NFSD_AVAIL)) {
261758b5c   Chuck Lever   NFSD: Stricter bu...
552
  			len = snprintf(buf, remaining, "%s%c%d", sep,
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
553
  				       nfsd_vers(num, NFSD_TEST)?'+':'-',
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
554
555
  				       num);
  			sep = " ";
261758b5c   Chuck Lever   NFSD: Stricter bu...
556
557
558
559
560
561
  
  			if (len > remaining)
  				break;
  			remaining -= len;
  			buf += len;
  			tlen += len;
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
562
  		}
8daf220a6   Benny Halevy   nfsd41: control n...
563
  	if (nfsd_vers(4, NFSD_AVAIL))
261758b5c   Chuck Lever   NFSD: Stricter bu...
564
565
566
  		for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION;
  		     minor++) {
  			len = snprintf(buf, remaining, " %c4.%u",
8daf220a6   Benny Halevy   nfsd41: control n...
567
568
569
570
  					(nfsd_vers(4, NFSD_TEST) &&
  					 nfsd_minorversion(minor, NFSD_TEST)) ?
  						'+' : '-',
  					minor);
261758b5c   Chuck Lever   NFSD: Stricter bu...
571
572
573
574
575
576
577
578
579
580
581
582
583
  
  			if (len > remaining)
  				break;
  			remaining -= len;
  			buf += len;
  			tlen += len;
  		}
  
  	len = snprintf(buf, remaining, "
  ");
  	if (len > remaining)
  		return -EINVAL;
  	return tlen + len;
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
584
  }
262a09823   Chuck Lever   NFSD: Add documen...
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
  /**
   * write_versions - Set or report the available NFS protocol versions
   *
   * Input:
   *			buf:		ignored
   *			size:		zero
   * Output:
   *	On success:	passed-in buffer filled with '
  '-terminated C
   *			string containing positive or negative integer
   *			values representing the current status of each
   *			protocol version;
   *			return code is the size in bytes of the string
   *	On error:	return code is zero or a negative errno value
   *
   * OR
   *
   * Input:
   * 			buf:		C string containing whitespace-
   * 					separated positive or negative
   * 					integer values representing NFS
   * 					protocol versions to enable ("+n")
   * 					or disable ("-n")
   *			size:		non-zero length of C string in @buf
   * Output:
   *	On success:	status of zero or more protocol versions has
   *			been updated; passed-in buffer filled with
   *			'
  '-terminated C string containing positive
   *			or negative integer values representing the
   *			current status of each protocol version;
   *			return code is the size in bytes of the string
   *	On error:	return code is zero or a negative errno value
   */
3dd98a3bc   Jeff Layton   knfsd: clean up n...
619
620
621
622
623
624
625
626
627
  static ssize_t write_versions(struct file *file, char *buf, size_t size)
  {
  	ssize_t rv;
  
  	mutex_lock(&nfsd_mutex);
  	rv = __write_versions(file, buf, size);
  	mutex_unlock(&nfsd_mutex);
  	return rv;
  }
4cd5dc751   Chuck Lever   NFSD: Refactor tr...
628
  /*
0a5372d8a   Chuck Lever   NFSD: Finish refa...
629
630
631
632
633
634
635
   * Zero-length write.  Return a list of NFSD's current listener
   * transports.
   */
  static ssize_t __write_ports_names(char *buf)
  {
  	if (nfsd_serv == NULL)
  		return 0;
335c54bdc   Chuck Lever   NFSD: Prevent a b...
636
  	return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
0a5372d8a   Chuck Lever   NFSD: Finish refa...
637
638
639
  }
  
  /*
0b7c2f6fc   Chuck Lever   NFSD: Refactor so...
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
   * A single 'fd' number was written, in which case it must be for
   * a socket of a supported family/protocol, and we use it as an
   * nfsd listener.
   */
  static ssize_t __write_ports_addfd(char *buf)
  {
  	char *mesg = buf;
  	int fd, err;
  
  	err = get_int(&mesg, &fd);
  	if (err != 0 || fd < 0)
  		return -EINVAL;
  
  	err = nfsd_create_serv();
  	if (err != 0)
  		return err;
bfba9ab4c   Chuck Lever   SUNRPC: pass buff...
656
  	err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
78a8d7c8c   Jeff Layton   nfsd: fix error h...
657
  	if (err < 0) {
78a8d7c8c   Jeff Layton   nfsd: fix error h...
658
659
660
  		svc_destroy(nfsd_serv);
  		return err;
  	}
0b7c2f6fc   Chuck Lever   NFSD: Refactor so...
661

ea068bad2   Chuck Lever   NFSD: move lockd_...
662
663
664
  	/* Decrease the count, but don't shut down the service */
  	nfsd_serv->sv_nrthreads--;
  	return err;
0b7c2f6fc   Chuck Lever   NFSD: Refactor so...
665
666
667
  }
  
  /*
82d565919   Chuck Lever   NFSD: Refactor po...
668
669
670
671
672
673
674
675
676
677
678
679
   * A '-' followed by the 'name' of a socket means we close the socket.
   */
  static ssize_t __write_ports_delfd(char *buf)
  {
  	char *toclose;
  	int len = 0;
  
  	toclose = kstrdup(buf + 1, GFP_KERNEL);
  	if (toclose == NULL)
  		return -ENOMEM;
  
  	if (nfsd_serv != NULL)
8435d34db   Chuck Lever   SUNRPC: pass buff...
680
681
  		len = svc_sock_names(nfsd_serv, buf,
  					SIMPLE_TRANSACTION_LIMIT, toclose);
82d565919   Chuck Lever   NFSD: Refactor po...
682
683
684
685
686
  	kfree(toclose);
  	return len;
  }
  
  /*
4eb68c266   Chuck Lever   NFSD: Refactor tr...
687
688
689
690
691
692
   * A transport listener is added by writing it's transport name and
   * a port number.
   */
  static ssize_t __write_ports_addxprt(char *buf)
  {
  	char transport[16];
37498292a   Chuck Lever   NFSD: Create PF_I...
693
  	struct svc_xprt *xprt;
4eb68c266   Chuck Lever   NFSD: Refactor tr...
694
695
696
697
  	int port, err;
  
  	if (sscanf(buf, "%15s %4u", transport, &port) != 2)
  		return -EINVAL;
4be929be3   Alexey Dobriyan   kernel-wide: repl...
698
  	if (port < 1 || port > USHRT_MAX)
4eb68c266   Chuck Lever   NFSD: Refactor tr...
699
700
701
702
703
  		return -EINVAL;
  
  	err = nfsd_create_serv();
  	if (err != 0)
  		return err;
fc5d00b04   Pavel Emelyanov   sunrpc: Add net a...
704
  	err = svc_create_xprt(nfsd_serv, transport, &init_net,
4eb68c266   Chuck Lever   NFSD: Refactor tr...
705
  				PF_INET, port, SVC_SOCK_ANONYMOUS);
687179081   Chuck Lever   SUNRPC: NFS kerne...
706
  	if (err < 0)
37498292a   Chuck Lever   NFSD: Create PF_I...
707
  		goto out_err;
fc5d00b04   Pavel Emelyanov   sunrpc: Add net a...
708
  	err = svc_create_xprt(nfsd_serv, transport, &init_net,
37498292a   Chuck Lever   NFSD: Create PF_I...
709
710
711
  				PF_INET6, port, SVC_SOCK_ANONYMOUS);
  	if (err < 0 && err != -EAFNOSUPPORT)
  		goto out_close;
0cd14a061   Jeff Layton   nfsd: fix error h...
712
713
714
  
  	/* Decrease the count, but don't shut down the service */
  	nfsd_serv->sv_nrthreads--;
4eb68c266   Chuck Lever   NFSD: Refactor tr...
715
  	return 0;
37498292a   Chuck Lever   NFSD: Create PF_I...
716
717
718
719
720
721
722
  out_close:
  	xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port);
  	if (xprt != NULL) {
  		svc_close_xprt(xprt);
  		svc_xprt_put(xprt);
  	}
  out_err:
0cd14a061   Jeff Layton   nfsd: fix error h...
723
  	svc_destroy(nfsd_serv);
37498292a   Chuck Lever   NFSD: Create PF_I...
724
  	return err;
4eb68c266   Chuck Lever   NFSD: Refactor tr...
725
726
727
  }
  
  /*
4cd5dc751   Chuck Lever   NFSD: Refactor tr...
728
729
730
731
732
733
734
735
736
737
738
   * A transport listener is removed by writing a "-", it's transport
   * name, and it's port number.
   */
  static ssize_t __write_ports_delxprt(char *buf)
  {
  	struct svc_xprt *xprt;
  	char transport[16];
  	int port;
  
  	if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2)
  		return -EINVAL;
4be929be3   Alexey Dobriyan   kernel-wide: repl...
739
  	if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL)
4cd5dc751   Chuck Lever   NFSD: Refactor tr...
740
741
742
743
744
745
746
747
748
749
  		return -EINVAL;
  
  	xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port);
  	if (xprt == NULL)
  		return -ENOTCONN;
  
  	svc_close_xprt(xprt);
  	svc_xprt_put(xprt);
  	return 0;
  }
bedbdd8ba   Neil Brown   knfsd: Replace lo...
750
  static ssize_t __write_ports(struct file *file, char *buf, size_t size)
80212d59e   NeilBrown   [PATCH] knfsd: de...
751
  {
0a5372d8a   Chuck Lever   NFSD: Finish refa...
752
753
  	if (size == 0)
  		return __write_ports_names(buf);
0b7c2f6fc   Chuck Lever   NFSD: Refactor so...
754
755
756
  
  	if (isdigit(buf[0]))
  		return __write_ports_addfd(buf);
82d565919   Chuck Lever   NFSD: Refactor po...
757
758
759
  
  	if (buf[0] == '-' && isdigit(buf[1]))
  		return __write_ports_delfd(buf);
4eb68c266   Chuck Lever   NFSD: Refactor tr...
760
761
762
  
  	if (isalpha(buf[0]))
  		return __write_ports_addxprt(buf);
4cd5dc751   Chuck Lever   NFSD: Refactor tr...
763
764
765
  
  	if (buf[0] == '-' && isalpha(buf[1]))
  		return __write_ports_delxprt(buf);
b41b66d63   NeilBrown   [PATCH] knfsd: al...
766
  	return -EINVAL;
80212d59e   NeilBrown   [PATCH] knfsd: de...
767
  }
262a09823   Chuck Lever   NFSD: Add documen...
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
  /**
   * write_ports - Pass a socket file descriptor or transport name to listen on
   *
   * Input:
   *			buf:		ignored
   *			size:		zero
   * Output:
   *	On success:	passed-in buffer filled with a '
  '-terminated C
   *			string containing a whitespace-separated list of
   *			named NFSD listeners;
   *			return code is the size in bytes of the string
   *	On error:	return code is zero or a negative errno value
   *
   * OR
   *
   * Input:
   *			buf:		C string containing an unsigned
   *					integer value representing a bound
   *					but unconnected socket that is to be
c71206a7b   Chuck Lever   NFSD: Note an add...
788
789
790
   *					used as an NFSD listener; listen(3)
   *					must be called for a SOCK_STREAM
   *					socket, otherwise it is ignored
262a09823   Chuck Lever   NFSD: Add documen...
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
   *			size:		non-zero length of C string in @buf
   * Output:
   *	On success:	NFS service is started;
   *			passed-in buffer filled with a '
  '-terminated C
   *			string containing a unique alphanumeric name of
   *			the listener;
   *			return code is the size in bytes of the string
   *	On error:	return code is a negative errno value
   *
   * OR
   *
   * Input:
   *			buf:		C string containing a "-" followed
   *					by an integer value representing a
   *					previously passed in socket file
   *					descriptor
   *			size:		non-zero length of C string in @buf
   * Output:
   *	On success:	NFS service no longer listens on that socket;
   *			passed-in buffer filled with a '
  '-terminated C
   *			string containing a unique name of the listener;
   *			return code is the size in bytes of the string
   *	On error:	return code is a negative errno value
   *
   * OR
   *
   * Input:
   *			buf:		C string containing a transport
   *					name and an unsigned integer value
   *					representing the port to listen on,
   *					separated by whitespace
   *			size:		non-zero length of C string in @buf
   * Output:
   *	On success:	returns zero; NFS service is started
   *	On error:	return code is a negative errno value
   *
   * OR
   *
   * Input:
   *			buf:		C string containing a "-" followed
   *					by a transport name and an unsigned
   *					integer value representing the port
   *					to listen on, separated by whitespace
   *			size:		non-zero length of C string in @buf
   * Output:
   *	On success:	returns zero; NFS service no longer listens
   *			on that transport
   *	On error:	return code is a negative errno value
   */
bedbdd8ba   Neil Brown   knfsd: Replace lo...
842
843
844
  static ssize_t write_ports(struct file *file, char *buf, size_t size)
  {
  	ssize_t rv;
3dd98a3bc   Jeff Layton   knfsd: clean up n...
845

bedbdd8ba   Neil Brown   knfsd: Replace lo...
846
847
848
849
850
  	mutex_lock(&nfsd_mutex);
  	rv = __write_ports(file, buf, size);
  	mutex_unlock(&nfsd_mutex);
  	return rv;
  }
596bbe53e   NeilBrown   [PATCH] knfsd: Al...
851
  int nfsd_max_blksize;
262a09823   Chuck Lever   NFSD: Add documen...
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
  /**
   * write_maxblksize - Set or report the current NFS blksize
   *
   * Input:
   *			buf:		ignored
   *			size:		zero
   *
   * OR
   *
   * Input:
   * 			buf:		C string containing an unsigned
   * 					integer value representing the new
   * 					NFS blksize
   *			size:		non-zero length of C string in @buf
   * Output:
   *	On success:	passed-in buffer filled with '
  '-terminated C string
   *			containing numeric value of the current NFS blksize
   *			setting;
   *			return code is the size in bytes of the string
   *	On error:	return code is zero or a negative errno value
   */
596bbe53e   NeilBrown   [PATCH] knfsd: Al...
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
  static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
  {
  	char *mesg = buf;
  	if (size > 0) {
  		int bsize;
  		int rv = get_int(&mesg, &bsize);
  		if (rv)
  			return rv;
  		/* force bsize into allowed range and
  		 * required alignment.
  		 */
  		if (bsize < 1024)
  			bsize = 1024;
  		if (bsize > NFSSVC_MAXBLKSIZE)
  			bsize = NFSSVC_MAXBLKSIZE;
  		bsize &= ~(1024-1);
bedbdd8ba   Neil Brown   knfsd: Replace lo...
890
  		mutex_lock(&nfsd_mutex);
7fa53cc87   J. Bruce Fields   nfsd: don't allow...
891
  		if (nfsd_serv) {
bedbdd8ba   Neil Brown   knfsd: Replace lo...
892
  			mutex_unlock(&nfsd_mutex);
596bbe53e   NeilBrown   [PATCH] knfsd: Al...
893
894
895
  			return -EBUSY;
  		}
  		nfsd_max_blksize = bsize;
bedbdd8ba   Neil Brown   knfsd: Replace lo...
896
  		mutex_unlock(&nfsd_mutex);
596bbe53e   NeilBrown   [PATCH] knfsd: Al...
897
  	}
e06b64050   Chuck Lever   NFSD: Stricter bu...
898
899
900
901
  
  	return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d
  ",
  							nfsd_max_blksize);
596bbe53e   NeilBrown   [PATCH] knfsd: Al...
902
  }
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
903
  #ifdef CONFIG_NFSD_V4
f01357401   J. Bruce Fields   nfsd4: reshuffle ...
904
  static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
  	char *mesg = buf;
f01357401   J. Bruce Fields   nfsd4: reshuffle ...
907
  	int rv, i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
909
  
  	if (size > 0) {
3dd98a3bc   Jeff Layton   knfsd: clean up n...
910
911
  		if (nfsd_serv)
  			return -EBUSY;
f01357401   J. Bruce Fields   nfsd4: reshuffle ...
912
  		rv = get_int(&mesg, &i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913
914
  		if (rv)
  			return rv;
e7b184f19   J. Bruce Fields   nfsd4: document l...
915
916
917
918
919
920
921
922
923
924
925
926
  		/*
  		 * Some sanity checking.  We don't have a reason for
  		 * these particular numbers, but problems with the
  		 * extremes are:
  		 *	- Too short: the briefest network outage may
  		 *	  cause clients to lose all their locks.  Also,
  		 *	  the frequent polling may be wasteful.
  		 *	- Too long: do you really want reboot recovery
  		 *	  to take more than an hour?  Or to make other
  		 *	  clients wait an hour before being able to
  		 *	  revoke a dead client's locks?
  		 */
f01357401   J. Bruce Fields   nfsd4: reshuffle ...
927
  		if (i < 10 || i > 3600)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928
  			return -EINVAL;
f01357401   J. Bruce Fields   nfsd4: reshuffle ...
929
  		*time = i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930
  	}
e06b64050   Chuck Lever   NFSD: Stricter bu...
931

f01357401   J. Bruce Fields   nfsd4: reshuffle ...
932
933
934
935
936
937
938
939
940
941
942
943
  	return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld
  ", *time);
  }
  
  static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time)
  {
  	ssize_t rv;
  
  	mutex_lock(&nfsd_mutex);
  	rv = __nfsd4_write_time(file, buf, size, time);
  	mutex_unlock(&nfsd_mutex);
  	return rv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
  }
262a09823   Chuck Lever   NFSD: Add documen...
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
  /**
   * write_leasetime - Set or report the current NFSv4 lease time
   *
   * Input:
   *			buf:		ignored
   *			size:		zero
   *
   * OR
   *
   * Input:
   *			buf:		C string containing an unsigned
   *					integer value representing the new
   *					NFSv4 lease expiry time
   *			size:		non-zero length of C string in @buf
   * Output:
   *	On success:	passed-in buffer filled with '
  '-terminated C
   *			string containing unsigned integer value of the
   *			current lease expiry time;
   *			return code is the size in bytes of the string
   *	On error:	return code is zero or a negative errno value
   */
3dd98a3bc   Jeff Layton   knfsd: clean up n...
967
968
  static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
  {
f01357401   J. Bruce Fields   nfsd4: reshuffle ...
969
  	return nfsd4_write_time(file, buf, size, &nfsd4_lease);
3dd98a3bc   Jeff Layton   knfsd: clean up n...
970
  }
efc4bb4fd   J. Bruce Fields   nfsd4: allow sett...
971
972
973
974
975
976
977
978
979
980
981
982
983
984
  /**
   * write_gracetime - Set or report current NFSv4 grace period time
   *
   * As above, but sets the time of the NFSv4 grace period.
   *
   * Note this should never be set to less than the *previous*
   * lease-period time, but we don't try to enforce this.  (In the common
   * case (a new boot), we don't know what the previous lease time was
   * anyway.)
   */
  static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
  {
  	return nfsd4_write_time(file, buf, size, &nfsd4_grace);
  }
3dd98a3bc   Jeff Layton   knfsd: clean up n...
985
986
987
  extern char *nfs4_recoverydir(void);
  
  static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
0964a3d3f   NeilBrown   [PATCH] knfsd: nf...
988
989
990
991
  {
  	char *mesg = buf;
  	char *recdir;
  	int len, status;
3dd98a3bc   Jeff Layton   knfsd: clean up n...
992
993
994
995
996
997
998
  	if (size > 0) {
  		if (nfsd_serv)
  			return -EBUSY;
  		if (size > PATH_MAX || buf[size-1] != '
  ')
  			return -EINVAL;
  		buf[size-1] = 0;
0964a3d3f   NeilBrown   [PATCH] knfsd: nf...
999

3dd98a3bc   Jeff Layton   knfsd: clean up n...
1000
1001
1002
1003
  		recdir = mesg;
  		len = qword_get(&mesg, recdir, size);
  		if (len <= 0)
  			return -EINVAL;
0964a3d3f   NeilBrown   [PATCH] knfsd: nf...
1004

3dd98a3bc   Jeff Layton   knfsd: clean up n...
1005
  		status = nfs4_reset_recoverydir(recdir);
690499610   Andi Kleen   gcc-4.6: nfsd: fi...
1006
1007
  		if (status)
  			return status;
3dd98a3bc   Jeff Layton   knfsd: clean up n...
1008
  	}
3d72ab8fd   Chuck Lever   NFSD: Stricter bu...
1009
1010
1011
1012
  
  	return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s
  ",
  							nfs4_recoverydir());
0964a3d3f   NeilBrown   [PATCH] knfsd: nf...
1013
  }
3dd98a3bc   Jeff Layton   knfsd: clean up n...
1014

262a09823   Chuck Lever   NFSD: Add documen...
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
  /**
   * write_recoverydir - Set or report the pathname of the recovery directory
   *
   * Input:
   *			buf:		ignored
   *			size:		zero
   *
   * OR
   *
   * Input:
   *			buf:		C string containing the pathname
   *					of the directory on a local file
   *					system containing permanent NFSv4
   *					recovery data
   *			size:		non-zero length of C string in @buf
   * Output:
   *	On success:	passed-in buffer filled with '
  '-terminated C string
   *			containing the current recovery pathname setting;
   *			return code is the size in bytes of the string
   *	On error:	return code is zero or a negative errno value
   */
3dd98a3bc   Jeff Layton   knfsd: clean up n...
1037
1038
1039
1040
1041
1042
1043
1044
1045
  static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
  {
  	ssize_t rv;
  
  	mutex_lock(&nfsd_mutex);
  	rv = __write_recoverydir(file, buf, size);
  	mutex_unlock(&nfsd_mutex);
  	return rv;
  }
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
1046
  #endif
0964a3d3f   NeilBrown   [PATCH] knfsd: nf...
1047

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
1049
1050
1051
1052
1053
1054
1055
  /*----------------------------------------------------------------------------*/
  /*
   *	populating the filesystem.
   */
  
  static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
  {
  	static struct tree_descr nfsd_files[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1056
  		[NFSD_List] = {"exports", &exports_operations, S_IRUGO},
e8e8753f7   J. Bruce Fields   nfsd: new interfa...
1057
1058
  		[NFSD_Export_features] = {"export_features",
  					&export_features_operations, S_IRUGO},
4373ea84c   Wendy Cheng   lockd: unlock loc...
1059
1060
  		[NFSD_FO_UnlockIP] = {"unlock_ip",
  					&transaction_ops, S_IWUSR|S_IRUSR},
17efa372c   Wendy Cheng   lockd: unlock loc...
1061
1062
  		[NFSD_FO_UnlockFS] = {"unlock_filesystem",
  					&transaction_ops, S_IWUSR|S_IRUSR},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063
1064
  		[NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
  		[NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
eed2965af   Greg Banks   [PATCH] knfsd: al...
1065
  		[NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
03cf6c9f4   Greg Banks   knfsd: add file t...
1066
  		[NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO},
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
1067
  		[NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
80212d59e   NeilBrown   [PATCH] knfsd: de...
1068
  		[NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
596bbe53e   NeilBrown   [PATCH] knfsd: Al...
1069
  		[NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
b084f598d   J. Bruce Fields   nfsd: fix depende...
1070
  #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
b0b0c0a26   Kevin Coffman   nfsd: add proc fi...
1071
  		[NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO},
b084f598d   J. Bruce Fields   nfsd: fix depende...
1072
  #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
1074
  #ifdef CONFIG_NFSD_V4
  		[NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
efc4bb4fd   J. Bruce Fields   nfsd4: allow sett...
1075
  		[NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR},
0964a3d3f   NeilBrown   [PATCH] knfsd: nf...
1076
  		[NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
1078
1079
1080
1081
  #endif
  		/* last one */ {""}
  	};
  	return simple_fill_super(sb, 0x6e667364, nfsd_files);
  }
fc14f2fef   Al Viro   convert get_sb_si...
1082
1083
  static struct dentry *nfsd_mount(struct file_system_type *fs_type,
  	int flags, const char *dev_name, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1084
  {
fc14f2fef   Al Viro   convert get_sb_si...
1085
  	return mount_single(fs_type, flags, data, nfsd_fill_super);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1086
1087
1088
1089
1090
  }
  
  static struct file_system_type nfsd_fs_type = {
  	.owner		= THIS_MODULE,
  	.name		= "nfsd",
fc14f2fef   Al Viro   convert get_sb_si...
1091
  	.mount		= nfsd_mount,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
1093
  	.kill_sb	= kill_litter_super,
  };
e331f606a   J. Bruce Fields   nfsd: fail init o...
1094
1095
1096
1097
1098
1099
1100
1101
  #ifdef CONFIG_PROC_FS
  static int create_proc_exports_entry(void)
  {
  	struct proc_dir_entry *entry;
  
  	entry = proc_mkdir("fs/nfs", NULL);
  	if (!entry)
  		return -ENOMEM;
9ef2db263   Denis V. Lunev   nfsd: use proc_cr...
1102
  	entry = proc_create("exports", 0, entry, &exports_operations);
e331f606a   J. Bruce Fields   nfsd: fail init o...
1103
1104
  	if (!entry)
  		return -ENOMEM;
e331f606a   J. Bruce Fields   nfsd: fail init o...
1105
1106
1107
1108
1109
1110
1111
1112
  	return 0;
  }
  #else /* CONFIG_PROC_FS */
  static int create_proc_exports_entry(void)
  {
  	return 0;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113
1114
1115
1116
1117
  static int __init init_nfsd(void)
  {
  	int retval;
  	printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
  ");
720833960   Bryan Schumaker   NFSD: Call nfsd4_...
1118
  	retval = nfsd4_init_slabs();
e8ff2a845   J. Bruce Fields   knfsd: move nfsv4...
1119
1120
  	if (retval)
  		return retval;
720833960   Bryan Schumaker   NFSD: Call nfsd4_...
1121
  	nfs4_state_init();
65178db42   Bryan Schumaker   NFSD: Added fault...
1122
1123
1124
  	retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */
  	if (retval)
  		goto out_free_slabs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1125
  	nfsd_stat_init();	/* Statistics */
d5c3428b2   J. Bruce Fields   nfsd: fail module...
1126
1127
1128
  	retval = nfsd_reply_cache_init();
  	if (retval)
  		goto out_free_stat;
dbf847ecb   J. Bruce Fields   knfsd: allow cach...
1129
1130
1131
  	retval = nfsd_export_init();
  	if (retval)
  		goto out_free_cache;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132
  	nfsd_lockd_init();	/* lockd->nfsd callbacks */
dbf847ecb   J. Bruce Fields   knfsd: allow cach...
1133
1134
1135
  	retval = nfsd_idmap_init();
  	if (retval)
  		goto out_free_lockd;
e331f606a   J. Bruce Fields   nfsd: fail init o...
1136
1137
1138
  	retval = create_proc_exports_entry();
  	if (retval)
  		goto out_free_idmap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1139
  	retval = register_filesystem(&nfsd_fs_type);
26808d3f1   J. Bruce Fields   nfsd: cleanup nfs...
1140
1141
1142
1143
  	if (retval)
  		goto out_free_all;
  	return 0;
  out_free_all:
26808d3f1   J. Bruce Fields   nfsd: cleanup nfs...
1144
1145
  	remove_proc_entry("fs/nfs/exports", NULL);
  	remove_proc_entry("fs/nfs", NULL);
e331f606a   J. Bruce Fields   nfsd: fail init o...
1146
  out_free_idmap:
dbf847ecb   J. Bruce Fields   knfsd: allow cach...
1147
1148
  	nfsd_idmap_shutdown();
  out_free_lockd:
26808d3f1   J. Bruce Fields   nfsd: cleanup nfs...
1149
  	nfsd_lockd_shutdown();
e331f606a   J. Bruce Fields   nfsd: fail init o...
1150
  	nfsd_export_shutdown();
dbf847ecb   J. Bruce Fields   knfsd: allow cach...
1151
  out_free_cache:
e331f606a   J. Bruce Fields   nfsd: fail init o...
1152
  	nfsd_reply_cache_shutdown();
d5c3428b2   J. Bruce Fields   nfsd: fail module...
1153
1154
  out_free_stat:
  	nfsd_stat_shutdown();
65178db42   Bryan Schumaker   NFSD: Added fault...
1155
1156
  	nfsd_fault_inject_cleanup();
  out_free_slabs:
26808d3f1   J. Bruce Fields   nfsd: cleanup nfs...
1157
  	nfsd4_free_slabs();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158
1159
1160
1161
1162
1163
  	return retval;
  }
  
  static void __exit exit_nfsd(void)
  {
  	nfsd_export_shutdown();
d5c3428b2   J. Bruce Fields   nfsd: fail module...
1164
  	nfsd_reply_cache_shutdown();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
1166
1167
1168
  	remove_proc_entry("fs/nfs/exports", NULL);
  	remove_proc_entry("fs/nfs", NULL);
  	nfsd_stat_shutdown();
  	nfsd_lockd_shutdown();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1169
  	nfsd_idmap_shutdown();
e8ff2a845   J. Bruce Fields   knfsd: move nfsv4...
1170
  	nfsd4_free_slabs();
65178db42   Bryan Schumaker   NFSD: Added fault...
1171
  	nfsd_fault_inject_cleanup();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1172
1173
1174
1175
1176
1177
1178
  	unregister_filesystem(&nfsd_fs_type);
  }
  
  MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
  MODULE_LICENSE("GPL");
  module_init(init_nfsd)
  module_exit(exit_nfsd)