blob: 5a1920a2de27715c00b34bdf6fc518400e85455d [file] [log] [blame]
Thomas Gleixner09c434b2019-05-19 13:08:20 +01001// SPDX-License-Identifier: GPL-2.0-only
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Syscall interface to knfsd.
4 *
5 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
6 */
7
Tejun Heo5a0e3ad2010-03-24 17:04:11 +09008#include <linux/slab.h>
Al Viro3f8206d2008-07-26 03:46:43 -04009#include <linux/namei.h>
NeilBrownb41b66d2006-10-02 02:17:48 -070010#include <linux/ctype.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070011
NeilBrown80212d52006-10-02 02:17:47 -070012#include <linux/sunrpc/svcsock.h>
Wendy Cheng4373ea82008-01-17 11:10:12 -050013#include <linux/lockd/lockd.h>
Jeff Layton59766872013-02-04 12:50:00 -050014#include <linux/sunrpc/addr.h>
Kevin Coffmanb0b0c0a2011-03-02 19:51:42 -050015#include <linux/sunrpc/gss_api.h>
J. Bruce Fieldsb084f592011-05-31 12:24:58 -040016#include <linux/sunrpc/gss_krb5_enctypes.h>
Jeff Layton813fd322012-03-21 09:52:08 -040017#include <linux/sunrpc/rpc_pipe_fs.h>
Paul Gortmaker143cb492011-07-01 14:23:34 -040018#include <linux/module.h>
J. Bruce Fieldse8a79fb2019-03-22 11:11:06 -040019#include <linux/fsnotify.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
J. Bruce Fields2ca72e12011-01-04 17:37:15 -050021#include "idmap.h"
Boaz Harrosh9a74af22009-12-03 20:30:56 +020022#include "nfsd.h"
23#include "cache.h"
Bryan Schumakerf3c75212012-11-27 09:35:10 -050024#include "state.h"
Jeff Layton7ea34ac2012-03-21 09:52:05 -040025#include "netns.h"
Christoph Hellwig9cf514c2014-05-05 13:11:59 +020026#include "pnfs.h"
Boaz Harrosh9a74af22009-12-03 20:30:56 +020027
Linus Torvalds1da177e2005-04-16 15:20:36 -070028/*
Kevin Coffmanb0b0c0a2011-03-02 19:51:42 -050029 * We have a single directory with several nodes in it.
Linus Torvalds1da177e2005-04-16 15:20:36 -070030 */
31enum {
32 NFSD_Root = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -070033 NFSD_List,
J. Bruce Fieldse8e87532009-12-14 12:53:32 -050034 NFSD_Export_features,
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 NFSD_Fh,
Wendy Cheng4373ea82008-01-17 11:10:12 -050036 NFSD_FO_UnlockIP,
Wendy Cheng17efa372008-01-17 11:10:12 -050037 NFSD_FO_UnlockFS,
Linus Torvalds1da177e2005-04-16 15:20:36 -070038 NFSD_Threads,
Greg Bankseed29652006-10-02 02:18:02 -070039 NFSD_Pool_Threads,
Greg Banks03cf6c92009-01-13 21:26:36 +110040 NFSD_Pool_Stats,
Jeff Laytona2f999a2013-03-27 10:15:38 -040041 NFSD_Reply_Cache_Stats,
NeilBrown70c3b762005-11-07 01:00:25 -080042 NFSD_Versions,
NeilBrown80212d52006-10-02 02:17:47 -070043 NFSD_Ports,
NeilBrown596bbe52006-10-04 02:15:48 -070044 NFSD_MaxBlkSize,
Jeff Layton5b8db002014-07-02 16:11:22 -040045 NFSD_MaxConnections,
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,
Jeff Layton7f5ef2e2014-09-12 16:40:21 -040055 NFSD_V4EndGrace,
NeilBrown70c3b762005-11-07 01:00:25 -080056#endif
J. Bruce Fieldse8a79fb2019-03-22 11:11:06 -040057 NFSD_MaxReserved
Linus Torvalds1da177e2005-04-16 15:20:36 -070058};
59
60/*
61 * write() for these nodes.
62 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070063static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
Chuck Leverb046ccd2008-12-12 16:57:13 -050064static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
65static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
Linus Torvalds1da177e2005-04-16 15:20:36 -070066static ssize_t write_threads(struct file *file, char *buf, size_t size);
Greg Bankseed29652006-10-02 02:18:02 -070067static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
NeilBrown70c3b762005-11-07 01:00:25 -080068static ssize_t write_versions(struct file *file, char *buf, size_t size);
NeilBrown80212d52006-10-02 02:17:47 -070069static ssize_t write_ports(struct file *file, char *buf, size_t size);
NeilBrown596bbe52006-10-04 02:15:48 -070070static ssize_t write_maxblksize(struct file *file, char *buf, size_t size);
Jeff Layton5b8db002014-07-02 16:11:22 -040071static ssize_t write_maxconn(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 Fieldsefc4bb4f2010-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);
Jeff Layton7f5ef2e2014-09-12 16:40:21 -040076static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size);
NeilBrown70c3b762005-11-07 01:00:25 -080077#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Eric Biggersc2cdc2a2018-07-17 11:01:25 -070079static ssize_t (*const write_op[])(struct file *, char *, size_t) = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 [NFSD_Fh] = write_filehandle,
Chuck Leverb046ccd2008-12-12 16:57:13 -050081 [NFSD_FO_UnlockIP] = write_unlock_ip,
82 [NFSD_FO_UnlockFS] = write_unlock_fs,
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 [NFSD_Threads] = write_threads,
Greg Bankseed29652006-10-02 02:18:02 -070084 [NFSD_Pool_Threads] = write_pool_threads,
NeilBrown70c3b762005-11-07 01:00:25 -080085 [NFSD_Versions] = write_versions,
NeilBrown80212d52006-10-02 02:17:47 -070086 [NFSD_Ports] = write_ports,
NeilBrown596bbe52006-10-04 02:15:48 -070087 [NFSD_MaxBlkSize] = write_maxblksize,
Jeff Layton5b8db002014-07-02 16:11:22 -040088 [NFSD_MaxConnections] = write_maxconn,
NeilBrown70c3b762005-11-07 01:00:25 -080089#ifdef CONFIG_NFSD_V4
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 [NFSD_Leasetime] = write_leasetime,
J. Bruce Fieldsefc4bb4f2010-03-02 11:04:06 -050091 [NFSD_Gracetime] = write_gracetime,
NeilBrown0964a3d2005-06-23 22:04:32 -070092 [NFSD_RecoveryDir] = write_recoverydir,
Jeff Layton7f5ef2e2014-09-12 16:40:21 -040093 [NFSD_V4EndGrace] = write_v4_end_grace,
NeilBrown70c3b762005-11-07 01:00:25 -080094#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070095};
96
97static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
98{
Al Viro496ad9a2013-01-23 17:07:38 -050099 ino_t ino = file_inode(file)->i_ino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 char *data;
101 ssize_t rv;
102
Tobias Klausere8c96f82006-03-24 03:15:34 -0800103 if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 return -EINVAL;
105
106 data = simple_transaction_get(file, buf, size);
107 if (IS_ERR(data))
108 return PTR_ERR(data);
109
110 rv = write_op[ino](file, data, size);
NeilBrown8971a102007-02-14 00:33:11 -0800111 if (rv >= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 simple_transaction_set(file, rv);
113 rv = size;
114 }
115 return rv;
116}
117
NeilBrown73900222005-11-07 01:00:24 -0800118static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
119{
120 if (! file->private_data) {
121 /* An attempt to read a transaction file without writing
122 * causes a 0-byte write so that the file can return
123 * state information
124 */
125 ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos);
126 if (rv < 0)
127 return rv;
128 }
129 return simple_transaction_read(file, buf, size, pos);
130}
131
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800132static const struct file_operations transaction_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 .write = nfsctl_transaction_write,
NeilBrown73900222005-11-07 01:00:24 -0800134 .read = nfsctl_transaction_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 .release = simple_transaction_release,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200136 .llseek = default_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137};
138
Stanislav Kinsbursky96d851c2013-02-01 15:56:17 +0300139static int exports_net_open(struct net *net, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140{
Stanislav Kinsburskyf2c7ea12012-03-28 19:09:29 +0400141 int err;
142 struct seq_file *seq;
Stanislav Kinsbursky96d851c2013-02-01 15:56:17 +0300143 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
Stanislav Kinsburskyf2c7ea12012-03-28 19:09:29 +0400144
145 err = seq_open(file, &nfs_exports_op);
146 if (err)
147 return err;
148
149 seq = file->private_data;
Stanislav Kinsburskye5f06f72012-04-11 15:13:28 +0400150 seq->private = nn->svc_export_cache;
Stanislav Kinsburskyf2c7ea12012-03-28 19:09:29 +0400151 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152}
153
Stanislav Kinsbursky96d851c2013-02-01 15:56:17 +0300154static int exports_proc_open(struct inode *inode, struct file *file)
155{
156 return exports_net_open(current->nsproxy->net_ns, file);
157}
158
159static const struct file_operations exports_proc_operations = {
160 .open = exports_proc_open,
161 .read = seq_read,
162 .llseek = seq_lseek,
163 .release = seq_release,
Stanislav Kinsbursky96d851c2013-02-01 15:56:17 +0300164};
165
166static int exports_nfsd_open(struct inode *inode, struct file *file)
167{
168 return exports_net_open(inode->i_sb->s_fs_info, file);
169}
170
171static const struct file_operations exports_nfsd_operations = {
172 .open = exports_nfsd_open,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 .read = seq_read,
174 .llseek = seq_lseek,
175 .release = seq_release,
176};
177
J. Bruce Fieldse8e87532009-12-14 12:53:32 -0500178static int export_features_show(struct seq_file *m, void *v)
179{
180 seq_printf(m, "0x%x 0x%x\n", NFSEXP_ALLFLAGS, NFSEXP_SECINFO_FLAGS);
181 return 0;
182}
183
184static int export_features_open(struct inode *inode, struct file *file)
185{
186 return single_open(file, export_features_show, NULL);
187}
188
Al Viro75ef9de2013-04-04 19:09:41 -0400189static const struct file_operations export_features_operations = {
J. Bruce Fieldse8e87532009-12-14 12:53:32 -0500190 .open = export_features_open,
191 .read = seq_read,
192 .llseek = seq_lseek,
193 .release = single_release,
194};
195
J. Bruce Fieldsb084f592011-05-31 12:24:58 -0400196#if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
Kevin Coffmanb0b0c0a2011-03-02 19:51:42 -0500197static int supported_enctypes_show(struct seq_file *m, void *v)
198{
J. Bruce Fieldsb084f592011-05-31 12:24:58 -0400199 seq_printf(m, KRB5_SUPPORTED_ENCTYPES);
Kevin Coffmanb0b0c0a2011-03-02 19:51:42 -0500200 return 0;
201}
202
203static int supported_enctypes_open(struct inode *inode, struct file *file)
204{
205 return single_open(file, supported_enctypes_show, NULL);
206}
207
Al Viro75ef9de2013-04-04 19:09:41 -0400208static const struct file_operations supported_enctypes_ops = {
Kevin Coffmanb0b0c0a2011-03-02 19:51:42 -0500209 .open = supported_enctypes_open,
210 .read = seq_read,
211 .llseek = seq_lseek,
212 .release = single_release,
213};
J. Bruce Fieldsb084f592011-05-31 12:24:58 -0400214#endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
Kevin Coffmanb0b0c0a2011-03-02 19:51:42 -0500215
Alexey Dobriyan828c0952009-10-01 15:43:56 -0700216static const struct file_operations pool_stats_operations = {
Greg Banks03cf6c92009-01-13 21:26:36 +1100217 .open = nfsd_pool_stats_open,
218 .read = seq_read,
219 .llseek = seq_lseek,
Ryusei Yamaguchied2d8ae2009-08-16 00:54:41 +0900220 .release = nfsd_pool_stats_release,
Greg Banks03cf6c92009-01-13 21:26:36 +1100221};
222
Julia Lawall7ba630f2016-08-28 22:36:55 +0200223static const struct file_operations reply_cache_stats_operations = {
Jeff Laytona2f999a2013-03-27 10:15:38 -0400224 .open = nfsd_reply_cache_stats_open,
225 .read = seq_read,
226 .llseek = seq_lseek,
227 .release = single_release,
228};
229
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230/*----------------------------------------------------------------------------*/
231/*
232 * payload - write methods
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 */
234
Al Viro244c7d42014-10-21 20:19:11 -0400235static inline struct net *netns(struct file *file)
236{
237 return file_inode(file)->i_sb->s_fs_info;
238}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
Chuck Lever262a0982008-12-12 16:57:35 -0500240/**
241 * write_unlock_ip - Release all locks used by a client
242 *
243 * Experimental.
244 *
245 * Input:
246 * buf: '\n'-terminated C string containing a
Chuck Lever41160922009-08-09 15:09:40 -0400247 * presentation format IP address
Chuck Lever262a0982008-12-12 16:57:35 -0500248 * size: length of C string in @buf
249 * Output:
250 * On success: returns zero if all specified locks were released;
251 * returns one if one or more locks were not released
252 * On error: return code is negative errno value
Chuck Lever262a0982008-12-12 16:57:35 -0500253 */
Chuck Leverb046ccd2008-12-12 16:57:13 -0500254static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
Wendy Cheng4373ea82008-01-17 11:10:12 -0500255{
Chuck Lever41160922009-08-09 15:09:40 -0400256 struct sockaddr_storage address;
257 struct sockaddr *sap = (struct sockaddr *)&address;
258 size_t salen = sizeof(address);
Chuck Lever367c8c72008-06-30 18:58:14 -0400259 char *fo_path;
Al Viro244c7d42014-10-21 20:19:11 -0400260 struct net *net = netns(file);
Wendy Cheng4373ea82008-01-17 11:10:12 -0500261
262 /* sanity check */
263 if (size == 0)
264 return -EINVAL;
265
266 if (buf[size-1] != '\n')
267 return -EINVAL;
268
269 fo_path = buf;
270 if (qword_get(&buf, fo_path, size) < 0)
271 return -EINVAL;
272
Stanislav Kinsbursky11f77942013-02-01 15:56:12 +0300273 if (rpc_pton(net, fo_path, size, sap, salen) == 0)
Wendy Cheng4373ea82008-01-17 11:10:12 -0500274 return -EINVAL;
Wendy Cheng4373ea82008-01-17 11:10:12 -0500275
Chuck Lever41160922009-08-09 15:09:40 -0400276 return nlmsvc_unlock_all_by_ip(sap);
Wendy Cheng4373ea82008-01-17 11:10:12 -0500277}
278
Chuck Lever262a0982008-12-12 16:57:35 -0500279/**
280 * write_unlock_fs - Release all locks on a local file system
281 *
282 * Experimental.
283 *
284 * Input:
285 * buf: '\n'-terminated C string containing the
286 * absolute pathname of a local file system
287 * size: length of C string in @buf
288 * Output:
289 * On success: returns zero if all specified locks were released;
290 * returns one if one or more locks were not released
291 * On error: return code is negative errno value
292 */
Chuck Leverb046ccd2008-12-12 16:57:13 -0500293static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
Wendy Cheng17efa372008-01-17 11:10:12 -0500294{
Al Viroa63bb992008-08-02 01:03:36 -0400295 struct path path;
Wendy Cheng17efa372008-01-17 11:10:12 -0500296 char *fo_path;
297 int error;
298
299 /* sanity check */
300 if (size == 0)
301 return -EINVAL;
302
303 if (buf[size-1] != '\n')
304 return -EINVAL;
305
306 fo_path = buf;
307 if (qword_get(&buf, fo_path, size) < 0)
308 return -EINVAL;
309
Al Viroa63bb992008-08-02 01:03:36 -0400310 error = kern_path(fo_path, 0, &path);
Wendy Cheng17efa372008-01-17 11:10:12 -0500311 if (error)
312 return error;
313
Chuck Lever262a0982008-12-12 16:57:35 -0500314 /*
315 * XXX: Needs better sanity checking. Otherwise we could end up
316 * releasing locks on the wrong file system.
317 *
318 * For example:
319 * 1. Does the path refer to a directory?
320 * 2. Is that directory a mount point, or
321 * 3. Is that directory the root of an exported file system?
322 */
Al Virod8c95842011-12-07 18:16:57 -0500323 error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb);
Wendy Cheng17efa372008-01-17 11:10:12 -0500324
Al Viroa63bb992008-08-02 01:03:36 -0400325 path_put(&path);
Wendy Cheng17efa372008-01-17 11:10:12 -0500326 return error;
327}
328
Chuck Lever262a0982008-12-12 16:57:35 -0500329/**
330 * write_filehandle - Get a variable-length NFS file handle by path
331 *
332 * On input, the buffer contains a '\n'-terminated C string comprised of
333 * three alphanumeric words separated by whitespace. The string may
334 * contain escape sequences.
335 *
336 * Input:
337 * buf:
338 * domain: client domain name
339 * path: export pathname
340 * maxsize: numeric maximum size of
341 * @buf
342 * size: length of C string in @buf
343 * Output:
344 * On success: passed-in buffer filled with '\n'-terminated C
345 * string containing a ASCII hex text version
346 * of the NFS file handle;
347 * return code is the size in bytes of the string
348 * On error: return code is negative errno value
349 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
351{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 char *dname, *path;
Andrew Morton246d95b2007-08-09 00:53:50 -0700353 int uninitialized_var(maxsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 char *mesg = buf;
355 int len;
356 struct auth_domain *dom;
357 struct knfsd_fh fh;
358
J. Bruce Fields87d26ea2008-01-22 17:40:42 -0500359 if (size == 0)
360 return -EINVAL;
361
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 if (buf[size-1] != '\n')
363 return -EINVAL;
364 buf[size-1] = 0;
365
366 dname = mesg;
367 len = qword_get(&mesg, dname, size);
Chuck Lever54224f02008-12-12 16:57:20 -0500368 if (len <= 0)
369 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371 path = dname+len+1;
372 len = qword_get(&mesg, path, size);
Chuck Lever54224f02008-12-12 16:57:20 -0500373 if (len <= 0)
374 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 len = get_int(&mesg, &maxsize);
377 if (len)
378 return len;
379
380 if (maxsize < NFS_FHSIZE)
381 return -EINVAL;
Kinglong Mee3c7aa152014-06-10 18:08:19 +0800382 maxsize = min(maxsize, NFS3_FHSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
384 if (qword_get(&mesg, mesg, size)>0)
385 return -EINVAL;
386
387 /* we have all the words, they are in buf.. */
388 dom = unix_domain_find(dname);
389 if (!dom)
390 return -ENOMEM;
391
Al Viro244c7d42014-10-21 20:19:11 -0400392 len = exp_rootfh(netns(file), dom, path, &fh, maxsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 auth_domain_put(dom);
394 if (len)
395 return len;
396
Chuck Lever54224f02008-12-12 16:57:20 -0500397 mesg = buf;
398 len = SIMPLE_TRANSACTION_LIMIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size);
400 mesg[-1] = '\n';
401 return mesg - buf;
402}
403
Chuck Lever262a0982008-12-12 16:57:35 -0500404/**
405 * write_threads - Start NFSD, or report the current number of running threads
406 *
407 * Input:
408 * buf: ignored
409 * size: zero
410 * Output:
411 * On success: passed-in buffer filled with '\n'-terminated C
412 * string numeric value representing the number of
413 * running NFSD threads;
414 * return code is the size in bytes of the string
415 * On error: return code is zero
416 *
417 * OR
418 *
419 * Input:
420 * buf: C string containing an unsigned
421 * integer value representing the
422 * number of NFSD threads to start
423 * size: non-zero length of C string in @buf
424 * Output:
425 * On success: NFS service is started;
426 * passed-in buffer filled with '\n'-terminated C
427 * string numeric value representing the number of
428 * running NFSD threads;
429 * return code is the size in bytes of the string
430 * On error: return code is zero or a negative errno value
431 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432static ssize_t write_threads(struct file *file, char *buf, size_t size)
433{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 char *mesg = buf;
435 int rv;
Al Viro244c7d42014-10-21 20:19:11 -0400436 struct net *net = netns(file);
Stanislav Kinsburskyd41a9412012-12-10 12:19:25 +0300437
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 if (size > 0) {
439 int newthreads;
440 rv = get_int(&mesg, &newthreads);
441 if (rv)
442 return rv;
Chuck Lever9e074852008-12-12 16:57:27 -0500443 if (newthreads < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 return -EINVAL;
Trond Myklebust4df493a2019-04-09 12:13:37 -0400445 rv = nfsd_svc(newthreads, net, file->f_cred);
NeilBrown82e12fe2009-06-16 11:03:07 +1000446 if (rv < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 return rv;
NeilBrown82e12fe2009-06-16 11:03:07 +1000448 } else
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300449 rv = nfsd_nrthreads(net);
Chuck Levere06b6402009-04-23 19:33:25 -0400450
NeilBrown82e12fe2009-06-16 11:03:07 +1000451 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452}
453
Chuck Lever262a0982008-12-12 16:57:35 -0500454/**
455 * write_pool_threads - Set or report the current number of threads per pool
456 *
457 * Input:
458 * buf: ignored
459 * size: zero
460 *
461 * OR
462 *
463 * Input:
464 * buf: C string containing whitespace-
465 * separated unsigned integer values
466 * representing the number of NFSD
467 * threads to start in each pool
468 * size: non-zero length of C string in @buf
469 * Output:
470 * On success: passed-in buffer filled with '\n'-terminated C
471 * string containing integer values representing the
472 * number of NFSD threads in each pool;
473 * return code is the size in bytes of the string
474 * On error: return code is zero or a negative errno value
475 */
Greg Bankseed29652006-10-02 02:18:02 -0700476static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
477{
478 /* if size > 0, look for an array of number of threads per node
479 * and apply them then write out number of threads per node as reply
480 */
481 char *mesg = buf;
482 int i;
483 int rv;
484 int len;
Neil Brownbedbdd82008-06-10 08:40:35 -0400485 int npools;
Greg Bankseed29652006-10-02 02:18:02 -0700486 int *nthreads;
Al Viro244c7d42014-10-21 20:19:11 -0400487 struct net *net = netns(file);
Greg Bankseed29652006-10-02 02:18:02 -0700488
Neil Brownbedbdd82008-06-10 08:40:35 -0400489 mutex_lock(&nfsd_mutex);
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300490 npools = nfsd_nrpools(net);
Greg Bankseed29652006-10-02 02:18:02 -0700491 if (npools == 0) {
492 /*
493 * NFS is shut down. The admin can start it by
494 * writing to the threads file but NOT the pool_threads
495 * file, sorry. Report zero threads.
496 */
Neil Brownbedbdd82008-06-10 08:40:35 -0400497 mutex_unlock(&nfsd_mutex);
Greg Bankseed29652006-10-02 02:18:02 -0700498 strcpy(buf, "0\n");
499 return strlen(buf);
500 }
501
502 nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL);
Neil Brownbedbdd82008-06-10 08:40:35 -0400503 rv = -ENOMEM;
Greg Bankseed29652006-10-02 02:18:02 -0700504 if (nthreads == NULL)
Neil Brownbedbdd82008-06-10 08:40:35 -0400505 goto out_free;
Greg Bankseed29652006-10-02 02:18:02 -0700506
507 if (size > 0) {
508 for (i = 0; i < npools; i++) {
509 rv = get_int(&mesg, &nthreads[i]);
510 if (rv == -ENOENT)
511 break; /* fewer numbers than pools */
512 if (rv)
513 goto out_free; /* syntax error */
514 rv = -EINVAL;
515 if (nthreads[i] < 0)
516 goto out_free;
517 }
Stanislav Kinsbursky3938a0d2012-12-10 12:19:30 +0300518 rv = nfsd_set_nrthreads(i, nthreads, net);
Greg Bankseed29652006-10-02 02:18:02 -0700519 if (rv)
520 goto out_free;
521 }
522
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300523 rv = nfsd_get_nrthreads(npools, nthreads, net);
Greg Bankseed29652006-10-02 02:18:02 -0700524 if (rv)
525 goto out_free;
526
527 mesg = buf;
528 size = SIMPLE_TRANSACTION_LIMIT;
529 for (i = 0; i < npools && size > 0; i++) {
530 snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' '));
531 len = strlen(mesg);
532 size -= len;
533 mesg += len;
534 }
J. Bruce Fields413d63d7102009-07-28 11:37:25 -0400535 rv = mesg - buf;
Greg Bankseed29652006-10-02 02:18:02 -0700536out_free:
537 kfree(nthreads);
Neil Brownbedbdd82008-06-10 08:40:35 -0400538 mutex_unlock(&nfsd_mutex);
Greg Bankseed29652006-10-02 02:18:02 -0700539 return rv;
540}
541
Trond Myklebustff7d1172017-02-22 18:35:33 -0500542static ssize_t
Trond Myklebuste333f3b2019-04-09 11:46:19 -0400543nfsd_print_version_support(struct nfsd_net *nn, char *buf, int remaining,
544 const char *sep, unsigned vers, int minor)
Trond Myklebustff7d1172017-02-22 18:35:33 -0500545{
NeilBrownabcb4da2017-03-10 11:36:39 +1100546 const char *format = minor < 0 ? "%s%c%u" : "%s%c%u.%u";
Trond Myklebuste333f3b2019-04-09 11:46:19 -0400547 bool supported = !!nfsd_vers(nn, vers, NFSD_TEST);
Trond Myklebustff7d1172017-02-22 18:35:33 -0500548
NeilBrownabcb4da2017-03-10 11:36:39 +1100549 if (vers == 4 && minor >= 0 &&
Trond Myklebuste333f3b2019-04-09 11:46:19 -0400550 !nfsd_minorversion(nn, minor, NFSD_TEST))
Trond Myklebustff7d1172017-02-22 18:35:33 -0500551 supported = false;
NeilBrownabcb4da2017-03-10 11:36:39 +1100552 if (minor == 0 && supported)
553 /*
554 * special case for backward compatability.
555 * +4.0 is never reported, it is implied by
556 * +4, unless -4.0 is present.
557 */
558 return 0;
Trond Myklebustff7d1172017-02-22 18:35:33 -0500559 return snprintf(buf, remaining, format, sep,
560 supported ? '+' : '-', vers, minor);
561}
562
Jeff Layton3dd98a32008-06-10 08:40:36 -0400563static ssize_t __write_versions(struct file *file, char *buf, size_t size)
NeilBrown70c3b762005-11-07 01:00:25 -0800564{
NeilBrown70c3b762005-11-07 01:00:25 -0800565 char *mesg = buf;
Benny Halevy8daf2202009-04-03 08:28:59 +0300566 char *vers, *minorp, sign;
Chuck Lever261758b2009-04-23 19:33:18 -0400567 int len, num, remaining;
NeilBrown70c3b762005-11-07 01:00:25 -0800568 ssize_t tlen = 0;
569 char *sep;
Al Viro244c7d42014-10-21 20:19:11 -0400570 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
NeilBrown70c3b762005-11-07 01:00:25 -0800571
572 if (size>0) {
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300573 if (nn->nfsd_serv)
NeilBrown6658d3a2006-10-02 02:17:46 -0700574 /* Cannot change versions without updating
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300575 * nn->nfsd_serv->sv_xdrsize, and reallocing
NeilBrown6658d3a2006-10-02 02:17:46 -0700576 * rq_argp and rq_resp
577 */
NeilBrown70c3b762005-11-07 01:00:25 -0800578 return -EBUSY;
579 if (buf[size-1] != '\n')
580 return -EINVAL;
581 buf[size-1] = 0;
582
583 vers = mesg;
584 len = qword_get(&mesg, vers, size);
585 if (len <= 0) return -EINVAL;
586 do {
Trond Myklebustd3635ff2017-02-22 18:35:32 -0500587 enum vers_op cmd;
NeilBrownabcb4da2017-03-10 11:36:39 +1100588 unsigned minor;
NeilBrown70c3b762005-11-07 01:00:25 -0800589 sign = *vers;
590 if (sign == '+' || sign == '-')
Benny Halevy8daf2202009-04-03 08:28:59 +0300591 num = simple_strtol((vers+1), &minorp, 0);
NeilBrown70c3b762005-11-07 01:00:25 -0800592 else
Benny Halevy8daf2202009-04-03 08:28:59 +0300593 num = simple_strtol(vers, &minorp, 0);
594 if (*minorp == '.') {
J. Bruce Fieldsff89be82013-01-23 18:25:01 -0500595 if (num != 4)
Benny Halevy8daf2202009-04-03 08:28:59 +0300596 return -EINVAL;
NeilBrowne35659f2016-12-21 14:32:19 +1100597 if (kstrtouint(minorp+1, 0, &minor) < 0)
Benny Halevy8daf2202009-04-03 08:28:59 +0300598 return -EINVAL;
NeilBrownabcb4da2017-03-10 11:36:39 +1100599 }
600
Trond Myklebustd3635ff2017-02-22 18:35:32 -0500601 cmd = sign == '-' ? NFSD_CLEAR : NFSD_SET;
NeilBrown70c3b762005-11-07 01:00:25 -0800602 switch(num) {
603 case 2:
604 case 3:
Trond Myklebuste333f3b2019-04-09 11:46:19 -0400605 nfsd_vers(nn, num, cmd);
NeilBrown70c3b762005-11-07 01:00:25 -0800606 break;
Trond Myklebustd3635ff2017-02-22 18:35:32 -0500607 case 4:
NeilBrownabcb4da2017-03-10 11:36:39 +1100608 if (*minorp == '.') {
Trond Myklebuste333f3b2019-04-09 11:46:19 -0400609 if (nfsd_minorversion(nn, minor, cmd) < 0)
NeilBrownabcb4da2017-03-10 11:36:39 +1100610 return -EINVAL;
Trond Myklebuste333f3b2019-04-09 11:46:19 -0400611 } else if ((cmd == NFSD_SET) != nfsd_vers(nn, num, NFSD_TEST)) {
NeilBrownabcb4da2017-03-10 11:36:39 +1100612 /*
613 * Either we have +4 and no minors are enabled,
614 * or we have -4 and at least one minor is enabled.
615 * In either case, propagate 'cmd' to all minors.
616 */
617 minor = 0;
Trond Myklebuste333f3b2019-04-09 11:46:19 -0400618 while (nfsd_minorversion(nn, minor, cmd) >= 0)
NeilBrownabcb4da2017-03-10 11:36:39 +1100619 minor++;
620 }
621 break;
NeilBrown70c3b762005-11-07 01:00:25 -0800622 default:
623 return -EINVAL;
624 }
625 vers += len + 1;
NeilBrown70c3b762005-11-07 01:00:25 -0800626 } while ((len = qword_get(&mesg, vers, size)) > 0);
627 /* If all get turned off, turn them back on, as
628 * having no versions is BAD
629 */
Trond Myklebuste333f3b2019-04-09 11:46:19 -0400630 nfsd_reset_versions(nn);
NeilBrown70c3b762005-11-07 01:00:25 -0800631 }
Chuck Lever261758b2009-04-23 19:33:18 -0400632
NeilBrown70c3b762005-11-07 01:00:25 -0800633 /* Now write current state into reply buffer */
634 len = 0;
635 sep = "";
Chuck Lever261758b2009-04-23 19:33:18 -0400636 remaining = SIMPLE_TRANSACTION_LIMIT;
Trond Myklebustff7d1172017-02-22 18:35:33 -0500637 for (num=2 ; num <= 4 ; num++) {
NeilBrownabcb4da2017-03-10 11:36:39 +1100638 int minor;
Trond Myklebuste333f3b2019-04-09 11:46:19 -0400639 if (!nfsd_vers(nn, num, NFSD_AVAIL))
Trond Myklebustff7d1172017-02-22 18:35:33 -0500640 continue;
NeilBrownabcb4da2017-03-10 11:36:39 +1100641
642 minor = -1;
Trond Myklebustff7d1172017-02-22 18:35:33 -0500643 do {
Trond Myklebuste333f3b2019-04-09 11:46:19 -0400644 len = nfsd_print_version_support(nn, buf, remaining,
Trond Myklebustff7d1172017-02-22 18:35:33 -0500645 sep, num, minor);
646 if (len >= remaining)
647 goto out;
648 remaining -= len;
649 buf += len;
650 tlen += len;
651 minor++;
NeilBrownabcb4da2017-03-10 11:36:39 +1100652 if (len)
653 sep = " ";
Trond Myklebustff7d1172017-02-22 18:35:33 -0500654 } while (num == 4 && minor <= NFSD_SUPPORTED_MINOR_VERSION);
655 }
656out:
Chuck Lever261758b2009-04-23 19:33:18 -0400657 len = snprintf(buf, remaining, "\n");
Dan Carpenter818f2f52014-11-27 18:58:54 +0300658 if (len >= remaining)
Chuck Lever261758b2009-04-23 19:33:18 -0400659 return -EINVAL;
660 return tlen + len;
NeilBrown70c3b762005-11-07 01:00:25 -0800661}
662
Chuck Lever262a0982008-12-12 16:57:35 -0500663/**
664 * write_versions - Set or report the available NFS protocol versions
665 *
666 * Input:
667 * buf: ignored
668 * size: zero
669 * Output:
670 * On success: passed-in buffer filled with '\n'-terminated C
671 * string containing positive or negative integer
672 * values representing the current status of each
673 * protocol version;
674 * return code is the size in bytes of the string
675 * On error: return code is zero or a negative errno value
676 *
677 * OR
678 *
679 * Input:
680 * buf: C string containing whitespace-
681 * separated positive or negative
682 * integer values representing NFS
683 * protocol versions to enable ("+n")
684 * or disable ("-n")
685 * size: non-zero length of C string in @buf
686 * Output:
687 * On success: status of zero or more protocol versions has
688 * been updated; passed-in buffer filled with
689 * '\n'-terminated C string containing positive
690 * or negative integer values representing the
691 * current status of each protocol version;
692 * return code is the size in bytes of the string
693 * On error: return code is zero or a negative errno value
694 */
Jeff Layton3dd98a32008-06-10 08:40:36 -0400695static ssize_t write_versions(struct file *file, char *buf, size_t size)
696{
697 ssize_t rv;
698
699 mutex_lock(&nfsd_mutex);
700 rv = __write_versions(file, buf, size);
701 mutex_unlock(&nfsd_mutex);
702 return rv;
703}
704
Chuck Lever4cd5dc72009-04-23 19:31:32 -0400705/*
Chuck Lever0a5372d2009-04-23 19:32:10 -0400706 * Zero-length write. Return a list of NFSD's current listener
707 * transports.
708 */
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300709static ssize_t __write_ports_names(char *buf, struct net *net)
Chuck Lever0a5372d2009-04-23 19:32:10 -0400710{
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300711 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
712
713 if (nn->nfsd_serv == NULL)
Chuck Lever0a5372d2009-04-23 19:32:10 -0400714 return 0;
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300715 return svc_xprt_names(nn->nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
Chuck Lever0a5372d2009-04-23 19:32:10 -0400716}
717
718/*
Chuck Lever0b7c2f62009-04-23 19:31:55 -0400719 * A single 'fd' number was written, in which case it must be for
720 * a socket of a supported family/protocol, and we use it as an
721 * nfsd listener.
722 */
Trond Myklebust4df493a2019-04-09 12:13:37 -0400723static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred *cred)
Chuck Lever0b7c2f62009-04-23 19:31:55 -0400724{
725 char *mesg = buf;
726 int fd, err;
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300727 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
Chuck Lever0b7c2f62009-04-23 19:31:55 -0400728
729 err = get_int(&mesg, &fd);
730 if (err != 0 || fd < 0)
731 return -EINVAL;
732
Stanislav Kinsbursky30646392014-02-26 16:50:01 +0300733 if (svc_alien_sock(net, fd)) {
734 printk(KERN_ERR "%s: socket net is different to NFSd's one\n", __func__);
735 return -EINVAL;
736 }
737
Stanislav Kinsbursky67774362012-12-10 12:19:20 +0300738 err = nfsd_create_serv(net);
Chuck Lever0b7c2f62009-04-23 19:31:55 -0400739 if (err != 0)
740 return err;
741
Trond Myklebust4df493a2019-04-09 12:13:37 -0400742 err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred);
Jeff Layton78a8d7c2010-07-19 16:50:05 -0400743 if (err < 0) {
Stanislav Kinsbursky19f7e2c2012-07-03 16:46:41 +0400744 nfsd_destroy(net);
Jeff Layton78a8d7c2010-07-19 16:50:05 -0400745 return err;
746 }
Chuck Lever0b7c2f62009-04-23 19:31:55 -0400747
Chuck Leverea068ba2009-04-23 19:32:18 -0400748 /* Decrease the count, but don't shut down the service */
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300749 nn->nfsd_serv->sv_nrthreads--;
Chuck Leverea068ba2009-04-23 19:32:18 -0400750 return err;
Chuck Lever0b7c2f62009-04-23 19:31:55 -0400751}
752
753/*
Chuck Lever4eb68c22009-04-23 19:31:40 -0400754 * A transport listener is added by writing it's transport name and
755 * a port number.
756 */
Trond Myklebust4df493a2019-04-09 12:13:37 -0400757static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cred *cred)
Chuck Lever4eb68c22009-04-23 19:31:40 -0400758{
759 char transport[16];
Chuck Lever37498292010-01-26 14:04:22 -0500760 struct svc_xprt *xprt;
Chuck Lever4eb68c22009-04-23 19:31:40 -0400761 int port, err;
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300762 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
Chuck Lever4eb68c22009-04-23 19:31:40 -0400763
J. Bruce Fieldsa10fded2012-08-14 17:48:39 -0400764 if (sscanf(buf, "%15s %5u", transport, &port) != 2)
Chuck Lever4eb68c22009-04-23 19:31:40 -0400765 return -EINVAL;
766
Alexey Dobriyan4be929b2010-05-24 14:33:03 -0700767 if (port < 1 || port > USHRT_MAX)
Chuck Lever4eb68c22009-04-23 19:31:40 -0400768 return -EINVAL;
769
Stanislav Kinsbursky67774362012-12-10 12:19:20 +0300770 err = nfsd_create_serv(net);
Chuck Lever4eb68c22009-04-23 19:31:40 -0400771 if (err != 0)
772 return err;
773
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300774 err = svc_create_xprt(nn->nfsd_serv, transport, net,
Trond Myklebust4df493a2019-04-09 12:13:37 -0400775 PF_INET, port, SVC_SOCK_ANONYMOUS, cred);
Chuck Lever68717902010-01-26 14:04:13 -0500776 if (err < 0)
Chuck Lever37498292010-01-26 14:04:22 -0500777 goto out_err;
778
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300779 err = svc_create_xprt(nn->nfsd_serv, transport, net,
Trond Myklebust4df493a2019-04-09 12:13:37 -0400780 PF_INET6, port, SVC_SOCK_ANONYMOUS, cred);
Chuck Lever37498292010-01-26 14:04:22 -0500781 if (err < 0 && err != -EAFNOSUPPORT)
782 goto out_close;
Jeff Layton0cd14a02010-07-19 16:50:06 -0400783
784 /* Decrease the count, but don't shut down the service */
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300785 nn->nfsd_serv->sv_nrthreads--;
Chuck Lever4eb68c22009-04-23 19:31:40 -0400786 return 0;
Chuck Lever37498292010-01-26 14:04:22 -0500787out_close:
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300788 xprt = svc_find_xprt(nn->nfsd_serv, transport, net, PF_INET, port);
Chuck Lever37498292010-01-26 14:04:22 -0500789 if (xprt != NULL) {
790 svc_close_xprt(xprt);
791 svc_xprt_put(xprt);
792 }
793out_err:
Stanislav Kinsbursky19f7e2c2012-07-03 16:46:41 +0400794 nfsd_destroy(net);
Chuck Lever37498292010-01-26 14:04:22 -0500795 return err;
Chuck Lever4eb68c22009-04-23 19:31:40 -0400796}
797
Stanislav Kinsbursky08160352012-12-10 12:19:35 +0300798static ssize_t __write_ports(struct file *file, char *buf, size_t size,
799 struct net *net)
NeilBrown80212d52006-10-02 02:17:47 -0700800{
Chuck Lever0a5372d2009-04-23 19:32:10 -0400801 if (size == 0)
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300802 return __write_ports_names(buf, net);
Chuck Lever0b7c2f62009-04-23 19:31:55 -0400803
804 if (isdigit(buf[0]))
Trond Myklebust4df493a2019-04-09 12:13:37 -0400805 return __write_ports_addfd(buf, net, file->f_cred);
Chuck Lever82d56592009-04-23 19:31:48 -0400806
Chuck Lever4eb68c22009-04-23 19:31:40 -0400807 if (isalpha(buf[0]))
Trond Myklebust4df493a2019-04-09 12:13:37 -0400808 return __write_ports_addxprt(buf, net, file->f_cred);
Chuck Lever4cd5dc72009-04-23 19:31:32 -0400809
NeilBrownb41b66d2006-10-02 02:17:48 -0700810 return -EINVAL;
NeilBrown80212d52006-10-02 02:17:47 -0700811}
812
Chuck Lever262a0982008-12-12 16:57:35 -0500813/**
814 * write_ports - Pass a socket file descriptor or transport name to listen on
815 *
816 * Input:
817 * buf: ignored
818 * size: zero
819 * Output:
820 * On success: passed-in buffer filled with a '\n'-terminated C
821 * string containing a whitespace-separated list of
822 * named NFSD listeners;
823 * return code is the size in bytes of the string
824 * On error: return code is zero or a negative errno value
825 *
826 * OR
827 *
828 * Input:
829 * buf: C string containing an unsigned
830 * integer value representing a bound
831 * but unconnected socket that is to be
Chuck Leverc71206a2009-04-23 19:32:03 -0400832 * used as an NFSD listener; listen(3)
833 * must be called for a SOCK_STREAM
834 * socket, otherwise it is ignored
Chuck Lever262a0982008-12-12 16:57:35 -0500835 * size: non-zero length of C string in @buf
836 * Output:
837 * On success: NFS service is started;
838 * passed-in buffer filled with a '\n'-terminated C
839 * string containing a unique alphanumeric name of
840 * the listener;
841 * return code is the size in bytes of the string
842 * On error: return code is a negative errno value
843 *
844 * OR
845 *
846 * Input:
Chuck Lever262a0982008-12-12 16:57:35 -0500847 * buf: C string containing a transport
848 * name and an unsigned integer value
849 * representing the port to listen on,
850 * separated by whitespace
851 * size: non-zero length of C string in @buf
852 * Output:
853 * On success: returns zero; NFS service is started
854 * On error: return code is a negative errno value
Chuck Lever262a0982008-12-12 16:57:35 -0500855 */
Neil Brownbedbdd82008-06-10 08:40:35 -0400856static ssize_t write_ports(struct file *file, char *buf, size_t size)
857{
858 ssize_t rv;
Jeff Layton3dd98a32008-06-10 08:40:36 -0400859
Neil Brownbedbdd82008-06-10 08:40:35 -0400860 mutex_lock(&nfsd_mutex);
Al Viro244c7d42014-10-21 20:19:11 -0400861 rv = __write_ports(file, buf, size, netns(file));
Neil Brownbedbdd82008-06-10 08:40:35 -0400862 mutex_unlock(&nfsd_mutex);
863 return rv;
864}
865
866
NeilBrown596bbe52006-10-04 02:15:48 -0700867int nfsd_max_blksize;
868
Chuck Lever262a0982008-12-12 16:57:35 -0500869/**
870 * write_maxblksize - Set or report the current NFS blksize
871 *
872 * Input:
873 * buf: ignored
874 * size: zero
875 *
876 * OR
877 *
878 * Input:
879 * buf: C string containing an unsigned
880 * integer value representing the new
881 * NFS blksize
882 * size: non-zero length of C string in @buf
883 * Output:
884 * On success: passed-in buffer filled with '\n'-terminated C string
885 * containing numeric value of the current NFS blksize
886 * setting;
887 * return code is the size in bytes of the string
888 * On error: return code is zero or a negative errno value
889 */
NeilBrown596bbe52006-10-04 02:15:48 -0700890static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
891{
892 char *mesg = buf;
Al Viro244c7d42014-10-21 20:19:11 -0400893 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300894
NeilBrown596bbe52006-10-04 02:15:48 -0700895 if (size > 0) {
896 int bsize;
897 int rv = get_int(&mesg, &bsize);
898 if (rv)
899 return rv;
900 /* force bsize into allowed range and
901 * required alignment.
902 */
Kinglong Mee3c7aa152014-06-10 18:08:19 +0800903 bsize = max_t(int, bsize, 1024);
904 bsize = min_t(int, bsize, NFSSVC_MAXBLKSIZE);
NeilBrown596bbe52006-10-04 02:15:48 -0700905 bsize &= ~(1024-1);
Neil Brownbedbdd82008-06-10 08:40:35 -0400906 mutex_lock(&nfsd_mutex);
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300907 if (nn->nfsd_serv) {
Neil Brownbedbdd82008-06-10 08:40:35 -0400908 mutex_unlock(&nfsd_mutex);
NeilBrown596bbe52006-10-04 02:15:48 -0700909 return -EBUSY;
910 }
911 nfsd_max_blksize = bsize;
Neil Brownbedbdd82008-06-10 08:40:35 -0400912 mutex_unlock(&nfsd_mutex);
NeilBrown596bbe52006-10-04 02:15:48 -0700913 }
Chuck Levere06b6402009-04-23 19:33:25 -0400914
915 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n",
916 nfsd_max_blksize);
NeilBrown596bbe52006-10-04 02:15:48 -0700917}
918
Jeff Layton5b8db002014-07-02 16:11:22 -0400919/**
920 * write_maxconn - Set or report the current max number of connections
921 *
922 * Input:
923 * buf: ignored
924 * size: zero
925 * OR
926 *
927 * Input:
928 * buf: C string containing an unsigned
929 * integer value representing the new
930 * number of max connections
931 * size: non-zero length of C string in @buf
932 * Output:
933 * On success: passed-in buffer filled with '\n'-terminated C string
934 * containing numeric value of max_connections setting
935 * for this net namespace;
936 * return code is the size in bytes of the string
937 * On error: return code is zero or a negative errno value
938 */
939static ssize_t write_maxconn(struct file *file, char *buf, size_t size)
940{
941 char *mesg = buf;
Al Viro244c7d42014-10-21 20:19:11 -0400942 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
Jeff Layton5b8db002014-07-02 16:11:22 -0400943 unsigned int maxconn = nn->max_connections;
944
945 if (size > 0) {
946 int rv = get_uint(&mesg, &maxconn);
947
948 if (rv)
949 return rv;
950 nn->max_connections = maxconn;
951 }
952
953 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%u\n", maxconn);
954}
955
NeilBrown70c3b762005-11-07 01:00:25 -0800956#ifdef CONFIG_NFSD_V4
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300957static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size,
958 time_t *time, struct nfsd_net *nn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 char *mesg = buf;
J. Bruce Fieldsf0135742010-03-01 19:32:36 -0500961 int rv, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
963 if (size > 0) {
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300964 if (nn->nfsd_serv)
Jeff Layton3dd98a32008-06-10 08:40:36 -0400965 return -EBUSY;
J. Bruce Fieldsf0135742010-03-01 19:32:36 -0500966 rv = get_int(&mesg, &i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 if (rv)
968 return rv;
J. Bruce Fieldse7b184f2010-03-02 11:18:40 -0500969 /*
970 * Some sanity checking. We don't have a reason for
971 * these particular numbers, but problems with the
972 * extremes are:
973 * - Too short: the briefest network outage may
974 * cause clients to lose all their locks. Also,
975 * the frequent polling may be wasteful.
976 * - Too long: do you really want reboot recovery
977 * to take more than an hour? Or to make other
978 * clients wait an hour before being able to
979 * revoke a dead client's locks?
980 */
J. Bruce Fieldsf0135742010-03-01 19:32:36 -0500981 if (i < 10 || i > 3600)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 return -EINVAL;
J. Bruce Fieldsf0135742010-03-01 19:32:36 -0500983 *time = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 }
Chuck Levere06b6402009-04-23 19:33:25 -0400985
J. Bruce Fieldsf0135742010-03-01 19:32:36 -0500986 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", *time);
987}
988
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300989static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size,
990 time_t *time, struct nfsd_net *nn)
J. Bruce Fieldsf0135742010-03-01 19:32:36 -0500991{
992 ssize_t rv;
993
994 mutex_lock(&nfsd_mutex);
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +0300995 rv = __nfsd4_write_time(file, buf, size, time, nn);
J. Bruce Fieldsf0135742010-03-01 19:32:36 -0500996 mutex_unlock(&nfsd_mutex);
997 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998}
999
Chuck Lever262a0982008-12-12 16:57:35 -05001000/**
1001 * write_leasetime - Set or report the current NFSv4 lease time
1002 *
1003 * Input:
1004 * buf: ignored
1005 * size: zero
1006 *
1007 * OR
1008 *
1009 * Input:
1010 * buf: C string containing an unsigned
1011 * integer value representing the new
1012 * NFSv4 lease expiry time
1013 * size: non-zero length of C string in @buf
1014 * Output:
1015 * On success: passed-in buffer filled with '\n'-terminated C
1016 * string containing unsigned integer value of the
1017 * current lease expiry time;
1018 * return code is the size in bytes of the string
1019 * On error: return code is zero or a negative errno value
1020 */
Jeff Layton3dd98a32008-06-10 08:40:36 -04001021static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
1022{
Al Viro244c7d42014-10-21 20:19:11 -04001023 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +03001024 return nfsd4_write_time(file, buf, size, &nn->nfsd4_lease, nn);
Jeff Layton3dd98a32008-06-10 08:40:36 -04001025}
1026
J. Bruce Fieldsefc4bb4f2010-03-02 11:04:06 -05001027/**
1028 * write_gracetime - Set or report current NFSv4 grace period time
1029 *
1030 * As above, but sets the time of the NFSv4 grace period.
1031 *
1032 * Note this should never be set to less than the *previous*
1033 * lease-period time, but we don't try to enforce this. (In the common
1034 * case (a new boot), we don't know what the previous lease time was
1035 * anyway.)
1036 */
1037static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
1038{
Al Viro244c7d42014-10-21 20:19:11 -04001039 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +03001040 return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace, nn);
J. Bruce Fieldsefc4bb4f2010-03-02 11:04:06 -05001041}
1042
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +03001043static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size,
1044 struct nfsd_net *nn)
NeilBrown0964a3d2005-06-23 22:04:32 -07001045{
1046 char *mesg = buf;
1047 char *recdir;
1048 int len, status;
1049
Jeff Layton3dd98a32008-06-10 08:40:36 -04001050 if (size > 0) {
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +03001051 if (nn->nfsd_serv)
Jeff Layton3dd98a32008-06-10 08:40:36 -04001052 return -EBUSY;
1053 if (size > PATH_MAX || buf[size-1] != '\n')
1054 return -EINVAL;
1055 buf[size-1] = 0;
NeilBrown0964a3d2005-06-23 22:04:32 -07001056
Jeff Layton3dd98a32008-06-10 08:40:36 -04001057 recdir = mesg;
1058 len = qword_get(&mesg, recdir, size);
1059 if (len <= 0)
1060 return -EINVAL;
NeilBrown0964a3d2005-06-23 22:04:32 -07001061
Jeff Layton3dd98a32008-06-10 08:40:36 -04001062 status = nfs4_reset_recoverydir(recdir);
Andi Kleen69049962010-07-20 15:24:27 -07001063 if (status)
1064 return status;
Jeff Layton3dd98a32008-06-10 08:40:36 -04001065 }
Chuck Lever3d72ab82009-04-23 19:33:10 -04001066
1067 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
1068 nfs4_recoverydir());
NeilBrown0964a3d2005-06-23 22:04:32 -07001069}
Jeff Layton3dd98a32008-06-10 08:40:36 -04001070
Chuck Lever262a0982008-12-12 16:57:35 -05001071/**
1072 * write_recoverydir - Set or report the pathname of the recovery directory
1073 *
1074 * Input:
1075 * buf: ignored
1076 * size: zero
1077 *
1078 * OR
1079 *
1080 * Input:
1081 * buf: C string containing the pathname
1082 * of the directory on a local file
1083 * system containing permanent NFSv4
1084 * recovery data
1085 * size: non-zero length of C string in @buf
1086 * Output:
1087 * On success: passed-in buffer filled with '\n'-terminated C string
1088 * containing the current recovery pathname setting;
1089 * return code is the size in bytes of the string
1090 * On error: return code is zero or a negative errno value
1091 */
Jeff Layton3dd98a32008-06-10 08:40:36 -04001092static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
1093{
1094 ssize_t rv;
Al Viro244c7d42014-10-21 20:19:11 -04001095 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
Jeff Layton3dd98a32008-06-10 08:40:36 -04001096
1097 mutex_lock(&nfsd_mutex);
Stanislav Kinsbursky9dd98452012-12-06 14:23:24 +03001098 rv = __write_recoverydir(file, buf, size, nn);
Jeff Layton3dd98a32008-06-10 08:40:36 -04001099 mutex_unlock(&nfsd_mutex);
1100 return rv;
1101}
1102
Jeff Layton7f5ef2e2014-09-12 16:40:21 -04001103/**
1104 * write_v4_end_grace - release grace period for nfsd's v4.x lock manager
1105 *
1106 * Input:
1107 * buf: ignored
1108 * size: zero
1109 * OR
1110 *
1111 * Input:
1112 * buf: any value
1113 * size: non-zero length of C string in @buf
1114 * Output:
1115 * passed-in buffer filled with "Y" or "N" with a newline
1116 * and NULL-terminated C string. This indicates whether
1117 * the grace period has ended in the current net
1118 * namespace. Return code is the size in bytes of the
1119 * string. Writing a string that starts with 'Y', 'y', or
1120 * '1' to the file will end the grace period for nfsd's v4
1121 * lock manager.
1122 */
1123static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size)
1124{
Al Viro244c7d42014-10-21 20:19:11 -04001125 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
Jeff Layton7f5ef2e2014-09-12 16:40:21 -04001126
1127 if (size > 0) {
1128 switch(buf[0]) {
1129 case 'Y':
1130 case 'y':
1131 case '1':
Yihao Wudd838822019-03-06 21:03:50 +08001132 if (!nn->nfsd_serv)
J. Bruce Fields62a063b2018-11-27 15:54:17 -05001133 return -EBUSY;
Jeff Layton7f5ef2e2014-09-12 16:40:21 -04001134 nfsd4_end_grace(nn);
1135 break;
1136 default:
1137 return -EINVAL;
1138 }
1139 }
1140
1141 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%c\n",
1142 nn->grace_ended ? 'Y' : 'N');
1143}
1144
NeilBrown70c3b762005-11-07 01:00:25 -08001145#endif
NeilBrown0964a3d2005-06-23 22:04:32 -07001146
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147/*----------------------------------------------------------------------------*/
1148/*
1149 * populating the filesystem.
1150 */
1151
J. Bruce Fieldse8a79fb2019-03-22 11:11:06 -04001152/* Basically copying rpc_get_inode. */
1153static struct inode *nfsd_get_inode(struct super_block *sb, umode_t mode)
1154{
1155 struct inode *inode = new_inode(sb);
1156 if (!inode)
1157 return NULL;
1158 /* Following advice from simple_fill_super documentation: */
1159 inode->i_ino = iunique(sb, NFSD_MaxReserved);
1160 inode->i_mode = mode;
1161 inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
1162 switch (mode & S_IFMT) {
1163 case S_IFDIR:
1164 inode->i_fop = &simple_dir_operations;
1165 inode->i_op = &simple_dir_inode_operations;
1166 inc_nlink(inode);
1167 default:
1168 break;
1169 }
1170 return inode;
1171}
1172
1173static int __nfsd_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
1174{
1175 struct inode *inode;
1176
1177 inode = nfsd_get_inode(dir->i_sb, mode);
1178 if (!inode)
1179 return -ENOMEM;
1180 d_add(dentry, inode);
1181 inc_nlink(dir);
1182 fsnotify_mkdir(dir, dentry);
1183 return 0;
1184}
1185
1186static struct dentry *nfsd_mkdir(struct dentry *parent, struct nfsdfs_client *ncl, char *name)
1187{
1188 struct inode *dir = parent->d_inode;
1189 struct dentry *dentry;
1190 int ret = -ENOMEM;
1191
1192 inode_lock(dir);
1193 dentry = d_alloc_name(parent, name);
1194 if (!dentry)
1195 goto out_err;
1196 ret = __nfsd_mkdir(d_inode(parent), dentry, S_IFDIR | 0600);
1197 if (ret)
1198 goto out_err;
1199 if (ncl) {
1200 d_inode(dentry)->i_private = ncl;
1201 kref_get(&ncl->cl_ref);
1202 }
1203out:
1204 inode_unlock(dir);
1205 return dentry;
1206out_err:
1207 dentry = ERR_PTR(ret);
1208 goto out;
1209}
1210
1211/* on success, returns positive number unique to that client. */
1212struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, struct nfsdfs_client *ncl, u32 id)
1213{
1214 char name[11];
1215
1216 sprintf(name, "%d", id++);
1217
1218 return nfsd_mkdir(nn->nfsd_client_dir, ncl, name);
1219}
1220
1221/* Taken from __rpc_rmdir: */
1222void nfsd_client_rmdir(struct dentry *dentry)
1223{
1224 struct inode *dir = d_inode(dentry->d_parent);
1225 struct inode *inode = d_inode(dentry);
1226 struct nfsdfs_client *ncl = inode->i_private;
1227 int ret;
1228
1229 inode->i_private = NULL;
1230 synchronize_rcu();
1231 kref_put(&ncl->cl_ref, ncl->cl_release);
1232 dget(dentry);
1233 ret = simple_rmdir(dir, dentry);
1234 WARN_ON_ONCE(ret);
1235 d_delete(dentry);
1236}
1237
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
1239{
J. Bruce Fieldse8a79fb2019-03-22 11:11:06 -04001240 struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
1241 nfsd_net_id);
1242 struct dentry *dentry;
1243 int ret;
1244
Eric Biggerscda37122017-03-25 21:15:37 -07001245 static const struct tree_descr nfsd_files[] = {
Stanislav Kinsbursky96d851c2013-02-01 15:56:17 +03001246 [NFSD_List] = {"exports", &exports_nfsd_operations, S_IRUGO},
J. Bruce Fieldse8e87532009-12-14 12:53:32 -05001247 [NFSD_Export_features] = {"export_features",
1248 &export_features_operations, S_IRUGO},
Wendy Cheng4373ea82008-01-17 11:10:12 -05001249 [NFSD_FO_UnlockIP] = {"unlock_ip",
1250 &transaction_ops, S_IWUSR|S_IRUSR},
Wendy Cheng17efa372008-01-17 11:10:12 -05001251 [NFSD_FO_UnlockFS] = {"unlock_filesystem",
1252 &transaction_ops, S_IWUSR|S_IRUSR},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
1254 [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
Greg Bankseed29652006-10-02 02:18:02 -07001255 [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
Greg Banks03cf6c92009-01-13 21:26:36 +11001256 [NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO},
Jeff Laytona2f999a2013-03-27 10:15:38 -04001257 [NFSD_Reply_Cache_Stats] = {"reply_cache_stats", &reply_cache_stats_operations, S_IRUGO},
NeilBrown70c3b762005-11-07 01:00:25 -08001258 [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
NeilBrown80212d52006-10-02 02:17:47 -07001259 [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
NeilBrown596bbe52006-10-04 02:15:48 -07001260 [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
Jeff Layton5b8db002014-07-02 16:11:22 -04001261 [NFSD_MaxConnections] = {"max_connections", &transaction_ops, S_IWUSR|S_IRUGO},
J. Bruce Fieldsb084f592011-05-31 12:24:58 -04001262#if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
Kevin Coffmanb0b0c0a2011-03-02 19:51:42 -05001263 [NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO},
J. Bruce Fieldsb084f592011-05-31 12:24:58 -04001264#endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265#ifdef CONFIG_NFSD_V4
1266 [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
J. Bruce Fieldsefc4bb4f2010-03-02 11:04:06 -05001267 [NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR},
NeilBrown0964a3d2005-06-23 22:04:32 -07001268 [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
Jeff Layton7f5ef2e2014-09-12 16:40:21 -04001269 [NFSD_V4EndGrace] = {"v4_end_grace", &transaction_ops, S_IWUSR|S_IRUGO},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270#endif
1271 /* last one */ {""}
1272 };
Eric W. Biedermand91ee872016-05-23 14:51:59 -05001273 get_net(sb->s_fs_info);
J. Bruce Fieldse8a79fb2019-03-22 11:11:06 -04001274 ret = simple_fill_super(sb, 0x6e667364, nfsd_files);
1275 if (ret)
1276 return ret;
1277 dentry = nfsd_mkdir(sb->s_root, NULL, "clients");
1278 if (IS_ERR(dentry))
1279 return PTR_ERR(dentry);
1280 nn->nfsd_client_dir = dentry;
1281 return 0;
1282
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283}
1284
Al Virofc14f2f2010-07-25 01:48:30 +04001285static struct dentry *nfsd_mount(struct file_system_type *fs_type,
1286 int flags, const char *dev_name, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287{
Eric W. Biedermand91ee872016-05-23 14:51:59 -05001288 struct net *net = current->nsproxy->net_ns;
1289 return mount_ns(fs_type, flags, data, net, net->user_ns, nfsd_fill_super);
Stanislav Kinsbursky11f77942013-02-01 15:56:12 +03001290}
1291
1292static void nfsd_umount(struct super_block *sb)
1293{
1294 struct net *net = sb->s_fs_info;
1295
1296 kill_litter_super(sb);
1297 put_net(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298}
1299
1300static struct file_system_type nfsd_fs_type = {
1301 .owner = THIS_MODULE,
1302 .name = "nfsd",
Al Virofc14f2f2010-07-25 01:48:30 +04001303 .mount = nfsd_mount,
Stanislav Kinsbursky11f77942013-02-01 15:56:12 +03001304 .kill_sb = nfsd_umount,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305};
Eric W. Biederman7f78e032013-03-02 19:39:14 -08001306MODULE_ALIAS_FS("nfsd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001308#ifdef CONFIG_PROC_FS
1309static int create_proc_exports_entry(void)
1310{
1311 struct proc_dir_entry *entry;
1312
1313 entry = proc_mkdir("fs/nfs", NULL);
1314 if (!entry)
1315 return -ENOMEM;
Stanislav Kinsbursky96d851c2013-02-01 15:56:17 +03001316 entry = proc_create("exports", 0, entry,
1317 &exports_proc_operations);
fanchaotingff7c4b32013-03-27 16:31:18 +08001318 if (!entry) {
1319 remove_proc_entry("fs/nfs", NULL);
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001320 return -ENOMEM;
fanchaotingff7c4b32013-03-27 16:31:18 +08001321 }
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001322 return 0;
1323}
1324#else /* CONFIG_PROC_FS */
1325static int create_proc_exports_entry(void)
1326{
1327 return 0;
1328}
1329#endif
1330
Alexey Dobriyanc7d03a02016-11-17 04:58:21 +03001331unsigned int nfsd_net_id;
Stanislav Kinsbursky5717e012012-04-11 15:13:35 +04001332
1333static __net_init int nfsd_init_net(struct net *net)
1334{
1335 int retval;
J. Bruce Fields2c830dd2018-12-14 09:40:56 -05001336 struct vfsmount *mnt;
Stanislav Kinsbursky3d733712012-11-27 14:11:44 +03001337 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
Stanislav Kinsbursky5717e012012-04-11 15:13:35 +04001338
1339 retval = nfsd_export_init(net);
1340 if (retval)
1341 goto out_export_error;
Stanislav Kinsburskyf69adb22012-04-11 17:33:05 +04001342 retval = nfsd_idmap_init(net);
1343 if (retval)
1344 goto out_idmap_error;
Trond Myklebuste333f3b2019-04-09 11:46:19 -04001345 nn->nfsd_versions = NULL;
1346 nn->nfsd4_minorversions = NULL;
J. Bruce Fields3ba75832019-05-17 09:03:38 -04001347 retval = nfsd_reply_cache_init(nn);
1348 if (retval)
1349 goto out_drc_error;
J. Bruce Fields3bf6b572019-02-14 12:33:19 -05001350 nn->nfsd4_lease = 90; /* default lease time */
1351 nn->nfsd4_grace = 90;
J. Bruce Fields03f318c2018-06-08 12:28:47 -04001352 nn->somebody_reclaimed = false;
Scott Mayhew362063a2019-03-26 18:06:28 -04001353 nn->track_reclaim_completes = false;
J. Bruce Fieldsebd7c722016-09-12 16:00:47 -04001354 nn->clverifier_counter = prandom_u32();
1355 nn->clientid_counter = prandom_u32();
Olga Kornievskaiae0639dc2018-07-20 18:19:20 -04001356 nn->s2s_cp_cl_id = nn->clientid_counter++;
Vasily Averin2317dc52017-11-10 10:19:35 +03001357
1358 atomic_set(&nn->ntf_refcnt, 0);
1359 init_waitqueue_head(&nn->ntf_wq);
J. Bruce Fields2c830dd2018-12-14 09:40:56 -05001360
1361 mnt = vfs_kern_mount(&nfsd_fs_type, SB_KERNMOUNT, "nfsd", NULL);
1362 if (IS_ERR(mnt)) {
1363 retval = PTR_ERR(mnt);
1364 goto out_mount_err;
1365 }
1366 nn->nfsd_mnt = mnt;
Stanislav Kinsbursky5717e012012-04-11 15:13:35 +04001367 return 0;
1368
J. Bruce Fields2c830dd2018-12-14 09:40:56 -05001369out_mount_err:
1370 nfsd_reply_cache_shutdown(nn);
J. Bruce Fields3ba75832019-05-17 09:03:38 -04001371out_drc_error:
1372 nfsd_idmap_shutdown(net);
Stanislav Kinsburskyf69adb22012-04-11 17:33:05 +04001373out_idmap_error:
1374 nfsd_export_shutdown(net);
Stanislav Kinsbursky5717e012012-04-11 15:13:35 +04001375out_export_error:
1376 return retval;
1377}
1378
1379static __net_exit void nfsd_exit_net(struct net *net)
1380{
J. Bruce Fields3ba75832019-05-17 09:03:38 -04001381 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1382
J. Bruce Fields2c830dd2018-12-14 09:40:56 -05001383 mntput(nn->nfsd_mnt);
J. Bruce Fields3ba75832019-05-17 09:03:38 -04001384 nfsd_reply_cache_shutdown(nn);
Stanislav Kinsburskyf69adb22012-04-11 17:33:05 +04001385 nfsd_idmap_shutdown(net);
Stanislav Kinsbursky5717e012012-04-11 15:13:35 +04001386 nfsd_export_shutdown(net);
Trond Myklebuste333f3b2019-04-09 11:46:19 -04001387 nfsd_netns_free_versions(net_generic(net, nfsd_net_id));
Stanislav Kinsbursky5717e012012-04-11 15:13:35 +04001388}
1389
Jeff Layton7ea34ac2012-03-21 09:52:05 -04001390static struct pernet_operations nfsd_net_ops = {
Stanislav Kinsbursky5717e012012-04-11 15:13:35 +04001391 .init = nfsd_init_net,
1392 .exit = nfsd_exit_net,
Jeff Layton7ea34ac2012-03-21 09:52:05 -04001393 .id = &nfsd_net_id,
1394 .size = sizeof(struct nfsd_net),
1395};
1396
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397static int __init init_nfsd(void)
1398{
1399 int retval;
1400 printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
1401
Jeff Layton7ea34ac2012-03-21 09:52:05 -04001402 retval = register_pernet_subsys(&nfsd_net_ops);
1403 if (retval < 0)
Giuseppe Cantavenerabb7ffbf2015-04-20 18:00:08 +02001404 return retval;
1405 retval = register_cld_notifier();
J. Bruce Fieldse8ff2a82007-08-01 15:30:59 -04001406 if (retval)
Jeff Layton7ea34ac2012-03-21 09:52:05 -04001407 goto out_unregister_pernet;
Giuseppe Cantavenerabb7ffbf2015-04-20 18:00:08 +02001408 retval = nfsd4_init_slabs();
1409 if (retval)
1410 goto out_unregister_notifier;
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02001411 retval = nfsd4_init_pnfs();
Bryan Schumaker65178db2011-11-01 13:35:21 -04001412 if (retval)
1413 goto out_free_slabs;
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02001414 retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */
1415 if (retval)
1416 goto out_exit_pnfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 nfsd_stat_init(); /* Statistics */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 nfsd_lockd_init(); /* lockd->nfsd callbacks */
J. Bruce Fieldse331f602007-11-12 17:32:21 -05001419 retval = create_proc_exports_entry();
1420 if (retval)
Stanislav Kinsburskyf69adb22012-04-11 17:33:05 +04001421 goto out_free_lockd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 retval = register_filesystem(&nfsd_fs_type);
J. Bruce Fields26808d32007-11-09 13:44:06 -05001423 if (retval)
1424 goto out_free_all;
1425 return 0;
1426out_free_all:
J. Bruce Fields26808d32007-11-09 13:44:06 -05001427 remove_proc_entry("fs/nfs/exports", NULL);
1428 remove_proc_entry("fs/nfs", NULL);
J. Bruce Fieldsdbf847e2007-11-08 17:20:34 -05001429out_free_lockd:
J. Bruce Fields26808d32007-11-09 13:44:06 -05001430 nfsd_lockd_shutdown();
J. Bruce Fieldsd5c34282007-11-09 14:10:56 -05001431 nfsd_stat_shutdown();
Bryan Schumaker65178db2011-11-01 13:35:21 -04001432 nfsd_fault_inject_cleanup();
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02001433out_exit_pnfs:
1434 nfsd4_exit_pnfs();
Bryan Schumaker65178db2011-11-01 13:35:21 -04001435out_free_slabs:
J. Bruce Fields26808d32007-11-09 13:44:06 -05001436 nfsd4_free_slabs();
Jeff Layton813fd322012-03-21 09:52:08 -04001437out_unregister_notifier:
Jeff Layton797a9d72012-03-29 07:52:49 -04001438 unregister_cld_notifier();
Giuseppe Cantavenerabb7ffbf2015-04-20 18:00:08 +02001439out_unregister_pernet:
1440 unregister_pernet_subsys(&nfsd_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 return retval;
1442}
1443
1444static void __exit exit_nfsd(void)
1445{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 remove_proc_entry("fs/nfs/exports", NULL);
1447 remove_proc_entry("fs/nfs", NULL);
1448 nfsd_stat_shutdown();
1449 nfsd_lockd_shutdown();
J. Bruce Fieldse8ff2a82007-08-01 15:30:59 -04001450 nfsd4_free_slabs();
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02001451 nfsd4_exit_pnfs();
Bryan Schumaker65178db2011-11-01 13:35:21 -04001452 nfsd_fault_inject_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 unregister_filesystem(&nfsd_fs_type);
Jeff Layton797a9d72012-03-29 07:52:49 -04001454 unregister_cld_notifier();
Giuseppe Cantavenerabb7ffbf2015-04-20 18:00:08 +02001455 unregister_pernet_subsys(&nfsd_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456}
1457
1458MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
1459MODULE_LICENSE("GPL");
1460module_init(init_nfsd)
1461module_exit(exit_nfsd)