blob: 7f0fc8861b854e90dd814a4d6f8c4090041eed3f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * Syscall interface to knfsd.
3 *
4 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
5 */
6
Tejun Heo5a0e3ad2010-03-24 17:04:11 +09007#include <linux/slab.h>
Al Viro3f8206d2008-07-26 03:46:43 -04008#include <linux/namei.h>
NeilBrownb41b66d2006-10-02 02:17:48 -07009#include <linux/ctype.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/nfsd_idmap.h>
NeilBrown80212d52006-10-02 02:17:47 -070012#include <linux/sunrpc/svcsock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/nfsd/syscall.h>
Wendy Cheng4373ea82008-01-17 11:10:12 -050014#include <linux/lockd/lockd.h>
Chuck Lever41160922009-08-09 15:09:40 -040015#include <linux/sunrpc/clnt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
Boaz Harrosh9a74af22009-12-03 20:30:56 +020017#include "nfsd.h"
18#include "cache.h"
19
Linus Torvalds1da177e2005-04-16 15:20:36 -070020/*
21 * We have a single directory with 9 nodes in it.
22 */
23enum {
24 NFSD_Root = 1,
25 NFSD_Svc,
26 NFSD_Add,
27 NFSD_Del,
28 NFSD_Export,
29 NFSD_Unexport,
30 NFSD_Getfd,
31 NFSD_Getfs,
32 NFSD_List,
J. Bruce Fieldse8e87532009-12-14 12:53:32 -050033 NFSD_Export_features,
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 NFSD_Fh,
Wendy Cheng4373ea82008-01-17 11:10:12 -050035 NFSD_FO_UnlockIP,
Wendy Cheng17efa372008-01-17 11:10:12 -050036 NFSD_FO_UnlockFS,
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 NFSD_Threads,
Greg Bankseed29652006-10-02 02:18:02 -070038 NFSD_Pool_Threads,
Greg Banks03cf6c92009-01-13 21:26:36 +110039 NFSD_Pool_Stats,
NeilBrown70c3b762005-11-07 01:00:25 -080040 NFSD_Versions,
NeilBrown80212d52006-10-02 02:17:47 -070041 NFSD_Ports,
NeilBrown596bbe52006-10-04 02:15:48 -070042 NFSD_MaxBlkSize,
NeilBrown70c3b762005-11-07 01:00:25 -080043 /*
44 * The below MUST come last. Otherwise we leave a hole in nfsd_files[]
45 * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
46 */
47#ifdef CONFIG_NFSD_V4
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 NFSD_Leasetime,
J. Bruce Fieldsefc4bb42010-03-02 11:04:06 -050049 NFSD_Gracetime,
NeilBrown0964a3d2005-06-23 22:04:32 -070050 NFSD_RecoveryDir,
NeilBrown70c3b762005-11-07 01:00:25 -080051#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070052};
53
54/*
55 * write() for these nodes.
56 */
57static ssize_t write_svc(struct file *file, char *buf, size_t size);
58static ssize_t write_add(struct file *file, char *buf, size_t size);
59static ssize_t write_del(struct file *file, char *buf, size_t size);
60static ssize_t write_export(struct file *file, char *buf, size_t size);
61static ssize_t write_unexport(struct file *file, char *buf, size_t size);
62static ssize_t write_getfd(struct file *file, char *buf, size_t size);
63static ssize_t write_getfs(struct file *file, char *buf, size_t size);
64static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
Chuck Leverb046ccd2008-12-12 16:57:13 -050065static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
66static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067static ssize_t write_threads(struct file *file, char *buf, size_t size);
Greg Bankseed29652006-10-02 02:18:02 -070068static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
NeilBrown70c3b762005-11-07 01:00:25 -080069static ssize_t write_versions(struct file *file, char *buf, size_t size);
NeilBrown80212d52006-10-02 02:17:47 -070070static ssize_t write_ports(struct file *file, char *buf, size_t size);
NeilBrown596bbe52006-10-04 02:15:48 -070071static ssize_t write_maxblksize(struct file *file, char *buf, size_t size);
NeilBrown70c3b762005-11-07 01:00:25 -080072#ifdef CONFIG_NFSD_V4
Linus Torvalds1da177e2005-04-16 15:20:36 -070073static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
J. Bruce Fieldsefc4bb42010-03-02 11:04:06 -050074static ssize_t write_gracetime(struct file *file, char *buf, size_t size);
NeilBrown0964a3d2005-06-23 22:04:32 -070075static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
NeilBrown70c3b762005-11-07 01:00:25 -080076#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78static ssize_t (*write_op[])(struct file *, char *, size_t) = {
79 [NFSD_Svc] = write_svc,
80 [NFSD_Add] = write_add,
81 [NFSD_Del] = write_del,
82 [NFSD_Export] = write_export,
83 [NFSD_Unexport] = write_unexport,
84 [NFSD_Getfd] = write_getfd,
85 [NFSD_Getfs] = write_getfs,
86 [NFSD_Fh] = write_filehandle,
Chuck Leverb046ccd2008-12-12 16:57:13 -050087 [NFSD_FO_UnlockIP] = write_unlock_ip,
88 [NFSD_FO_UnlockFS] = write_unlock_fs,
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 [NFSD_Threads] = write_threads,
Greg Bankseed29652006-10-02 02:18:02 -070090 [NFSD_Pool_Threads] = write_pool_threads,
NeilBrown70c3b762005-11-07 01:00:25 -080091 [NFSD_Versions] = write_versions,
NeilBrown80212d52006-10-02 02:17:47 -070092 [NFSD_Ports] = write_ports,
NeilBrown596bbe52006-10-04 02:15:48 -070093 [NFSD_MaxBlkSize] = write_maxblksize,
NeilBrown70c3b762005-11-07 01:00:25 -080094#ifdef CONFIG_NFSD_V4
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 [NFSD_Leasetime] = write_leasetime,
J. Bruce Fieldsefc4bb42010-03-02 11:04:06 -050096 [NFSD_Gracetime] = write_gracetime,
NeilBrown0964a3d2005-06-23 22:04:32 -070097 [NFSD_RecoveryDir] = write_recoverydir,
NeilBrown70c3b762005-11-07 01:00:25 -080098#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070099};
100
101static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
102{
Josef "Jeff" Sipek7eaa36e2006-12-08 02:36:41 -0800103 ino_t ino = file->f_path.dentry->d_inode->i_ino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 char *data;
105 ssize_t rv;
106
Tobias Klausere8c96f82006-03-24 03:15:34 -0800107 if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 return -EINVAL;
109
110 data = simple_transaction_get(file, buf, size);
111 if (IS_ERR(data))
112 return PTR_ERR(data);
113
114 rv = write_op[ino](file, data, size);
NeilBrown8971a102007-02-14 00:33:11 -0800115 if (rv >= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 simple_transaction_set(file, rv);
117 rv = size;
118 }
119 return rv;
120}
121
NeilBrown73900222005-11-07 01:00:24 -0800122static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
123{
NeilBrownc67874f2010-09-22 12:55:07 +1000124 static int warned;
125 if (file->f_dentry->d_name.name[0] == '.' && !warned) {
126 char name[sizeof(current->comm)];
127 printk(KERN_INFO
128 "Warning: \"%s\" uses deprecated NFSD interface: %s."
129 " This will be removed in 2.6.40\n",
130 get_task_comm(name, current),
131 file->f_dentry->d_name.name);
132 warned = 1;
133 }
NeilBrown73900222005-11-07 01:00:24 -0800134 if (! file->private_data) {
135 /* An attempt to read a transaction file without writing
136 * causes a 0-byte write so that the file can return
137 * state information
138 */
139 ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos);
140 if (rv < 0)
141 return rv;
142 }
143 return simple_transaction_read(file, buf, size, pos);
144}
145
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800146static const struct file_operations transaction_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 .write = nfsctl_transaction_write,
NeilBrown73900222005-11-07 01:00:24 -0800148 .read = nfsctl_transaction_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 .release = simple_transaction_release,
150};
151
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static int exports_open(struct inode *inode, struct file *file)
153{
154 return seq_open(file, &nfs_exports_op);
155}
156
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800157static const struct file_operations exports_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 .open = exports_open,
159 .read = seq_read,
160 .llseek = seq_lseek,
161 .release = seq_release,
Denis V. Lunev9ef2db22008-04-29 01:02:04 -0700162 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163};
164
J. Bruce Fieldse8e87532009-12-14 12:53:32 -0500165static int export_features_show(struct seq_file *m, void *v)
166{
167 seq_printf(m, "0x%x 0x%x\n", NFSEXP_ALLFLAGS, NFSEXP_SECINFO_FLAGS);
168 return 0;
169}
170
171static int export_features_open(struct inode *inode, struct file *file)
172{
173 return single_open(file, export_features_show, NULL);
174}
175
176static struct file_operations export_features_operations = {
177 .open = export_features_open,
178 .read = seq_read,
179 .llseek = seq_lseek,
180 .release = single_release,
181};
182
Greg Banks03cf6c92009-01-13 21:26:36 +1100183extern int nfsd_pool_stats_open(struct inode *inode, struct file *file);
Ryusei Yamaguchied2d8ae2009-08-16 00:54:41 +0900184extern int nfsd_pool_stats_release(struct inode *inode, struct file *file);
Greg Banks03cf6c92009-01-13 21:26:36 +1100185
Alexey Dobriyan828c0952009-10-01 15:43:56 -0700186static const struct file_operations pool_stats_operations = {
Greg Banks03cf6c92009-01-13 21:26:36 +1100187 .open = nfsd_pool_stats_open,
188 .read = seq_read,
189 .llseek = seq_lseek,
Ryusei Yamaguchied2d8ae2009-08-16 00:54:41 +0900190 .release = nfsd_pool_stats_release,
Greg Banks03cf6c92009-01-13 21:26:36 +1100191 .owner = THIS_MODULE,
192};
193
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194/*----------------------------------------------------------------------------*/
195/*
196 * payload - write methods
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 */
198
Chuck Lever262a0982008-12-12 16:57:35 -0500199/**
200 * write_svc - Start kernel's NFSD server
201 *
202 * Deprecated. /proc/fs/nfsd/threads is preferred.
203 * Function remains to support old versions of nfs-utils.
204 *
205 * Input:
206 * buf: struct nfsctl_svc
207 * svc_port: port number of this
208 * server's listener
209 * svc_nthreads: number of threads to start
210 * size: size in bytes of passed in nfsctl_svc
211 * Output:
212 * On success: returns zero
213 * On error: return code is negative errno value
214 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215static ssize_t write_svc(struct file *file, char *buf, size_t size)
216{
217 struct nfsctl_svc *data;
NeilBrown82e12fe2009-06-16 11:03:07 +1000218 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 if (size < sizeof(*data))
220 return -EINVAL;
221 data = (struct nfsctl_svc*) buf;
NeilBrown82e12fe2009-06-16 11:03:07 +1000222 err = nfsd_svc(data->svc_port, data->svc_nthreads);
223 if (err < 0)
224 return err;
225 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226}
227
Chuck Lever262a0982008-12-12 16:57:35 -0500228/**
229 * write_add - Add or modify client entry in auth unix cache
230 *
231 * Deprecated. /proc/net/rpc/auth.unix.ip is preferred.
232 * Function remains to support old versions of nfs-utils.
233 *
234 * Input:
235 * buf: struct nfsctl_client
236 * cl_ident: '\0'-terminated C string
237 * containing domain name
238 * of client
239 * cl_naddr: no. of items in cl_addrlist
240 * cl_addrlist: array of client addresses
241 * cl_fhkeytype: ignored
242 * cl_fhkeylen: ignored
243 * cl_fhkey: ignored
244 * size: size in bytes of passed in nfsctl_client
245 * Output:
246 * On success: returns zero
247 * On error: return code is negative errno value
248 *
249 * Note: Only AF_INET client addresses are passed in, since
250 * nfsctl_client.cl_addrlist contains only in_addr fields for addresses.
251 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252static ssize_t write_add(struct file *file, char *buf, size_t size)
253{
254 struct nfsctl_client *data;
255 if (size < sizeof(*data))
256 return -EINVAL;
257 data = (struct nfsctl_client *)buf;
258 return exp_addclient(data);
259}
260
Chuck Lever262a0982008-12-12 16:57:35 -0500261/**
262 * write_del - Remove client from auth unix cache
263 *
264 * Deprecated. /proc/net/rpc/auth.unix.ip is preferred.
265 * Function remains to support old versions of nfs-utils.
266 *
267 * Input:
268 * buf: struct nfsctl_client
269 * cl_ident: '\0'-terminated C string
270 * containing domain name
271 * of client
272 * cl_naddr: ignored
273 * cl_addrlist: ignored
274 * cl_fhkeytype: ignored
275 * cl_fhkeylen: ignored
276 * cl_fhkey: ignored
277 * size: size in bytes of passed in nfsctl_client
278 * Output:
279 * On success: returns zero
280 * On error: return code is negative errno value
281 *
282 * Note: Only AF_INET client addresses are passed in, since
283 * nfsctl_client.cl_addrlist contains only in_addr fields for addresses.
284 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285static ssize_t write_del(struct file *file, char *buf, size_t size)
286{
287 struct nfsctl_client *data;
288 if (size < sizeof(*data))
289 return -EINVAL;
290 data = (struct nfsctl_client *)buf;
291 return exp_delclient(data);
292}
293
Chuck Lever262a0982008-12-12 16:57:35 -0500294/**
295 * write_export - Export part or all of a local file system
296 *
297 * Deprecated. /proc/net/rpc/{nfsd.export,nfsd.fh} are preferred.
298 * Function remains to support old versions of nfs-utils.
299 *
300 * Input:
301 * buf: struct nfsctl_export
302 * ex_client: '\0'-terminated C string
303 * containing domain name
304 * of client allowed to access
305 * this export
306 * ex_path: '\0'-terminated C string
307 * containing pathname of
308 * directory in local file system
309 * ex_dev: fsid to use for this export
310 * ex_ino: ignored
311 * ex_flags: export flags for this export
312 * ex_anon_uid: UID to use for anonymous
313 * requests
314 * ex_anon_gid: GID to use for anonymous
315 * requests
316 * size: size in bytes of passed in nfsctl_export
317 * Output:
318 * On success: returns zero
319 * On error: return code is negative errno value
320 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321static ssize_t write_export(struct file *file, char *buf, size_t size)
322{
323 struct nfsctl_export *data;
324 if (size < sizeof(*data))
325 return -EINVAL;
326 data = (struct nfsctl_export*)buf;
327 return exp_export(data);
328}
329
Chuck Lever262a0982008-12-12 16:57:35 -0500330/**
331 * write_unexport - Unexport a previously exported file system
332 *
333 * Deprecated. /proc/net/rpc/{nfsd.export,nfsd.fh} are preferred.
334 * Function remains to support old versions of nfs-utils.
335 *
336 * Input:
337 * buf: struct nfsctl_export
338 * ex_client: '\0'-terminated C string
339 * containing domain name
340 * of client no longer allowed
341 * to access this export
342 * ex_path: '\0'-terminated C string
343 * containing pathname of
344 * directory in local file system
345 * ex_dev: ignored
346 * ex_ino: ignored
347 * ex_flags: ignored
348 * ex_anon_uid: ignored
349 * ex_anon_gid: ignored
350 * size: size in bytes of passed in nfsctl_export
351 * Output:
352 * On success: returns zero
353 * On error: return code is negative errno value
354 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355static ssize_t write_unexport(struct file *file, char *buf, size_t size)
356{
357 struct nfsctl_export *data;
358
359 if (size < sizeof(*data))
360 return -EINVAL;
361 data = (struct nfsctl_export*)buf;
362 return exp_unexport(data);
363}
364
Chuck Lever262a0982008-12-12 16:57:35 -0500365/**
366 * write_getfs - Get a variable-length NFS file handle by path
367 *
368 * Deprecated. /proc/fs/nfsd/filehandle is preferred.
369 * Function remains to support old versions of nfs-utils.
370 *
371 * Input:
372 * buf: struct nfsctl_fsparm
373 * gd_addr: socket address of client
374 * gd_path: '\0'-terminated C string
375 * containing pathname of
376 * directory in local file system
377 * gd_maxlen: maximum size of returned file
378 * handle
379 * size: size in bytes of passed in nfsctl_fsparm
380 * Output:
381 * On success: passed-in buffer filled with a knfsd_fh structure
382 * (a variable-length raw NFS file handle);
383 * return code is the size in bytes of the file handle
384 * On error: return code is negative errno value
385 *
386 * Note: Only AF_INET client addresses are passed in, since gd_addr
387 * is the same size as a struct sockaddr_in.
388 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389static ssize_t write_getfs(struct file *file, char *buf, size_t size)
390{
391 struct nfsctl_fsparm *data;
392 struct sockaddr_in *sin;
393 struct auth_domain *clp;
394 int err = 0;
395 struct knfsd_fh *res;
Aurélien Charbonf15364b2008-01-18 15:50:56 +0100396 struct in6_addr in6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
398 if (size < sizeof(*data))
399 return -EINVAL;
400 data = (struct nfsctl_fsparm*)buf;
401 err = -EPROTONOSUPPORT;
402 if (data->gd_addr.sa_family != AF_INET)
403 goto out;
404 sin = (struct sockaddr_in *)&data->gd_addr;
405 if (data->gd_maxlen > NFS3_FHSIZE)
406 data->gd_maxlen = NFS3_FHSIZE;
407
408 res = (struct knfsd_fh*)buf;
409
410 exp_readlock();
Aurélien Charbonf15364b2008-01-18 15:50:56 +0100411
412 ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
413
414 clp = auth_unix_lookup(&in6);
415 if (!clp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 err = -EPERM;
417 else {
418 err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
419 auth_domain_put(clp);
420 }
421 exp_readunlock();
422 if (err == 0)
Andrew Morton12127492007-07-17 04:04:34 -0700423 err = res->fh_size + offsetof(struct knfsd_fh, fh_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 out:
425 return err;
426}
427
Chuck Lever262a0982008-12-12 16:57:35 -0500428/**
429 * write_getfd - Get a fixed-length NFS file handle by path (used by mountd)
430 *
431 * Deprecated. /proc/fs/nfsd/filehandle is preferred.
432 * Function remains to support old versions of nfs-utils.
433 *
434 * Input:
435 * buf: struct nfsctl_fdparm
436 * gd_addr: socket address of client
437 * gd_path: '\0'-terminated C string
438 * containing pathname of
439 * directory in local file system
440 * gd_version: fdparm structure version
441 * size: size in bytes of passed in nfsctl_fdparm
442 * Output:
443 * On success: passed-in buffer filled with nfsctl_res
444 * (a fixed-length raw NFS file handle);
445 * return code is the size in bytes of the file handle
446 * On error: return code is negative errno value
447 *
448 * Note: Only AF_INET client addresses are passed in, since gd_addr
449 * is the same size as a struct sockaddr_in.
450 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451static ssize_t write_getfd(struct file *file, char *buf, size_t size)
452{
453 struct nfsctl_fdparm *data;
454 struct sockaddr_in *sin;
455 struct auth_domain *clp;
456 int err = 0;
457 struct knfsd_fh fh;
458 char *res;
Aurélien Charbonf15364b2008-01-18 15:50:56 +0100459 struct in6_addr in6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
461 if (size < sizeof(*data))
462 return -EINVAL;
463 data = (struct nfsctl_fdparm*)buf;
464 err = -EPROTONOSUPPORT;
465 if (data->gd_addr.sa_family != AF_INET)
466 goto out;
467 err = -EINVAL;
468 if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
469 goto out;
470
471 res = buf;
472 sin = (struct sockaddr_in *)&data->gd_addr;
473 exp_readlock();
Aurélien Charbonf15364b2008-01-18 15:50:56 +0100474
475 ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
476
477 clp = auth_unix_lookup(&in6);
478 if (!clp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 err = -EPERM;
480 else {
481 err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
482 auth_domain_put(clp);
483 }
484 exp_readunlock();
485
486 if (err == 0) {
487 memset(res,0, NFS_FHSIZE);
488 memcpy(res, &fh.fh_base, fh.fh_size);
489 err = NFS_FHSIZE;
490 }
491 out:
492 return err;
493}
494
Chuck Lever262a0982008-12-12 16:57:35 -0500495/**
496 * write_unlock_ip - Release all locks used by a client
497 *
498 * Experimental.
499 *
500 * Input:
501 * buf: '\n'-terminated C string containing a
Chuck Lever41160922009-08-09 15:09:40 -0400502 * presentation format IP address
Chuck Lever262a0982008-12-12 16:57:35 -0500503 * size: length of C string in @buf
504 * Output:
505 * On success: returns zero if all specified locks were released;
506 * returns one if one or more locks were not released
507 * On error: return code is negative errno value
Chuck Lever262a0982008-12-12 16:57:35 -0500508 */
Chuck Leverb046ccd2008-12-12 16:57:13 -0500509static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
Wendy Cheng4373ea82008-01-17 11:10:12 -0500510{
Chuck Lever41160922009-08-09 15:09:40 -0400511 struct sockaddr_storage address;
512 struct sockaddr *sap = (struct sockaddr *)&address;
513 size_t salen = sizeof(address);
Chuck Lever367c8c72008-06-30 18:58:14 -0400514 char *fo_path;
Wendy Cheng4373ea82008-01-17 11:10:12 -0500515
516 /* sanity check */
517 if (size == 0)
518 return -EINVAL;
519
520 if (buf[size-1] != '\n')
521 return -EINVAL;
522
523 fo_path = buf;
524 if (qword_get(&buf, fo_path, size) < 0)
525 return -EINVAL;
526
Chuck Lever41160922009-08-09 15:09:40 -0400527 if (rpc_pton(fo_path, size, sap, salen) == 0)
Wendy Cheng4373ea82008-01-17 11:10:12 -0500528 return -EINVAL;
Wendy Cheng4373ea82008-01-17 11:10:12 -0500529
Chuck Lever41160922009-08-09 15:09:40 -0400530 return nlmsvc_unlock_all_by_ip(sap);
Wendy Cheng4373ea82008-01-17 11:10:12 -0500531}
532
Chuck Lever262a0982008-12-12 16:57:35 -0500533/**
534 * write_unlock_fs - Release all locks on a local file system
535 *
536 * Experimental.
537 *
538 * Input:
539 * buf: '\n'-terminated C string containing the
540 * absolute pathname of a local file system
541 * size: length of C string in @buf
542 * Output:
543 * On success: returns zero if all specified locks were released;
544 * returns one if one or more locks were not released
545 * On error: return code is negative errno value
546 */
Chuck Leverb046ccd2008-12-12 16:57:13 -0500547static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
Wendy Cheng17efa372008-01-17 11:10:12 -0500548{
Al Viroa63bb992008-08-02 01:03:36 -0400549 struct path path;
Wendy Cheng17efa372008-01-17 11:10:12 -0500550 char *fo_path;
551 int error;
552
553 /* sanity check */
554 if (size == 0)
555 return -EINVAL;
556
557 if (buf[size-1] != '\n')
558 return -EINVAL;
559
560 fo_path = buf;
561 if (qword_get(&buf, fo_path, size) < 0)
562 return -EINVAL;
563
Al Viroa63bb992008-08-02 01:03:36 -0400564 error = kern_path(fo_path, 0, &path);
Wendy Cheng17efa372008-01-17 11:10:12 -0500565 if (error)
566 return error;
567
Chuck Lever262a0982008-12-12 16:57:35 -0500568 /*
569 * XXX: Needs better sanity checking. Otherwise we could end up
570 * releasing locks on the wrong file system.
571 *
572 * For example:
573 * 1. Does the path refer to a directory?
574 * 2. Is that directory a mount point, or
575 * 3. Is that directory the root of an exported file system?
576 */
Al Viroa63bb992008-08-02 01:03:36 -0400577 error = nlmsvc_unlock_all_by_sb(path.mnt->mnt_sb);
Wendy Cheng17efa372008-01-17 11:10:12 -0500578
Al Viroa63bb992008-08-02 01:03:36 -0400579 path_put(&path);
Wendy Cheng17efa372008-01-17 11:10:12 -0500580 return error;
581}
582
Chuck Lever262a0982008-12-12 16:57:35 -0500583/**
584 * write_filehandle - Get a variable-length NFS file handle by path
585 *
586 * On input, the buffer contains a '\n'-terminated C string comprised of
587 * three alphanumeric words separated by whitespace. The string may
588 * contain escape sequences.
589 *
590 * Input:
591 * buf:
592 * domain: client domain name
593 * path: export pathname
594 * maxsize: numeric maximum size of
595 * @buf
596 * size: length of C string in @buf
597 * Output:
598 * On success: passed-in buffer filled with '\n'-terminated C
599 * string containing a ASCII hex text version
600 * of the NFS file handle;
601 * return code is the size in bytes of the string
602 * On error: return code is negative errno value
603 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
605{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 char *dname, *path;
Andrew Morton246d95b2007-08-09 00:53:50 -0700607 int uninitialized_var(maxsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 char *mesg = buf;
609 int len;
610 struct auth_domain *dom;
611 struct knfsd_fh fh;
612
J. Bruce Fields87d26ea2008-01-22 17:40:42 -0500613 if (size == 0)
614 return -EINVAL;
615
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 if (buf[size-1] != '\n')
617 return -EINVAL;
618 buf[size-1] = 0;
619
620 dname = mesg;
621 len = qword_get(&mesg, dname, size);
Chuck Lever54224f02008-12-12 16:57:20 -0500622 if (len <= 0)
623 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
625 path = dname+len+1;
626 len = qword_get(&mesg, path, size);
Chuck Lever54224f02008-12-12 16:57:20 -0500627 if (len <= 0)
628 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630 len = get_int(&mesg, &maxsize);
631 if (len)
632 return len;
633
634 if (maxsize < NFS_FHSIZE)
635 return -EINVAL;
636 if (maxsize > NFS3_FHSIZE)
637 maxsize = NFS3_FHSIZE;
638
639 if (qword_get(&mesg, mesg, size)>0)
640 return -EINVAL;
641
642 /* we have all the words, they are in buf.. */
643 dom = unix_domain_find(dname);
644 if (!dom)
645 return -ENOMEM;
646
647 len = exp_rootfh(dom, path, &fh, maxsize);
648 auth_domain_put(dom);
649 if (len)
650 return len;
651
Chuck Lever54224f02008-12-12 16:57:20 -0500652 mesg = buf;
653 len = SIMPLE_TRANSACTION_LIMIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size);
655 mesg[-1] = '\n';
656 return mesg - buf;
657}
658
Chuck Lever262a0982008-12-12 16:57:35 -0500659/**
660 * write_threads - Start NFSD, or report the current number of running threads
661 *
662 * Input:
663 * buf: ignored
664 * size: zero
665 * Output:
666 * On success: passed-in buffer filled with '\n'-terminated C
667 * string numeric value representing the number of
668 * running NFSD threads;
669 * return code is the size in bytes of the string
670 * On error: return code is zero
671 *
672 * OR
673 *
674 * Input:
675 * buf: C string containing an unsigned
676 * integer value representing the
677 * number of NFSD threads to start
678 * size: non-zero length of C string in @buf
679 * Output:
680 * On success: NFS service is started;
681 * passed-in buffer filled with '\n'-terminated C
682 * string numeric value representing the number of
683 * running NFSD threads;
684 * return code is the size in bytes of the string
685 * On error: return code is zero or a negative errno value
686 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687static ssize_t write_threads(struct file *file, char *buf, size_t size)
688{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 char *mesg = buf;
690 int rv;
691 if (size > 0) {
692 int newthreads;
693 rv = get_int(&mesg, &newthreads);
694 if (rv)
695 return rv;
Chuck Lever9e074852008-12-12 16:57:27 -0500696 if (newthreads < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 return -EINVAL;
Chuck Lever9e074852008-12-12 16:57:27 -0500698 rv = nfsd_svc(NFS_PORT, newthreads);
NeilBrown82e12fe2009-06-16 11:03:07 +1000699 if (rv < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 return rv;
NeilBrown82e12fe2009-06-16 11:03:07 +1000701 } else
702 rv = nfsd_nrthreads();
Chuck Levere06b6402009-04-23 19:33:25 -0400703
NeilBrown82e12fe2009-06-16 11:03:07 +1000704 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705}
706
Chuck Lever262a0982008-12-12 16:57:35 -0500707/**
708 * write_pool_threads - Set or report the current number of threads per pool
709 *
710 * Input:
711 * buf: ignored
712 * size: zero
713 *
714 * OR
715 *
716 * Input:
717 * buf: C string containing whitespace-
718 * separated unsigned integer values
719 * representing the number of NFSD
720 * threads to start in each pool
721 * size: non-zero length of C string in @buf
722 * Output:
723 * On success: passed-in buffer filled with '\n'-terminated C
724 * string containing integer values representing the
725 * number of NFSD threads in each pool;
726 * return code is the size in bytes of the string
727 * On error: return code is zero or a negative errno value
728 */
Greg Bankseed29652006-10-02 02:18:02 -0700729static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
730{
731 /* if size > 0, look for an array of number of threads per node
732 * and apply them then write out number of threads per node as reply
733 */
734 char *mesg = buf;
735 int i;
736 int rv;
737 int len;
Neil Brownbedbdd82008-06-10 08:40:35 -0400738 int npools;
Greg Bankseed29652006-10-02 02:18:02 -0700739 int *nthreads;
740
Neil Brownbedbdd82008-06-10 08:40:35 -0400741 mutex_lock(&nfsd_mutex);
742 npools = nfsd_nrpools();
Greg Bankseed29652006-10-02 02:18:02 -0700743 if (npools == 0) {
744 /*
745 * NFS is shut down. The admin can start it by
746 * writing to the threads file but NOT the pool_threads
747 * file, sorry. Report zero threads.
748 */
Neil Brownbedbdd82008-06-10 08:40:35 -0400749 mutex_unlock(&nfsd_mutex);
Greg Bankseed29652006-10-02 02:18:02 -0700750 strcpy(buf, "0\n");
751 return strlen(buf);
752 }
753
754 nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL);
Neil Brownbedbdd82008-06-10 08:40:35 -0400755 rv = -ENOMEM;
Greg Bankseed29652006-10-02 02:18:02 -0700756 if (nthreads == NULL)
Neil Brownbedbdd82008-06-10 08:40:35 -0400757 goto out_free;
Greg Bankseed29652006-10-02 02:18:02 -0700758
759 if (size > 0) {
760 for (i = 0; i < npools; i++) {
761 rv = get_int(&mesg, &nthreads[i]);
762 if (rv == -ENOENT)
763 break; /* fewer numbers than pools */
764 if (rv)
765 goto out_free; /* syntax error */
766 rv = -EINVAL;
767 if (nthreads[i] < 0)
768 goto out_free;
769 }
770 rv = nfsd_set_nrthreads(i, nthreads);
771 if (rv)
772 goto out_free;
773 }
774
775 rv = nfsd_get_nrthreads(npools, nthreads);
776 if (rv)
777 goto out_free;
778
779 mesg = buf;
780 size = SIMPLE_TRANSACTION_LIMIT;
781 for (i = 0; i < npools && size > 0; i++) {
782 snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' '));
783 len = strlen(mesg);
784 size -= len;
785 mesg += len;
786 }
J. Bruce Fields413d63d2009-07-28 11:37:25 -0400787 rv = mesg - buf;
Greg Bankseed29652006-10-02 02:18:02 -0700788out_free:
789 kfree(nthreads);
Neil Brownbedbdd82008-06-10 08:40:35 -0400790 mutex_unlock(&nfsd_mutex);
Greg Bankseed29652006-10-02 02:18:02 -0700791 return rv;
792}
793
Jeff Layton3dd98a32008-06-10 08:40:36 -0400794static ssize_t __write_versions(struct file *file, char *buf, size_t size)
NeilBrown70c3b762005-11-07 01:00:25 -0800795{
NeilBrown70c3b762005-11-07 01:00:25 -0800796 char *mesg = buf;
Benny Halevy8daf2202009-04-03 08:28:59 +0300797 char *vers, *minorp, sign;
Chuck Lever261758b2009-04-23 19:33:18 -0400798 int len, num, remaining;
Benny Halevy8daf2202009-04-03 08:28:59 +0300799 unsigned minor;
NeilBrown70c3b762005-11-07 01:00:25 -0800800 ssize_t tlen = 0;
801 char *sep;
802
803 if (size>0) {
804 if (nfsd_serv)
NeilBrown6658d3a2006-10-02 02:17:46 -0700805 /* Cannot change versions without updating
806 * nfsd_serv->sv_xdrsize, and reallocing
807 * rq_argp and rq_resp
808 */
NeilBrown70c3b762005-11-07 01:00:25 -0800809 return -EBUSY;
810 if (buf[size-1] != '\n')
811 return -EINVAL;
812 buf[size-1] = 0;
813
814 vers = mesg;
815 len = qword_get(&mesg, vers, size);
816 if (len <= 0) return -EINVAL;
817 do {
818 sign = *vers;
819 if (sign == '+' || sign == '-')
Benny Halevy8daf2202009-04-03 08:28:59 +0300820 num = simple_strtol((vers+1), &minorp, 0);
NeilBrown70c3b762005-11-07 01:00:25 -0800821 else
Benny Halevy8daf2202009-04-03 08:28:59 +0300822 num = simple_strtol(vers, &minorp, 0);
823 if (*minorp == '.') {
824 if (num < 4)
825 return -EINVAL;
826 minor = simple_strtoul(minorp+1, NULL, 0);
827 if (minor == 0)
828 return -EINVAL;
829 if (nfsd_minorversion(minor, sign == '-' ?
830 NFSD_CLEAR : NFSD_SET) < 0)
831 return -EINVAL;
832 goto next;
833 }
NeilBrown70c3b762005-11-07 01:00:25 -0800834 switch(num) {
835 case 2:
836 case 3:
837 case 4:
NeilBrown6658d3a2006-10-02 02:17:46 -0700838 nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET);
NeilBrown70c3b762005-11-07 01:00:25 -0800839 break;
840 default:
841 return -EINVAL;
842 }
Benny Halevy8daf2202009-04-03 08:28:59 +0300843 next:
NeilBrown70c3b762005-11-07 01:00:25 -0800844 vers += len + 1;
NeilBrown70c3b762005-11-07 01:00:25 -0800845 } while ((len = qword_get(&mesg, vers, size)) > 0);
846 /* If all get turned off, turn them back on, as
847 * having no versions is BAD
848 */
NeilBrown6658d3a2006-10-02 02:17:46 -0700849 nfsd_reset_versions();
NeilBrown70c3b762005-11-07 01:00:25 -0800850 }
Chuck Lever261758b2009-04-23 19:33:18 -0400851
NeilBrown70c3b762005-11-07 01:00:25 -0800852 /* Now write current state into reply buffer */
853 len = 0;
854 sep = "";
Chuck Lever261758b2009-04-23 19:33:18 -0400855 remaining = SIMPLE_TRANSACTION_LIMIT;
NeilBrown70c3b762005-11-07 01:00:25 -0800856 for (num=2 ; num <= 4 ; num++)
NeilBrown6658d3a2006-10-02 02:17:46 -0700857 if (nfsd_vers(num, NFSD_AVAIL)) {
Chuck Lever261758b2009-04-23 19:33:18 -0400858 len = snprintf(buf, remaining, "%s%c%d", sep,
NeilBrown6658d3a2006-10-02 02:17:46 -0700859 nfsd_vers(num, NFSD_TEST)?'+':'-',
NeilBrown70c3b762005-11-07 01:00:25 -0800860 num);
861 sep = " ";
Chuck Lever261758b2009-04-23 19:33:18 -0400862
863 if (len > remaining)
864 break;
865 remaining -= len;
866 buf += len;
867 tlen += len;
NeilBrown70c3b762005-11-07 01:00:25 -0800868 }
Benny Halevy8daf2202009-04-03 08:28:59 +0300869 if (nfsd_vers(4, NFSD_AVAIL))
Chuck Lever261758b2009-04-23 19:33:18 -0400870 for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION;
871 minor++) {
872 len = snprintf(buf, remaining, " %c4.%u",
Benny Halevy8daf2202009-04-03 08:28:59 +0300873 (nfsd_vers(4, NFSD_TEST) &&
874 nfsd_minorversion(minor, NFSD_TEST)) ?
875 '+' : '-',
876 minor);
Chuck Lever261758b2009-04-23 19:33:18 -0400877
878 if (len > remaining)
879 break;
880 remaining -= len;
881 buf += len;
882 tlen += len;
883 }
884
885 len = snprintf(buf, remaining, "\n");
886 if (len > remaining)
887 return -EINVAL;
888 return tlen + len;
NeilBrown70c3b762005-11-07 01:00:25 -0800889}
890
Chuck Lever262a0982008-12-12 16:57:35 -0500891/**
892 * write_versions - Set or report the available NFS protocol versions
893 *
894 * Input:
895 * buf: ignored
896 * size: zero
897 * Output:
898 * On success: passed-in buffer filled with '\n'-terminated C
899 * string containing positive or negative integer
900 * values representing the current status of each
901 * protocol version;
902 * return code is the size in bytes of the string
903 * On error: return code is zero or a negative errno value
904 *
905 * OR
906 *
907 * Input:
908 * buf: C string containing whitespace-
909 * separated positive or negative
910 * integer values representing NFS
911 * protocol versions to enable ("+n")
912 * or disable ("-n")
913 * size: non-zero length of C string in @buf
914 * Output:
915 * On success: status of zero or more protocol versions has
916 * been updated; passed-in buffer filled with
917 * '\n'-terminated C string containing positive
918 * or negative integer values representing the
919 * current status of each protocol version;
920 * return code is the size in bytes of the string
921 * On error: return code is zero or a negative errno value
922 */
Jeff Layton3dd98a32008-06-10 08:40:36 -0400923static ssize_t write_versions(struct file *file, char *buf, size_t size)
924{
925 ssize_t rv;
926
927 mutex_lock(&nfsd_mutex);
928 rv = __write_versions(file, buf, size);
929 mutex_unlock(&nfsd_mutex);
930 return rv;
931}
932
Chuck Lever4cd5dc72009-04-23 19:31:32 -0400933/*
Chuck Lever0a5372d2009-04-23 19:32:10 -0400934 * Zero-length write. Return a list of NFSD's current listener
935 * transports.
936 */
937static ssize_t __write_ports_names(char *buf)
938{
939 if (nfsd_serv == NULL)
940 return 0;
Chuck Lever335c54b2009-04-23 19:32:25 -0400941 return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
Chuck Lever0a5372d2009-04-23 19:32:10 -0400942}
943
944/*
Chuck Lever0b7c2f62009-04-23 19:31:55 -0400945 * A single 'fd' number was written, in which case it must be for
946 * a socket of a supported family/protocol, and we use it as an
947 * nfsd listener.
948 */
949static ssize_t __write_ports_addfd(char *buf)
950{
951 char *mesg = buf;
952 int fd, err;
953
954 err = get_int(&mesg, &fd);
955 if (err != 0 || fd < 0)
956 return -EINVAL;
957
958 err = nfsd_create_serv();
959 if (err != 0)
960 return err;
961
Chuck Leverbfba9ab2009-04-23 19:32:33 -0400962 err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
Jeff Layton78a8d7c2010-07-19 16:50:05 -0400963 if (err < 0) {
Jeff Layton78a8d7c2010-07-19 16:50:05 -0400964 svc_destroy(nfsd_serv);
965 return err;
966 }
Chuck Lever0b7c2f62009-04-23 19:31:55 -0400967
Chuck Leverea068ba2009-04-23 19:32:18 -0400968 /* Decrease the count, but don't shut down the service */
969 nfsd_serv->sv_nrthreads--;
970 return err;
Chuck Lever0b7c2f62009-04-23 19:31:55 -0400971}
972
973/*
Chuck Lever82d56592009-04-23 19:31:48 -0400974 * A '-' followed by the 'name' of a socket means we close the socket.
975 */
976static ssize_t __write_ports_delfd(char *buf)
977{
978 char *toclose;
979 int len = 0;
980
981 toclose = kstrdup(buf + 1, GFP_KERNEL);
982 if (toclose == NULL)
983 return -ENOMEM;
984
985 if (nfsd_serv != NULL)
Chuck Lever8435d342009-04-23 19:32:40 -0400986 len = svc_sock_names(nfsd_serv, buf,
987 SIMPLE_TRANSACTION_LIMIT, toclose);
Chuck Lever82d56592009-04-23 19:31:48 -0400988 kfree(toclose);
989 return len;
990}
991
992/*
Chuck Lever4eb68c22009-04-23 19:31:40 -0400993 * A transport listener is added by writing it's transport name and
994 * a port number.
995 */
996static ssize_t __write_ports_addxprt(char *buf)
997{
998 char transport[16];
Chuck Lever37498292010-01-26 14:04:22 -0500999 struct svc_xprt *xprt;
Chuck Lever4eb68c22009-04-23 19:31:40 -04001000 int port, err;
1001
1002 if (sscanf(buf, "%15s %4u", transport, &port) != 2)
1003 return -EINVAL;
1004
Alexey Dobriyan4be929b2010-05-24 14:33:03 -07001005 if (port < 1 || port > USHRT_MAX)
Chuck Lever4eb68c22009-04-23 19:31:40 -04001006 return -EINVAL;
1007
1008 err = nfsd_create_serv();
1009 if (err != 0)
1010 return err;
1011
1012 err = svc_create_xprt(nfsd_serv, transport,
1013 PF_INET, port, SVC_SOCK_ANONYMOUS);
Chuck Lever68717902010-01-26 14:04:13 -05001014 if (err < 0)
Chuck Lever37498292010-01-26 14:04:22 -05001015 goto out_err;
1016
1017 err = svc_create_xprt(nfsd_serv, transport,
1018 PF_INET6, port, SVC_SOCK_ANONYMOUS);
1019 if (err < 0 && err != -EAFNOSUPPORT)
1020 goto out_close;
Jeff Layton0cd14a062010-07-19 16:50:06 -04001021
1022 /* Decrease the count, but don't shut down the service */
1023 nfsd_serv->sv_nrthreads--;
Chuck Lever4eb68c22009-04-23 19:31:40 -04001024 return 0;
Chuck Lever37498292010-01-26 14:04:22 -05001025out_close:
1026 xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port);
1027 if (xprt != NULL) {
1028 svc_close_xprt(xprt);
1029 svc_xprt_put(xprt);
1030 }
1031out_err:
Jeff Layton0cd14a062010-07-19 16:50:06 -04001032 svc_destroy(nfsd_serv);
Chuck Lever37498292010-01-26 14:04:22 -05001033 return err;
Chuck Lever4eb68c22009-04-23 19:31:40 -04001034}
1035
1036/*
Chuck Lever4cd5dc72009-04-23 19:31:32 -04001037 * A transport listener is removed by writing a "-", it's transport
1038 * name, and it's port number.
1039 */
1040static ssize_t __write_ports_delxprt(char *buf)
1041{
1042 struct svc_xprt *xprt;
1043 char transport[16];
1044 int port;
1045
1046 if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2)
1047 return -EINVAL;
1048
Alexey Dobriyan4be929b2010-05-24 14:33:03 -07001049 if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL)
Chuck Lever4cd5dc72009-04-23 19:31:32 -04001050 return -EINVAL;
1051
1052 xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port);
1053 if (xprt == NULL)
1054 return -ENOTCONN;
1055
1056 svc_close_xprt(xprt);
1057 svc_xprt_put(xprt);
1058 return 0;
1059}
1060
Neil Brownbedbdd82008-06-10 08:40:35 -04001061static ssize_t __write_ports(struct file *file, char *buf, size_t size)
NeilBrown80212d52006-10-02 02:17:47 -07001062{
Chuck Lever0a5372d2009-04-23 19:32:10 -04001063 if (size == 0)
1064 return __write_ports_names(buf);
Chuck Lever0b7c2f62009-04-23 19:31:55 -04001065
1066 if (isdigit(buf[0]))
1067 return __write_ports_addfd(buf);
Chuck Lever82d56592009-04-23 19:31:48 -04001068
1069 if (buf[0] == '-' && isdigit(buf[1]))
1070 return __write_ports_delfd(buf);
Chuck Lever4eb68c22009-04-23 19:31:40 -04001071
1072 if (isalpha(buf[0]))
1073 return __write_ports_addxprt(buf);
Chuck Lever4cd5dc72009-04-23 19:31:32 -04001074
1075 if (buf[0] == '-' && isalpha(buf[1]))
1076 return __write_ports_delxprt(buf);
1077
NeilBrownb41b66d2006-10-02 02:17:48 -07001078 return -EINVAL;
NeilBrown80212d52006-10-02 02:17:47 -07001079}
1080
Chuck Lever262a0982008-12-12 16:57:35 -05001081/**
1082 * write_ports - Pass a socket file descriptor or transport name to listen on
1083 *
1084 * Input:
1085 * buf: ignored
1086 * size: zero
1087 * Output:
1088 * On success: passed-in buffer filled with a '\n'-terminated C
1089 * string containing a whitespace-separated list of
1090 * named NFSD listeners;
1091 * return code is the size in bytes of the string
1092 * On error: return code is zero or a negative errno value
1093 *
1094 * OR
1095 *
1096 * Input:
1097 * buf: C string containing an unsigned
1098 * integer value representing a bound
1099 * but unconnected socket that is to be
Chuck Leverc71206a2009-04-23 19:32:03 -04001100 * used as an NFSD listener; listen(3)
1101 * must be called for a SOCK_STREAM
1102 * socket, otherwise it is ignored
Chuck Lever262a0982008-12-12 16:57:35 -05001103 * size: non-zero length of C string in @buf
1104 * Output:
1105 * On success: NFS service is started;
1106 * passed-in buffer filled with a '\n'-terminated C
1107 * string containing a unique alphanumeric name of
1108 * the listener;
1109 * return code is the size in bytes of the string
1110 * On error: return code is a negative errno value
1111 *
1112 * OR
1113 *
1114 * Input:
1115 * buf: C string containing a "-" followed
1116 * by an integer value representing a
1117 * previously passed in socket file
1118 * descriptor
1119 * size: non-zero length of C string in @buf
1120 * Output:
1121 * On success: NFS service no longer listens on that socket;
1122 * passed-in buffer filled with a '\n'-terminated C
1123 * string containing a unique name of the listener;
1124 * return code is the size in bytes of the string
1125 * On error: return code is a negative errno value
1126 *
1127 * OR
1128 *
1129 * Input:
1130 * buf: C string containing a transport
1131 * name and an unsigned integer value
1132 * representing the port to listen on,
1133 * separated by whitespace
1134 * size: non-zero length of C string in @buf
1135 * Output:
1136 * On success: returns zero; NFS service is started
1137 * On error: return code is a negative errno value
1138 *
1139 * OR
1140 *
1141 * Input:
1142 * buf: C string containing a "-" followed
1143 * by a transport name and an unsigned
1144 * integer value representing the port
1145 * to listen on, separated by whitespace
1146 * size: non-zero length of C string in @buf
1147 * Output:
1148 * On success: returns zero; NFS service no longer listens
1149 * on that transport
1150 * On error: return code is a negative errno value
1151 */
Neil Brownbedbdd82008-06-10 08:40:35 -04001152static ssize_t write_ports(struct file *file, char *buf, size_t size)
1153{
1154 ssize_t rv;
Jeff Layton3dd98a32008-06-10 08:40:36 -04001155
Neil Brownbedbdd82008-06-10 08:40:35 -04001156 mutex_lock(&nfsd_mutex);
1157 rv = __write_ports(file, buf, size);
1158 mutex_unlock(&nfsd_mutex);
1159 return rv;
1160}
1161
1162
NeilBrown596bbe52006-10-04 02:15:48 -07001163int nfsd_max_blksize;
1164
Chuck Lever262a0982008-12-12 16:57:35 -05001165/**
1166 * write_maxblksize - Set or report the current NFS blksize
1167 *
1168 * Input:
1169 * buf: ignored
1170 * size: zero
1171 *
1172 * OR
1173 *
1174 * Input:
1175 * buf: C string containing an unsigned
1176 * integer value representing the new
1177 * NFS blksize
1178 * size: non-zero length of C string in @buf
1179 * Output:
1180 * On success: passed-in buffer filled with '\n'-terminated C string
1181 * containing numeric value of the current NFS blksize
1182 * setting;
1183 * return code is the size in bytes of the string
1184 * On error: return code is zero or a negative errno value
1185 */
NeilBrown596bbe52006-10-04 02:15:48 -07001186static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
1187{
1188 char *mesg = buf;
1189 if (size > 0) {
1190 int bsize;
1191 int rv = get_int(&mesg, &bsize);
1192 if (rv)
1193 return rv;
1194 /* force bsize into allowed range and
1195 * required alignment.
1196 */
1197 if (bsize < 1024)
1198 bsize = 1024;
1199 if (bsize > NFSSVC_MAXBLKSIZE)
1200 bsize = NFSSVC_MAXBLKSIZE;
1201 bsize &= ~(1024-1);
Neil Brownbedbdd82008-06-10 08:40:35 -04001202 mutex_lock(&nfsd_mutex);
J. Bruce Fields7fa53cc2010-08-06 18:00:33 -04001203 if (nfsd_serv) {
Neil Brownbedbdd82008-06-10 08:40:35 -04001204 mutex_unlock(&nfsd_mutex);
NeilBrown596bbe52006-10-04 02:15:48 -07001205 return -EBUSY;
1206 }
1207 nfsd_max_blksize = bsize;
Neil Brownbedbdd82008-06-10 08:40:35 -04001208 mutex_unlock(&nfsd_mutex);
NeilBrown596bbe52006-10-04 02:15:48 -07001209 }
Chuck Levere06b6402009-04-23 19:33:25 -04001210
1211 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n",
1212 nfsd_max_blksize);
NeilBrown596bbe52006-10-04 02:15:48 -07001213}
1214
NeilBrown70c3b762005-11-07 01:00:25 -08001215#ifdef CONFIG_NFSD_V4
J. Bruce Fieldsf0135742010-03-01 19:32:36 -05001216static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 char *mesg = buf;
J. Bruce Fieldsf0135742010-03-01 19:32:36 -05001219 int rv, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
1221 if (size > 0) {
Jeff Layton3dd98a32008-06-10 08:40:36 -04001222 if (nfsd_serv)
1223 return -EBUSY;
J. Bruce Fieldsf0135742010-03-01 19:32:36 -05001224 rv = get_int(&mesg, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 if (rv)
1226 return rv;
J. Bruce Fieldse7b184f2010-03-02 11:18:40 -05001227 /*
1228 * Some sanity checking. We don't have a reason for
1229 * these particular numbers, but problems with the
1230 * extremes are:
1231 * - Too short: the briefest network outage may
1232 * cause clients to lose all their locks. Also,
1233 * the frequent polling may be wasteful.
1234 * - Too long: do you really want reboot recovery
1235 * to take more than an hour? Or to make other
1236 * clients wait an hour before being able to
1237 * revoke a dead client's locks?
1238 */
J. Bruce Fieldsf0135742010-03-01 19:32:36 -05001239 if (i < 10 || i > 3600)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 return -EINVAL;
J. Bruce Fieldsf0135742010-03-01 19:32:36 -05001241 *time = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 }
Chuck Levere06b6402009-04-23 19:33:25 -04001243
J. Bruce Fieldsf0135742010-03-01 19:32:36 -05001244 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", *time);
1245}
1246
1247static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time)
1248{
1249 ssize_t rv;
1250
1251 mutex_lock(&nfsd_mutex);
1252 rv = __nfsd4_write_time(file, buf, size, time);
1253 mutex_unlock(&nfsd_mutex);
1254 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255}
1256
Chuck Lever262a0982008-12-12 16:57:35 -05001257/**
1258 * write_leasetime - Set or report the current NFSv4 lease time
1259 *
1260 * Input:
1261 * buf: ignored
1262 * size: zero
1263 *
1264 * OR
1265 *
1266 * Input:
1267 * buf: C string containing an unsigned
1268 * integer value representing the new
1269 * NFSv4 lease expiry time
1270 * size: non-zero length of C string in @buf
1271 * Output:
1272 * On success: passed-in buffer filled with '\n'-terminated C
1273 * string containing unsigned integer value of the
1274 * current lease expiry time;
1275 * return code is the size in bytes of the string
1276 * On error: return code is zero or a negative errno value
1277 */
Jeff Layton3dd98a32008-06-10 08:40:36 -04001278static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
1279{
J. Bruce Fieldsf0135742010-03-01 19:32:36 -05001280 return nfsd4_write_time(file, buf, size, &nfsd4_lease);
Jeff Layton3dd98a32008-06-10 08:40:36 -04001281}
1282
J. Bruce Fieldsefc4bb42010-03-02 11:04:06 -05001283/**
1284 * write_gracetime - Set or report current NFSv4 grace period time
1285 *
1286 * As above, but sets the time of the NFSv4 grace period.
1287 *
1288 * Note this should never be set to less than the *previous*
1289 * lease-period time, but we don't try to enforce this. (In the common
1290 * case (a new boot), we don't know what the previous lease time was
1291 * anyway.)
1292 */
1293static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
1294{
1295 return nfsd4_write_time(file, buf, size, &nfsd4_grace);
1296}
1297
Jeff Layton3dd98a32008-06-10 08:40:36 -04001298extern char *nfs4_recoverydir(void);
1299
1300static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
NeilBrown0964a3d2005-06-23 22:04:32 -07001301{
1302 char *mesg = buf;
1303 char *recdir;
1304 int len, status;
1305
Jeff Layton3dd98a32008-06-10 08:40:36 -04001306 if (size > 0) {
1307 if (nfsd_serv)
1308 return -EBUSY;
1309 if (size > PATH_MAX || buf[size-1] != '\n')
1310 return -EINVAL;
1311 buf[size-1] = 0;
NeilBrown0964a3d2005-06-23 22:04:32 -07001312
Jeff Layton3dd98a32008-06-10 08:40:36 -04001313 recdir = mesg;
1314 len = qword_get(&mesg, recdir, size);
1315 if (len <= 0)
1316 return -EINVAL;
NeilBrown0964a3d2005-06-23 22:04:32 -07001317
Jeff Layton3dd98a32008-06-10 08:40:36 -04001318 status = nfs4_reset_recoverydir(recdir);
Andi Kleen69049962010-07-20 15:24:27 -07001319 if (status)
1320 return status;
Jeff Layton3dd98a32008-06-10 08:40:36 -04001321 }
Chuck Lever3d72ab82009-04-23 19:33:10 -04001322
1323 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
1324 nfs4_recoverydir());
NeilBrown0964a3d2005-06-23 22:04:32 -07001325}
Jeff Layton3dd98a32008-06-10 08:40:36 -04001326
Chuck Lever262a0982008-12-12 16:57:35 -05001327/**
1328 * write_recoverydir - Set or report the pathname of the recovery directory
1329 *
1330 * Input:
1331 * buf: ignored
1332 * size: zero
1333 *
1334 * OR
1335 *
1336 * Input:
1337 * buf: C string containing the pathname
1338 * of the directory on a local file
1339 * system containing permanent NFSv4
1340 * recovery data
1341 * size: non-zero length of C string in @buf
1342 * Output:
1343 * On success: passed-in buffer filled with '\n'-terminated C string
1344 * containing the current recovery pathname setting;
1345 * return code is the size in bytes of the string
1346 * On error: return code is zero or a negative errno value
1347 */
Jeff Layton3dd98a32008-06-10 08:40:36 -04001348static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
1349{
1350 ssize_t rv;
1351
1352 mutex_lock(&nfsd_mutex);
1353 rv = __write_recoverydir(file, buf, size);
1354 mutex_unlock(&nfsd_mutex);
1355 return rv;
1356}
1357
NeilBrown70c3b762005-11-07 01:00:25 -08001358#endif
NeilBrown0964a3d2005-06-23 22:04:32 -07001359
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360/*----------------------------------------------------------------------------*/
1361/*
1362 * populating the filesystem.
1363 */
1364
1365static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
1366{
1367 static struct tree_descr nfsd_files[] = {
1368 [NFSD_Svc] = {".svc", &transaction_ops, S_IWUSR},
1369 [NFSD_Add] = {".add", &transaction_ops, S_IWUSR},
1370 [NFSD_Del] = {".del", &transaction_ops, S_IWUSR},
1371 [NFSD_Export] = {".export", &transaction_ops, S_IWUSR},
1372 [NFSD_Unexport] = {".unexport", &transaction_ops, S_IWUSR},
1373 [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR},
1374 [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR},
1375 [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
J. Bruce Fieldse8e87532009-12-14 12:53:32 -05001376 [NFSD_Export_features] = {"export_features",
1377 &export_features_operations, S_IRUGO},
Wendy Cheng4373ea82008-01-17 11:10:12 -05001378 [NFSD_FO_UnlockIP] = {"unlock_ip",
1379 &transaction_ops, S_IWUSR|S_IRUSR},
Wendy Cheng17efa372008-01-17 11:10:12 -05001380 [NFSD_FO_UnlockFS] = {"unlock_filesystem",
1381 &transaction_ops, S_IWUSR|S_IRUSR},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
1383 [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
Greg Bankseed29652006-10-02 02:18:02 -07001384 [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
Greg Banks03cf6c92009-01-13 21:26:36 +11001385 [NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO},
NeilBrown70c3b762005-11-07 01:00:25 -08001386 [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
NeilBrown80212d52006-10-02 02:17:47 -07001387 [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
NeilBrown596bbe52006-10-04 02:15:48 -07001388 [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389#ifdef CONFIG_NFSD_V4
1390 [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
J. Bruce Fieldsefc4bb42010-03-02 11:04:06 -05001391 [NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR},
NeilBrown0964a3d2005-06-23 22:04:32 -07001392 [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393#endif
1394 /* last one */ {""}
1395 };
1396 return simple_fill_super(sb, 0x6e667364, nfsd_files);
1397}
1398
David Howells454e2392006-06-23 02:02:57 -07001399static int nfsd_get_sb(struct file_system_type *fs_type,
1400 int flags, const char *dev_name, void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401{
David Howells454e2392006-06-23 02:02:57 -07001402 return get_sb_single(fs_type, flags, data, nfsd_fill_super, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403}
1404
1405static struct file_system_type nfsd_fs_type = {
1406 .owner = THIS_MODULE,
1407 .name = "nfsd",
1408 .get_sb = nfsd_get_sb,
1409 .kill_sb = kill_litter_super,
1410};
1411
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001412#ifdef CONFIG_PROC_FS
1413static int create_proc_exports_entry(void)
1414{
1415 struct proc_dir_entry *entry;
1416
1417 entry = proc_mkdir("fs/nfs", NULL);
1418 if (!entry)
1419 return -ENOMEM;
Denis V. Lunev9ef2db22008-04-29 01:02:04 -07001420 entry = proc_create("exports", 0, entry, &exports_operations);
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001421 if (!entry)
1422 return -ENOMEM;
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001423 return 0;
1424}
1425#else /* CONFIG_PROC_FS */
1426static int create_proc_exports_entry(void)
1427{
1428 return 0;
1429}
1430#endif
1431
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432static int __init init_nfsd(void)
1433{
1434 int retval;
1435 printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
1436
J. Bruce Fieldse8ff2a82007-08-01 15:30:59 -04001437 retval = nfs4_state_init(); /* nfs4 locking state */
1438 if (retval)
1439 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 nfsd_stat_init(); /* Statistics */
J. Bruce Fieldsd5c34282007-11-09 14:10:56 -05001441 retval = nfsd_reply_cache_init();
1442 if (retval)
1443 goto out_free_stat;
J. Bruce Fieldsdbf847e2007-11-08 17:20:34 -05001444 retval = nfsd_export_init();
1445 if (retval)
1446 goto out_free_cache;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 nfsd_lockd_init(); /* lockd->nfsd callbacks */
J. Bruce Fieldsdbf847e2007-11-08 17:20:34 -05001448 retval = nfsd_idmap_init();
1449 if (retval)
1450 goto out_free_lockd;
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001451 retval = create_proc_exports_entry();
1452 if (retval)
1453 goto out_free_idmap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 retval = register_filesystem(&nfsd_fs_type);
J. Bruce Fields26808d32007-11-09 13:44:06 -05001455 if (retval)
1456 goto out_free_all;
1457 return 0;
1458out_free_all:
J. Bruce Fields26808d32007-11-09 13:44:06 -05001459 remove_proc_entry("fs/nfs/exports", NULL);
1460 remove_proc_entry("fs/nfs", NULL);
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001461out_free_idmap:
J. Bruce Fieldsdbf847e2007-11-08 17:20:34 -05001462 nfsd_idmap_shutdown();
1463out_free_lockd:
J. Bruce Fields26808d32007-11-09 13:44:06 -05001464 nfsd_lockd_shutdown();
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001465 nfsd_export_shutdown();
J. Bruce Fieldsdbf847e2007-11-08 17:20:34 -05001466out_free_cache:
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001467 nfsd_reply_cache_shutdown();
J. Bruce Fieldsd5c34282007-11-09 14:10:56 -05001468out_free_stat:
1469 nfsd_stat_shutdown();
J. Bruce Fields26808d32007-11-09 13:44:06 -05001470 nfsd4_free_slabs();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 return retval;
1472}
1473
1474static void __exit exit_nfsd(void)
1475{
1476 nfsd_export_shutdown();
J. Bruce Fieldsd5c34282007-11-09 14:10:56 -05001477 nfsd_reply_cache_shutdown();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 remove_proc_entry("fs/nfs/exports", NULL);
1479 remove_proc_entry("fs/nfs", NULL);
1480 nfsd_stat_shutdown();
1481 nfsd_lockd_shutdown();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 nfsd_idmap_shutdown();
J. Bruce Fieldse8ff2a82007-08-01 15:30:59 -04001483 nfsd4_free_slabs();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 unregister_filesystem(&nfsd_fs_type);
1485}
1486
1487MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
1488MODULE_LICENSE("GPL");
1489module_init(init_nfsd)
1490module_exit(exit_nfsd)