blob: 35dcfa8eba2193a6448e3946ae84283b0deec766 [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
NeilBrown80212d52006-10-02 02:17:47 -070011#include <linux/sunrpc/svcsock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/nfsd/syscall.h>
Wendy Cheng4373ea82008-01-17 11:10:12 -050013#include <linux/lockd/lockd.h>
Chuck Lever41160922009-08-09 15:09:40 -040014#include <linux/sunrpc/clnt.h>
Kevin Coffmanb0b0c0a2011-03-02 19:51:42 -050015#include <linux/sunrpc/gss_api.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
J. Bruce Fields2ca72e12011-01-04 17:37:15 -050017#include "idmap.h"
Boaz Harrosh9a74af22009-12-03 20:30:56 +020018#include "nfsd.h"
19#include "cache.h"
20
Linus Torvalds1da177e2005-04-16 15:20:36 -070021/*
Kevin Coffmanb0b0c0a2011-03-02 19:51:42 -050022 * We have a single directory with several nodes in it.
Linus Torvalds1da177e2005-04-16 15:20:36 -070023 */
24enum {
25 NFSD_Root = 1,
NeilBrown1e140562010-09-22 12:55:07 +100026#ifdef CONFIG_NFSD_DEPRECATED
Linus Torvalds1da177e2005-04-16 15:20:36 -070027 NFSD_Svc,
28 NFSD_Add,
29 NFSD_Del,
30 NFSD_Export,
31 NFSD_Unexport,
32 NFSD_Getfd,
33 NFSD_Getfs,
NeilBrown1e140562010-09-22 12:55:07 +100034#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 NFSD_List,
J. Bruce Fieldse8e87532009-12-14 12:53:32 -050036 NFSD_Export_features,
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 NFSD_Fh,
Wendy Cheng4373ea82008-01-17 11:10:12 -050038 NFSD_FO_UnlockIP,
Wendy Cheng17efa372008-01-17 11:10:12 -050039 NFSD_FO_UnlockFS,
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 NFSD_Threads,
Greg Bankseed29652006-10-02 02:18:02 -070041 NFSD_Pool_Threads,
Greg Banks03cf6c92009-01-13 21:26:36 +110042 NFSD_Pool_Stats,
NeilBrown70c3b762005-11-07 01:00:25 -080043 NFSD_Versions,
NeilBrown80212d52006-10-02 02:17:47 -070044 NFSD_Ports,
NeilBrown596bbe52006-10-04 02:15:48 -070045 NFSD_MaxBlkSize,
Kevin Coffmanb0b0c0a2011-03-02 19:51:42 -050046 NFSD_SupportedEnctypes,
NeilBrown70c3b762005-11-07 01:00:25 -080047 /*
48 * The below MUST come last. Otherwise we leave a hole in nfsd_files[]
49 * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
50 */
51#ifdef CONFIG_NFSD_V4
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 NFSD_Leasetime,
J. Bruce Fieldsefc4bb4f2010-03-02 11:04:06 -050053 NFSD_Gracetime,
NeilBrown0964a3d2005-06-23 22:04:32 -070054 NFSD_RecoveryDir,
NeilBrown70c3b762005-11-07 01:00:25 -080055#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070056};
57
58/*
59 * write() for these nodes.
60 */
NeilBrown1e140562010-09-22 12:55:07 +100061#ifdef CONFIG_NFSD_DEPRECATED
Linus Torvalds1da177e2005-04-16 15:20:36 -070062static ssize_t write_svc(struct file *file, char *buf, size_t size);
63static ssize_t write_add(struct file *file, char *buf, size_t size);
64static ssize_t write_del(struct file *file, char *buf, size_t size);
65static ssize_t write_export(struct file *file, char *buf, size_t size);
66static ssize_t write_unexport(struct file *file, char *buf, size_t size);
67static ssize_t write_getfd(struct file *file, char *buf, size_t size);
68static ssize_t write_getfs(struct file *file, char *buf, size_t size);
NeilBrown1e140562010-09-22 12:55:07 +100069#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070070static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
Chuck Leverb046ccd2008-12-12 16:57:13 -050071static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
72static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073static ssize_t write_threads(struct file *file, char *buf, size_t size);
Greg Bankseed29652006-10-02 02:18:02 -070074static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
NeilBrown70c3b762005-11-07 01:00:25 -080075static ssize_t write_versions(struct file *file, char *buf, size_t size);
NeilBrown80212d52006-10-02 02:17:47 -070076static ssize_t write_ports(struct file *file, char *buf, size_t size);
NeilBrown596bbe52006-10-04 02:15:48 -070077static ssize_t write_maxblksize(struct file *file, char *buf, size_t size);
NeilBrown70c3b762005-11-07 01:00:25 -080078#ifdef CONFIG_NFSD_V4
Linus Torvalds1da177e2005-04-16 15:20:36 -070079static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
J. Bruce Fieldsefc4bb4f2010-03-02 11:04:06 -050080static ssize_t write_gracetime(struct file *file, char *buf, size_t size);
NeilBrown0964a3d2005-06-23 22:04:32 -070081static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
NeilBrown70c3b762005-11-07 01:00:25 -080082#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84static ssize_t (*write_op[])(struct file *, char *, size_t) = {
NeilBrown1e140562010-09-22 12:55:07 +100085#ifdef CONFIG_NFSD_DEPRECATED
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 [NFSD_Svc] = write_svc,
87 [NFSD_Add] = write_add,
88 [NFSD_Del] = write_del,
89 [NFSD_Export] = write_export,
90 [NFSD_Unexport] = write_unexport,
91 [NFSD_Getfd] = write_getfd,
92 [NFSD_Getfs] = write_getfs,
NeilBrown1e140562010-09-22 12:55:07 +100093#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 [NFSD_Fh] = write_filehandle,
Chuck Leverb046ccd2008-12-12 16:57:13 -050095 [NFSD_FO_UnlockIP] = write_unlock_ip,
96 [NFSD_FO_UnlockFS] = write_unlock_fs,
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 [NFSD_Threads] = write_threads,
Greg Bankseed29652006-10-02 02:18:02 -070098 [NFSD_Pool_Threads] = write_pool_threads,
NeilBrown70c3b762005-11-07 01:00:25 -080099 [NFSD_Versions] = write_versions,
NeilBrown80212d52006-10-02 02:17:47 -0700100 [NFSD_Ports] = write_ports,
NeilBrown596bbe52006-10-04 02:15:48 -0700101 [NFSD_MaxBlkSize] = write_maxblksize,
NeilBrown70c3b762005-11-07 01:00:25 -0800102#ifdef CONFIG_NFSD_V4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 [NFSD_Leasetime] = write_leasetime,
J. Bruce Fieldsefc4bb4f2010-03-02 11:04:06 -0500104 [NFSD_Gracetime] = write_gracetime,
NeilBrown0964a3d2005-06-23 22:04:32 -0700105 [NFSD_RecoveryDir] = write_recoverydir,
NeilBrown70c3b762005-11-07 01:00:25 -0800106#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107};
108
109static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
110{
Josef "Jeff" Sipek7eaa36e2006-12-08 02:36:41 -0800111 ino_t ino = file->f_path.dentry->d_inode->i_ino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 char *data;
113 ssize_t rv;
114
Tobias Klausere8c96f82006-03-24 03:15:34 -0800115 if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 return -EINVAL;
117
118 data = simple_transaction_get(file, buf, size);
119 if (IS_ERR(data))
120 return PTR_ERR(data);
121
122 rv = write_op[ino](file, data, size);
NeilBrown8971a102007-02-14 00:33:11 -0800123 if (rv >= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 simple_transaction_set(file, rv);
125 rv = size;
126 }
127 return rv;
128}
129
NeilBrown73900222005-11-07 01:00:24 -0800130static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
131{
bookjovi@gmail.com5b6a5992010-12-11 00:21:17 -0500132#ifdef CONFIG_NFSD_DEPRECATED
NeilBrownc67874f2010-09-22 12:55:07 +1000133 static int warned;
134 if (file->f_dentry->d_name.name[0] == '.' && !warned) {
NeilBrownc67874f2010-09-22 12:55:07 +1000135 printk(KERN_INFO
136 "Warning: \"%s\" uses deprecated NFSD interface: %s."
137 " This will be removed in 2.6.40\n",
Pavel Emelyanov049ef272010-09-23 18:26:58 +0400138 current->comm, file->f_dentry->d_name.name);
NeilBrownc67874f2010-09-22 12:55:07 +1000139 warned = 1;
140 }
bookjovi@gmail.com5b6a5992010-12-11 00:21:17 -0500141#endif
NeilBrown73900222005-11-07 01:00:24 -0800142 if (! file->private_data) {
143 /* An attempt to read a transaction file without writing
144 * causes a 0-byte write so that the file can return
145 * state information
146 */
147 ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos);
148 if (rv < 0)
149 return rv;
150 }
151 return simple_transaction_read(file, buf, size, pos);
152}
153
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800154static const struct file_operations transaction_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 .write = nfsctl_transaction_write,
NeilBrown73900222005-11-07 01:00:24 -0800156 .read = nfsctl_transaction_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 .release = simple_transaction_release,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200158 .llseek = default_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159};
160
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161static int exports_open(struct inode *inode, struct file *file)
162{
163 return seq_open(file, &nfs_exports_op);
164}
165
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800166static const struct file_operations exports_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 .open = exports_open,
168 .read = seq_read,
169 .llseek = seq_lseek,
170 .release = seq_release,
Denis V. Lunev9ef2db22008-04-29 01:02:04 -0700171 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172};
173
J. Bruce Fieldse8e87532009-12-14 12:53:32 -0500174static int export_features_show(struct seq_file *m, void *v)
175{
176 seq_printf(m, "0x%x 0x%x\n", NFSEXP_ALLFLAGS, NFSEXP_SECINFO_FLAGS);
177 return 0;
178}
179
180static int export_features_open(struct inode *inode, struct file *file)
181{
182 return single_open(file, export_features_show, NULL);
183}
184
185static struct file_operations export_features_operations = {
186 .open = export_features_open,
187 .read = seq_read,
188 .llseek = seq_lseek,
189 .release = single_release,
190};
191
Kevin Coffmanb0b0c0a2011-03-02 19:51:42 -0500192static int supported_enctypes_show(struct seq_file *m, void *v)
193{
194 struct gss_api_mech *k5mech;
195
196 k5mech = gss_mech_get_by_name("krb5");
197 if (k5mech == NULL)
198 goto out;
199 if (k5mech->gm_upcall_enctypes != NULL)
200 seq_printf(m, k5mech->gm_upcall_enctypes);
201 gss_mech_put(k5mech);
202out:
203 return 0;
204}
205
206static int supported_enctypes_open(struct inode *inode, struct file *file)
207{
208 return single_open(file, supported_enctypes_show, NULL);
209}
210
211static struct file_operations supported_enctypes_ops = {
212 .open = supported_enctypes_open,
213 .read = seq_read,
214 .llseek = seq_lseek,
215 .release = single_release,
216};
217
Greg Banks03cf6c92009-01-13 21:26:36 +1100218extern int nfsd_pool_stats_open(struct inode *inode, struct file *file);
Ryusei Yamaguchied2d8ae2009-08-16 00:54:41 +0900219extern int nfsd_pool_stats_release(struct inode *inode, struct file *file);
Greg Banks03cf6c92009-01-13 21:26:36 +1100220
Alexey Dobriyan828c0952009-10-01 15:43:56 -0700221static const struct file_operations pool_stats_operations = {
Greg Banks03cf6c92009-01-13 21:26:36 +1100222 .open = nfsd_pool_stats_open,
223 .read = seq_read,
224 .llseek = seq_lseek,
Ryusei Yamaguchied2d8ae2009-08-16 00:54:41 +0900225 .release = nfsd_pool_stats_release,
Greg Banks03cf6c92009-01-13 21:26:36 +1100226 .owner = THIS_MODULE,
227};
228
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229/*----------------------------------------------------------------------------*/
230/*
231 * payload - write methods
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 */
233
NeilBrown1e140562010-09-22 12:55:07 +1000234#ifdef CONFIG_NFSD_DEPRECATED
Chuck Lever262a0982008-12-12 16:57:35 -0500235/**
236 * write_svc - Start kernel's NFSD server
237 *
238 * Deprecated. /proc/fs/nfsd/threads is preferred.
239 * Function remains to support old versions of nfs-utils.
240 *
241 * Input:
242 * buf: struct nfsctl_svc
243 * svc_port: port number of this
244 * server's listener
245 * svc_nthreads: number of threads to start
246 * size: size in bytes of passed in nfsctl_svc
247 * Output:
248 * On success: returns zero
249 * On error: return code is negative errno value
250 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251static ssize_t write_svc(struct file *file, char *buf, size_t size)
252{
253 struct nfsctl_svc *data;
NeilBrown82e12fe2009-06-16 11:03:07 +1000254 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 if (size < sizeof(*data))
256 return -EINVAL;
257 data = (struct nfsctl_svc*) buf;
NeilBrown82e12fe2009-06-16 11:03:07 +1000258 err = nfsd_svc(data->svc_port, data->svc_nthreads);
259 if (err < 0)
260 return err;
261 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262}
263
Chuck Lever262a0982008-12-12 16:57:35 -0500264/**
265 * write_add - Add or modify client entry in auth unix cache
266 *
267 * Deprecated. /proc/net/rpc/auth.unix.ip is preferred.
268 * Function remains to support old versions of nfs-utils.
269 *
270 * Input:
271 * buf: struct nfsctl_client
272 * cl_ident: '\0'-terminated C string
273 * containing domain name
274 * of client
275 * cl_naddr: no. of items in cl_addrlist
276 * cl_addrlist: array of client addresses
277 * cl_fhkeytype: ignored
278 * cl_fhkeylen: ignored
279 * cl_fhkey: ignored
280 * size: size in bytes of passed in nfsctl_client
281 * Output:
282 * On success: returns zero
283 * On error: return code is negative errno value
284 *
285 * Note: Only AF_INET client addresses are passed in, since
286 * nfsctl_client.cl_addrlist contains only in_addr fields for addresses.
287 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288static ssize_t write_add(struct file *file, char *buf, size_t size)
289{
290 struct nfsctl_client *data;
291 if (size < sizeof(*data))
292 return -EINVAL;
293 data = (struct nfsctl_client *)buf;
294 return exp_addclient(data);
295}
296
Chuck Lever262a0982008-12-12 16:57:35 -0500297/**
298 * write_del - Remove client from auth unix cache
299 *
300 * Deprecated. /proc/net/rpc/auth.unix.ip is preferred.
301 * Function remains to support old versions of nfs-utils.
302 *
303 * Input:
304 * buf: struct nfsctl_client
305 * cl_ident: '\0'-terminated C string
306 * containing domain name
307 * of client
308 * cl_naddr: ignored
309 * cl_addrlist: ignored
310 * cl_fhkeytype: ignored
311 * cl_fhkeylen: ignored
312 * cl_fhkey: ignored
313 * size: size in bytes of passed in nfsctl_client
314 * Output:
315 * On success: returns zero
316 * On error: return code is negative errno value
317 *
318 * Note: Only AF_INET client addresses are passed in, since
319 * nfsctl_client.cl_addrlist contains only in_addr fields for addresses.
320 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321static ssize_t write_del(struct file *file, char *buf, size_t size)
322{
323 struct nfsctl_client *data;
324 if (size < sizeof(*data))
325 return -EINVAL;
326 data = (struct nfsctl_client *)buf;
327 return exp_delclient(data);
328}
329
Chuck Lever262a0982008-12-12 16:57:35 -0500330/**
331 * write_export - Export part or all of a local 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 allowed to access
341 * this export
342 * ex_path: '\0'-terminated C string
343 * containing pathname of
344 * directory in local file system
345 * ex_dev: fsid to use for this export
346 * ex_ino: ignored
347 * ex_flags: export flags for this export
348 * ex_anon_uid: UID to use for anonymous
349 * requests
350 * ex_anon_gid: GID to use for anonymous
351 * requests
352 * size: size in bytes of passed in nfsctl_export
353 * Output:
354 * On success: returns zero
355 * On error: return code is negative errno value
356 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357static ssize_t write_export(struct file *file, char *buf, size_t size)
358{
359 struct nfsctl_export *data;
360 if (size < sizeof(*data))
361 return -EINVAL;
362 data = (struct nfsctl_export*)buf;
363 return exp_export(data);
364}
365
Chuck Lever262a0982008-12-12 16:57:35 -0500366/**
367 * write_unexport - Unexport a previously exported file system
368 *
369 * Deprecated. /proc/net/rpc/{nfsd.export,nfsd.fh} are preferred.
370 * Function remains to support old versions of nfs-utils.
371 *
372 * Input:
373 * buf: struct nfsctl_export
374 * ex_client: '\0'-terminated C string
375 * containing domain name
376 * of client no longer allowed
377 * to access this export
378 * ex_path: '\0'-terminated C string
379 * containing pathname of
380 * directory in local file system
381 * ex_dev: ignored
382 * ex_ino: ignored
383 * ex_flags: ignored
384 * ex_anon_uid: ignored
385 * ex_anon_gid: ignored
386 * size: size in bytes of passed in nfsctl_export
387 * Output:
388 * On success: returns zero
389 * On error: return code is negative errno value
390 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391static ssize_t write_unexport(struct file *file, char *buf, size_t size)
392{
393 struct nfsctl_export *data;
394
395 if (size < sizeof(*data))
396 return -EINVAL;
397 data = (struct nfsctl_export*)buf;
398 return exp_unexport(data);
399}
400
Chuck Lever262a0982008-12-12 16:57:35 -0500401/**
402 * write_getfs - Get a variable-length NFS file handle by path
403 *
404 * Deprecated. /proc/fs/nfsd/filehandle is preferred.
405 * Function remains to support old versions of nfs-utils.
406 *
407 * Input:
408 * buf: struct nfsctl_fsparm
409 * gd_addr: socket address of client
410 * gd_path: '\0'-terminated C string
411 * containing pathname of
412 * directory in local file system
413 * gd_maxlen: maximum size of returned file
414 * handle
415 * size: size in bytes of passed in nfsctl_fsparm
416 * Output:
417 * On success: passed-in buffer filled with a knfsd_fh structure
418 * (a variable-length raw NFS file handle);
419 * return code is the size in bytes of the file handle
420 * On error: return code is negative errno value
421 *
422 * Note: Only AF_INET client addresses are passed in, since gd_addr
423 * is the same size as a struct sockaddr_in.
424 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425static ssize_t write_getfs(struct file *file, char *buf, size_t size)
426{
427 struct nfsctl_fsparm *data;
428 struct sockaddr_in *sin;
429 struct auth_domain *clp;
430 int err = 0;
431 struct knfsd_fh *res;
Aurélien Charbonf15364b2008-01-18 15:50:56 +0100432 struct in6_addr in6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
434 if (size < sizeof(*data))
435 return -EINVAL;
436 data = (struct nfsctl_fsparm*)buf;
437 err = -EPROTONOSUPPORT;
438 if (data->gd_addr.sa_family != AF_INET)
439 goto out;
440 sin = (struct sockaddr_in *)&data->gd_addr;
441 if (data->gd_maxlen > NFS3_FHSIZE)
442 data->gd_maxlen = NFS3_FHSIZE;
443
444 res = (struct knfsd_fh*)buf;
445
446 exp_readlock();
Aurélien Charbonf15364b2008-01-18 15:50:56 +0100447
448 ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
449
Pavel Emelyanov352114f2010-09-27 13:59:48 +0400450 clp = auth_unix_lookup(&init_net, &in6);
Aurélien Charbonf15364b2008-01-18 15:50:56 +0100451 if (!clp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 err = -EPERM;
453 else {
454 err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
455 auth_domain_put(clp);
456 }
457 exp_readunlock();
458 if (err == 0)
Andrew Morton12127492007-07-17 04:04:34 -0700459 err = res->fh_size + offsetof(struct knfsd_fh, fh_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 out:
461 return err;
462}
463
Chuck Lever262a0982008-12-12 16:57:35 -0500464/**
465 * write_getfd - Get a fixed-length NFS file handle by path (used by mountd)
466 *
467 * Deprecated. /proc/fs/nfsd/filehandle is preferred.
468 * Function remains to support old versions of nfs-utils.
469 *
470 * Input:
471 * buf: struct nfsctl_fdparm
472 * gd_addr: socket address of client
473 * gd_path: '\0'-terminated C string
474 * containing pathname of
475 * directory in local file system
476 * gd_version: fdparm structure version
477 * size: size in bytes of passed in nfsctl_fdparm
478 * Output:
479 * On success: passed-in buffer filled with nfsctl_res
480 * (a fixed-length raw NFS file handle);
481 * return code is the size in bytes of the file handle
482 * On error: return code is negative errno value
483 *
484 * Note: Only AF_INET client addresses are passed in, since gd_addr
485 * is the same size as a struct sockaddr_in.
486 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487static ssize_t write_getfd(struct file *file, char *buf, size_t size)
488{
489 struct nfsctl_fdparm *data;
490 struct sockaddr_in *sin;
491 struct auth_domain *clp;
492 int err = 0;
493 struct knfsd_fh fh;
494 char *res;
Aurélien Charbonf15364b2008-01-18 15:50:56 +0100495 struct in6_addr in6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
497 if (size < sizeof(*data))
498 return -EINVAL;
499 data = (struct nfsctl_fdparm*)buf;
500 err = -EPROTONOSUPPORT;
501 if (data->gd_addr.sa_family != AF_INET)
502 goto out;
503 err = -EINVAL;
504 if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
505 goto out;
506
507 res = buf;
508 sin = (struct sockaddr_in *)&data->gd_addr;
509 exp_readlock();
Aurélien Charbonf15364b2008-01-18 15:50:56 +0100510
511 ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
512
Pavel Emelyanov352114f2010-09-27 13:59:48 +0400513 clp = auth_unix_lookup(&init_net, &in6);
Aurélien Charbonf15364b2008-01-18 15:50:56 +0100514 if (!clp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 err = -EPERM;
516 else {
517 err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
518 auth_domain_put(clp);
519 }
520 exp_readunlock();
521
522 if (err == 0) {
523 memset(res,0, NFS_FHSIZE);
524 memcpy(res, &fh.fh_base, fh.fh_size);
525 err = NFS_FHSIZE;
526 }
527 out:
528 return err;
529}
NeilBrown1e140562010-09-22 12:55:07 +1000530#endif /* CONFIG_NFSD_DEPRECATED */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
Chuck Lever262a0982008-12-12 16:57:35 -0500532/**
533 * write_unlock_ip - Release all locks used by a client
534 *
535 * Experimental.
536 *
537 * Input:
538 * buf: '\n'-terminated C string containing a
Chuck Lever41160922009-08-09 15:09:40 -0400539 * presentation format IP address
Chuck Lever262a0982008-12-12 16:57:35 -0500540 * size: length of C string in @buf
541 * Output:
542 * On success: returns zero if all specified locks were released;
543 * returns one if one or more locks were not released
544 * On error: return code is negative errno value
Chuck Lever262a0982008-12-12 16:57:35 -0500545 */
Chuck Leverb046ccd2008-12-12 16:57:13 -0500546static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
Wendy Cheng4373ea82008-01-17 11:10:12 -0500547{
Chuck Lever41160922009-08-09 15:09:40 -0400548 struct sockaddr_storage address;
549 struct sockaddr *sap = (struct sockaddr *)&address;
550 size_t salen = sizeof(address);
Chuck Lever367c8c72008-06-30 18:58:14 -0400551 char *fo_path;
Wendy Cheng4373ea82008-01-17 11:10:12 -0500552
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
Chuck Lever41160922009-08-09 15:09:40 -0400564 if (rpc_pton(fo_path, size, sap, salen) == 0)
Wendy Cheng4373ea82008-01-17 11:10:12 -0500565 return -EINVAL;
Wendy Cheng4373ea82008-01-17 11:10:12 -0500566
Chuck Lever41160922009-08-09 15:09:40 -0400567 return nlmsvc_unlock_all_by_ip(sap);
Wendy Cheng4373ea82008-01-17 11:10:12 -0500568}
569
Chuck Lever262a0982008-12-12 16:57:35 -0500570/**
571 * write_unlock_fs - Release all locks on a local file system
572 *
573 * Experimental.
574 *
575 * Input:
576 * buf: '\n'-terminated C string containing the
577 * absolute pathname of a local file system
578 * size: length of C string in @buf
579 * Output:
580 * On success: returns zero if all specified locks were released;
581 * returns one if one or more locks were not released
582 * On error: return code is negative errno value
583 */
Chuck Leverb046ccd2008-12-12 16:57:13 -0500584static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
Wendy Cheng17efa372008-01-17 11:10:12 -0500585{
Al Viroa63bb992008-08-02 01:03:36 -0400586 struct path path;
Wendy Cheng17efa372008-01-17 11:10:12 -0500587 char *fo_path;
588 int error;
589
590 /* sanity check */
591 if (size == 0)
592 return -EINVAL;
593
594 if (buf[size-1] != '\n')
595 return -EINVAL;
596
597 fo_path = buf;
598 if (qword_get(&buf, fo_path, size) < 0)
599 return -EINVAL;
600
Al Viroa63bb992008-08-02 01:03:36 -0400601 error = kern_path(fo_path, 0, &path);
Wendy Cheng17efa372008-01-17 11:10:12 -0500602 if (error)
603 return error;
604
Chuck Lever262a0982008-12-12 16:57:35 -0500605 /*
606 * XXX: Needs better sanity checking. Otherwise we could end up
607 * releasing locks on the wrong file system.
608 *
609 * For example:
610 * 1. Does the path refer to a directory?
611 * 2. Is that directory a mount point, or
612 * 3. Is that directory the root of an exported file system?
613 */
Al Viroa63bb992008-08-02 01:03:36 -0400614 error = nlmsvc_unlock_all_by_sb(path.mnt->mnt_sb);
Wendy Cheng17efa372008-01-17 11:10:12 -0500615
Al Viroa63bb992008-08-02 01:03:36 -0400616 path_put(&path);
Wendy Cheng17efa372008-01-17 11:10:12 -0500617 return error;
618}
619
Chuck Lever262a0982008-12-12 16:57:35 -0500620/**
621 * write_filehandle - Get a variable-length NFS file handle by path
622 *
623 * On input, the buffer contains a '\n'-terminated C string comprised of
624 * three alphanumeric words separated by whitespace. The string may
625 * contain escape sequences.
626 *
627 * Input:
628 * buf:
629 * domain: client domain name
630 * path: export pathname
631 * maxsize: numeric maximum size of
632 * @buf
633 * size: length of C string in @buf
634 * Output:
635 * On success: passed-in buffer filled with '\n'-terminated C
636 * string containing a ASCII hex text version
637 * of the NFS file handle;
638 * return code is the size in bytes of the string
639 * On error: return code is negative errno value
640 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
642{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 char *dname, *path;
Andrew Morton246d95b2007-08-09 00:53:50 -0700644 int uninitialized_var(maxsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 char *mesg = buf;
646 int len;
647 struct auth_domain *dom;
648 struct knfsd_fh fh;
649
J. Bruce Fields87d26ea2008-01-22 17:40:42 -0500650 if (size == 0)
651 return -EINVAL;
652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 if (buf[size-1] != '\n')
654 return -EINVAL;
655 buf[size-1] = 0;
656
657 dname = mesg;
658 len = qword_get(&mesg, dname, size);
Chuck Lever54224f02008-12-12 16:57:20 -0500659 if (len <= 0)
660 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
662 path = dname+len+1;
663 len = qword_get(&mesg, path, size);
Chuck Lever54224f02008-12-12 16:57:20 -0500664 if (len <= 0)
665 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
667 len = get_int(&mesg, &maxsize);
668 if (len)
669 return len;
670
671 if (maxsize < NFS_FHSIZE)
672 return -EINVAL;
673 if (maxsize > NFS3_FHSIZE)
674 maxsize = NFS3_FHSIZE;
675
676 if (qword_get(&mesg, mesg, size)>0)
677 return -EINVAL;
678
679 /* we have all the words, they are in buf.. */
680 dom = unix_domain_find(dname);
681 if (!dom)
682 return -ENOMEM;
683
684 len = exp_rootfh(dom, path, &fh, maxsize);
685 auth_domain_put(dom);
686 if (len)
687 return len;
688
Chuck Lever54224f02008-12-12 16:57:20 -0500689 mesg = buf;
690 len = SIMPLE_TRANSACTION_LIMIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size);
692 mesg[-1] = '\n';
693 return mesg - buf;
694}
695
Chuck Lever262a0982008-12-12 16:57:35 -0500696/**
697 * write_threads - Start NFSD, or report the current number of running threads
698 *
699 * Input:
700 * buf: ignored
701 * size: zero
702 * Output:
703 * On success: passed-in buffer filled with '\n'-terminated C
704 * string numeric value representing the number of
705 * running NFSD threads;
706 * return code is the size in bytes of the string
707 * On error: return code is zero
708 *
709 * OR
710 *
711 * Input:
712 * buf: C string containing an unsigned
713 * integer value representing the
714 * number of NFSD threads to start
715 * size: non-zero length of C string in @buf
716 * Output:
717 * On success: NFS service is started;
718 * passed-in buffer filled with '\n'-terminated C
719 * string numeric value representing the number of
720 * running NFSD threads;
721 * return code is the size in bytes of the string
722 * On error: return code is zero or a negative errno value
723 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724static ssize_t write_threads(struct file *file, char *buf, size_t size)
725{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 char *mesg = buf;
727 int rv;
728 if (size > 0) {
729 int newthreads;
730 rv = get_int(&mesg, &newthreads);
731 if (rv)
732 return rv;
Chuck Lever9e074852008-12-12 16:57:27 -0500733 if (newthreads < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 return -EINVAL;
Chuck Lever9e074852008-12-12 16:57:27 -0500735 rv = nfsd_svc(NFS_PORT, newthreads);
NeilBrown82e12fe2009-06-16 11:03:07 +1000736 if (rv < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 return rv;
NeilBrown82e12fe2009-06-16 11:03:07 +1000738 } else
739 rv = nfsd_nrthreads();
Chuck Levere06b6402009-04-23 19:33:25 -0400740
NeilBrown82e12fe2009-06-16 11:03:07 +1000741 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742}
743
Chuck Lever262a0982008-12-12 16:57:35 -0500744/**
745 * write_pool_threads - Set or report the current number of threads per pool
746 *
747 * Input:
748 * buf: ignored
749 * size: zero
750 *
751 * OR
752 *
753 * Input:
754 * buf: C string containing whitespace-
755 * separated unsigned integer values
756 * representing the number of NFSD
757 * threads to start in each pool
758 * size: non-zero length of C string in @buf
759 * Output:
760 * On success: passed-in buffer filled with '\n'-terminated C
761 * string containing integer values representing the
762 * number of NFSD threads in each pool;
763 * return code is the size in bytes of the string
764 * On error: return code is zero or a negative errno value
765 */
Greg Bankseed29652006-10-02 02:18:02 -0700766static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
767{
768 /* if size > 0, look for an array of number of threads per node
769 * and apply them then write out number of threads per node as reply
770 */
771 char *mesg = buf;
772 int i;
773 int rv;
774 int len;
Neil Brownbedbdd82008-06-10 08:40:35 -0400775 int npools;
Greg Bankseed29652006-10-02 02:18:02 -0700776 int *nthreads;
777
Neil Brownbedbdd82008-06-10 08:40:35 -0400778 mutex_lock(&nfsd_mutex);
779 npools = nfsd_nrpools();
Greg Bankseed29652006-10-02 02:18:02 -0700780 if (npools == 0) {
781 /*
782 * NFS is shut down. The admin can start it by
783 * writing to the threads file but NOT the pool_threads
784 * file, sorry. Report zero threads.
785 */
Neil Brownbedbdd82008-06-10 08:40:35 -0400786 mutex_unlock(&nfsd_mutex);
Greg Bankseed29652006-10-02 02:18:02 -0700787 strcpy(buf, "0\n");
788 return strlen(buf);
789 }
790
791 nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL);
Neil Brownbedbdd82008-06-10 08:40:35 -0400792 rv = -ENOMEM;
Greg Bankseed29652006-10-02 02:18:02 -0700793 if (nthreads == NULL)
Neil Brownbedbdd82008-06-10 08:40:35 -0400794 goto out_free;
Greg Bankseed29652006-10-02 02:18:02 -0700795
796 if (size > 0) {
797 for (i = 0; i < npools; i++) {
798 rv = get_int(&mesg, &nthreads[i]);
799 if (rv == -ENOENT)
800 break; /* fewer numbers than pools */
801 if (rv)
802 goto out_free; /* syntax error */
803 rv = -EINVAL;
804 if (nthreads[i] < 0)
805 goto out_free;
806 }
807 rv = nfsd_set_nrthreads(i, nthreads);
808 if (rv)
809 goto out_free;
810 }
811
812 rv = nfsd_get_nrthreads(npools, nthreads);
813 if (rv)
814 goto out_free;
815
816 mesg = buf;
817 size = SIMPLE_TRANSACTION_LIMIT;
818 for (i = 0; i < npools && size > 0; i++) {
819 snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' '));
820 len = strlen(mesg);
821 size -= len;
822 mesg += len;
823 }
J. Bruce Fields413d63d7102009-07-28 11:37:25 -0400824 rv = mesg - buf;
Greg Bankseed29652006-10-02 02:18:02 -0700825out_free:
826 kfree(nthreads);
Neil Brownbedbdd82008-06-10 08:40:35 -0400827 mutex_unlock(&nfsd_mutex);
Greg Bankseed29652006-10-02 02:18:02 -0700828 return rv;
829}
830
Jeff Layton3dd98a32008-06-10 08:40:36 -0400831static ssize_t __write_versions(struct file *file, char *buf, size_t size)
NeilBrown70c3b762005-11-07 01:00:25 -0800832{
NeilBrown70c3b762005-11-07 01:00:25 -0800833 char *mesg = buf;
Benny Halevy8daf2202009-04-03 08:28:59 +0300834 char *vers, *minorp, sign;
Chuck Lever261758b2009-04-23 19:33:18 -0400835 int len, num, remaining;
Benny Halevy8daf2202009-04-03 08:28:59 +0300836 unsigned minor;
NeilBrown70c3b762005-11-07 01:00:25 -0800837 ssize_t tlen = 0;
838 char *sep;
839
840 if (size>0) {
841 if (nfsd_serv)
NeilBrown6658d3a2006-10-02 02:17:46 -0700842 /* Cannot change versions without updating
843 * nfsd_serv->sv_xdrsize, and reallocing
844 * rq_argp and rq_resp
845 */
NeilBrown70c3b762005-11-07 01:00:25 -0800846 return -EBUSY;
847 if (buf[size-1] != '\n')
848 return -EINVAL;
849 buf[size-1] = 0;
850
851 vers = mesg;
852 len = qword_get(&mesg, vers, size);
853 if (len <= 0) return -EINVAL;
854 do {
855 sign = *vers;
856 if (sign == '+' || sign == '-')
Benny Halevy8daf2202009-04-03 08:28:59 +0300857 num = simple_strtol((vers+1), &minorp, 0);
NeilBrown70c3b762005-11-07 01:00:25 -0800858 else
Benny Halevy8daf2202009-04-03 08:28:59 +0300859 num = simple_strtol(vers, &minorp, 0);
860 if (*minorp == '.') {
861 if (num < 4)
862 return -EINVAL;
863 minor = simple_strtoul(minorp+1, NULL, 0);
864 if (minor == 0)
865 return -EINVAL;
866 if (nfsd_minorversion(minor, sign == '-' ?
867 NFSD_CLEAR : NFSD_SET) < 0)
868 return -EINVAL;
869 goto next;
870 }
NeilBrown70c3b762005-11-07 01:00:25 -0800871 switch(num) {
872 case 2:
873 case 3:
874 case 4:
NeilBrown6658d3a2006-10-02 02:17:46 -0700875 nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET);
NeilBrown70c3b762005-11-07 01:00:25 -0800876 break;
877 default:
878 return -EINVAL;
879 }
Benny Halevy8daf2202009-04-03 08:28:59 +0300880 next:
NeilBrown70c3b762005-11-07 01:00:25 -0800881 vers += len + 1;
NeilBrown70c3b762005-11-07 01:00:25 -0800882 } while ((len = qword_get(&mesg, vers, size)) > 0);
883 /* If all get turned off, turn them back on, as
884 * having no versions is BAD
885 */
NeilBrown6658d3a2006-10-02 02:17:46 -0700886 nfsd_reset_versions();
NeilBrown70c3b762005-11-07 01:00:25 -0800887 }
Chuck Lever261758b2009-04-23 19:33:18 -0400888
NeilBrown70c3b762005-11-07 01:00:25 -0800889 /* Now write current state into reply buffer */
890 len = 0;
891 sep = "";
Chuck Lever261758b2009-04-23 19:33:18 -0400892 remaining = SIMPLE_TRANSACTION_LIMIT;
NeilBrown70c3b762005-11-07 01:00:25 -0800893 for (num=2 ; num <= 4 ; num++)
NeilBrown6658d3a2006-10-02 02:17:46 -0700894 if (nfsd_vers(num, NFSD_AVAIL)) {
Chuck Lever261758b2009-04-23 19:33:18 -0400895 len = snprintf(buf, remaining, "%s%c%d", sep,
NeilBrown6658d3a2006-10-02 02:17:46 -0700896 nfsd_vers(num, NFSD_TEST)?'+':'-',
NeilBrown70c3b762005-11-07 01:00:25 -0800897 num);
898 sep = " ";
Chuck Lever261758b2009-04-23 19:33:18 -0400899
900 if (len > remaining)
901 break;
902 remaining -= len;
903 buf += len;
904 tlen += len;
NeilBrown70c3b762005-11-07 01:00:25 -0800905 }
Benny Halevy8daf2202009-04-03 08:28:59 +0300906 if (nfsd_vers(4, NFSD_AVAIL))
Chuck Lever261758b2009-04-23 19:33:18 -0400907 for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION;
908 minor++) {
909 len = snprintf(buf, remaining, " %c4.%u",
Benny Halevy8daf2202009-04-03 08:28:59 +0300910 (nfsd_vers(4, NFSD_TEST) &&
911 nfsd_minorversion(minor, NFSD_TEST)) ?
912 '+' : '-',
913 minor);
Chuck Lever261758b2009-04-23 19:33:18 -0400914
915 if (len > remaining)
916 break;
917 remaining -= len;
918 buf += len;
919 tlen += len;
920 }
921
922 len = snprintf(buf, remaining, "\n");
923 if (len > remaining)
924 return -EINVAL;
925 return tlen + len;
NeilBrown70c3b762005-11-07 01:00:25 -0800926}
927
Chuck Lever262a0982008-12-12 16:57:35 -0500928/**
929 * write_versions - Set or report the available NFS protocol versions
930 *
931 * Input:
932 * buf: ignored
933 * size: zero
934 * Output:
935 * On success: passed-in buffer filled with '\n'-terminated C
936 * string containing positive or negative integer
937 * values representing the current status of each
938 * protocol version;
939 * return code is the size in bytes of the string
940 * On error: return code is zero or a negative errno value
941 *
942 * OR
943 *
944 * Input:
945 * buf: C string containing whitespace-
946 * separated positive or negative
947 * integer values representing NFS
948 * protocol versions to enable ("+n")
949 * or disable ("-n")
950 * size: non-zero length of C string in @buf
951 * Output:
952 * On success: status of zero or more protocol versions has
953 * been updated; passed-in buffer filled with
954 * '\n'-terminated C string containing positive
955 * or negative integer values representing the
956 * current status of each protocol version;
957 * return code is the size in bytes of the string
958 * On error: return code is zero or a negative errno value
959 */
Jeff Layton3dd98a32008-06-10 08:40:36 -0400960static ssize_t write_versions(struct file *file, char *buf, size_t size)
961{
962 ssize_t rv;
963
964 mutex_lock(&nfsd_mutex);
965 rv = __write_versions(file, buf, size);
966 mutex_unlock(&nfsd_mutex);
967 return rv;
968}
969
Chuck Lever4cd5dc72009-04-23 19:31:32 -0400970/*
Chuck Lever0a5372d2009-04-23 19:32:10 -0400971 * Zero-length write. Return a list of NFSD's current listener
972 * transports.
973 */
974static ssize_t __write_ports_names(char *buf)
975{
976 if (nfsd_serv == NULL)
977 return 0;
Chuck Lever335c54b2009-04-23 19:32:25 -0400978 return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
Chuck Lever0a5372d2009-04-23 19:32:10 -0400979}
980
981/*
Chuck Lever0b7c2f62009-04-23 19:31:55 -0400982 * A single 'fd' number was written, in which case it must be for
983 * a socket of a supported family/protocol, and we use it as an
984 * nfsd listener.
985 */
986static ssize_t __write_ports_addfd(char *buf)
987{
988 char *mesg = buf;
989 int fd, err;
990
991 err = get_int(&mesg, &fd);
992 if (err != 0 || fd < 0)
993 return -EINVAL;
994
995 err = nfsd_create_serv();
996 if (err != 0)
997 return err;
998
Chuck Leverbfba9ab2009-04-23 19:32:33 -0400999 err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
Jeff Layton78a8d7c2010-07-19 16:50:05 -04001000 if (err < 0) {
Jeff Layton78a8d7c2010-07-19 16:50:05 -04001001 svc_destroy(nfsd_serv);
1002 return err;
1003 }
Chuck Lever0b7c2f62009-04-23 19:31:55 -04001004
Chuck Leverea068ba2009-04-23 19:32:18 -04001005 /* Decrease the count, but don't shut down the service */
1006 nfsd_serv->sv_nrthreads--;
1007 return err;
Chuck Lever0b7c2f62009-04-23 19:31:55 -04001008}
1009
1010/*
Chuck Lever82d56592009-04-23 19:31:48 -04001011 * A '-' followed by the 'name' of a socket means we close the socket.
1012 */
1013static ssize_t __write_ports_delfd(char *buf)
1014{
1015 char *toclose;
1016 int len = 0;
1017
1018 toclose = kstrdup(buf + 1, GFP_KERNEL);
1019 if (toclose == NULL)
1020 return -ENOMEM;
1021
1022 if (nfsd_serv != NULL)
Chuck Lever8435d342009-04-23 19:32:40 -04001023 len = svc_sock_names(nfsd_serv, buf,
1024 SIMPLE_TRANSACTION_LIMIT, toclose);
Chuck Lever82d56592009-04-23 19:31:48 -04001025 kfree(toclose);
1026 return len;
1027}
1028
1029/*
Chuck Lever4eb68c22009-04-23 19:31:40 -04001030 * A transport listener is added by writing it's transport name and
1031 * a port number.
1032 */
1033static ssize_t __write_ports_addxprt(char *buf)
1034{
1035 char transport[16];
Chuck Lever37498292010-01-26 14:04:22 -05001036 struct svc_xprt *xprt;
Chuck Lever4eb68c22009-04-23 19:31:40 -04001037 int port, err;
1038
1039 if (sscanf(buf, "%15s %4u", transport, &port) != 2)
1040 return -EINVAL;
1041
Alexey Dobriyan4be929b2010-05-24 14:33:03 -07001042 if (port < 1 || port > USHRT_MAX)
Chuck Lever4eb68c22009-04-23 19:31:40 -04001043 return -EINVAL;
1044
1045 err = nfsd_create_serv();
1046 if (err != 0)
1047 return err;
1048
Pavel Emelyanovfc5d00b2010-09-29 16:03:50 +04001049 err = svc_create_xprt(nfsd_serv, transport, &init_net,
Chuck Lever4eb68c22009-04-23 19:31:40 -04001050 PF_INET, port, SVC_SOCK_ANONYMOUS);
Chuck Lever68717902010-01-26 14:04:13 -05001051 if (err < 0)
Chuck Lever37498292010-01-26 14:04:22 -05001052 goto out_err;
1053
Pavel Emelyanovfc5d00b2010-09-29 16:03:50 +04001054 err = svc_create_xprt(nfsd_serv, transport, &init_net,
Chuck Lever37498292010-01-26 14:04:22 -05001055 PF_INET6, port, SVC_SOCK_ANONYMOUS);
1056 if (err < 0 && err != -EAFNOSUPPORT)
1057 goto out_close;
Jeff Layton0cd14a02010-07-19 16:50:06 -04001058
1059 /* Decrease the count, but don't shut down the service */
1060 nfsd_serv->sv_nrthreads--;
Chuck Lever4eb68c22009-04-23 19:31:40 -04001061 return 0;
Chuck Lever37498292010-01-26 14:04:22 -05001062out_close:
1063 xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port);
1064 if (xprt != NULL) {
1065 svc_close_xprt(xprt);
1066 svc_xprt_put(xprt);
1067 }
1068out_err:
Jeff Layton0cd14a02010-07-19 16:50:06 -04001069 svc_destroy(nfsd_serv);
Chuck Lever37498292010-01-26 14:04:22 -05001070 return err;
Chuck Lever4eb68c22009-04-23 19:31:40 -04001071}
1072
1073/*
Chuck Lever4cd5dc72009-04-23 19:31:32 -04001074 * A transport listener is removed by writing a "-", it's transport
1075 * name, and it's port number.
1076 */
1077static ssize_t __write_ports_delxprt(char *buf)
1078{
1079 struct svc_xprt *xprt;
1080 char transport[16];
1081 int port;
1082
1083 if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2)
1084 return -EINVAL;
1085
Alexey Dobriyan4be929b2010-05-24 14:33:03 -07001086 if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL)
Chuck Lever4cd5dc72009-04-23 19:31:32 -04001087 return -EINVAL;
1088
1089 xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port);
1090 if (xprt == NULL)
1091 return -ENOTCONN;
1092
1093 svc_close_xprt(xprt);
1094 svc_xprt_put(xprt);
1095 return 0;
1096}
1097
Neil Brownbedbdd82008-06-10 08:40:35 -04001098static ssize_t __write_ports(struct file *file, char *buf, size_t size)
NeilBrown80212d52006-10-02 02:17:47 -07001099{
Chuck Lever0a5372d2009-04-23 19:32:10 -04001100 if (size == 0)
1101 return __write_ports_names(buf);
Chuck Lever0b7c2f62009-04-23 19:31:55 -04001102
1103 if (isdigit(buf[0]))
1104 return __write_ports_addfd(buf);
Chuck Lever82d56592009-04-23 19:31:48 -04001105
1106 if (buf[0] == '-' && isdigit(buf[1]))
1107 return __write_ports_delfd(buf);
Chuck Lever4eb68c22009-04-23 19:31:40 -04001108
1109 if (isalpha(buf[0]))
1110 return __write_ports_addxprt(buf);
Chuck Lever4cd5dc72009-04-23 19:31:32 -04001111
1112 if (buf[0] == '-' && isalpha(buf[1]))
1113 return __write_ports_delxprt(buf);
1114
NeilBrownb41b66d2006-10-02 02:17:48 -07001115 return -EINVAL;
NeilBrown80212d52006-10-02 02:17:47 -07001116}
1117
Chuck Lever262a0982008-12-12 16:57:35 -05001118/**
1119 * write_ports - Pass a socket file descriptor or transport name to listen on
1120 *
1121 * Input:
1122 * buf: ignored
1123 * size: zero
1124 * Output:
1125 * On success: passed-in buffer filled with a '\n'-terminated C
1126 * string containing a whitespace-separated list of
1127 * named NFSD listeners;
1128 * return code is the size in bytes of the string
1129 * On error: return code is zero or a negative errno value
1130 *
1131 * OR
1132 *
1133 * Input:
1134 * buf: C string containing an unsigned
1135 * integer value representing a bound
1136 * but unconnected socket that is to be
Chuck Leverc71206a2009-04-23 19:32:03 -04001137 * used as an NFSD listener; listen(3)
1138 * must be called for a SOCK_STREAM
1139 * socket, otherwise it is ignored
Chuck Lever262a0982008-12-12 16:57:35 -05001140 * size: non-zero length of C string in @buf
1141 * Output:
1142 * On success: NFS service is started;
1143 * passed-in buffer filled with a '\n'-terminated C
1144 * string containing a unique alphanumeric name of
1145 * the listener;
1146 * return code is the size in bytes of the string
1147 * On error: return code is a negative errno value
1148 *
1149 * OR
1150 *
1151 * Input:
1152 * buf: C string containing a "-" followed
1153 * by an integer value representing a
1154 * previously passed in socket file
1155 * descriptor
1156 * size: non-zero length of C string in @buf
1157 * Output:
1158 * On success: NFS service no longer listens on that socket;
1159 * passed-in buffer filled with a '\n'-terminated C
1160 * string containing a unique name of the listener;
1161 * return code is the size in bytes of the string
1162 * On error: return code is a negative errno value
1163 *
1164 * OR
1165 *
1166 * Input:
1167 * buf: C string containing a transport
1168 * name and an unsigned integer value
1169 * representing the port to listen on,
1170 * separated by whitespace
1171 * size: non-zero length of C string in @buf
1172 * Output:
1173 * On success: returns zero; NFS service is started
1174 * On error: return code is a negative errno value
1175 *
1176 * OR
1177 *
1178 * Input:
1179 * buf: C string containing a "-" followed
1180 * by a transport name and an unsigned
1181 * integer value representing the port
1182 * to listen on, separated by whitespace
1183 * size: non-zero length of C string in @buf
1184 * Output:
1185 * On success: returns zero; NFS service no longer listens
1186 * on that transport
1187 * On error: return code is a negative errno value
1188 */
Neil Brownbedbdd82008-06-10 08:40:35 -04001189static ssize_t write_ports(struct file *file, char *buf, size_t size)
1190{
1191 ssize_t rv;
Jeff Layton3dd98a32008-06-10 08:40:36 -04001192
Neil Brownbedbdd82008-06-10 08:40:35 -04001193 mutex_lock(&nfsd_mutex);
1194 rv = __write_ports(file, buf, size);
1195 mutex_unlock(&nfsd_mutex);
1196 return rv;
1197}
1198
1199
NeilBrown596bbe52006-10-04 02:15:48 -07001200int nfsd_max_blksize;
1201
Chuck Lever262a0982008-12-12 16:57:35 -05001202/**
1203 * write_maxblksize - Set or report the current NFS blksize
1204 *
1205 * Input:
1206 * buf: ignored
1207 * size: zero
1208 *
1209 * OR
1210 *
1211 * Input:
1212 * buf: C string containing an unsigned
1213 * integer value representing the new
1214 * NFS blksize
1215 * size: non-zero length of C string in @buf
1216 * Output:
1217 * On success: passed-in buffer filled with '\n'-terminated C string
1218 * containing numeric value of the current NFS blksize
1219 * setting;
1220 * return code is the size in bytes of the string
1221 * On error: return code is zero or a negative errno value
1222 */
NeilBrown596bbe52006-10-04 02:15:48 -07001223static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
1224{
1225 char *mesg = buf;
1226 if (size > 0) {
1227 int bsize;
1228 int rv = get_int(&mesg, &bsize);
1229 if (rv)
1230 return rv;
1231 /* force bsize into allowed range and
1232 * required alignment.
1233 */
1234 if (bsize < 1024)
1235 bsize = 1024;
1236 if (bsize > NFSSVC_MAXBLKSIZE)
1237 bsize = NFSSVC_MAXBLKSIZE;
1238 bsize &= ~(1024-1);
Neil Brownbedbdd82008-06-10 08:40:35 -04001239 mutex_lock(&nfsd_mutex);
J. Bruce Fields7fa53cc2010-08-06 18:00:33 -04001240 if (nfsd_serv) {
Neil Brownbedbdd82008-06-10 08:40:35 -04001241 mutex_unlock(&nfsd_mutex);
NeilBrown596bbe52006-10-04 02:15:48 -07001242 return -EBUSY;
1243 }
1244 nfsd_max_blksize = bsize;
Neil Brownbedbdd82008-06-10 08:40:35 -04001245 mutex_unlock(&nfsd_mutex);
NeilBrown596bbe52006-10-04 02:15:48 -07001246 }
Chuck Levere06b6402009-04-23 19:33:25 -04001247
1248 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n",
1249 nfsd_max_blksize);
NeilBrown596bbe52006-10-04 02:15:48 -07001250}
1251
NeilBrown70c3b762005-11-07 01:00:25 -08001252#ifdef CONFIG_NFSD_V4
J. Bruce Fieldsf0135742010-03-01 19:32:36 -05001253static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 char *mesg = buf;
J. Bruce Fieldsf0135742010-03-01 19:32:36 -05001256 int rv, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
1258 if (size > 0) {
Jeff Layton3dd98a32008-06-10 08:40:36 -04001259 if (nfsd_serv)
1260 return -EBUSY;
J. Bruce Fieldsf0135742010-03-01 19:32:36 -05001261 rv = get_int(&mesg, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 if (rv)
1263 return rv;
J. Bruce Fieldse7b184f2010-03-02 11:18:40 -05001264 /*
1265 * Some sanity checking. We don't have a reason for
1266 * these particular numbers, but problems with the
1267 * extremes are:
1268 * - Too short: the briefest network outage may
1269 * cause clients to lose all their locks. Also,
1270 * the frequent polling may be wasteful.
1271 * - Too long: do you really want reboot recovery
1272 * to take more than an hour? Or to make other
1273 * clients wait an hour before being able to
1274 * revoke a dead client's locks?
1275 */
J. Bruce Fieldsf0135742010-03-01 19:32:36 -05001276 if (i < 10 || i > 3600)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 return -EINVAL;
J. Bruce Fieldsf0135742010-03-01 19:32:36 -05001278 *time = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 }
Chuck Levere06b6402009-04-23 19:33:25 -04001280
J. Bruce Fieldsf0135742010-03-01 19:32:36 -05001281 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", *time);
1282}
1283
1284static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time)
1285{
1286 ssize_t rv;
1287
1288 mutex_lock(&nfsd_mutex);
1289 rv = __nfsd4_write_time(file, buf, size, time);
1290 mutex_unlock(&nfsd_mutex);
1291 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292}
1293
Chuck Lever262a0982008-12-12 16:57:35 -05001294/**
1295 * write_leasetime - Set or report the current NFSv4 lease time
1296 *
1297 * Input:
1298 * buf: ignored
1299 * size: zero
1300 *
1301 * OR
1302 *
1303 * Input:
1304 * buf: C string containing an unsigned
1305 * integer value representing the new
1306 * NFSv4 lease expiry time
1307 * size: non-zero length of C string in @buf
1308 * Output:
1309 * On success: passed-in buffer filled with '\n'-terminated C
1310 * string containing unsigned integer value of the
1311 * current lease expiry time;
1312 * return code is the size in bytes of the string
1313 * On error: return code is zero or a negative errno value
1314 */
Jeff Layton3dd98a32008-06-10 08:40:36 -04001315static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
1316{
J. Bruce Fieldsf0135742010-03-01 19:32:36 -05001317 return nfsd4_write_time(file, buf, size, &nfsd4_lease);
Jeff Layton3dd98a32008-06-10 08:40:36 -04001318}
1319
J. Bruce Fieldsefc4bb4f2010-03-02 11:04:06 -05001320/**
1321 * write_gracetime - Set or report current NFSv4 grace period time
1322 *
1323 * As above, but sets the time of the NFSv4 grace period.
1324 *
1325 * Note this should never be set to less than the *previous*
1326 * lease-period time, but we don't try to enforce this. (In the common
1327 * case (a new boot), we don't know what the previous lease time was
1328 * anyway.)
1329 */
1330static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
1331{
1332 return nfsd4_write_time(file, buf, size, &nfsd4_grace);
1333}
1334
Jeff Layton3dd98a32008-06-10 08:40:36 -04001335extern char *nfs4_recoverydir(void);
1336
1337static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
NeilBrown0964a3d2005-06-23 22:04:32 -07001338{
1339 char *mesg = buf;
1340 char *recdir;
1341 int len, status;
1342
Jeff Layton3dd98a32008-06-10 08:40:36 -04001343 if (size > 0) {
1344 if (nfsd_serv)
1345 return -EBUSY;
1346 if (size > PATH_MAX || buf[size-1] != '\n')
1347 return -EINVAL;
1348 buf[size-1] = 0;
NeilBrown0964a3d2005-06-23 22:04:32 -07001349
Jeff Layton3dd98a32008-06-10 08:40:36 -04001350 recdir = mesg;
1351 len = qword_get(&mesg, recdir, size);
1352 if (len <= 0)
1353 return -EINVAL;
NeilBrown0964a3d2005-06-23 22:04:32 -07001354
Jeff Layton3dd98a32008-06-10 08:40:36 -04001355 status = nfs4_reset_recoverydir(recdir);
Andi Kleen69049962010-07-20 15:24:27 -07001356 if (status)
1357 return status;
Jeff Layton3dd98a32008-06-10 08:40:36 -04001358 }
Chuck Lever3d72ab82009-04-23 19:33:10 -04001359
1360 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
1361 nfs4_recoverydir());
NeilBrown0964a3d2005-06-23 22:04:32 -07001362}
Jeff Layton3dd98a32008-06-10 08:40:36 -04001363
Chuck Lever262a0982008-12-12 16:57:35 -05001364/**
1365 * write_recoverydir - Set or report the pathname of the recovery directory
1366 *
1367 * Input:
1368 * buf: ignored
1369 * size: zero
1370 *
1371 * OR
1372 *
1373 * Input:
1374 * buf: C string containing the pathname
1375 * of the directory on a local file
1376 * system containing permanent NFSv4
1377 * recovery data
1378 * size: non-zero length of C string in @buf
1379 * Output:
1380 * On success: passed-in buffer filled with '\n'-terminated C string
1381 * containing the current recovery pathname setting;
1382 * return code is the size in bytes of the string
1383 * On error: return code is zero or a negative errno value
1384 */
Jeff Layton3dd98a32008-06-10 08:40:36 -04001385static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
1386{
1387 ssize_t rv;
1388
1389 mutex_lock(&nfsd_mutex);
1390 rv = __write_recoverydir(file, buf, size);
1391 mutex_unlock(&nfsd_mutex);
1392 return rv;
1393}
1394
NeilBrown70c3b762005-11-07 01:00:25 -08001395#endif
NeilBrown0964a3d2005-06-23 22:04:32 -07001396
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397/*----------------------------------------------------------------------------*/
1398/*
1399 * populating the filesystem.
1400 */
1401
1402static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
1403{
1404 static struct tree_descr nfsd_files[] = {
NeilBrown1e140562010-09-22 12:55:07 +10001405#ifdef CONFIG_NFSD_DEPRECATED
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 [NFSD_Svc] = {".svc", &transaction_ops, S_IWUSR},
1407 [NFSD_Add] = {".add", &transaction_ops, S_IWUSR},
1408 [NFSD_Del] = {".del", &transaction_ops, S_IWUSR},
1409 [NFSD_Export] = {".export", &transaction_ops, S_IWUSR},
1410 [NFSD_Unexport] = {".unexport", &transaction_ops, S_IWUSR},
1411 [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR},
1412 [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR},
NeilBrown1e140562010-09-22 12:55:07 +10001413#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
J. Bruce Fieldse8e87532009-12-14 12:53:32 -05001415 [NFSD_Export_features] = {"export_features",
1416 &export_features_operations, S_IRUGO},
Wendy Cheng4373ea82008-01-17 11:10:12 -05001417 [NFSD_FO_UnlockIP] = {"unlock_ip",
1418 &transaction_ops, S_IWUSR|S_IRUSR},
Wendy Cheng17efa372008-01-17 11:10:12 -05001419 [NFSD_FO_UnlockFS] = {"unlock_filesystem",
1420 &transaction_ops, S_IWUSR|S_IRUSR},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
1422 [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
Greg Bankseed29652006-10-02 02:18:02 -07001423 [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
Greg Banks03cf6c92009-01-13 21:26:36 +11001424 [NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO},
NeilBrown70c3b762005-11-07 01:00:25 -08001425 [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
NeilBrown80212d52006-10-02 02:17:47 -07001426 [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
NeilBrown596bbe52006-10-04 02:15:48 -07001427 [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
Kevin Coffmanb0b0c0a2011-03-02 19:51:42 -05001428 [NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429#ifdef CONFIG_NFSD_V4
1430 [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
J. Bruce Fieldsefc4bb4f2010-03-02 11:04:06 -05001431 [NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR},
NeilBrown0964a3d2005-06-23 22:04:32 -07001432 [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433#endif
1434 /* last one */ {""}
1435 };
1436 return simple_fill_super(sb, 0x6e667364, nfsd_files);
1437}
1438
Al Virofc14f2f2010-07-25 01:48:30 +04001439static struct dentry *nfsd_mount(struct file_system_type *fs_type,
1440 int flags, const char *dev_name, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441{
Al Virofc14f2f2010-07-25 01:48:30 +04001442 return mount_single(fs_type, flags, data, nfsd_fill_super);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443}
1444
1445static struct file_system_type nfsd_fs_type = {
1446 .owner = THIS_MODULE,
1447 .name = "nfsd",
Al Virofc14f2f2010-07-25 01:48:30 +04001448 .mount = nfsd_mount,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 .kill_sb = kill_litter_super,
1450};
1451
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001452#ifdef CONFIG_PROC_FS
1453static int create_proc_exports_entry(void)
1454{
1455 struct proc_dir_entry *entry;
1456
1457 entry = proc_mkdir("fs/nfs", NULL);
1458 if (!entry)
1459 return -ENOMEM;
Denis V. Lunev9ef2db22008-04-29 01:02:04 -07001460 entry = proc_create("exports", 0, entry, &exports_operations);
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001461 if (!entry)
1462 return -ENOMEM;
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001463 return 0;
1464}
1465#else /* CONFIG_PROC_FS */
1466static int create_proc_exports_entry(void)
1467{
1468 return 0;
1469}
1470#endif
1471
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472static int __init init_nfsd(void)
1473{
1474 int retval;
1475 printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
1476
J. Bruce Fieldse8ff2a82007-08-01 15:30:59 -04001477 retval = nfs4_state_init(); /* nfs4 locking state */
1478 if (retval)
1479 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 nfsd_stat_init(); /* Statistics */
J. Bruce Fieldsd5c34282007-11-09 14:10:56 -05001481 retval = nfsd_reply_cache_init();
1482 if (retval)
1483 goto out_free_stat;
J. Bruce Fieldsdbf847e2007-11-08 17:20:34 -05001484 retval = nfsd_export_init();
1485 if (retval)
1486 goto out_free_cache;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 nfsd_lockd_init(); /* lockd->nfsd callbacks */
J. Bruce Fieldsdbf847e2007-11-08 17:20:34 -05001488 retval = nfsd_idmap_init();
1489 if (retval)
1490 goto out_free_lockd;
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001491 retval = create_proc_exports_entry();
1492 if (retval)
1493 goto out_free_idmap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 retval = register_filesystem(&nfsd_fs_type);
J. Bruce Fields26808d32007-11-09 13:44:06 -05001495 if (retval)
1496 goto out_free_all;
1497 return 0;
1498out_free_all:
J. Bruce Fields26808d32007-11-09 13:44:06 -05001499 remove_proc_entry("fs/nfs/exports", NULL);
1500 remove_proc_entry("fs/nfs", NULL);
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001501out_free_idmap:
J. Bruce Fieldsdbf847e2007-11-08 17:20:34 -05001502 nfsd_idmap_shutdown();
1503out_free_lockd:
J. Bruce Fields26808d32007-11-09 13:44:06 -05001504 nfsd_lockd_shutdown();
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001505 nfsd_export_shutdown();
J. Bruce Fieldsdbf847e2007-11-08 17:20:34 -05001506out_free_cache:
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001507 nfsd_reply_cache_shutdown();
J. Bruce Fieldsd5c34282007-11-09 14:10:56 -05001508out_free_stat:
1509 nfsd_stat_shutdown();
J. Bruce Fields26808d32007-11-09 13:44:06 -05001510 nfsd4_free_slabs();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 return retval;
1512}
1513
1514static void __exit exit_nfsd(void)
1515{
1516 nfsd_export_shutdown();
J. Bruce Fieldsd5c34282007-11-09 14:10:56 -05001517 nfsd_reply_cache_shutdown();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 remove_proc_entry("fs/nfs/exports", NULL);
1519 remove_proc_entry("fs/nfs", NULL);
1520 nfsd_stat_shutdown();
1521 nfsd_lockd_shutdown();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 nfsd_idmap_shutdown();
J. Bruce Fieldse8ff2a82007-08-01 15:30:59 -04001523 nfsd4_free_slabs();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 unregister_filesystem(&nfsd_fs_type);
1525}
1526
1527MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
1528MODULE_LICENSE("GPL");
1529module_init(init_nfsd)
1530module_exit(exit_nfsd)