2019-05-19 12:08:20 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Syscall interface to knfsd.
|
|
|
|
*
|
|
|
|
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
|
|
|
|
*/
|
|
|
|
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/slab.h>
|
2008-07-26 07:46:43 +00:00
|
|
|
#include <linux/namei.h>
|
2006-10-02 09:17:48 +00:00
|
|
|
#include <linux/ctype.h>
|
2019-03-25 16:38:27 +00:00
|
|
|
#include <linux/fs_context.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2006-10-02 09:17:47 +00:00
|
|
|
#include <linux/sunrpc/svcsock.h>
|
lockd: unlock lockd locks associated with a given server ip
For high-availability NFS service, we generally need to be able to drop
file locks held on the exported filesystem before moving clients to a
new server. Currently the only way to do that is by shutting down lockd
entirely, which is often undesireable (for example, if you want to
continue exporting other filesystems).
This patch allows the administrator to release all locks held by clients
accessing the client through a given server ip address, by echoing that
address to a new file, /proc/fs/nfsd/unlock_ip, as in:
shell> echo 10.1.1.2 > /proc/fs/nfsd/unlock_ip
The expected sequence of events can be:
1. Tear down the IP address
2. Unexport the path
3. Write IP to /proc/fs/nfsd/unlock_ip to unlock files
4. Signal peer to begin take-over.
For now we only support IPv4 addresses and NFSv2/v3 (NFSv4 locks are not
affected).
Also, if unmounting the filesystem is required, we assume at step 3 that
clients using the given server ip are the only clients holding locks on
the given filesystem; otherwise, an additional patch is required to
allow revoking all locks held by lockd on a given filesystem.
Signed-off-by: S. Wendy Cheng <wcheng@redhat.com>
Cc: Lon Hohberger <lhh@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
fs/lockd/svcsubs.c | 66 +++++++++++++++++++++++++++++++++++++++-----
fs/nfsd/nfsctl.c | 65 +++++++++++++++++++++++++++++++++++++++++++
include/linux/lockd/lockd.h | 7 ++++
3 files changed, 131 insertions(+), 7 deletions(-)
2008-01-17 16:10:12 +00:00
|
|
|
#include <linux/lockd/lockd.h>
|
2013-02-04 17:50:00 +00:00
|
|
|
#include <linux/sunrpc/addr.h>
|
2011-03-03 00:51:42 +00:00
|
|
|
#include <linux/sunrpc/gss_api.h>
|
2012-03-21 13:52:08 +00:00
|
|
|
#include <linux/sunrpc/rpc_pipe_fs.h>
|
2024-04-23 13:25:40 +00:00
|
|
|
#include <linux/sunrpc/svc.h>
|
2011-07-01 18:23:34 +00:00
|
|
|
#include <linux/module.h>
|
2019-03-22 15:11:06 +00:00
|
|
|
#include <linux/fsnotify.h>
|
2024-09-05 19:09:50 +00:00
|
|
|
#include <linux/nfslocalio.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2011-01-04 22:37:15 +00:00
|
|
|
#include "idmap.h"
|
2009-12-03 18:30:56 +00:00
|
|
|
#include "nfsd.h"
|
|
|
|
#include "cache.h"
|
2012-11-27 14:35:10 +00:00
|
|
|
#include "state.h"
|
2012-03-21 13:52:05 +00:00
|
|
|
#include "netns.h"
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 11:11:59 +00:00
|
|
|
#include "pnfs.h"
|
2022-07-08 18:24:58 +00:00
|
|
|
#include "filecache.h"
|
2023-05-15 13:35:50 +00:00
|
|
|
#include "trace.h"
|
2023-09-11 12:49:44 +00:00
|
|
|
#include "netlink.h"
|
2009-12-03 18:30:56 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
2011-03-03 00:51:42 +00:00
|
|
|
* We have a single directory with several nodes in it.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
|
|
|
enum {
|
|
|
|
NFSD_Root = 1,
|
|
|
|
NFSD_List,
|
2021-01-06 07:52:36 +00:00
|
|
|
NFSD_Export_Stats,
|
2009-12-14 17:53:32 +00:00
|
|
|
NFSD_Export_features,
|
2005-04-16 22:20:36 +00:00
|
|
|
NFSD_Fh,
|
lockd: unlock lockd locks associated with a given server ip
For high-availability NFS service, we generally need to be able to drop
file locks held on the exported filesystem before moving clients to a
new server. Currently the only way to do that is by shutting down lockd
entirely, which is often undesireable (for example, if you want to
continue exporting other filesystems).
This patch allows the administrator to release all locks held by clients
accessing the client through a given server ip address, by echoing that
address to a new file, /proc/fs/nfsd/unlock_ip, as in:
shell> echo 10.1.1.2 > /proc/fs/nfsd/unlock_ip
The expected sequence of events can be:
1. Tear down the IP address
2. Unexport the path
3. Write IP to /proc/fs/nfsd/unlock_ip to unlock files
4. Signal peer to begin take-over.
For now we only support IPv4 addresses and NFSv2/v3 (NFSv4 locks are not
affected).
Also, if unmounting the filesystem is required, we assume at step 3 that
clients using the given server ip are the only clients holding locks on
the given filesystem; otherwise, an additional patch is required to
allow revoking all locks held by lockd on a given filesystem.
Signed-off-by: S. Wendy Cheng <wcheng@redhat.com>
Cc: Lon Hohberger <lhh@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
fs/lockd/svcsubs.c | 66 +++++++++++++++++++++++++++++++++++++++-----
fs/nfsd/nfsctl.c | 65 +++++++++++++++++++++++++++++++++++++++++++
include/linux/lockd/lockd.h | 7 ++++
3 files changed, 131 insertions(+), 7 deletions(-)
2008-01-17 16:10:12 +00:00
|
|
|
NFSD_FO_UnlockIP,
|
2008-01-17 16:10:12 +00:00
|
|
|
NFSD_FO_UnlockFS,
|
2005-04-16 22:20:36 +00:00
|
|
|
NFSD_Threads,
|
2006-10-02 09:18:02 +00:00
|
|
|
NFSD_Pool_Threads,
|
2009-01-13 10:26:36 +00:00
|
|
|
NFSD_Pool_Stats,
|
2013-03-27 14:15:38 +00:00
|
|
|
NFSD_Reply_Cache_Stats,
|
2005-11-07 09:00:25 +00:00
|
|
|
NFSD_Versions,
|
2006-10-02 09:17:47 +00:00
|
|
|
NFSD_Ports,
|
2006-10-04 09:15:48 +00:00
|
|
|
NFSD_MaxBlkSize,
|
2014-07-02 20:11:22 +00:00
|
|
|
NFSD_MaxConnections,
|
2022-07-08 18:24:58 +00:00
|
|
|
NFSD_Filecache,
|
2005-04-16 22:20:36 +00:00
|
|
|
NFSD_Leasetime,
|
2010-03-02 16:04:06 +00:00
|
|
|
NFSD_Gracetime,
|
2005-06-24 05:04:32 +00:00
|
|
|
NFSD_RecoveryDir,
|
2014-09-12 20:40:21 +00:00
|
|
|
NFSD_V4EndGrace,
|
2019-03-22 15:11:06 +00:00
|
|
|
NFSD_MaxReserved
|
2005-04-16 22:20:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* write() for these nodes.
|
|
|
|
*/
|
|
|
|
static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
|
2008-12-12 21:57:13 +00:00
|
|
|
static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
|
|
|
|
static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
|
2005-04-16 22:20:36 +00:00
|
|
|
static ssize_t write_threads(struct file *file, char *buf, size_t size);
|
2006-10-02 09:18:02 +00:00
|
|
|
static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
|
2005-11-07 09:00:25 +00:00
|
|
|
static ssize_t write_versions(struct file *file, char *buf, size_t size);
|
2006-10-02 09:17:47 +00:00
|
|
|
static ssize_t write_ports(struct file *file, char *buf, size_t size);
|
2006-10-04 09:15:48 +00:00
|
|
|
static ssize_t write_maxblksize(struct file *file, char *buf, size_t size);
|
2014-07-02 20:11:22 +00:00
|
|
|
static ssize_t write_maxconn(struct file *file, char *buf, size_t size);
|
2005-11-07 09:00:25 +00:00
|
|
|
#ifdef CONFIG_NFSD_V4
|
2005-04-16 22:20:36 +00:00
|
|
|
static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
|
2010-03-02 16:04:06 +00:00
|
|
|
static ssize_t write_gracetime(struct file *file, char *buf, size_t size);
|
2023-10-13 13:03:53 +00:00
|
|
|
#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
|
2005-06-24 05:04:32 +00:00
|
|
|
static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
|
2023-10-13 13:03:53 +00:00
|
|
|
#endif
|
2014-09-12 20:40:21 +00:00
|
|
|
static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size);
|
2005-11-07 09:00:25 +00:00
|
|
|
#endif
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2018-07-17 18:01:25 +00:00
|
|
|
static ssize_t (*const write_op[])(struct file *, char *, size_t) = {
|
2005-04-16 22:20:36 +00:00
|
|
|
[NFSD_Fh] = write_filehandle,
|
2008-12-12 21:57:13 +00:00
|
|
|
[NFSD_FO_UnlockIP] = write_unlock_ip,
|
|
|
|
[NFSD_FO_UnlockFS] = write_unlock_fs,
|
2005-04-16 22:20:36 +00:00
|
|
|
[NFSD_Threads] = write_threads,
|
2006-10-02 09:18:02 +00:00
|
|
|
[NFSD_Pool_Threads] = write_pool_threads,
|
2005-11-07 09:00:25 +00:00
|
|
|
[NFSD_Versions] = write_versions,
|
2006-10-02 09:17:47 +00:00
|
|
|
[NFSD_Ports] = write_ports,
|
2006-10-04 09:15:48 +00:00
|
|
|
[NFSD_MaxBlkSize] = write_maxblksize,
|
2014-07-02 20:11:22 +00:00
|
|
|
[NFSD_MaxConnections] = write_maxconn,
|
2005-11-07 09:00:25 +00:00
|
|
|
#ifdef CONFIG_NFSD_V4
|
2005-04-16 22:20:36 +00:00
|
|
|
[NFSD_Leasetime] = write_leasetime,
|
2010-03-02 16:04:06 +00:00
|
|
|
[NFSD_Gracetime] = write_gracetime,
|
2023-10-13 13:03:53 +00:00
|
|
|
#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
|
2005-06-24 05:04:32 +00:00
|
|
|
[NFSD_RecoveryDir] = write_recoverydir,
|
2023-10-13 13:03:53 +00:00
|
|
|
#endif
|
2014-09-12 20:40:21 +00:00
|
|
|
[NFSD_V4EndGrace] = write_v4_end_grace,
|
2005-11-07 09:00:25 +00:00
|
|
|
#endif
|
2005-04-16 22:20:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
|
|
|
|
{
|
2013-01-23 22:07:38 +00:00
|
|
|
ino_t ino = file_inode(file)->i_ino;
|
2005-04-16 22:20:36 +00:00
|
|
|
char *data;
|
|
|
|
ssize_t rv;
|
|
|
|
|
2006-03-24 11:15:34 +00:00
|
|
|
if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
|
2005-04-16 22:20:36 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
data = simple_transaction_get(file, buf, size);
|
|
|
|
if (IS_ERR(data))
|
|
|
|
return PTR_ERR(data);
|
|
|
|
|
2023-05-15 13:35:44 +00:00
|
|
|
rv = write_op[ino](file, data, size);
|
|
|
|
if (rv < 0)
|
|
|
|
return rv;
|
|
|
|
|
|
|
|
simple_transaction_set(file, rv);
|
|
|
|
return size;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2005-11-07 09:00:24 +00:00
|
|
|
static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
|
|
|
|
{
|
|
|
|
if (! file->private_data) {
|
|
|
|
/* An attempt to read a transaction file without writing
|
|
|
|
* causes a 0-byte write so that the file can return
|
|
|
|
* state information
|
|
|
|
*/
|
|
|
|
ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos);
|
|
|
|
if (rv < 0)
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
return simple_transaction_read(file, buf, size, pos);
|
|
|
|
}
|
|
|
|
|
2006-03-28 09:56:42 +00:00
|
|
|
static const struct file_operations transaction_ops = {
|
2005-04-16 22:20:36 +00:00
|
|
|
.write = nfsctl_transaction_write,
|
2005-11-07 09:00:24 +00:00
|
|
|
.read = nfsctl_transaction_read,
|
2005-04-16 22:20:36 +00:00
|
|
|
.release = simple_transaction_release,
|
llseek: automatically add .llseek fop
All file_operations should get a .llseek operation so we can make
nonseekable_open the default for future file operations without a
.llseek pointer.
The three cases that we can automatically detect are no_llseek, seq_lseek
and default_llseek. For cases where we can we can automatically prove that
the file offset is always ignored, we use noop_llseek, which maintains
the current behavior of not returning an error from a seek.
New drivers should normally not use noop_llseek but instead use no_llseek
and call nonseekable_open at open time. Existing drivers can be converted
to do the same when the maintainer knows for certain that no user code
relies on calling seek on the device file.
The generated code is often incorrectly indented and right now contains
comments that clarify for each added line why a specific variant was
chosen. In the version that gets submitted upstream, the comments will
be gone and I will manually fix the indentation, because there does not
seem to be a way to do that using coccinelle.
Some amount of new code is currently sitting in linux-next that should get
the same modifications, which I will do at the end of the merge window.
Many thanks to Julia Lawall for helping me learn to write a semantic
patch that does all this.
===== begin semantic patch =====
// This adds an llseek= method to all file operations,
// as a preparation for making no_llseek the default.
//
// The rules are
// - use no_llseek explicitly if we do nonseekable_open
// - use seq_lseek for sequential files
// - use default_llseek if we know we access f_pos
// - use noop_llseek if we know we don't access f_pos,
// but we still want to allow users to call lseek
//
@ open1 exists @
identifier nested_open;
@@
nested_open(...)
{
<+...
nonseekable_open(...)
...+>
}
@ open exists@
identifier open_f;
identifier i, f;
identifier open1.nested_open;
@@
int open_f(struct inode *i, struct file *f)
{
<+...
(
nonseekable_open(...)
|
nested_open(...)
)
...+>
}
@ read disable optional_qualifier exists @
identifier read_f;
identifier f, p, s, off;
type ssize_t, size_t, loff_t;
expression E;
identifier func;
@@
ssize_t read_f(struct file *f, char *p, size_t s, loff_t *off)
{
<+...
(
*off = E
|
*off += E
|
func(..., off, ...)
|
E = *off
)
...+>
}
@ read_no_fpos disable optional_qualifier exists @
identifier read_f;
identifier f, p, s, off;
type ssize_t, size_t, loff_t;
@@
ssize_t read_f(struct file *f, char *p, size_t s, loff_t *off)
{
... when != off
}
@ write @
identifier write_f;
identifier f, p, s, off;
type ssize_t, size_t, loff_t;
expression E;
identifier func;
@@
ssize_t write_f(struct file *f, const char *p, size_t s, loff_t *off)
{
<+...
(
*off = E
|
*off += E
|
func(..., off, ...)
|
E = *off
)
...+>
}
@ write_no_fpos @
identifier write_f;
identifier f, p, s, off;
type ssize_t, size_t, loff_t;
@@
ssize_t write_f(struct file *f, const char *p, size_t s, loff_t *off)
{
... when != off
}
@ fops0 @
identifier fops;
@@
struct file_operations fops = {
...
};
@ has_llseek depends on fops0 @
identifier fops0.fops;
identifier llseek_f;
@@
struct file_operations fops = {
...
.llseek = llseek_f,
...
};
@ has_read depends on fops0 @
identifier fops0.fops;
identifier read_f;
@@
struct file_operations fops = {
...
.read = read_f,
...
};
@ has_write depends on fops0 @
identifier fops0.fops;
identifier write_f;
@@
struct file_operations fops = {
...
.write = write_f,
...
};
@ has_open depends on fops0 @
identifier fops0.fops;
identifier open_f;
@@
struct file_operations fops = {
...
.open = open_f,
...
};
// use no_llseek if we call nonseekable_open
////////////////////////////////////////////
@ nonseekable1 depends on !has_llseek && has_open @
identifier fops0.fops;
identifier nso ~= "nonseekable_open";
@@
struct file_operations fops = {
... .open = nso, ...
+.llseek = no_llseek, /* nonseekable */
};
@ nonseekable2 depends on !has_llseek @
identifier fops0.fops;
identifier open.open_f;
@@
struct file_operations fops = {
... .open = open_f, ...
+.llseek = no_llseek, /* open uses nonseekable */
};
// use seq_lseek for sequential files
/////////////////////////////////////
@ seq depends on !has_llseek @
identifier fops0.fops;
identifier sr ~= "seq_read";
@@
struct file_operations fops = {
... .read = sr, ...
+.llseek = seq_lseek, /* we have seq_read */
};
// use default_llseek if there is a readdir
///////////////////////////////////////////
@ fops1 depends on !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
identifier fops0.fops;
identifier readdir_e;
@@
// any other fop is used that changes pos
struct file_operations fops = {
... .readdir = readdir_e, ...
+.llseek = default_llseek, /* readdir is present */
};
// use default_llseek if at least one of read/write touches f_pos
/////////////////////////////////////////////////////////////////
@ fops2 depends on !fops1 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
identifier fops0.fops;
identifier read.read_f;
@@
// read fops use offset
struct file_operations fops = {
... .read = read_f, ...
+.llseek = default_llseek, /* read accesses f_pos */
};
@ fops3 depends on !fops1 && !fops2 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
identifier fops0.fops;
identifier write.write_f;
@@
// write fops use offset
struct file_operations fops = {
... .write = write_f, ...
+ .llseek = default_llseek, /* write accesses f_pos */
};
// Use noop_llseek if neither read nor write accesses f_pos
///////////////////////////////////////////////////////////
@ fops4 depends on !fops1 && !fops2 && !fops3 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
identifier fops0.fops;
identifier read_no_fpos.read_f;
identifier write_no_fpos.write_f;
@@
// write fops use offset
struct file_operations fops = {
...
.write = write_f,
.read = read_f,
...
+.llseek = noop_llseek, /* read and write both use no f_pos */
};
@ depends on has_write && !has_read && !fops1 && !fops2 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
identifier fops0.fops;
identifier write_no_fpos.write_f;
@@
struct file_operations fops = {
... .write = write_f, ...
+.llseek = noop_llseek, /* write uses no f_pos */
};
@ depends on has_read && !has_write && !fops1 && !fops2 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
identifier fops0.fops;
identifier read_no_fpos.read_f;
@@
struct file_operations fops = {
... .read = read_f, ...
+.llseek = noop_llseek, /* read uses no f_pos */
};
@ depends on !has_read && !has_write && !fops1 && !fops2 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
identifier fops0.fops;
@@
struct file_operations fops = {
...
+.llseek = noop_llseek, /* no read or write fn */
};
===== End semantic patch =====
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Julia Lawall <julia@diku.dk>
Cc: Christoph Hellwig <hch@infradead.org>
2010-08-15 16:52:59 +00:00
|
|
|
.llseek = default_llseek,
|
2005-04-16 22:20:36 +00:00
|
|
|
};
|
|
|
|
|
2013-02-01 12:56:17 +00:00
|
|
|
static int exports_net_open(struct net *net, struct file *file)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2012-03-28 15:09:29 +00:00
|
|
|
int err;
|
|
|
|
struct seq_file *seq;
|
2013-02-01 12:56:17 +00:00
|
|
|
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
2012-03-28 15:09:29 +00:00
|
|
|
|
|
|
|
err = seq_open(file, &nfs_exports_op);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
seq = file->private_data;
|
2012-04-11 11:13:28 +00:00
|
|
|
seq->private = nn->svc_export_cache;
|
2012-03-28 15:09:29 +00:00
|
|
|
return 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2013-02-01 12:56:17 +00:00
|
|
|
static int exports_nfsd_open(struct inode *inode, struct file *file)
|
|
|
|
{
|
|
|
|
return exports_net_open(inode->i_sb->s_fs_info, file);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct file_operations exports_nfsd_operations = {
|
|
|
|
.open = exports_nfsd_open,
|
2005-04-16 22:20:36 +00:00
|
|
|
.read = seq_read,
|
|
|
|
.llseek = seq_lseek,
|
|
|
|
.release = seq_release,
|
|
|
|
};
|
|
|
|
|
2009-12-14 17:53:32 +00:00
|
|
|
static int export_features_show(struct seq_file *m, void *v)
|
|
|
|
{
|
|
|
|
seq_printf(m, "0x%x 0x%x\n", NFSEXP_ALLFLAGS, NFSEXP_SECINFO_FLAGS);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-09-22 16:31:53 +00:00
|
|
|
DEFINE_SHOW_ATTRIBUTE(export_features);
|
2009-12-14 17:53:32 +00:00
|
|
|
|
2024-07-15 07:14:16 +00:00
|
|
|
static int nfsd_pool_stats_open(struct inode *inode, struct file *file)
|
|
|
|
{
|
|
|
|
struct nfsd_net *nn = net_generic(inode->i_sb->s_fs_info, nfsd_net_id);
|
|
|
|
|
|
|
|
return svc_pool_stats_open(&nn->nfsd_info, file);
|
|
|
|
}
|
|
|
|
|
2009-10-01 22:43:56 +00:00
|
|
|
static const struct file_operations pool_stats_operations = {
|
2009-01-13 10:26:36 +00:00
|
|
|
.open = nfsd_pool_stats_open,
|
|
|
|
.read = seq_read,
|
|
|
|
.llseek = seq_lseek,
|
2023-12-15 00:56:32 +00:00
|
|
|
.release = seq_release,
|
2009-01-13 10:26:36 +00:00
|
|
|
};
|
|
|
|
|
2022-09-22 16:31:55 +00:00
|
|
|
DEFINE_SHOW_ATTRIBUTE(nfsd_reply_cache_stats);
|
2013-03-27 14:15:38 +00:00
|
|
|
|
2022-09-22 16:31:56 +00:00
|
|
|
DEFINE_SHOW_ATTRIBUTE(nfsd_file_cache_stats);
|
2022-07-08 18:24:58 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
|
|
* payload - write methods
|
|
|
|
*/
|
|
|
|
|
2014-10-22 00:19:11 +00:00
|
|
|
static inline struct net *netns(struct file *file)
|
|
|
|
{
|
|
|
|
return file_inode(file)->i_sb->s_fs_info;
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2020-04-06 20:01:42 +00:00
|
|
|
/*
|
2008-12-12 21:57:35 +00:00
|
|
|
* write_unlock_ip - Release all locks used by a client
|
|
|
|
*
|
|
|
|
* Experimental.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf: '\n'-terminated C string containing a
|
2009-08-09 19:09:40 +00:00
|
|
|
* presentation format IP address
|
2008-12-12 21:57:35 +00:00
|
|
|
* size: length of C string in @buf
|
|
|
|
* Output:
|
|
|
|
* On success: returns zero if all specified locks were released;
|
|
|
|
* returns one if one or more locks were not released
|
|
|
|
* On error: return code is negative errno value
|
|
|
|
*/
|
2008-12-12 21:57:13 +00:00
|
|
|
static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
|
lockd: unlock lockd locks associated with a given server ip
For high-availability NFS service, we generally need to be able to drop
file locks held on the exported filesystem before moving clients to a
new server. Currently the only way to do that is by shutting down lockd
entirely, which is often undesireable (for example, if you want to
continue exporting other filesystems).
This patch allows the administrator to release all locks held by clients
accessing the client through a given server ip address, by echoing that
address to a new file, /proc/fs/nfsd/unlock_ip, as in:
shell> echo 10.1.1.2 > /proc/fs/nfsd/unlock_ip
The expected sequence of events can be:
1. Tear down the IP address
2. Unexport the path
3. Write IP to /proc/fs/nfsd/unlock_ip to unlock files
4. Signal peer to begin take-over.
For now we only support IPv4 addresses and NFSv2/v3 (NFSv4 locks are not
affected).
Also, if unmounting the filesystem is required, we assume at step 3 that
clients using the given server ip are the only clients holding locks on
the given filesystem; otherwise, an additional patch is required to
allow revoking all locks held by lockd on a given filesystem.
Signed-off-by: S. Wendy Cheng <wcheng@redhat.com>
Cc: Lon Hohberger <lhh@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
fs/lockd/svcsubs.c | 66 +++++++++++++++++++++++++++++++++++++++-----
fs/nfsd/nfsctl.c | 65 +++++++++++++++++++++++++++++++++++++++++++
include/linux/lockd/lockd.h | 7 ++++
3 files changed, 131 insertions(+), 7 deletions(-)
2008-01-17 16:10:12 +00:00
|
|
|
{
|
2009-08-09 19:09:40 +00:00
|
|
|
struct sockaddr_storage address;
|
|
|
|
struct sockaddr *sap = (struct sockaddr *)&address;
|
|
|
|
size_t salen = sizeof(address);
|
2008-06-30 22:58:14 +00:00
|
|
|
char *fo_path;
|
2014-10-22 00:19:11 +00:00
|
|
|
struct net *net = netns(file);
|
lockd: unlock lockd locks associated with a given server ip
For high-availability NFS service, we generally need to be able to drop
file locks held on the exported filesystem before moving clients to a
new server. Currently the only way to do that is by shutting down lockd
entirely, which is often undesireable (for example, if you want to
continue exporting other filesystems).
This patch allows the administrator to release all locks held by clients
accessing the client through a given server ip address, by echoing that
address to a new file, /proc/fs/nfsd/unlock_ip, as in:
shell> echo 10.1.1.2 > /proc/fs/nfsd/unlock_ip
The expected sequence of events can be:
1. Tear down the IP address
2. Unexport the path
3. Write IP to /proc/fs/nfsd/unlock_ip to unlock files
4. Signal peer to begin take-over.
For now we only support IPv4 addresses and NFSv2/v3 (NFSv4 locks are not
affected).
Also, if unmounting the filesystem is required, we assume at step 3 that
clients using the given server ip are the only clients holding locks on
the given filesystem; otherwise, an additional patch is required to
allow revoking all locks held by lockd on a given filesystem.
Signed-off-by: S. Wendy Cheng <wcheng@redhat.com>
Cc: Lon Hohberger <lhh@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
fs/lockd/svcsubs.c | 66 +++++++++++++++++++++++++++++++++++++++-----
fs/nfsd/nfsctl.c | 65 +++++++++++++++++++++++++++++++++++++++++++
include/linux/lockd/lockd.h | 7 ++++
3 files changed, 131 insertions(+), 7 deletions(-)
2008-01-17 16:10:12 +00:00
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (size == 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (buf[size-1] != '\n')
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
fo_path = buf;
|
|
|
|
if (qword_get(&buf, fo_path, size) < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2013-02-01 12:56:12 +00:00
|
|
|
if (rpc_pton(net, fo_path, size, sap, salen) == 0)
|
lockd: unlock lockd locks associated with a given server ip
For high-availability NFS service, we generally need to be able to drop
file locks held on the exported filesystem before moving clients to a
new server. Currently the only way to do that is by shutting down lockd
entirely, which is often undesireable (for example, if you want to
continue exporting other filesystems).
This patch allows the administrator to release all locks held by clients
accessing the client through a given server ip address, by echoing that
address to a new file, /proc/fs/nfsd/unlock_ip, as in:
shell> echo 10.1.1.2 > /proc/fs/nfsd/unlock_ip
The expected sequence of events can be:
1. Tear down the IP address
2. Unexport the path
3. Write IP to /proc/fs/nfsd/unlock_ip to unlock files
4. Signal peer to begin take-over.
For now we only support IPv4 addresses and NFSv2/v3 (NFSv4 locks are not
affected).
Also, if unmounting the filesystem is required, we assume at step 3 that
clients using the given server ip are the only clients holding locks on
the given filesystem; otherwise, an additional patch is required to
allow revoking all locks held by lockd on a given filesystem.
Signed-off-by: S. Wendy Cheng <wcheng@redhat.com>
Cc: Lon Hohberger <lhh@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
fs/lockd/svcsubs.c | 66 +++++++++++++++++++++++++++++++++++++++-----
fs/nfsd/nfsctl.c | 65 +++++++++++++++++++++++++++++++++++++++++++
include/linux/lockd/lockd.h | 7 ++++
3 files changed, 131 insertions(+), 7 deletions(-)
2008-01-17 16:10:12 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
2023-05-15 13:35:50 +00:00
|
|
|
trace_nfsd_ctl_unlock_ip(net, buf);
|
2009-08-09 19:09:40 +00:00
|
|
|
return nlmsvc_unlock_all_by_ip(sap);
|
lockd: unlock lockd locks associated with a given server ip
For high-availability NFS service, we generally need to be able to drop
file locks held on the exported filesystem before moving clients to a
new server. Currently the only way to do that is by shutting down lockd
entirely, which is often undesireable (for example, if you want to
continue exporting other filesystems).
This patch allows the administrator to release all locks held by clients
accessing the client through a given server ip address, by echoing that
address to a new file, /proc/fs/nfsd/unlock_ip, as in:
shell> echo 10.1.1.2 > /proc/fs/nfsd/unlock_ip
The expected sequence of events can be:
1. Tear down the IP address
2. Unexport the path
3. Write IP to /proc/fs/nfsd/unlock_ip to unlock files
4. Signal peer to begin take-over.
For now we only support IPv4 addresses and NFSv2/v3 (NFSv4 locks are not
affected).
Also, if unmounting the filesystem is required, we assume at step 3 that
clients using the given server ip are the only clients holding locks on
the given filesystem; otherwise, an additional patch is required to
allow revoking all locks held by lockd on a given filesystem.
Signed-off-by: S. Wendy Cheng <wcheng@redhat.com>
Cc: Lon Hohberger <lhh@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
fs/lockd/svcsubs.c | 66 +++++++++++++++++++++++++++++++++++++++-----
fs/nfsd/nfsctl.c | 65 +++++++++++++++++++++++++++++++++++++++++++
include/linux/lockd/lockd.h | 7 ++++
3 files changed, 131 insertions(+), 7 deletions(-)
2008-01-17 16:10:12 +00:00
|
|
|
}
|
|
|
|
|
2020-04-06 20:01:42 +00:00
|
|
|
/*
|
2008-12-12 21:57:35 +00:00
|
|
|
* write_unlock_fs - Release all locks on a local file system
|
|
|
|
*
|
|
|
|
* Experimental.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf: '\n'-terminated C string containing the
|
|
|
|
* absolute pathname of a local file system
|
|
|
|
* size: length of C string in @buf
|
|
|
|
* Output:
|
|
|
|
* On success: returns zero if all specified locks were released;
|
|
|
|
* returns one if one or more locks were not released
|
|
|
|
* On error: return code is negative errno value
|
|
|
|
*/
|
2008-12-12 21:57:13 +00:00
|
|
|
static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
|
2008-01-17 16:10:12 +00:00
|
|
|
{
|
2008-08-02 05:03:36 +00:00
|
|
|
struct path path;
|
2008-01-17 16:10:12 +00:00
|
|
|
char *fo_path;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (size == 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (buf[size-1] != '\n')
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
fo_path = buf;
|
|
|
|
if (qword_get(&buf, fo_path, size) < 0)
|
|
|
|
return -EINVAL;
|
2023-05-15 13:35:50 +00:00
|
|
|
trace_nfsd_ctl_unlock_fs(netns(file), fo_path);
|
2008-08-02 05:03:36 +00:00
|
|
|
error = kern_path(fo_path, 0, &path);
|
2008-01-17 16:10:12 +00:00
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
|
2008-12-12 21:57:35 +00:00
|
|
|
/*
|
|
|
|
* XXX: Needs better sanity checking. Otherwise we could end up
|
|
|
|
* releasing locks on the wrong file system.
|
|
|
|
*
|
|
|
|
* For example:
|
|
|
|
* 1. Does the path refer to a directory?
|
|
|
|
* 2. Is that directory a mount point, or
|
|
|
|
* 3. Is that directory the root of an exported file system?
|
|
|
|
*/
|
2011-12-07 23:16:57 +00:00
|
|
|
error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb);
|
2024-01-30 01:08:26 +00:00
|
|
|
nfsd4_revoke_states(netns(file), path.dentry->d_sb);
|
2008-01-17 16:10:12 +00:00
|
|
|
|
2008-08-02 05:03:36 +00:00
|
|
|
path_put(&path);
|
2008-01-17 16:10:12 +00:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2020-04-06 20:01:42 +00:00
|
|
|
/*
|
2008-12-12 21:57:35 +00:00
|
|
|
* write_filehandle - Get a variable-length NFS file handle by path
|
|
|
|
*
|
|
|
|
* On input, the buffer contains a '\n'-terminated C string comprised of
|
|
|
|
* three alphanumeric words separated by whitespace. The string may
|
|
|
|
* contain escape sequences.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf:
|
|
|
|
* domain: client domain name
|
|
|
|
* path: export pathname
|
|
|
|
* maxsize: numeric maximum size of
|
|
|
|
* @buf
|
|
|
|
* size: length of C string in @buf
|
|
|
|
* Output:
|
|
|
|
* On success: passed-in buffer filled with '\n'-terminated C
|
|
|
|
* string containing a ASCII hex text version
|
|
|
|
* of the NFS file handle;
|
|
|
|
* return code is the size in bytes of the string
|
|
|
|
* On error: return code is negative errno value
|
|
|
|
*/
|
2005-04-16 22:20:36 +00:00
|
|
|
static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
|
|
|
|
{
|
|
|
|
char *dname, *path;
|
treewide: Remove uninitialized_var() usage
Using uninitialized_var() is dangerous as it papers over real bugs[1]
(or can in the future), and suppresses unrelated compiler warnings
(e.g. "unused variable"). If the compiler thinks it is uninitialized,
either simply initialize the variable or make compiler changes.
In preparation for removing[2] the[3] macro[4], remove all remaining
needless uses with the following script:
git grep '\buninitialized_var\b' | cut -d: -f1 | sort -u | \
xargs perl -pi -e \
's/\buninitialized_var\(([^\)]+)\)/\1/g;
s:\s*/\* (GCC be quiet|to make compiler happy) \*/$::g;'
drivers/video/fbdev/riva/riva_hw.c was manually tweaked to avoid
pathological white-space.
No outstanding warnings were found building allmodconfig with GCC 9.3.0
for x86_64, i386, arm64, arm, powerpc, powerpc64le, s390x, mips, sparc64,
alpha, and m68k.
[1] https://lore.kernel.org/lkml/20200603174714.192027-1-glider@google.com/
[2] https://lore.kernel.org/lkml/CA+55aFw+Vbj0i=1TGqCR5vQkCzWJ0QxK6CernOU6eedsudAixw@mail.gmail.com/
[3] https://lore.kernel.org/lkml/CA+55aFwgbgqhbp1fkxvRKEpzyR5J8n1vKT1VZdz9knmPuXhOeg@mail.gmail.com/
[4] https://lore.kernel.org/lkml/CA+55aFz2500WfbKXAx8s67wrm9=yVJu65TpLgN_ybYNv0VEOKA@mail.gmail.com/
Reviewed-by: Leon Romanovsky <leonro@mellanox.com> # drivers/infiniband and mlx4/mlx5
Acked-by: Jason Gunthorpe <jgg@mellanox.com> # IB
Acked-by: Kalle Valo <kvalo@codeaurora.org> # wireless drivers
Reviewed-by: Chao Yu <yuchao0@huawei.com> # erofs
Signed-off-by: Kees Cook <keescook@chromium.org>
2020-06-03 20:09:38 +00:00
|
|
|
int maxsize;
|
2005-04-16 22:20:36 +00:00
|
|
|
char *mesg = buf;
|
|
|
|
int len;
|
|
|
|
struct auth_domain *dom;
|
|
|
|
struct knfsd_fh fh;
|
|
|
|
|
2008-01-22 22:40:42 +00:00
|
|
|
if (size == 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (buf[size-1] != '\n')
|
|
|
|
return -EINVAL;
|
|
|
|
buf[size-1] = 0;
|
|
|
|
|
|
|
|
dname = mesg;
|
|
|
|
len = qword_get(&mesg, dname, size);
|
2008-12-12 21:57:20 +00:00
|
|
|
if (len <= 0)
|
|
|
|
return -EINVAL;
|
2023-05-15 13:35:38 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
path = dname+len+1;
|
|
|
|
len = qword_get(&mesg, path, size);
|
2008-12-12 21:57:20 +00:00
|
|
|
if (len <= 0)
|
|
|
|
return -EINVAL;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
len = get_int(&mesg, &maxsize);
|
|
|
|
if (len)
|
|
|
|
return len;
|
|
|
|
|
|
|
|
if (maxsize < NFS_FHSIZE)
|
|
|
|
return -EINVAL;
|
2014-06-10 10:08:19 +00:00
|
|
|
maxsize = min(maxsize, NFS3_FHSIZE);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2023-05-15 13:35:38 +00:00
|
|
|
if (qword_get(&mesg, mesg, size) > 0)
|
2005-04-16 22:20:36 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
2023-05-15 13:35:50 +00:00
|
|
|
trace_nfsd_ctl_filehandle(netns(file), dname, path, maxsize);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/* we have all the words, they are in buf.. */
|
|
|
|
dom = unix_domain_find(dname);
|
|
|
|
if (!dom)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2023-05-15 13:35:38 +00:00
|
|
|
len = exp_rootfh(netns(file), dom, path, &fh, maxsize);
|
2005-04-16 22:20:36 +00:00
|
|
|
auth_domain_put(dom);
|
|
|
|
if (len)
|
|
|
|
return len;
|
2021-09-02 01:16:32 +00:00
|
|
|
|
2008-12-12 21:57:20 +00:00
|
|
|
mesg = buf;
|
|
|
|
len = SIMPLE_TRANSACTION_LIMIT;
|
2021-09-02 01:16:32 +00:00
|
|
|
qword_addhex(&mesg, &len, fh.fh_raw, fh.fh_size);
|
2005-04-16 22:20:36 +00:00
|
|
|
mesg[-1] = '\n';
|
2021-09-02 01:16:32 +00:00
|
|
|
return mesg - buf;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2020-04-06 20:01:42 +00:00
|
|
|
/*
|
2008-12-12 21:57:35 +00:00
|
|
|
* write_threads - Start NFSD, or report the current number of running threads
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf: ignored
|
|
|
|
* size: zero
|
|
|
|
* Output:
|
|
|
|
* On success: passed-in buffer filled with '\n'-terminated C
|
|
|
|
* string numeric value representing the number of
|
|
|
|
* running NFSD threads;
|
|
|
|
* return code is the size in bytes of the string
|
|
|
|
* On error: return code is zero
|
|
|
|
*
|
|
|
|
* OR
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf: C string containing an unsigned
|
|
|
|
* integer value representing the
|
|
|
|
* number of NFSD threads to start
|
|
|
|
* size: non-zero length of C string in @buf
|
|
|
|
* Output:
|
|
|
|
* On success: NFS service is started;
|
|
|
|
* passed-in buffer filled with '\n'-terminated C
|
|
|
|
* string numeric value representing the number of
|
|
|
|
* running NFSD threads;
|
|
|
|
* return code is the size in bytes of the string
|
|
|
|
* On error: return code is zero or a negative errno value
|
|
|
|
*/
|
2005-04-16 22:20:36 +00:00
|
|
|
static ssize_t write_threads(struct file *file, char *buf, size_t size)
|
|
|
|
{
|
|
|
|
char *mesg = buf;
|
|
|
|
int rv;
|
2014-10-22 00:19:11 +00:00
|
|
|
struct net *net = netns(file);
|
2012-12-10 09:19:25 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (size > 0) {
|
|
|
|
int newthreads;
|
|
|
|
rv = get_int(&mesg, &newthreads);
|
|
|
|
if (rv)
|
|
|
|
return rv;
|
2008-12-12 21:57:27 +00:00
|
|
|
if (newthreads < 0)
|
2005-04-16 22:20:36 +00:00
|
|
|
return -EINVAL;
|
2023-05-15 13:35:50 +00:00
|
|
|
trace_nfsd_ctl_threads(net, newthreads);
|
2024-04-23 13:25:38 +00:00
|
|
|
mutex_lock(&nfsd_mutex);
|
2024-06-13 18:34:31 +00:00
|
|
|
rv = nfsd_svc(1, &newthreads, net, file->f_cred, NULL);
|
2024-04-23 13:25:38 +00:00
|
|
|
mutex_unlock(&nfsd_mutex);
|
nfsd: don't take nfsd_mutex twice when setting number of threads.
Currently when we write a number to 'threads' in nfsdfs,
we take the nfsd_mutex, update the number of threads, then take the
mutex again to read the number of threads.
Mostly this isn't a big deal. However if we are write '0', and
portmap happens to be dead, then we can get unpredictable behaviour.
If the nfsd threads all got killed quickly and the last thread is
waiting for portmap to respond, then the second time we take the mutex
we will block waiting for the last thread.
However if the nfsd threads didn't die quite that fast, then there
will be no contention when we try to take the mutex again.
Unpredictability isn't fun, and waiting for the last thread to exit is
pointless, so avoid taking the lock twice.
To achieve this, get nfsd_svc return a non-negative number of active
threads when not returning a negative error.
Signed-off-by: NeilBrown <neilb@suse.de>
2009-06-16 01:03:07 +00:00
|
|
|
if (rv < 0)
|
2005-04-16 22:20:36 +00:00
|
|
|
return rv;
|
nfsd: don't take nfsd_mutex twice when setting number of threads.
Currently when we write a number to 'threads' in nfsdfs,
we take the nfsd_mutex, update the number of threads, then take the
mutex again to read the number of threads.
Mostly this isn't a big deal. However if we are write '0', and
portmap happens to be dead, then we can get unpredictable behaviour.
If the nfsd threads all got killed quickly and the last thread is
waiting for portmap to respond, then the second time we take the mutex
we will block waiting for the last thread.
However if the nfsd threads didn't die quite that fast, then there
will be no contention when we try to take the mutex again.
Unpredictability isn't fun, and waiting for the last thread to exit is
pointless, so avoid taking the lock twice.
To achieve this, get nfsd_svc return a non-negative number of active
threads when not returning a negative error.
Signed-off-by: NeilBrown <neilb@suse.de>
2009-06-16 01:03:07 +00:00
|
|
|
} else
|
2012-12-06 11:23:24 +00:00
|
|
|
rv = nfsd_nrthreads(net);
|
2009-04-23 23:33:25 +00:00
|
|
|
|
nfsd: don't take nfsd_mutex twice when setting number of threads.
Currently when we write a number to 'threads' in nfsdfs,
we take the nfsd_mutex, update the number of threads, then take the
mutex again to read the number of threads.
Mostly this isn't a big deal. However if we are write '0', and
portmap happens to be dead, then we can get unpredictable behaviour.
If the nfsd threads all got killed quickly and the last thread is
waiting for portmap to respond, then the second time we take the mutex
we will block waiting for the last thread.
However if the nfsd threads didn't die quite that fast, then there
will be no contention when we try to take the mutex again.
Unpredictability isn't fun, and waiting for the last thread to exit is
pointless, so avoid taking the lock twice.
To achieve this, get nfsd_svc return a non-negative number of active
threads when not returning a negative error.
Signed-off-by: NeilBrown <neilb@suse.de>
2009-06-16 01:03:07 +00:00
|
|
|
return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2020-04-06 20:01:42 +00:00
|
|
|
/*
|
2008-12-12 21:57:35 +00:00
|
|
|
* write_pool_threads - Set or report the current number of threads per pool
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf: ignored
|
|
|
|
* size: zero
|
|
|
|
*
|
|
|
|
* OR
|
|
|
|
*
|
|
|
|
* Input:
|
2023-05-15 13:35:38 +00:00
|
|
|
* buf: C string containing whitespace-
|
|
|
|
* separated unsigned integer values
|
2008-12-12 21:57:35 +00:00
|
|
|
* representing the number of NFSD
|
|
|
|
* threads to start in each pool
|
|
|
|
* size: non-zero length of C string in @buf
|
|
|
|
* Output:
|
|
|
|
* On success: passed-in buffer filled with '\n'-terminated C
|
|
|
|
* string containing integer values representing the
|
|
|
|
* number of NFSD threads in each pool;
|
|
|
|
* return code is the size in bytes of the string
|
|
|
|
* On error: return code is zero or a negative errno value
|
|
|
|
*/
|
2006-10-02 09:18:02 +00:00
|
|
|
static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
|
|
|
|
{
|
|
|
|
/* if size > 0, look for an array of number of threads per node
|
|
|
|
* and apply them then write out number of threads per node as reply
|
|
|
|
*/
|
|
|
|
char *mesg = buf;
|
|
|
|
int i;
|
|
|
|
int rv;
|
|
|
|
int len;
|
2008-06-10 12:40:35 +00:00
|
|
|
int npools;
|
2006-10-02 09:18:02 +00:00
|
|
|
int *nthreads;
|
2014-10-22 00:19:11 +00:00
|
|
|
struct net *net = netns(file);
|
2006-10-02 09:18:02 +00:00
|
|
|
|
2008-06-10 12:40:35 +00:00
|
|
|
mutex_lock(&nfsd_mutex);
|
2012-12-06 11:23:24 +00:00
|
|
|
npools = nfsd_nrpools(net);
|
2006-10-02 09:18:02 +00:00
|
|
|
if (npools == 0) {
|
|
|
|
/*
|
|
|
|
* NFS is shut down. The admin can start it by
|
|
|
|
* writing to the threads file but NOT the pool_threads
|
|
|
|
* file, sorry. Report zero threads.
|
|
|
|
*/
|
2008-06-10 12:40:35 +00:00
|
|
|
mutex_unlock(&nfsd_mutex);
|
2006-10-02 09:18:02 +00:00
|
|
|
strcpy(buf, "0\n");
|
|
|
|
return strlen(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL);
|
2008-06-10 12:40:35 +00:00
|
|
|
rv = -ENOMEM;
|
2006-10-02 09:18:02 +00:00
|
|
|
if (nthreads == NULL)
|
2008-06-10 12:40:35 +00:00
|
|
|
goto out_free;
|
2006-10-02 09:18:02 +00:00
|
|
|
|
|
|
|
if (size > 0) {
|
|
|
|
for (i = 0; i < npools; i++) {
|
|
|
|
rv = get_int(&mesg, &nthreads[i]);
|
|
|
|
if (rv == -ENOENT)
|
|
|
|
break; /* fewer numbers than pools */
|
|
|
|
if (rv)
|
|
|
|
goto out_free; /* syntax error */
|
|
|
|
rv = -EINVAL;
|
|
|
|
if (nthreads[i] < 0)
|
|
|
|
goto out_free;
|
2023-05-15 13:35:50 +00:00
|
|
|
trace_nfsd_ctl_pool_threads(net, i, nthreads[i]);
|
2006-10-02 09:18:02 +00:00
|
|
|
}
|
2024-06-13 18:34:31 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* There must always be a thread in pool 0; the admin
|
|
|
|
* can't shut down NFS completely using pool_threads.
|
|
|
|
*/
|
|
|
|
if (nthreads[0] == 0)
|
|
|
|
nthreads[0] = 1;
|
|
|
|
|
2012-12-10 09:19:30 +00:00
|
|
|
rv = nfsd_set_nrthreads(i, nthreads, net);
|
2006-10-02 09:18:02 +00:00
|
|
|
if (rv)
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
2012-12-06 11:23:24 +00:00
|
|
|
rv = nfsd_get_nrthreads(npools, nthreads, net);
|
2006-10-02 09:18:02 +00:00
|
|
|
if (rv)
|
|
|
|
goto out_free;
|
|
|
|
|
|
|
|
mesg = buf;
|
|
|
|
size = SIMPLE_TRANSACTION_LIMIT;
|
|
|
|
for (i = 0; i < npools && size > 0; i++) {
|
|
|
|
snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' '));
|
|
|
|
len = strlen(mesg);
|
|
|
|
size -= len;
|
|
|
|
mesg += len;
|
|
|
|
}
|
2009-07-28 15:37:25 +00:00
|
|
|
rv = mesg - buf;
|
2006-10-02 09:18:02 +00:00
|
|
|
out_free:
|
|
|
|
kfree(nthreads);
|
2008-06-10 12:40:35 +00:00
|
|
|
mutex_unlock(&nfsd_mutex);
|
2006-10-02 09:18:02 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2017-02-22 23:35:33 +00:00
|
|
|
static ssize_t
|
2019-04-09 15:46:19 +00:00
|
|
|
nfsd_print_version_support(struct nfsd_net *nn, char *buf, int remaining,
|
|
|
|
const char *sep, unsigned vers, int minor)
|
2017-02-22 23:35:33 +00:00
|
|
|
{
|
NFSD: further refinement of content of /proc/fs/nfsd/versions
Prior to
e35659f1b03c ("NFSD: correctly range-check v4.x minor version when setting versions.")
v4.0 could not be disabled without disabling all NFSv4 protocols.
So the 'versions' file contained ±4 ±4.1 ±4.2.
Writing "-4" would disable all v4 completely. Writing +4 would enabled those
minor versions that are currently enabled, either by default or otherwise.
After that commit, it was possible to disable v4.0 independently. To
maximize backward compatibility with use cases which never disabled
v4.0, the "versions" file would never contain "+4.0" - that was implied
by "+4", unless explicitly negated by "-4.0".
This introduced an inconsistency in that it was possible to disable all
minor versions, but still have the major version advertised.
e.g. "-4.0 -4.1 -4.2 +4" would result in NFSv4 support being advertised,
but all attempts to use it rejected.
Commit
d3635ff07e8c ("nfsd: fix configuration of supported minor versions")
and following removed this inconsistency. If all minor version were disabled,
the major would be disabled too. If any minor was enabled, the major would be
disabled.
This patch also treated "+4" as equivalent to "+4.0" and "-4" as "-4.0".
A consequence of this is that writing "-4" would only disable 4.0.
This is a regression against the earlier behaviour, in a use case that rpc.nfsd
actually uses.
The command "rpc.nfsd -N 4" will write "+2 +3 -4" to the versions files.
Previously, that would disable v4 completely. Now it will only disable v4.0.
Also "4.0" never appears in the "versions" file when read.
So if only v4.1 is available, the previous kernel would have reported
"+4 -4.0 +4.1 -4.2" the current kernel reports "-4 +4.1 -4.2" which
could easily confuse.
This patch restores the implication that "+4" and "-4" apply more
globals and do not imply "4.0".
Specifically:
writing "-4" will disable all 4.x minor versions.
writing "+4" will enable all 4.1 minor version if none are currently enabled.
rpc.nfsd will list minor versions before major versions, so
rpc.nfsd -V 4.2 -N 4.1
will write "-4.1 +4.2 +2 +3 +4"
so it would be a regression for "+4" to enable always all versions.
reading "-4" implies that no v4.x are enabled
reading "+4" implies that some v4.x are enabled, and that v4.0 is enabled unless
"-4.0" is also present. All other minor versions will explicitly be listed.
Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2017-03-10 00:36:39 +00:00
|
|
|
const char *format = minor < 0 ? "%s%c%u" : "%s%c%u.%u";
|
2019-04-09 15:46:19 +00:00
|
|
|
bool supported = !!nfsd_vers(nn, vers, NFSD_TEST);
|
2017-02-22 23:35:33 +00:00
|
|
|
|
NFSD: further refinement of content of /proc/fs/nfsd/versions
Prior to
e35659f1b03c ("NFSD: correctly range-check v4.x minor version when setting versions.")
v4.0 could not be disabled without disabling all NFSv4 protocols.
So the 'versions' file contained ±4 ±4.1 ±4.2.
Writing "-4" would disable all v4 completely. Writing +4 would enabled those
minor versions that are currently enabled, either by default or otherwise.
After that commit, it was possible to disable v4.0 independently. To
maximize backward compatibility with use cases which never disabled
v4.0, the "versions" file would never contain "+4.0" - that was implied
by "+4", unless explicitly negated by "-4.0".
This introduced an inconsistency in that it was possible to disable all
minor versions, but still have the major version advertised.
e.g. "-4.0 -4.1 -4.2 +4" would result in NFSv4 support being advertised,
but all attempts to use it rejected.
Commit
d3635ff07e8c ("nfsd: fix configuration of supported minor versions")
and following removed this inconsistency. If all minor version were disabled,
the major would be disabled too. If any minor was enabled, the major would be
disabled.
This patch also treated "+4" as equivalent to "+4.0" and "-4" as "-4.0".
A consequence of this is that writing "-4" would only disable 4.0.
This is a regression against the earlier behaviour, in a use case that rpc.nfsd
actually uses.
The command "rpc.nfsd -N 4" will write "+2 +3 -4" to the versions files.
Previously, that would disable v4 completely. Now it will only disable v4.0.
Also "4.0" never appears in the "versions" file when read.
So if only v4.1 is available, the previous kernel would have reported
"+4 -4.0 +4.1 -4.2" the current kernel reports "-4 +4.1 -4.2" which
could easily confuse.
This patch restores the implication that "+4" and "-4" apply more
globals and do not imply "4.0".
Specifically:
writing "-4" will disable all 4.x minor versions.
writing "+4" will enable all 4.1 minor version if none are currently enabled.
rpc.nfsd will list minor versions before major versions, so
rpc.nfsd -V 4.2 -N 4.1
will write "-4.1 +4.2 +2 +3 +4"
so it would be a regression for "+4" to enable always all versions.
reading "-4" implies that no v4.x are enabled
reading "+4" implies that some v4.x are enabled, and that v4.0 is enabled unless
"-4.0" is also present. All other minor versions will explicitly be listed.
Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2017-03-10 00:36:39 +00:00
|
|
|
if (vers == 4 && minor >= 0 &&
|
2019-04-09 15:46:19 +00:00
|
|
|
!nfsd_minorversion(nn, minor, NFSD_TEST))
|
2017-02-22 23:35:33 +00:00
|
|
|
supported = false;
|
NFSD: further refinement of content of /proc/fs/nfsd/versions
Prior to
e35659f1b03c ("NFSD: correctly range-check v4.x minor version when setting versions.")
v4.0 could not be disabled without disabling all NFSv4 protocols.
So the 'versions' file contained ±4 ±4.1 ±4.2.
Writing "-4" would disable all v4 completely. Writing +4 would enabled those
minor versions that are currently enabled, either by default or otherwise.
After that commit, it was possible to disable v4.0 independently. To
maximize backward compatibility with use cases which never disabled
v4.0, the "versions" file would never contain "+4.0" - that was implied
by "+4", unless explicitly negated by "-4.0".
This introduced an inconsistency in that it was possible to disable all
minor versions, but still have the major version advertised.
e.g. "-4.0 -4.1 -4.2 +4" would result in NFSv4 support being advertised,
but all attempts to use it rejected.
Commit
d3635ff07e8c ("nfsd: fix configuration of supported minor versions")
and following removed this inconsistency. If all minor version were disabled,
the major would be disabled too. If any minor was enabled, the major would be
disabled.
This patch also treated "+4" as equivalent to "+4.0" and "-4" as "-4.0".
A consequence of this is that writing "-4" would only disable 4.0.
This is a regression against the earlier behaviour, in a use case that rpc.nfsd
actually uses.
The command "rpc.nfsd -N 4" will write "+2 +3 -4" to the versions files.
Previously, that would disable v4 completely. Now it will only disable v4.0.
Also "4.0" never appears in the "versions" file when read.
So if only v4.1 is available, the previous kernel would have reported
"+4 -4.0 +4.1 -4.2" the current kernel reports "-4 +4.1 -4.2" which
could easily confuse.
This patch restores the implication that "+4" and "-4" apply more
globals and do not imply "4.0".
Specifically:
writing "-4" will disable all 4.x minor versions.
writing "+4" will enable all 4.1 minor version if none are currently enabled.
rpc.nfsd will list minor versions before major versions, so
rpc.nfsd -V 4.2 -N 4.1
will write "-4.1 +4.2 +2 +3 +4"
so it would be a regression for "+4" to enable always all versions.
reading "-4" implies that no v4.x are enabled
reading "+4" implies that some v4.x are enabled, and that v4.0 is enabled unless
"-4.0" is also present. All other minor versions will explicitly be listed.
Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2017-03-10 00:36:39 +00:00
|
|
|
if (minor == 0 && supported)
|
|
|
|
/*
|
|
|
|
* special case for backward compatability.
|
|
|
|
* +4.0 is never reported, it is implied by
|
|
|
|
* +4, unless -4.0 is present.
|
|
|
|
*/
|
|
|
|
return 0;
|
2017-02-22 23:35:33 +00:00
|
|
|
return snprintf(buf, remaining, format, sep,
|
|
|
|
supported ? '+' : '-', vers, minor);
|
|
|
|
}
|
|
|
|
|
2008-06-10 12:40:36 +00:00
|
|
|
static ssize_t __write_versions(struct file *file, char *buf, size_t size)
|
2005-11-07 09:00:25 +00:00
|
|
|
{
|
|
|
|
char *mesg = buf;
|
2009-04-03 05:28:59 +00:00
|
|
|
char *vers, *minorp, sign;
|
2009-04-23 23:33:18 +00:00
|
|
|
int len, num, remaining;
|
2005-11-07 09:00:25 +00:00
|
|
|
ssize_t tlen = 0;
|
|
|
|
char *sep;
|
2014-10-22 00:19:11 +00:00
|
|
|
struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
|
2005-11-07 09:00:25 +00:00
|
|
|
|
2023-05-15 13:35:38 +00:00
|
|
|
if (size > 0) {
|
2012-12-06 11:23:24 +00:00
|
|
|
if (nn->nfsd_serv)
|
2006-10-02 09:17:46 +00:00
|
|
|
/* Cannot change versions without updating
|
2012-12-06 11:23:24 +00:00
|
|
|
* nn->nfsd_serv->sv_xdrsize, and reallocing
|
2006-10-02 09:17:46 +00:00
|
|
|
* rq_argp and rq_resp
|
|
|
|
*/
|
2005-11-07 09:00:25 +00:00
|
|
|
return -EBUSY;
|
|
|
|
if (buf[size-1] != '\n')
|
|
|
|
return -EINVAL;
|
|
|
|
buf[size-1] = 0;
|
2023-05-15 13:35:50 +00:00
|
|
|
trace_nfsd_ctl_version(netns(file), buf);
|
2005-11-07 09:00:25 +00:00
|
|
|
|
|
|
|
vers = mesg;
|
|
|
|
len = qword_get(&mesg, vers, size);
|
|
|
|
if (len <= 0) return -EINVAL;
|
|
|
|
do {
|
2017-02-22 23:35:32 +00:00
|
|
|
enum vers_op cmd;
|
NFSD: further refinement of content of /proc/fs/nfsd/versions
Prior to
e35659f1b03c ("NFSD: correctly range-check v4.x minor version when setting versions.")
v4.0 could not be disabled without disabling all NFSv4 protocols.
So the 'versions' file contained ±4 ±4.1 ±4.2.
Writing "-4" would disable all v4 completely. Writing +4 would enabled those
minor versions that are currently enabled, either by default or otherwise.
After that commit, it was possible to disable v4.0 independently. To
maximize backward compatibility with use cases which never disabled
v4.0, the "versions" file would never contain "+4.0" - that was implied
by "+4", unless explicitly negated by "-4.0".
This introduced an inconsistency in that it was possible to disable all
minor versions, but still have the major version advertised.
e.g. "-4.0 -4.1 -4.2 +4" would result in NFSv4 support being advertised,
but all attempts to use it rejected.
Commit
d3635ff07e8c ("nfsd: fix configuration of supported minor versions")
and following removed this inconsistency. If all minor version were disabled,
the major would be disabled too. If any minor was enabled, the major would be
disabled.
This patch also treated "+4" as equivalent to "+4.0" and "-4" as "-4.0".
A consequence of this is that writing "-4" would only disable 4.0.
This is a regression against the earlier behaviour, in a use case that rpc.nfsd
actually uses.
The command "rpc.nfsd -N 4" will write "+2 +3 -4" to the versions files.
Previously, that would disable v4 completely. Now it will only disable v4.0.
Also "4.0" never appears in the "versions" file when read.
So if only v4.1 is available, the previous kernel would have reported
"+4 -4.0 +4.1 -4.2" the current kernel reports "-4 +4.1 -4.2" which
could easily confuse.
This patch restores the implication that "+4" and "-4" apply more
globals and do not imply "4.0".
Specifically:
writing "-4" will disable all 4.x minor versions.
writing "+4" will enable all 4.1 minor version if none are currently enabled.
rpc.nfsd will list minor versions before major versions, so
rpc.nfsd -V 4.2 -N 4.1
will write "-4.1 +4.2 +2 +3 +4"
so it would be a regression for "+4" to enable always all versions.
reading "-4" implies that no v4.x are enabled
reading "+4" implies that some v4.x are enabled, and that v4.0 is enabled unless
"-4.0" is also present. All other minor versions will explicitly be listed.
Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2017-03-10 00:36:39 +00:00
|
|
|
unsigned minor;
|
2005-11-07 09:00:25 +00:00
|
|
|
sign = *vers;
|
|
|
|
if (sign == '+' || sign == '-')
|
2009-04-03 05:28:59 +00:00
|
|
|
num = simple_strtol((vers+1), &minorp, 0);
|
2005-11-07 09:00:25 +00:00
|
|
|
else
|
2009-04-03 05:28:59 +00:00
|
|
|
num = simple_strtol(vers, &minorp, 0);
|
|
|
|
if (*minorp == '.') {
|
2013-01-23 23:25:01 +00:00
|
|
|
if (num != 4)
|
2009-04-03 05:28:59 +00:00
|
|
|
return -EINVAL;
|
2016-12-21 03:32:19 +00:00
|
|
|
if (kstrtouint(minorp+1, 0, &minor) < 0)
|
2009-04-03 05:28:59 +00:00
|
|
|
return -EINVAL;
|
NFSD: further refinement of content of /proc/fs/nfsd/versions
Prior to
e35659f1b03c ("NFSD: correctly range-check v4.x minor version when setting versions.")
v4.0 could not be disabled without disabling all NFSv4 protocols.
So the 'versions' file contained ±4 ±4.1 ±4.2.
Writing "-4" would disable all v4 completely. Writing +4 would enabled those
minor versions that are currently enabled, either by default or otherwise.
After that commit, it was possible to disable v4.0 independently. To
maximize backward compatibility with use cases which never disabled
v4.0, the "versions" file would never contain "+4.0" - that was implied
by "+4", unless explicitly negated by "-4.0".
This introduced an inconsistency in that it was possible to disable all
minor versions, but still have the major version advertised.
e.g. "-4.0 -4.1 -4.2 +4" would result in NFSv4 support being advertised,
but all attempts to use it rejected.
Commit
d3635ff07e8c ("nfsd: fix configuration of supported minor versions")
and following removed this inconsistency. If all minor version were disabled,
the major would be disabled too. If any minor was enabled, the major would be
disabled.
This patch also treated "+4" as equivalent to "+4.0" and "-4" as "-4.0".
A consequence of this is that writing "-4" would only disable 4.0.
This is a regression against the earlier behaviour, in a use case that rpc.nfsd
actually uses.
The command "rpc.nfsd -N 4" will write "+2 +3 -4" to the versions files.
Previously, that would disable v4 completely. Now it will only disable v4.0.
Also "4.0" never appears in the "versions" file when read.
So if only v4.1 is available, the previous kernel would have reported
"+4 -4.0 +4.1 -4.2" the current kernel reports "-4 +4.1 -4.2" which
could easily confuse.
This patch restores the implication that "+4" and "-4" apply more
globals and do not imply "4.0".
Specifically:
writing "-4" will disable all 4.x minor versions.
writing "+4" will enable all 4.1 minor version if none are currently enabled.
rpc.nfsd will list minor versions before major versions, so
rpc.nfsd -V 4.2 -N 4.1
will write "-4.1 +4.2 +2 +3 +4"
so it would be a regression for "+4" to enable always all versions.
reading "-4" implies that no v4.x are enabled
reading "+4" implies that some v4.x are enabled, and that v4.0 is enabled unless
"-4.0" is also present. All other minor versions will explicitly be listed.
Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2017-03-10 00:36:39 +00:00
|
|
|
}
|
|
|
|
|
2017-02-22 23:35:32 +00:00
|
|
|
cmd = sign == '-' ? NFSD_CLEAR : NFSD_SET;
|
2005-11-07 09:00:25 +00:00
|
|
|
switch(num) {
|
2022-10-18 11:47:56 +00:00
|
|
|
#ifdef CONFIG_NFSD_V2
|
2005-11-07 09:00:25 +00:00
|
|
|
case 2:
|
2022-10-18 11:47:56 +00:00
|
|
|
#endif
|
2005-11-07 09:00:25 +00:00
|
|
|
case 3:
|
2019-04-09 15:46:19 +00:00
|
|
|
nfsd_vers(nn, num, cmd);
|
2005-11-07 09:00:25 +00:00
|
|
|
break;
|
2017-02-22 23:35:32 +00:00
|
|
|
case 4:
|
NFSD: further refinement of content of /proc/fs/nfsd/versions
Prior to
e35659f1b03c ("NFSD: correctly range-check v4.x minor version when setting versions.")
v4.0 could not be disabled without disabling all NFSv4 protocols.
So the 'versions' file contained ±4 ±4.1 ±4.2.
Writing "-4" would disable all v4 completely. Writing +4 would enabled those
minor versions that are currently enabled, either by default or otherwise.
After that commit, it was possible to disable v4.0 independently. To
maximize backward compatibility with use cases which never disabled
v4.0, the "versions" file would never contain "+4.0" - that was implied
by "+4", unless explicitly negated by "-4.0".
This introduced an inconsistency in that it was possible to disable all
minor versions, but still have the major version advertised.
e.g. "-4.0 -4.1 -4.2 +4" would result in NFSv4 support being advertised,
but all attempts to use it rejected.
Commit
d3635ff07e8c ("nfsd: fix configuration of supported minor versions")
and following removed this inconsistency. If all minor version were disabled,
the major would be disabled too. If any minor was enabled, the major would be
disabled.
This patch also treated "+4" as equivalent to "+4.0" and "-4" as "-4.0".
A consequence of this is that writing "-4" would only disable 4.0.
This is a regression against the earlier behaviour, in a use case that rpc.nfsd
actually uses.
The command "rpc.nfsd -N 4" will write "+2 +3 -4" to the versions files.
Previously, that would disable v4 completely. Now it will only disable v4.0.
Also "4.0" never appears in the "versions" file when read.
So if only v4.1 is available, the previous kernel would have reported
"+4 -4.0 +4.1 -4.2" the current kernel reports "-4 +4.1 -4.2" which
could easily confuse.
This patch restores the implication that "+4" and "-4" apply more
globals and do not imply "4.0".
Specifically:
writing "-4" will disable all 4.x minor versions.
writing "+4" will enable all 4.1 minor version if none are currently enabled.
rpc.nfsd will list minor versions before major versions, so
rpc.nfsd -V 4.2 -N 4.1
will write "-4.1 +4.2 +2 +3 +4"
so it would be a regression for "+4" to enable always all versions.
reading "-4" implies that no v4.x are enabled
reading "+4" implies that some v4.x are enabled, and that v4.0 is enabled unless
"-4.0" is also present. All other minor versions will explicitly be listed.
Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2017-03-10 00:36:39 +00:00
|
|
|
if (*minorp == '.') {
|
2019-04-09 15:46:19 +00:00
|
|
|
if (nfsd_minorversion(nn, minor, cmd) < 0)
|
NFSD: further refinement of content of /proc/fs/nfsd/versions
Prior to
e35659f1b03c ("NFSD: correctly range-check v4.x minor version when setting versions.")
v4.0 could not be disabled without disabling all NFSv4 protocols.
So the 'versions' file contained ±4 ±4.1 ±4.2.
Writing "-4" would disable all v4 completely. Writing +4 would enabled those
minor versions that are currently enabled, either by default or otherwise.
After that commit, it was possible to disable v4.0 independently. To
maximize backward compatibility with use cases which never disabled
v4.0, the "versions" file would never contain "+4.0" - that was implied
by "+4", unless explicitly negated by "-4.0".
This introduced an inconsistency in that it was possible to disable all
minor versions, but still have the major version advertised.
e.g. "-4.0 -4.1 -4.2 +4" would result in NFSv4 support being advertised,
but all attempts to use it rejected.
Commit
d3635ff07e8c ("nfsd: fix configuration of supported minor versions")
and following removed this inconsistency. If all minor version were disabled,
the major would be disabled too. If any minor was enabled, the major would be
disabled.
This patch also treated "+4" as equivalent to "+4.0" and "-4" as "-4.0".
A consequence of this is that writing "-4" would only disable 4.0.
This is a regression against the earlier behaviour, in a use case that rpc.nfsd
actually uses.
The command "rpc.nfsd -N 4" will write "+2 +3 -4" to the versions files.
Previously, that would disable v4 completely. Now it will only disable v4.0.
Also "4.0" never appears in the "versions" file when read.
So if only v4.1 is available, the previous kernel would have reported
"+4 -4.0 +4.1 -4.2" the current kernel reports "-4 +4.1 -4.2" which
could easily confuse.
This patch restores the implication that "+4" and "-4" apply more
globals and do not imply "4.0".
Specifically:
writing "-4" will disable all 4.x minor versions.
writing "+4" will enable all 4.1 minor version if none are currently enabled.
rpc.nfsd will list minor versions before major versions, so
rpc.nfsd -V 4.2 -N 4.1
will write "-4.1 +4.2 +2 +3 +4"
so it would be a regression for "+4" to enable always all versions.
reading "-4" implies that no v4.x are enabled
reading "+4" implies that some v4.x are enabled, and that v4.0 is enabled unless
"-4.0" is also present. All other minor versions will explicitly be listed.
Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2017-03-10 00:36:39 +00:00
|
|
|
return -EINVAL;
|
2019-04-09 15:46:19 +00:00
|
|
|
} else if ((cmd == NFSD_SET) != nfsd_vers(nn, num, NFSD_TEST)) {
|
NFSD: further refinement of content of /proc/fs/nfsd/versions
Prior to
e35659f1b03c ("NFSD: correctly range-check v4.x minor version when setting versions.")
v4.0 could not be disabled without disabling all NFSv4 protocols.
So the 'versions' file contained ±4 ±4.1 ±4.2.
Writing "-4" would disable all v4 completely. Writing +4 would enabled those
minor versions that are currently enabled, either by default or otherwise.
After that commit, it was possible to disable v4.0 independently. To
maximize backward compatibility with use cases which never disabled
v4.0, the "versions" file would never contain "+4.0" - that was implied
by "+4", unless explicitly negated by "-4.0".
This introduced an inconsistency in that it was possible to disable all
minor versions, but still have the major version advertised.
e.g. "-4.0 -4.1 -4.2 +4" would result in NFSv4 support being advertised,
but all attempts to use it rejected.
Commit
d3635ff07e8c ("nfsd: fix configuration of supported minor versions")
and following removed this inconsistency. If all minor version were disabled,
the major would be disabled too. If any minor was enabled, the major would be
disabled.
This patch also treated "+4" as equivalent to "+4.0" and "-4" as "-4.0".
A consequence of this is that writing "-4" would only disable 4.0.
This is a regression against the earlier behaviour, in a use case that rpc.nfsd
actually uses.
The command "rpc.nfsd -N 4" will write "+2 +3 -4" to the versions files.
Previously, that would disable v4 completely. Now it will only disable v4.0.
Also "4.0" never appears in the "versions" file when read.
So if only v4.1 is available, the previous kernel would have reported
"+4 -4.0 +4.1 -4.2" the current kernel reports "-4 +4.1 -4.2" which
could easily confuse.
This patch restores the implication that "+4" and "-4" apply more
globals and do not imply "4.0".
Specifically:
writing "-4" will disable all 4.x minor versions.
writing "+4" will enable all 4.1 minor version if none are currently enabled.
rpc.nfsd will list minor versions before major versions, so
rpc.nfsd -V 4.2 -N 4.1
will write "-4.1 +4.2 +2 +3 +4"
so it would be a regression for "+4" to enable always all versions.
reading "-4" implies that no v4.x are enabled
reading "+4" implies that some v4.x are enabled, and that v4.0 is enabled unless
"-4.0" is also present. All other minor versions will explicitly be listed.
Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2017-03-10 00:36:39 +00:00
|
|
|
/*
|
|
|
|
* Either we have +4 and no minors are enabled,
|
|
|
|
* or we have -4 and at least one minor is enabled.
|
|
|
|
* In either case, propagate 'cmd' to all minors.
|
|
|
|
*/
|
|
|
|
minor = 0;
|
2019-04-09 15:46:19 +00:00
|
|
|
while (nfsd_minorversion(nn, minor, cmd) >= 0)
|
NFSD: further refinement of content of /proc/fs/nfsd/versions
Prior to
e35659f1b03c ("NFSD: correctly range-check v4.x minor version when setting versions.")
v4.0 could not be disabled without disabling all NFSv4 protocols.
So the 'versions' file contained ±4 ±4.1 ±4.2.
Writing "-4" would disable all v4 completely. Writing +4 would enabled those
minor versions that are currently enabled, either by default or otherwise.
After that commit, it was possible to disable v4.0 independently. To
maximize backward compatibility with use cases which never disabled
v4.0, the "versions" file would never contain "+4.0" - that was implied
by "+4", unless explicitly negated by "-4.0".
This introduced an inconsistency in that it was possible to disable all
minor versions, but still have the major version advertised.
e.g. "-4.0 -4.1 -4.2 +4" would result in NFSv4 support being advertised,
but all attempts to use it rejected.
Commit
d3635ff07e8c ("nfsd: fix configuration of supported minor versions")
and following removed this inconsistency. If all minor version were disabled,
the major would be disabled too. If any minor was enabled, the major would be
disabled.
This patch also treated "+4" as equivalent to "+4.0" and "-4" as "-4.0".
A consequence of this is that writing "-4" would only disable 4.0.
This is a regression against the earlier behaviour, in a use case that rpc.nfsd
actually uses.
The command "rpc.nfsd -N 4" will write "+2 +3 -4" to the versions files.
Previously, that would disable v4 completely. Now it will only disable v4.0.
Also "4.0" never appears in the "versions" file when read.
So if only v4.1 is available, the previous kernel would have reported
"+4 -4.0 +4.1 -4.2" the current kernel reports "-4 +4.1 -4.2" which
could easily confuse.
This patch restores the implication that "+4" and "-4" apply more
globals and do not imply "4.0".
Specifically:
writing "-4" will disable all 4.x minor versions.
writing "+4" will enable all 4.1 minor version if none are currently enabled.
rpc.nfsd will list minor versions before major versions, so
rpc.nfsd -V 4.2 -N 4.1
will write "-4.1 +4.2 +2 +3 +4"
so it would be a regression for "+4" to enable always all versions.
reading "-4" implies that no v4.x are enabled
reading "+4" implies that some v4.x are enabled, and that v4.0 is enabled unless
"-4.0" is also present. All other minor versions will explicitly be listed.
Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2017-03-10 00:36:39 +00:00
|
|
|
minor++;
|
|
|
|
}
|
|
|
|
break;
|
2005-11-07 09:00:25 +00:00
|
|
|
default:
|
2022-10-18 11:47:54 +00:00
|
|
|
/* Ignore requests to disable non-existent versions */
|
|
|
|
if (cmd == NFSD_SET)
|
|
|
|
return -EINVAL;
|
2005-11-07 09:00:25 +00:00
|
|
|
}
|
|
|
|
vers += len + 1;
|
|
|
|
} while ((len = qword_get(&mesg, vers, size)) > 0);
|
|
|
|
/* If all get turned off, turn them back on, as
|
|
|
|
* having no versions is BAD
|
|
|
|
*/
|
2019-04-09 15:46:19 +00:00
|
|
|
nfsd_reset_versions(nn);
|
2005-11-07 09:00:25 +00:00
|
|
|
}
|
2009-04-23 23:33:18 +00:00
|
|
|
|
2005-11-07 09:00:25 +00:00
|
|
|
/* Now write current state into reply buffer */
|
|
|
|
sep = "";
|
2009-04-23 23:33:18 +00:00
|
|
|
remaining = SIMPLE_TRANSACTION_LIMIT;
|
2017-02-22 23:35:33 +00:00
|
|
|
for (num=2 ; num <= 4 ; num++) {
|
NFSD: further refinement of content of /proc/fs/nfsd/versions
Prior to
e35659f1b03c ("NFSD: correctly range-check v4.x minor version when setting versions.")
v4.0 could not be disabled without disabling all NFSv4 protocols.
So the 'versions' file contained ±4 ±4.1 ±4.2.
Writing "-4" would disable all v4 completely. Writing +4 would enabled those
minor versions that are currently enabled, either by default or otherwise.
After that commit, it was possible to disable v4.0 independently. To
maximize backward compatibility with use cases which never disabled
v4.0, the "versions" file would never contain "+4.0" - that was implied
by "+4", unless explicitly negated by "-4.0".
This introduced an inconsistency in that it was possible to disable all
minor versions, but still have the major version advertised.
e.g. "-4.0 -4.1 -4.2 +4" would result in NFSv4 support being advertised,
but all attempts to use it rejected.
Commit
d3635ff07e8c ("nfsd: fix configuration of supported minor versions")
and following removed this inconsistency. If all minor version were disabled,
the major would be disabled too. If any minor was enabled, the major would be
disabled.
This patch also treated "+4" as equivalent to "+4.0" and "-4" as "-4.0".
A consequence of this is that writing "-4" would only disable 4.0.
This is a regression against the earlier behaviour, in a use case that rpc.nfsd
actually uses.
The command "rpc.nfsd -N 4" will write "+2 +3 -4" to the versions files.
Previously, that would disable v4 completely. Now it will only disable v4.0.
Also "4.0" never appears in the "versions" file when read.
So if only v4.1 is available, the previous kernel would have reported
"+4 -4.0 +4.1 -4.2" the current kernel reports "-4 +4.1 -4.2" which
could easily confuse.
This patch restores the implication that "+4" and "-4" apply more
globals and do not imply "4.0".
Specifically:
writing "-4" will disable all 4.x minor versions.
writing "+4" will enable all 4.1 minor version if none are currently enabled.
rpc.nfsd will list minor versions before major versions, so
rpc.nfsd -V 4.2 -N 4.1
will write "-4.1 +4.2 +2 +3 +4"
so it would be a regression for "+4" to enable always all versions.
reading "-4" implies that no v4.x are enabled
reading "+4" implies that some v4.x are enabled, and that v4.0 is enabled unless
"-4.0" is also present. All other minor versions will explicitly be listed.
Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2017-03-10 00:36:39 +00:00
|
|
|
int minor;
|
2019-04-09 15:46:19 +00:00
|
|
|
if (!nfsd_vers(nn, num, NFSD_AVAIL))
|
2017-02-22 23:35:33 +00:00
|
|
|
continue;
|
NFSD: further refinement of content of /proc/fs/nfsd/versions
Prior to
e35659f1b03c ("NFSD: correctly range-check v4.x minor version when setting versions.")
v4.0 could not be disabled without disabling all NFSv4 protocols.
So the 'versions' file contained ±4 ±4.1 ±4.2.
Writing "-4" would disable all v4 completely. Writing +4 would enabled those
minor versions that are currently enabled, either by default or otherwise.
After that commit, it was possible to disable v4.0 independently. To
maximize backward compatibility with use cases which never disabled
v4.0, the "versions" file would never contain "+4.0" - that was implied
by "+4", unless explicitly negated by "-4.0".
This introduced an inconsistency in that it was possible to disable all
minor versions, but still have the major version advertised.
e.g. "-4.0 -4.1 -4.2 +4" would result in NFSv4 support being advertised,
but all attempts to use it rejected.
Commit
d3635ff07e8c ("nfsd: fix configuration of supported minor versions")
and following removed this inconsistency. If all minor version were disabled,
the major would be disabled too. If any minor was enabled, the major would be
disabled.
This patch also treated "+4" as equivalent to "+4.0" and "-4" as "-4.0".
A consequence of this is that writing "-4" would only disable 4.0.
This is a regression against the earlier behaviour, in a use case that rpc.nfsd
actually uses.
The command "rpc.nfsd -N 4" will write "+2 +3 -4" to the versions files.
Previously, that would disable v4 completely. Now it will only disable v4.0.
Also "4.0" never appears in the "versions" file when read.
So if only v4.1 is available, the previous kernel would have reported
"+4 -4.0 +4.1 -4.2" the current kernel reports "-4 +4.1 -4.2" which
could easily confuse.
This patch restores the implication that "+4" and "-4" apply more
globals and do not imply "4.0".
Specifically:
writing "-4" will disable all 4.x minor versions.
writing "+4" will enable all 4.1 minor version if none are currently enabled.
rpc.nfsd will list minor versions before major versions, so
rpc.nfsd -V 4.2 -N 4.1
will write "-4.1 +4.2 +2 +3 +4"
so it would be a regression for "+4" to enable always all versions.
reading "-4" implies that no v4.x are enabled
reading "+4" implies that some v4.x are enabled, and that v4.0 is enabled unless
"-4.0" is also present. All other minor versions will explicitly be listed.
Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2017-03-10 00:36:39 +00:00
|
|
|
|
|
|
|
minor = -1;
|
2017-02-22 23:35:33 +00:00
|
|
|
do {
|
2019-04-09 15:46:19 +00:00
|
|
|
len = nfsd_print_version_support(nn, buf, remaining,
|
2017-02-22 23:35:33 +00:00
|
|
|
sep, num, minor);
|
2014-11-27 15:58:54 +00:00
|
|
|
if (len >= remaining)
|
2017-02-22 23:35:33 +00:00
|
|
|
goto out;
|
2009-04-23 23:33:18 +00:00
|
|
|
remaining -= len;
|
|
|
|
buf += len;
|
|
|
|
tlen += len;
|
2017-02-22 23:35:33 +00:00
|
|
|
minor++;
|
NFSD: further refinement of content of /proc/fs/nfsd/versions
Prior to
e35659f1b03c ("NFSD: correctly range-check v4.x minor version when setting versions.")
v4.0 could not be disabled without disabling all NFSv4 protocols.
So the 'versions' file contained ±4 ±4.1 ±4.2.
Writing "-4" would disable all v4 completely. Writing +4 would enabled those
minor versions that are currently enabled, either by default or otherwise.
After that commit, it was possible to disable v4.0 independently. To
maximize backward compatibility with use cases which never disabled
v4.0, the "versions" file would never contain "+4.0" - that was implied
by "+4", unless explicitly negated by "-4.0".
This introduced an inconsistency in that it was possible to disable all
minor versions, but still have the major version advertised.
e.g. "-4.0 -4.1 -4.2 +4" would result in NFSv4 support being advertised,
but all attempts to use it rejected.
Commit
d3635ff07e8c ("nfsd: fix configuration of supported minor versions")
and following removed this inconsistency. If all minor version were disabled,
the major would be disabled too. If any minor was enabled, the major would be
disabled.
This patch also treated "+4" as equivalent to "+4.0" and "-4" as "-4.0".
A consequence of this is that writing "-4" would only disable 4.0.
This is a regression against the earlier behaviour, in a use case that rpc.nfsd
actually uses.
The command "rpc.nfsd -N 4" will write "+2 +3 -4" to the versions files.
Previously, that would disable v4 completely. Now it will only disable v4.0.
Also "4.0" never appears in the "versions" file when read.
So if only v4.1 is available, the previous kernel would have reported
"+4 -4.0 +4.1 -4.2" the current kernel reports "-4 +4.1 -4.2" which
could easily confuse.
This patch restores the implication that "+4" and "-4" apply more
globals and do not imply "4.0".
Specifically:
writing "-4" will disable all 4.x minor versions.
writing "+4" will enable all 4.1 minor version if none are currently enabled.
rpc.nfsd will list minor versions before major versions, so
rpc.nfsd -V 4.2 -N 4.1
will write "-4.1 +4.2 +2 +3 +4"
so it would be a regression for "+4" to enable always all versions.
reading "-4" implies that no v4.x are enabled
reading "+4" implies that some v4.x are enabled, and that v4.0 is enabled unless
"-4.0" is also present. All other minor versions will explicitly be listed.
Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2017-03-10 00:36:39 +00:00
|
|
|
if (len)
|
|
|
|
sep = " ";
|
2017-02-22 23:35:33 +00:00
|
|
|
} while (num == 4 && minor <= NFSD_SUPPORTED_MINOR_VERSION);
|
|
|
|
}
|
|
|
|
out:
|
2009-04-23 23:33:18 +00:00
|
|
|
len = snprintf(buf, remaining, "\n");
|
2014-11-27 15:58:54 +00:00
|
|
|
if (len >= remaining)
|
2009-04-23 23:33:18 +00:00
|
|
|
return -EINVAL;
|
|
|
|
return tlen + len;
|
2005-11-07 09:00:25 +00:00
|
|
|
}
|
|
|
|
|
2020-04-06 20:01:42 +00:00
|
|
|
/*
|
2008-12-12 21:57:35 +00:00
|
|
|
* write_versions - Set or report the available NFS protocol versions
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf: ignored
|
|
|
|
* size: zero
|
|
|
|
* Output:
|
|
|
|
* On success: passed-in buffer filled with '\n'-terminated C
|
|
|
|
* string containing positive or negative integer
|
|
|
|
* values representing the current status of each
|
|
|
|
* protocol version;
|
|
|
|
* return code is the size in bytes of the string
|
|
|
|
* On error: return code is zero or a negative errno value
|
|
|
|
*
|
|
|
|
* OR
|
|
|
|
*
|
|
|
|
* Input:
|
2023-05-15 13:35:38 +00:00
|
|
|
* buf: C string containing whitespace-
|
|
|
|
* separated positive or negative
|
|
|
|
* integer values representing NFS
|
|
|
|
* protocol versions to enable ("+n")
|
|
|
|
* or disable ("-n")
|
2008-12-12 21:57:35 +00:00
|
|
|
* size: non-zero length of C string in @buf
|
|
|
|
* Output:
|
|
|
|
* On success: status of zero or more protocol versions has
|
|
|
|
* been updated; passed-in buffer filled with
|
|
|
|
* '\n'-terminated C string containing positive
|
|
|
|
* or negative integer values representing the
|
|
|
|
* current status of each protocol version;
|
|
|
|
* return code is the size in bytes of the string
|
|
|
|
* On error: return code is zero or a negative errno value
|
|
|
|
*/
|
2008-06-10 12:40:36 +00:00
|
|
|
static ssize_t write_versions(struct file *file, char *buf, size_t size)
|
|
|
|
{
|
|
|
|
ssize_t rv;
|
|
|
|
|
|
|
|
mutex_lock(&nfsd_mutex);
|
|
|
|
rv = __write_versions(file, buf, size);
|
|
|
|
mutex_unlock(&nfsd_mutex);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2009-04-23 23:32:10 +00:00
|
|
|
/*
|
|
|
|
* Zero-length write. Return a list of NFSD's current listener
|
|
|
|
* transports.
|
|
|
|
*/
|
2012-12-06 11:23:24 +00:00
|
|
|
static ssize_t __write_ports_names(char *buf, struct net *net)
|
2009-04-23 23:32:10 +00:00
|
|
|
{
|
2012-12-06 11:23:24 +00:00
|
|
|
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
|
|
|
|
|
|
|
if (nn->nfsd_serv == NULL)
|
2009-04-23 23:32:10 +00:00
|
|
|
return 0;
|
2012-12-06 11:23:24 +00:00
|
|
|
return svc_xprt_names(nn->nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
|
2009-04-23 23:32:10 +00:00
|
|
|
}
|
|
|
|
|
2009-04-23 23:31:55 +00:00
|
|
|
/*
|
|
|
|
* A single 'fd' number was written, in which case it must be for
|
|
|
|
* a socket of a supported family/protocol, and we use it as an
|
|
|
|
* nfsd listener.
|
|
|
|
*/
|
2019-04-09 16:13:37 +00:00
|
|
|
static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred *cred)
|
2009-04-23 23:31:55 +00:00
|
|
|
{
|
|
|
|
char *mesg = buf;
|
|
|
|
int fd, err;
|
2012-12-06 11:23:24 +00:00
|
|
|
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
2024-01-03 13:36:52 +00:00
|
|
|
struct svc_serv *serv;
|
2009-04-23 23:31:55 +00:00
|
|
|
|
|
|
|
err = get_int(&mesg, &fd);
|
|
|
|
if (err != 0 || fd < 0)
|
|
|
|
return -EINVAL;
|
2023-05-15 13:35:50 +00:00
|
|
|
trace_nfsd_ctl_ports_addfd(net, fd);
|
2009-04-23 23:31:55 +00:00
|
|
|
|
2012-12-10 09:19:20 +00:00
|
|
|
err = nfsd_create_serv(net);
|
2009-04-23 23:31:55 +00:00
|
|
|
if (err != 0)
|
|
|
|
return err;
|
|
|
|
|
2024-01-03 13:36:52 +00:00
|
|
|
serv = nn->nfsd_serv;
|
|
|
|
err = svc_addsock(serv, net, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred);
|
2009-04-23 23:31:55 +00:00
|
|
|
|
2023-12-15 00:56:34 +00:00
|
|
|
if (!serv->sv_nrthreads && list_empty(&nn->nfsd_serv->sv_permsocks))
|
2023-12-15 00:56:35 +00:00
|
|
|
nfsd_destroy_serv(net);
|
|
|
|
|
2009-04-23 23:32:18 +00:00
|
|
|
return err;
|
2009-04-23 23:31:55 +00:00
|
|
|
}
|
|
|
|
|
2009-04-23 23:31:40 +00:00
|
|
|
/*
|
2023-05-15 13:35:38 +00:00
|
|
|
* A transport listener is added by writing its transport name and
|
2009-04-23 23:31:40 +00:00
|
|
|
* a port number.
|
|
|
|
*/
|
2019-04-09 16:13:37 +00:00
|
|
|
static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cred *cred)
|
2009-04-23 23:31:40 +00:00
|
|
|
{
|
|
|
|
char transport[16];
|
2010-01-26 19:04:22 +00:00
|
|
|
struct svc_xprt *xprt;
|
2009-04-23 23:31:40 +00:00
|
|
|
int port, err;
|
2012-12-06 11:23:24 +00:00
|
|
|
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
2024-01-03 13:36:52 +00:00
|
|
|
struct svc_serv *serv;
|
2009-04-23 23:31:40 +00:00
|
|
|
|
2012-08-14 21:48:39 +00:00
|
|
|
if (sscanf(buf, "%15s %5u", transport, &port) != 2)
|
2009-04-23 23:31:40 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
2010-05-24 21:33:03 +00:00
|
|
|
if (port < 1 || port > USHRT_MAX)
|
2009-04-23 23:31:40 +00:00
|
|
|
return -EINVAL;
|
2023-05-15 13:35:50 +00:00
|
|
|
trace_nfsd_ctl_ports_addxprt(net, transport, port);
|
2009-04-23 23:31:40 +00:00
|
|
|
|
2012-12-10 09:19:20 +00:00
|
|
|
err = nfsd_create_serv(net);
|
2009-04-23 23:31:40 +00:00
|
|
|
if (err != 0)
|
|
|
|
return err;
|
|
|
|
|
2024-01-03 13:36:52 +00:00
|
|
|
serv = nn->nfsd_serv;
|
|
|
|
err = svc_xprt_create(serv, transport, net,
|
2022-01-26 16:42:08 +00:00
|
|
|
PF_INET, port, SVC_SOCK_ANONYMOUS, cred);
|
2010-01-26 19:04:13 +00:00
|
|
|
if (err < 0)
|
2010-01-26 19:04:22 +00:00
|
|
|
goto out_err;
|
|
|
|
|
2024-01-03 13:36:52 +00:00
|
|
|
err = svc_xprt_create(serv, transport, net,
|
2022-01-26 16:42:08 +00:00
|
|
|
PF_INET6, port, SVC_SOCK_ANONYMOUS, cred);
|
2010-01-26 19:04:22 +00:00
|
|
|
if (err < 0 && err != -EAFNOSUPPORT)
|
|
|
|
goto out_close;
|
2010-07-19 20:50:06 +00:00
|
|
|
|
2009-04-23 23:31:40 +00:00
|
|
|
return 0;
|
2010-01-26 19:04:22 +00:00
|
|
|
out_close:
|
2024-01-03 13:36:52 +00:00
|
|
|
xprt = svc_find_xprt(serv, transport, net, PF_INET, port);
|
2010-01-26 19:04:22 +00:00
|
|
|
if (xprt != NULL) {
|
2022-01-31 18:34:29 +00:00
|
|
|
svc_xprt_close(xprt);
|
2010-01-26 19:04:22 +00:00
|
|
|
svc_xprt_put(xprt);
|
|
|
|
}
|
|
|
|
out_err:
|
2023-12-15 00:56:34 +00:00
|
|
|
if (!serv->sv_nrthreads && list_empty(&nn->nfsd_serv->sv_permsocks))
|
2023-12-15 00:56:35 +00:00
|
|
|
nfsd_destroy_serv(net);
|
2023-12-15 00:56:31 +00:00
|
|
|
|
2010-01-26 19:04:22 +00:00
|
|
|
return err;
|
2009-04-23 23:31:40 +00:00
|
|
|
}
|
|
|
|
|
2012-12-10 09:19:35 +00:00
|
|
|
static ssize_t __write_ports(struct file *file, char *buf, size_t size,
|
|
|
|
struct net *net)
|
2006-10-02 09:17:47 +00:00
|
|
|
{
|
2009-04-23 23:32:10 +00:00
|
|
|
if (size == 0)
|
2012-12-06 11:23:24 +00:00
|
|
|
return __write_ports_names(buf, net);
|
2009-04-23 23:31:55 +00:00
|
|
|
|
|
|
|
if (isdigit(buf[0]))
|
2019-04-09 16:13:37 +00:00
|
|
|
return __write_ports_addfd(buf, net, file->f_cred);
|
2009-04-23 23:31:48 +00:00
|
|
|
|
2009-04-23 23:31:40 +00:00
|
|
|
if (isalpha(buf[0]))
|
2019-04-09 16:13:37 +00:00
|
|
|
return __write_ports_addxprt(buf, net, file->f_cred);
|
2009-04-23 23:31:32 +00:00
|
|
|
|
2006-10-02 09:17:48 +00:00
|
|
|
return -EINVAL;
|
2006-10-02 09:17:47 +00:00
|
|
|
}
|
|
|
|
|
2020-04-06 20:01:42 +00:00
|
|
|
/*
|
2008-12-12 21:57:35 +00:00
|
|
|
* write_ports - Pass a socket file descriptor or transport name to listen on
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf: ignored
|
|
|
|
* size: zero
|
|
|
|
* Output:
|
|
|
|
* On success: passed-in buffer filled with a '\n'-terminated C
|
|
|
|
* string containing a whitespace-separated list of
|
|
|
|
* named NFSD listeners;
|
|
|
|
* return code is the size in bytes of the string
|
|
|
|
* On error: return code is zero or a negative errno value
|
|
|
|
*
|
|
|
|
* OR
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf: C string containing an unsigned
|
|
|
|
* integer value representing a bound
|
|
|
|
* but unconnected socket that is to be
|
2009-04-23 23:32:03 +00:00
|
|
|
* used as an NFSD listener; listen(3)
|
|
|
|
* must be called for a SOCK_STREAM
|
|
|
|
* socket, otherwise it is ignored
|
2008-12-12 21:57:35 +00:00
|
|
|
* size: non-zero length of C string in @buf
|
|
|
|
* Output:
|
|
|
|
* On success: NFS service is started;
|
|
|
|
* passed-in buffer filled with a '\n'-terminated C
|
|
|
|
* string containing a unique alphanumeric name of
|
|
|
|
* the listener;
|
|
|
|
* return code is the size in bytes of the string
|
|
|
|
* On error: return code is a negative errno value
|
|
|
|
*
|
|
|
|
* OR
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf: C string containing a transport
|
|
|
|
* name and an unsigned integer value
|
|
|
|
* representing the port to listen on,
|
|
|
|
* separated by whitespace
|
|
|
|
* size: non-zero length of C string in @buf
|
|
|
|
* Output:
|
|
|
|
* On success: returns zero; NFS service is started
|
|
|
|
* On error: return code is a negative errno value
|
|
|
|
*/
|
2008-06-10 12:40:35 +00:00
|
|
|
static ssize_t write_ports(struct file *file, char *buf, size_t size)
|
|
|
|
{
|
|
|
|
ssize_t rv;
|
2008-06-10 12:40:36 +00:00
|
|
|
|
2008-06-10 12:40:35 +00:00
|
|
|
mutex_lock(&nfsd_mutex);
|
2014-10-22 00:19:11 +00:00
|
|
|
rv = __write_ports(file, buf, size, netns(file));
|
2008-06-10 12:40:35 +00:00
|
|
|
mutex_unlock(&nfsd_mutex);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-10-04 09:15:48 +00:00
|
|
|
int nfsd_max_blksize;
|
|
|
|
|
2020-04-06 20:01:42 +00:00
|
|
|
/*
|
2008-12-12 21:57:35 +00:00
|
|
|
* write_maxblksize - Set or report the current NFS blksize
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf: ignored
|
|
|
|
* size: zero
|
|
|
|
*
|
|
|
|
* OR
|
|
|
|
*
|
|
|
|
* Input:
|
2023-05-15 13:35:38 +00:00
|
|
|
* buf: C string containing an unsigned
|
|
|
|
* integer value representing the new
|
|
|
|
* NFS blksize
|
2008-12-12 21:57:35 +00:00
|
|
|
* size: non-zero length of C string in @buf
|
|
|
|
* Output:
|
|
|
|
* On success: passed-in buffer filled with '\n'-terminated C string
|
|
|
|
* containing numeric value of the current NFS blksize
|
|
|
|
* setting;
|
|
|
|
* return code is the size in bytes of the string
|
|
|
|
* On error: return code is zero or a negative errno value
|
|
|
|
*/
|
2006-10-04 09:15:48 +00:00
|
|
|
static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
|
|
|
|
{
|
|
|
|
char *mesg = buf;
|
2014-10-22 00:19:11 +00:00
|
|
|
struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
|
2012-12-06 11:23:24 +00:00
|
|
|
|
2006-10-04 09:15:48 +00:00
|
|
|
if (size > 0) {
|
|
|
|
int bsize;
|
|
|
|
int rv = get_int(&mesg, &bsize);
|
|
|
|
if (rv)
|
|
|
|
return rv;
|
2023-05-15 13:35:50 +00:00
|
|
|
trace_nfsd_ctl_maxblksize(netns(file), bsize);
|
|
|
|
|
2006-10-04 09:15:48 +00:00
|
|
|
/* force bsize into allowed range and
|
|
|
|
* required alignment.
|
|
|
|
*/
|
2014-06-10 10:08:19 +00:00
|
|
|
bsize = max_t(int, bsize, 1024);
|
|
|
|
bsize = min_t(int, bsize, NFSSVC_MAXBLKSIZE);
|
2006-10-04 09:15:48 +00:00
|
|
|
bsize &= ~(1024-1);
|
2008-06-10 12:40:35 +00:00
|
|
|
mutex_lock(&nfsd_mutex);
|
2012-12-06 11:23:24 +00:00
|
|
|
if (nn->nfsd_serv) {
|
2008-06-10 12:40:35 +00:00
|
|
|
mutex_unlock(&nfsd_mutex);
|
2006-10-04 09:15:48 +00:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
nfsd_max_blksize = bsize;
|
2008-06-10 12:40:35 +00:00
|
|
|
mutex_unlock(&nfsd_mutex);
|
2006-10-04 09:15:48 +00:00
|
|
|
}
|
2009-04-23 23:33:25 +00:00
|
|
|
|
|
|
|
return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n",
|
|
|
|
nfsd_max_blksize);
|
2006-10-04 09:15:48 +00:00
|
|
|
}
|
|
|
|
|
2020-04-06 20:01:42 +00:00
|
|
|
/*
|
2014-07-02 20:11:22 +00:00
|
|
|
* write_maxconn - Set or report the current max number of connections
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf: ignored
|
|
|
|
* size: zero
|
|
|
|
* OR
|
|
|
|
*
|
|
|
|
* Input:
|
2023-05-15 13:35:38 +00:00
|
|
|
* buf: C string containing an unsigned
|
|
|
|
* integer value representing the new
|
|
|
|
* number of max connections
|
2014-07-02 20:11:22 +00:00
|
|
|
* size: non-zero length of C string in @buf
|
|
|
|
* Output:
|
|
|
|
* On success: passed-in buffer filled with '\n'-terminated C string
|
|
|
|
* containing numeric value of max_connections setting
|
|
|
|
* for this net namespace;
|
|
|
|
* return code is the size in bytes of the string
|
|
|
|
* On error: return code is zero or a negative errno value
|
|
|
|
*/
|
|
|
|
static ssize_t write_maxconn(struct file *file, char *buf, size_t size)
|
|
|
|
{
|
|
|
|
char *mesg = buf;
|
2014-10-22 00:19:11 +00:00
|
|
|
struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
|
2014-07-02 20:11:22 +00:00
|
|
|
unsigned int maxconn = nn->max_connections;
|
|
|
|
|
|
|
|
if (size > 0) {
|
|
|
|
int rv = get_uint(&mesg, &maxconn);
|
|
|
|
|
|
|
|
if (rv)
|
|
|
|
return rv;
|
2023-05-15 13:35:50 +00:00
|
|
|
trace_nfsd_ctl_maxconn(netns(file), maxconn);
|
2014-07-02 20:11:22 +00:00
|
|
|
nn->max_connections = maxconn;
|
|
|
|
}
|
|
|
|
|
|
|
|
return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%u\n", maxconn);
|
|
|
|
}
|
|
|
|
|
2005-11-07 09:00:25 +00:00
|
|
|
#ifdef CONFIG_NFSD_V4
|
2012-12-06 11:23:24 +00:00
|
|
|
static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size,
|
2019-11-04 15:31:52 +00:00
|
|
|
time64_t *time, struct nfsd_net *nn)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2023-05-15 13:35:50 +00:00
|
|
|
struct dentry *dentry = file_dentry(file);
|
2005-04-16 22:20:36 +00:00
|
|
|
char *mesg = buf;
|
2010-03-02 00:32:36 +00:00
|
|
|
int rv, i;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (size > 0) {
|
2012-12-06 11:23:24 +00:00
|
|
|
if (nn->nfsd_serv)
|
2008-06-10 12:40:36 +00:00
|
|
|
return -EBUSY;
|
2010-03-02 00:32:36 +00:00
|
|
|
rv = get_int(&mesg, &i);
|
2005-04-16 22:20:36 +00:00
|
|
|
if (rv)
|
|
|
|
return rv;
|
2023-05-15 13:35:50 +00:00
|
|
|
trace_nfsd_ctl_time(netns(file), dentry->d_name.name,
|
|
|
|
dentry->d_name.len, i);
|
|
|
|
|
2010-03-02 16:18:40 +00:00
|
|
|
/*
|
|
|
|
* Some sanity checking. We don't have a reason for
|
|
|
|
* these particular numbers, but problems with the
|
|
|
|
* extremes are:
|
|
|
|
* - Too short: the briefest network outage may
|
|
|
|
* cause clients to lose all their locks. Also,
|
|
|
|
* the frequent polling may be wasteful.
|
|
|
|
* - Too long: do you really want reboot recovery
|
|
|
|
* to take more than an hour? Or to make other
|
|
|
|
* clients wait an hour before being able to
|
|
|
|
* revoke a dead client's locks?
|
|
|
|
*/
|
2010-03-02 00:32:36 +00:00
|
|
|
if (i < 10 || i > 3600)
|
2005-04-16 22:20:36 +00:00
|
|
|
return -EINVAL;
|
2010-03-02 00:32:36 +00:00
|
|
|
*time = i;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2009-04-23 23:33:25 +00:00
|
|
|
|
2019-11-04 15:31:52 +00:00
|
|
|
return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%lld\n", *time);
|
2010-03-02 00:32:36 +00:00
|
|
|
}
|
|
|
|
|
2012-12-06 11:23:24 +00:00
|
|
|
static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size,
|
2019-11-04 15:31:52 +00:00
|
|
|
time64_t *time, struct nfsd_net *nn)
|
2010-03-02 00:32:36 +00:00
|
|
|
{
|
|
|
|
ssize_t rv;
|
|
|
|
|
|
|
|
mutex_lock(&nfsd_mutex);
|
2012-12-06 11:23:24 +00:00
|
|
|
rv = __nfsd4_write_time(file, buf, size, time, nn);
|
2010-03-02 00:32:36 +00:00
|
|
|
mutex_unlock(&nfsd_mutex);
|
|
|
|
return rv;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2020-04-06 20:01:42 +00:00
|
|
|
/*
|
2008-12-12 21:57:35 +00:00
|
|
|
* write_leasetime - Set or report the current NFSv4 lease time
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf: ignored
|
|
|
|
* size: zero
|
|
|
|
*
|
|
|
|
* OR
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf: C string containing an unsigned
|
|
|
|
* integer value representing the new
|
|
|
|
* NFSv4 lease expiry time
|
|
|
|
* size: non-zero length of C string in @buf
|
|
|
|
* Output:
|
|
|
|
* On success: passed-in buffer filled with '\n'-terminated C
|
|
|
|
* string containing unsigned integer value of the
|
|
|
|
* current lease expiry time;
|
|
|
|
* return code is the size in bytes of the string
|
|
|
|
* On error: return code is zero or a negative errno value
|
|
|
|
*/
|
2008-06-10 12:40:36 +00:00
|
|
|
static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
|
|
|
|
{
|
2014-10-22 00:19:11 +00:00
|
|
|
struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
|
2012-12-06 11:23:24 +00:00
|
|
|
return nfsd4_write_time(file, buf, size, &nn->nfsd4_lease, nn);
|
2008-06-10 12:40:36 +00:00
|
|
|
}
|
|
|
|
|
2020-04-06 20:01:42 +00:00
|
|
|
/*
|
2010-03-02 16:04:06 +00:00
|
|
|
* write_gracetime - Set or report current NFSv4 grace period time
|
|
|
|
*
|
|
|
|
* As above, but sets the time of the NFSv4 grace period.
|
|
|
|
*
|
|
|
|
* Note this should never be set to less than the *previous*
|
|
|
|
* lease-period time, but we don't try to enforce this. (In the common
|
|
|
|
* case (a new boot), we don't know what the previous lease time was
|
|
|
|
* anyway.)
|
|
|
|
*/
|
|
|
|
static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
|
|
|
|
{
|
2014-10-22 00:19:11 +00:00
|
|
|
struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
|
2012-12-06 11:23:24 +00:00
|
|
|
return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace, nn);
|
2010-03-02 16:04:06 +00:00
|
|
|
}
|
|
|
|
|
2023-10-13 13:03:53 +00:00
|
|
|
#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
|
2012-12-06 11:23:24 +00:00
|
|
|
static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size,
|
|
|
|
struct nfsd_net *nn)
|
2005-06-24 05:04:32 +00:00
|
|
|
{
|
|
|
|
char *mesg = buf;
|
|
|
|
char *recdir;
|
|
|
|
int len, status;
|
|
|
|
|
2008-06-10 12:40:36 +00:00
|
|
|
if (size > 0) {
|
2012-12-06 11:23:24 +00:00
|
|
|
if (nn->nfsd_serv)
|
2008-06-10 12:40:36 +00:00
|
|
|
return -EBUSY;
|
|
|
|
if (size > PATH_MAX || buf[size-1] != '\n')
|
|
|
|
return -EINVAL;
|
|
|
|
buf[size-1] = 0;
|
2005-06-24 05:04:32 +00:00
|
|
|
|
2008-06-10 12:40:36 +00:00
|
|
|
recdir = mesg;
|
|
|
|
len = qword_get(&mesg, recdir, size);
|
|
|
|
if (len <= 0)
|
|
|
|
return -EINVAL;
|
2023-05-15 13:35:50 +00:00
|
|
|
trace_nfsd_ctl_recoverydir(netns(file), recdir);
|
2005-06-24 05:04:32 +00:00
|
|
|
|
2008-06-10 12:40:36 +00:00
|
|
|
status = nfs4_reset_recoverydir(recdir);
|
2010-07-20 22:24:27 +00:00
|
|
|
if (status)
|
|
|
|
return status;
|
2008-06-10 12:40:36 +00:00
|
|
|
}
|
2009-04-23 23:33:10 +00:00
|
|
|
|
|
|
|
return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
|
|
|
|
nfs4_recoverydir());
|
2005-06-24 05:04:32 +00:00
|
|
|
}
|
2008-06-10 12:40:36 +00:00
|
|
|
|
2020-04-06 20:01:42 +00:00
|
|
|
/*
|
2008-12-12 21:57:35 +00:00
|
|
|
* write_recoverydir - Set or report the pathname of the recovery directory
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf: ignored
|
|
|
|
* size: zero
|
|
|
|
*
|
|
|
|
* OR
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf: C string containing the pathname
|
|
|
|
* of the directory on a local file
|
|
|
|
* system containing permanent NFSv4
|
|
|
|
* recovery data
|
|
|
|
* size: non-zero length of C string in @buf
|
|
|
|
* Output:
|
|
|
|
* On success: passed-in buffer filled with '\n'-terminated C string
|
|
|
|
* containing the current recovery pathname setting;
|
|
|
|
* return code is the size in bytes of the string
|
|
|
|
* On error: return code is zero or a negative errno value
|
|
|
|
*/
|
2008-06-10 12:40:36 +00:00
|
|
|
static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
|
|
|
|
{
|
|
|
|
ssize_t rv;
|
2014-10-22 00:19:11 +00:00
|
|
|
struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
|
2008-06-10 12:40:36 +00:00
|
|
|
|
|
|
|
mutex_lock(&nfsd_mutex);
|
2012-12-06 11:23:24 +00:00
|
|
|
rv = __write_recoverydir(file, buf, size, nn);
|
2008-06-10 12:40:36 +00:00
|
|
|
mutex_unlock(&nfsd_mutex);
|
|
|
|
return rv;
|
|
|
|
}
|
2023-10-13 13:03:53 +00:00
|
|
|
#endif
|
2008-06-10 12:40:36 +00:00
|
|
|
|
2020-04-06 20:01:42 +00:00
|
|
|
/*
|
2014-09-12 20:40:21 +00:00
|
|
|
* write_v4_end_grace - release grace period for nfsd's v4.x lock manager
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* buf: ignored
|
|
|
|
* size: zero
|
|
|
|
* OR
|
|
|
|
*
|
|
|
|
* Input:
|
2023-05-15 13:35:38 +00:00
|
|
|
* buf: any value
|
2014-09-12 20:40:21 +00:00
|
|
|
* size: non-zero length of C string in @buf
|
|
|
|
* Output:
|
|
|
|
* passed-in buffer filled with "Y" or "N" with a newline
|
|
|
|
* and NULL-terminated C string. This indicates whether
|
|
|
|
* the grace period has ended in the current net
|
|
|
|
* namespace. Return code is the size in bytes of the
|
|
|
|
* string. Writing a string that starts with 'Y', 'y', or
|
|
|
|
* '1' to the file will end the grace period for nfsd's v4
|
|
|
|
* lock manager.
|
|
|
|
*/
|
|
|
|
static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size)
|
|
|
|
{
|
2014-10-22 00:19:11 +00:00
|
|
|
struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
|
2014-09-12 20:40:21 +00:00
|
|
|
|
|
|
|
if (size > 0) {
|
|
|
|
switch(buf[0]) {
|
|
|
|
case 'Y':
|
|
|
|
case 'y':
|
|
|
|
case '1':
|
2019-03-06 13:03:50 +00:00
|
|
|
if (!nn->nfsd_serv)
|
2018-11-27 20:54:17 +00:00
|
|
|
return -EBUSY;
|
2023-05-15 13:35:50 +00:00
|
|
|
trace_nfsd_end_grace(netns(file));
|
2023-08-24 14:30:27 +00:00
|
|
|
nfsd4_end_grace(nn);
|
2014-09-12 20:40:21 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%c\n",
|
|
|
|
nn->grace_ended ? 'Y' : 'N');
|
|
|
|
}
|
|
|
|
|
2005-11-07 09:00:25 +00:00
|
|
|
#endif
|
2005-06-24 05:04:32 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
|
|
* populating the filesystem.
|
|
|
|
*/
|
|
|
|
|
2019-03-22 15:11:06 +00:00
|
|
|
/* Basically copying rpc_get_inode. */
|
|
|
|
static struct inode *nfsd_get_inode(struct super_block *sb, umode_t mode)
|
|
|
|
{
|
|
|
|
struct inode *inode = new_inode(sb);
|
|
|
|
if (!inode)
|
|
|
|
return NULL;
|
|
|
|
/* Following advice from simple_fill_super documentation: */
|
|
|
|
inode->i_ino = iunique(sb, NFSD_MaxReserved);
|
|
|
|
inode->i_mode = mode;
|
2023-10-04 18:52:37 +00:00
|
|
|
simple_inode_init_ts(inode);
|
2019-03-22 15:11:06 +00:00
|
|
|
switch (mode & S_IFMT) {
|
|
|
|
case S_IFDIR:
|
|
|
|
inode->i_fop = &simple_dir_operations;
|
|
|
|
inode->i_op = &simple_dir_inode_operations;
|
|
|
|
inc_nlink(inode);
|
2020-11-20 18:26:40 +00:00
|
|
|
break;
|
2023-01-15 17:21:39 +00:00
|
|
|
case S_IFLNK:
|
|
|
|
inode->i_op = &simple_symlink_inode_operations;
|
|
|
|
break;
|
2019-03-22 15:11:06 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return inode;
|
|
|
|
}
|
|
|
|
|
2019-08-15 20:18:26 +00:00
|
|
|
static int __nfsd_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode, struct nfsdfs_client *ncl)
|
2019-03-22 15:11:06 +00:00
|
|
|
{
|
|
|
|
struct inode *inode;
|
|
|
|
|
|
|
|
inode = nfsd_get_inode(dir->i_sb, mode);
|
|
|
|
if (!inode)
|
|
|
|
return -ENOMEM;
|
2019-08-15 20:18:26 +00:00
|
|
|
if (ncl) {
|
|
|
|
inode->i_private = ncl;
|
|
|
|
kref_get(&ncl->cl_ref);
|
|
|
|
}
|
2019-03-22 15:11:06 +00:00
|
|
|
d_add(dentry, inode);
|
|
|
|
inc_nlink(dir);
|
|
|
|
fsnotify_mkdir(dir, dentry);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct dentry *nfsd_mkdir(struct dentry *parent, struct nfsdfs_client *ncl, char *name)
|
|
|
|
{
|
|
|
|
struct inode *dir = parent->d_inode;
|
|
|
|
struct dentry *dentry;
|
|
|
|
int ret = -ENOMEM;
|
|
|
|
|
|
|
|
inode_lock(dir);
|
|
|
|
dentry = d_alloc_name(parent, name);
|
|
|
|
if (!dentry)
|
|
|
|
goto out_err;
|
2019-08-15 20:18:26 +00:00
|
|
|
ret = __nfsd_mkdir(d_inode(parent), dentry, S_IFDIR | 0600, ncl);
|
2019-03-22 15:11:06 +00:00
|
|
|
if (ret)
|
|
|
|
goto out_err;
|
|
|
|
out:
|
|
|
|
inode_unlock(dir);
|
|
|
|
return dentry;
|
|
|
|
out_err:
|
2019-08-12 02:16:11 +00:00
|
|
|
dput(dentry);
|
2019-03-22 15:11:06 +00:00
|
|
|
dentry = ERR_PTR(ret);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2023-01-15 17:21:39 +00:00
|
|
|
#if IS_ENABLED(CONFIG_SUNRPC_GSS)
|
|
|
|
static int __nfsd_symlink(struct inode *dir, struct dentry *dentry,
|
|
|
|
umode_t mode, const char *content)
|
|
|
|
{
|
|
|
|
struct inode *inode;
|
|
|
|
|
|
|
|
inode = nfsd_get_inode(dir->i_sb, mode);
|
|
|
|
if (!inode)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
inode->i_link = (char *)content;
|
|
|
|
inode->i_size = strlen(content);
|
|
|
|
|
|
|
|
d_add(dentry, inode);
|
|
|
|
inc_nlink(dir);
|
|
|
|
fsnotify_create(dir, dentry);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @content is assumed to be a NUL-terminated string that lives
|
|
|
|
* longer than the symlink itself.
|
|
|
|
*/
|
2023-05-15 13:35:50 +00:00
|
|
|
static void _nfsd_symlink(struct dentry *parent, const char *name,
|
|
|
|
const char *content)
|
2023-01-15 17:21:39 +00:00
|
|
|
{
|
|
|
|
struct inode *dir = parent->d_inode;
|
|
|
|
struct dentry *dentry;
|
2023-02-14 15:19:30 +00:00
|
|
|
int ret;
|
2023-01-15 17:21:39 +00:00
|
|
|
|
|
|
|
inode_lock(dir);
|
|
|
|
dentry = d_alloc_name(parent, name);
|
|
|
|
if (!dentry)
|
2023-02-14 15:19:30 +00:00
|
|
|
goto out;
|
2023-01-15 17:21:39 +00:00
|
|
|
ret = __nfsd_symlink(d_inode(parent), dentry, S_IFLNK | 0777, content);
|
|
|
|
if (ret)
|
2023-02-14 15:19:30 +00:00
|
|
|
dput(dentry);
|
2023-01-15 17:21:39 +00:00
|
|
|
out:
|
|
|
|
inode_unlock(dir);
|
|
|
|
}
|
|
|
|
#else
|
2023-05-15 13:35:50 +00:00
|
|
|
static inline void _nfsd_symlink(struct dentry *parent, const char *name,
|
|
|
|
const char *content)
|
2023-01-15 17:21:39 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2023-11-03 18:35:16 +00:00
|
|
|
static void clear_ncl(struct dentry *dentry)
|
2019-04-09 19:56:57 +00:00
|
|
|
{
|
2023-11-03 18:35:16 +00:00
|
|
|
struct inode *inode = d_inode(dentry);
|
2019-04-09 19:56:57 +00:00
|
|
|
struct nfsdfs_client *ncl = inode->i_private;
|
|
|
|
|
2023-11-03 18:35:16 +00:00
|
|
|
spin_lock(&inode->i_lock);
|
2019-04-09 19:56:57 +00:00
|
|
|
inode->i_private = NULL;
|
2023-11-03 18:35:16 +00:00
|
|
|
spin_unlock(&inode->i_lock);
|
2019-04-09 19:56:57 +00:00
|
|
|
kref_put(&ncl->cl_ref, ncl->cl_release);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct nfsdfs_client *get_nfsdfs_client(struct inode *inode)
|
|
|
|
{
|
|
|
|
struct nfsdfs_client *nc;
|
|
|
|
|
2023-11-03 18:35:16 +00:00
|
|
|
spin_lock(&inode->i_lock);
|
|
|
|
nc = inode->i_private;
|
|
|
|
if (nc)
|
|
|
|
kref_get(&nc->cl_ref);
|
|
|
|
spin_unlock(&inode->i_lock);
|
2019-04-09 19:56:57 +00:00
|
|
|
return nc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: cut'n'paste from simple_fill_super; figure out if we could share
|
|
|
|
* code instead. */
|
|
|
|
static int nfsdfs_create_files(struct dentry *root,
|
2021-03-19 22:38:04 +00:00
|
|
|
const struct tree_descr *files,
|
2023-11-03 18:35:16 +00:00
|
|
|
struct nfsdfs_client *ncl,
|
2021-03-19 22:38:04 +00:00
|
|
|
struct dentry **fdentries)
|
2019-04-09 19:56:57 +00:00
|
|
|
{
|
|
|
|
struct inode *dir = d_inode(root);
|
|
|
|
struct inode *inode;
|
|
|
|
struct dentry *dentry;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
inode_lock(dir);
|
|
|
|
for (i = 0; files->name && files->name[0]; i++, files++) {
|
|
|
|
dentry = d_alloc_name(root, files->name);
|
|
|
|
if (!dentry)
|
|
|
|
goto out;
|
|
|
|
inode = nfsd_get_inode(d_inode(root)->i_sb,
|
|
|
|
S_IFREG | files->mode);
|
|
|
|
if (!inode) {
|
|
|
|
dput(dentry);
|
|
|
|
goto out;
|
|
|
|
}
|
2023-11-03 18:35:16 +00:00
|
|
|
kref_get(&ncl->cl_ref);
|
2019-04-09 19:56:57 +00:00
|
|
|
inode->i_fop = files->ops;
|
2023-11-03 18:35:16 +00:00
|
|
|
inode->i_private = ncl;
|
2019-04-09 19:56:57 +00:00
|
|
|
d_add(dentry, inode);
|
|
|
|
fsnotify_create(dir, dentry);
|
2021-03-19 22:38:04 +00:00
|
|
|
if (fdentries)
|
|
|
|
fdentries[i] = dentry;
|
2019-04-09 19:56:57 +00:00
|
|
|
}
|
|
|
|
inode_unlock(dir);
|
|
|
|
return 0;
|
|
|
|
out:
|
|
|
|
inode_unlock(dir);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2019-03-22 15:11:06 +00:00
|
|
|
/* on success, returns positive number unique to that client. */
|
2019-04-09 19:56:57 +00:00
|
|
|
struct dentry *nfsd_client_mkdir(struct nfsd_net *nn,
|
2021-03-19 22:38:04 +00:00
|
|
|
struct nfsdfs_client *ncl, u32 id,
|
|
|
|
const struct tree_descr *files,
|
|
|
|
struct dentry **fdentries)
|
2019-03-22 15:11:06 +00:00
|
|
|
{
|
2019-04-09 19:56:57 +00:00
|
|
|
struct dentry *dentry;
|
2019-03-22 15:11:06 +00:00
|
|
|
char name[11];
|
2019-04-09 19:56:57 +00:00
|
|
|
int ret;
|
2019-03-22 15:11:06 +00:00
|
|
|
|
2019-03-14 20:20:19 +00:00
|
|
|
sprintf(name, "%u", id);
|
2019-03-22 15:11:06 +00:00
|
|
|
|
2019-04-09 19:56:57 +00:00
|
|
|
dentry = nfsd_mkdir(nn->nfsd_client_dir, ncl, name);
|
|
|
|
if (IS_ERR(dentry)) /* XXX: tossing errors? */
|
|
|
|
return NULL;
|
2023-11-03 18:35:16 +00:00
|
|
|
ret = nfsdfs_create_files(dentry, files, ncl, fdentries);
|
2019-04-09 19:56:57 +00:00
|
|
|
if (ret) {
|
|
|
|
nfsd_client_rmdir(dentry);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return dentry;
|
2019-03-22 15:11:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Taken from __rpc_rmdir: */
|
|
|
|
void nfsd_client_rmdir(struct dentry *dentry)
|
|
|
|
{
|
2023-11-03 18:35:16 +00:00
|
|
|
simple_recursive_removal(dentry, clear_ncl);
|
2019-03-22 15:11:06 +00:00
|
|
|
}
|
|
|
|
|
2019-03-25 16:38:27 +00:00
|
|
|
static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2019-03-22 15:11:06 +00:00
|
|
|
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
|
|
|
nfsd_net_id);
|
|
|
|
struct dentry *dentry;
|
|
|
|
int ret;
|
|
|
|
|
2017-03-26 04:15:37 +00:00
|
|
|
static const struct tree_descr nfsd_files[] = {
|
2013-02-01 12:56:17 +00:00
|
|
|
[NFSD_List] = {"exports", &exports_nfsd_operations, S_IRUGO},
|
2021-01-06 07:52:36 +00:00
|
|
|
/* Per-export io stats use same ops as exports file */
|
|
|
|
[NFSD_Export_Stats] = {"export_stats", &exports_nfsd_operations, S_IRUGO},
|
2009-12-14 17:53:32 +00:00
|
|
|
[NFSD_Export_features] = {"export_features",
|
2022-09-22 16:31:53 +00:00
|
|
|
&export_features_fops, S_IRUGO},
|
lockd: unlock lockd locks associated with a given server ip
For high-availability NFS service, we generally need to be able to drop
file locks held on the exported filesystem before moving clients to a
new server. Currently the only way to do that is by shutting down lockd
entirely, which is often undesireable (for example, if you want to
continue exporting other filesystems).
This patch allows the administrator to release all locks held by clients
accessing the client through a given server ip address, by echoing that
address to a new file, /proc/fs/nfsd/unlock_ip, as in:
shell> echo 10.1.1.2 > /proc/fs/nfsd/unlock_ip
The expected sequence of events can be:
1. Tear down the IP address
2. Unexport the path
3. Write IP to /proc/fs/nfsd/unlock_ip to unlock files
4. Signal peer to begin take-over.
For now we only support IPv4 addresses and NFSv2/v3 (NFSv4 locks are not
affected).
Also, if unmounting the filesystem is required, we assume at step 3 that
clients using the given server ip are the only clients holding locks on
the given filesystem; otherwise, an additional patch is required to
allow revoking all locks held by lockd on a given filesystem.
Signed-off-by: S. Wendy Cheng <wcheng@redhat.com>
Cc: Lon Hohberger <lhh@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
fs/lockd/svcsubs.c | 66 +++++++++++++++++++++++++++++++++++++++-----
fs/nfsd/nfsctl.c | 65 +++++++++++++++++++++++++++++++++++++++++++
include/linux/lockd/lockd.h | 7 ++++
3 files changed, 131 insertions(+), 7 deletions(-)
2008-01-17 16:10:12 +00:00
|
|
|
[NFSD_FO_UnlockIP] = {"unlock_ip",
|
|
|
|
&transaction_ops, S_IWUSR|S_IRUSR},
|
2008-01-17 16:10:12 +00:00
|
|
|
[NFSD_FO_UnlockFS] = {"unlock_filesystem",
|
|
|
|
&transaction_ops, S_IWUSR|S_IRUSR},
|
2005-04-16 22:20:36 +00:00
|
|
|
[NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
|
|
|
|
[NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
|
2006-10-02 09:18:02 +00:00
|
|
|
[NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
|
2009-01-13 10:26:36 +00:00
|
|
|
[NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO},
|
2022-09-22 16:31:55 +00:00
|
|
|
[NFSD_Reply_Cache_Stats] = {"reply_cache_stats",
|
|
|
|
&nfsd_reply_cache_stats_fops, S_IRUGO},
|
2005-11-07 09:00:25 +00:00
|
|
|
[NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
|
2006-10-02 09:17:47 +00:00
|
|
|
[NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
|
2006-10-04 09:15:48 +00:00
|
|
|
[NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
|
2014-07-02 20:11:22 +00:00
|
|
|
[NFSD_MaxConnections] = {"max_connections", &transaction_ops, S_IWUSR|S_IRUGO},
|
2022-09-22 16:31:56 +00:00
|
|
|
[NFSD_Filecache] = {"filecache", &nfsd_file_cache_stats_fops, S_IRUGO},
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef CONFIG_NFSD_V4
|
|
|
|
[NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
|
2010-03-02 16:04:06 +00:00
|
|
|
[NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR},
|
2024-04-16 21:23:02 +00:00
|
|
|
#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
|
2005-06-24 05:04:32 +00:00
|
|
|
[NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
|
2024-04-16 21:23:02 +00:00
|
|
|
#endif
|
2014-09-12 20:40:21 +00:00
|
|
|
[NFSD_V4EndGrace] = {"v4_end_grace", &transaction_ops, S_IWUSR|S_IRUGO},
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif
|
|
|
|
/* last one */ {""}
|
|
|
|
};
|
2019-03-25 16:38:27 +00:00
|
|
|
|
2019-03-22 15:11:06 +00:00
|
|
|
ret = simple_fill_super(sb, 0x6e667364, nfsd_files);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2023-05-15 13:35:50 +00:00
|
|
|
_nfsd_symlink(sb->s_root, "supported_krb5_enctypes",
|
|
|
|
"/proc/net/rpc/gss_krb5_enctypes");
|
2019-03-22 15:11:06 +00:00
|
|
|
dentry = nfsd_mkdir(sb->s_root, NULL, "clients");
|
|
|
|
if (IS_ERR(dentry))
|
|
|
|
return PTR_ERR(dentry);
|
|
|
|
nn->nfsd_client_dir = dentry;
|
|
|
|
return 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2019-03-22 15:11:06 +00:00
|
|
|
|
2019-03-25 16:38:27 +00:00
|
|
|
static int nfsd_fs_get_tree(struct fs_context *fc)
|
|
|
|
{
|
2019-09-03 23:05:48 +00:00
|
|
|
return get_tree_keyed(fc, nfsd_fill_super, get_net(fc->net_ns));
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2019-03-25 16:38:27 +00:00
|
|
|
static void nfsd_fs_free_fc(struct fs_context *fc)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2019-03-25 16:38:27 +00:00
|
|
|
if (fc->s_fs_info)
|
|
|
|
put_net(fc->s_fs_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct fs_context_operations nfsd_fs_context_ops = {
|
|
|
|
.free = nfsd_fs_free_fc,
|
|
|
|
.get_tree = nfsd_fs_get_tree,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int nfsd_init_fs_context(struct fs_context *fc)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2019-03-25 16:38:27 +00:00
|
|
|
put_user_ns(fc->user_ns);
|
|
|
|
fc->user_ns = get_user_ns(fc->net_ns->user_ns);
|
|
|
|
fc->ops = &nfsd_fs_context_ops;
|
|
|
|
return 0;
|
2013-02-01 12:56:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void nfsd_umount(struct super_block *sb)
|
|
|
|
{
|
|
|
|
struct net *net = sb->s_fs_info;
|
|
|
|
|
2021-03-13 21:08:47 +00:00
|
|
|
nfsd_shutdown_threads(net);
|
|
|
|
|
2013-02-01 12:56:12 +00:00
|
|
|
kill_litter_super(sb);
|
|
|
|
put_net(net);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct file_system_type nfsd_fs_type = {
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.name = "nfsd",
|
2019-03-25 16:38:27 +00:00
|
|
|
.init_fs_context = nfsd_init_fs_context,
|
2013-02-01 12:56:12 +00:00
|
|
|
.kill_sb = nfsd_umount,
|
2005-04-16 22:20:36 +00:00
|
|
|
};
|
2013-03-03 03:39:14 +00:00
|
|
|
MODULE_ALIAS_FS("nfsd");
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-11-12 22:32:21 +00:00
|
|
|
#ifdef CONFIG_PROC_FS
|
2023-05-02 17:11:21 +00:00
|
|
|
|
|
|
|
static int exports_proc_open(struct inode *inode, struct file *file)
|
|
|
|
{
|
|
|
|
return exports_net_open(current->nsproxy->net_ns, file);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct proc_ops exports_proc_ops = {
|
|
|
|
.proc_open = exports_proc_open,
|
|
|
|
.proc_read = seq_read,
|
|
|
|
.proc_lseek = seq_lseek,
|
|
|
|
.proc_release = seq_release,
|
|
|
|
};
|
|
|
|
|
2007-11-12 22:32:21 +00:00
|
|
|
static int create_proc_exports_entry(void)
|
|
|
|
{
|
|
|
|
struct proc_dir_entry *entry;
|
|
|
|
|
|
|
|
entry = proc_mkdir("fs/nfs", NULL);
|
|
|
|
if (!entry)
|
|
|
|
return -ENOMEM;
|
2020-02-04 01:37:17 +00:00
|
|
|
entry = proc_create("exports", 0, entry, &exports_proc_ops);
|
2013-03-27 08:31:18 +00:00
|
|
|
if (!entry) {
|
|
|
|
remove_proc_entry("fs/nfs", NULL);
|
2007-11-12 22:32:21 +00:00
|
|
|
return -ENOMEM;
|
2013-03-27 08:31:18 +00:00
|
|
|
}
|
2007-11-12 22:32:21 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#else /* CONFIG_PROC_FS */
|
|
|
|
static int create_proc_exports_entry(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
netns: make struct pernet_operations::id unsigned int
Make struct pernet_operations::id unsigned.
There are 2 reasons to do so:
1)
This field is really an index into an zero based array and
thus is unsigned entity. Using negative value is out-of-bound
access by definition.
2)
On x86_64 unsigned 32-bit data which are mixed with pointers
via array indexing or offsets added or subtracted to pointers
are preffered to signed 32-bit data.
"int" being used as an array index needs to be sign-extended
to 64-bit before being used.
void f(long *p, int i)
{
g(p[i]);
}
roughly translates to
movsx rsi, esi
mov rdi, [rsi+...]
call g
MOVSX is 3 byte instruction which isn't necessary if the variable is
unsigned because x86_64 is zero extending by default.
Now, there is net_generic() function which, you guessed it right, uses
"int" as an array index:
static inline void *net_generic(const struct net *net, int id)
{
...
ptr = ng->ptr[id - 1];
...
}
And this function is used a lot, so those sign extensions add up.
Patch snipes ~1730 bytes on allyesconfig kernel (without all junk
messing with code generation):
add/remove: 0/0 grow/shrink: 70/598 up/down: 396/-2126 (-1730)
Unfortunately some functions actually grow bigger.
This is a semmingly random artefact of code generation with register
allocator being used differently. gcc decides that some variable
needs to live in new r8+ registers and every access now requires REX
prefix. Or it is shifted into r12, so [r12+0] addressing mode has to be
used which is longer than [r8]
However, overall balance is in negative direction:
add/remove: 0/0 grow/shrink: 70/598 up/down: 396/-2126 (-1730)
function old new delta
nfsd4_lock 3886 3959 +73
tipc_link_build_proto_msg 1096 1140 +44
mac80211_hwsim_new_radio 2776 2808 +32
tipc_mon_rcv 1032 1058 +26
svcauth_gss_legacy_init 1413 1429 +16
tipc_bcbase_select_primary 379 392 +13
nfsd4_exchange_id 1247 1260 +13
nfsd4_setclientid_confirm 782 793 +11
...
put_client_renew_locked 494 480 -14
ip_set_sockfn_get 730 716 -14
geneve_sock_add 829 813 -16
nfsd4_sequence_done 721 703 -18
nlmclnt_lookup_host 708 686 -22
nfsd4_lockt 1085 1063 -22
nfs_get_client 1077 1050 -27
tcf_bpf_init 1106 1076 -30
nfsd4_encode_fattr 5997 5930 -67
Total: Before=154856051, After=154854321, chg -0.00%
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-11-17 01:58:21 +00:00
|
|
|
unsigned int nfsd_net_id;
|
2012-04-11 11:13:35 +00:00
|
|
|
|
2023-09-11 12:49:46 +00:00
|
|
|
static int nfsd_genl_rpc_status_compose_msg(struct sk_buff *skb,
|
|
|
|
struct netlink_callback *cb,
|
|
|
|
struct nfsd_genl_rqstp *rqstp)
|
|
|
|
{
|
|
|
|
void *hdr;
|
|
|
|
u32 i;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
|
|
|
|
&nfsd_nl_family, 0, NFSD_CMD_RPC_STATUS_GET);
|
|
|
|
if (!hdr)
|
|
|
|
return -ENOBUFS;
|
|
|
|
|
|
|
|
if (nla_put_be32(skb, NFSD_A_RPC_STATUS_XID, rqstp->rq_xid) ||
|
|
|
|
nla_put_u32(skb, NFSD_A_RPC_STATUS_FLAGS, rqstp->rq_flags) ||
|
|
|
|
nla_put_u32(skb, NFSD_A_RPC_STATUS_PROG, rqstp->rq_prog) ||
|
|
|
|
nla_put_u32(skb, NFSD_A_RPC_STATUS_PROC, rqstp->rq_proc) ||
|
|
|
|
nla_put_u8(skb, NFSD_A_RPC_STATUS_VERSION, rqstp->rq_vers) ||
|
|
|
|
nla_put_s64(skb, NFSD_A_RPC_STATUS_SERVICE_TIME,
|
|
|
|
ktime_to_us(rqstp->rq_stime),
|
|
|
|
NFSD_A_RPC_STATUS_PAD))
|
|
|
|
return -ENOBUFS;
|
|
|
|
|
|
|
|
switch (rqstp->rq_saddr.sa_family) {
|
|
|
|
case AF_INET: {
|
|
|
|
const struct sockaddr_in *s_in, *d_in;
|
|
|
|
|
|
|
|
s_in = (const struct sockaddr_in *)&rqstp->rq_saddr;
|
|
|
|
d_in = (const struct sockaddr_in *)&rqstp->rq_daddr;
|
|
|
|
if (nla_put_in_addr(skb, NFSD_A_RPC_STATUS_SADDR4,
|
|
|
|
s_in->sin_addr.s_addr) ||
|
|
|
|
nla_put_in_addr(skb, NFSD_A_RPC_STATUS_DADDR4,
|
|
|
|
d_in->sin_addr.s_addr) ||
|
|
|
|
nla_put_be16(skb, NFSD_A_RPC_STATUS_SPORT,
|
|
|
|
s_in->sin_port) ||
|
|
|
|
nla_put_be16(skb, NFSD_A_RPC_STATUS_DPORT,
|
|
|
|
d_in->sin_port))
|
|
|
|
return -ENOBUFS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case AF_INET6: {
|
|
|
|
const struct sockaddr_in6 *s_in, *d_in;
|
|
|
|
|
|
|
|
s_in = (const struct sockaddr_in6 *)&rqstp->rq_saddr;
|
|
|
|
d_in = (const struct sockaddr_in6 *)&rqstp->rq_daddr;
|
|
|
|
if (nla_put_in6_addr(skb, NFSD_A_RPC_STATUS_SADDR6,
|
|
|
|
&s_in->sin6_addr) ||
|
|
|
|
nla_put_in6_addr(skb, NFSD_A_RPC_STATUS_DADDR6,
|
|
|
|
&d_in->sin6_addr) ||
|
|
|
|
nla_put_be16(skb, NFSD_A_RPC_STATUS_SPORT,
|
|
|
|
s_in->sin6_port) ||
|
|
|
|
nla_put_be16(skb, NFSD_A_RPC_STATUS_DPORT,
|
|
|
|
d_in->sin6_port))
|
|
|
|
return -ENOBUFS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < rqstp->rq_opcnt; i++)
|
|
|
|
if (nla_put_u32(skb, NFSD_A_RPC_STATUS_COMPOUND_OPS,
|
|
|
|
rqstp->rq_opnum[i]))
|
|
|
|
return -ENOBUFS;
|
|
|
|
|
|
|
|
genlmsg_end(skb, hdr);
|
2023-09-11 12:49:44 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-09-11 12:49:46 +00:00
|
|
|
/**
|
|
|
|
* nfsd_nl_rpc_status_get_dumpit - Handle rpc_status_get dumpit
|
|
|
|
* @skb: reply buffer
|
|
|
|
* @cb: netlink metadata and command arguments
|
|
|
|
*
|
|
|
|
* Returns the size of the reply or a negative errno.
|
|
|
|
*/
|
2023-09-11 12:49:44 +00:00
|
|
|
int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb,
|
|
|
|
struct netlink_callback *cb)
|
|
|
|
{
|
2023-09-11 12:49:46 +00:00
|
|
|
int i, ret, rqstp_index = 0;
|
2024-06-17 14:26:26 +00:00
|
|
|
struct nfsd_net *nn;
|
|
|
|
|
|
|
|
mutex_lock(&nfsd_mutex);
|
|
|
|
|
|
|
|
nn = net_generic(sock_net(skb->sk), nfsd_net_id);
|
|
|
|
if (!nn->nfsd_serv) {
|
|
|
|
ret = -ENODEV;
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
2023-09-11 12:49:46 +00:00
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
|
|
|
for (i = 0; i < nn->nfsd_serv->sv_nrpools; i++) {
|
|
|
|
struct svc_rqst *rqstp;
|
|
|
|
|
|
|
|
if (i < cb->args[0]) /* already consumed */
|
|
|
|
continue;
|
|
|
|
|
|
|
|
rqstp_index = 0;
|
|
|
|
list_for_each_entry_rcu(rqstp,
|
|
|
|
&nn->nfsd_serv->sv_pools[i].sp_all_threads,
|
|
|
|
rq_all) {
|
|
|
|
struct nfsd_genl_rqstp genl_rqstp;
|
|
|
|
unsigned int status_counter;
|
|
|
|
|
|
|
|
if (rqstp_index++ < cb->args[1]) /* already consumed */
|
|
|
|
continue;
|
|
|
|
/*
|
|
|
|
* Acquire rq_status_counter before parsing the rqst
|
|
|
|
* fields. rq_status_counter is set to an odd value in
|
|
|
|
* order to notify the consumers the rqstp fields are
|
|
|
|
* meaningful.
|
|
|
|
*/
|
|
|
|
status_counter =
|
|
|
|
smp_load_acquire(&rqstp->rq_status_counter);
|
|
|
|
if (!(status_counter & 1))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
genl_rqstp.rq_xid = rqstp->rq_xid;
|
|
|
|
genl_rqstp.rq_flags = rqstp->rq_flags;
|
|
|
|
genl_rqstp.rq_vers = rqstp->rq_vers;
|
|
|
|
genl_rqstp.rq_prog = rqstp->rq_prog;
|
|
|
|
genl_rqstp.rq_proc = rqstp->rq_proc;
|
|
|
|
genl_rqstp.rq_stime = rqstp->rq_stime;
|
|
|
|
genl_rqstp.rq_opcnt = 0;
|
|
|
|
memcpy(&genl_rqstp.rq_daddr, svc_daddr(rqstp),
|
|
|
|
sizeof(struct sockaddr));
|
|
|
|
memcpy(&genl_rqstp.rq_saddr, svc_addr(rqstp),
|
|
|
|
sizeof(struct sockaddr));
|
|
|
|
|
|
|
|
#ifdef CONFIG_NFSD_V4
|
|
|
|
if (rqstp->rq_vers == NFS4_VERSION &&
|
|
|
|
rqstp->rq_proc == NFSPROC4_COMPOUND) {
|
|
|
|
/* NFSv4 compound */
|
|
|
|
struct nfsd4_compoundargs *args;
|
|
|
|
int j;
|
|
|
|
|
|
|
|
args = rqstp->rq_argp;
|
|
|
|
genl_rqstp.rq_opcnt = args->opcnt;
|
|
|
|
for (j = 0; j < genl_rqstp.rq_opcnt; j++)
|
|
|
|
genl_rqstp.rq_opnum[j] =
|
|
|
|
args->ops[j].opnum;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NFSD_V4 */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Acquire rq_status_counter before reporting the rqst
|
|
|
|
* fields to the user.
|
|
|
|
*/
|
|
|
|
if (smp_load_acquire(&rqstp->rq_status_counter) !=
|
|
|
|
status_counter)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ret = nfsd_genl_rpc_status_compose_msg(skb, cb,
|
|
|
|
&genl_rqstp);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cb->args[0] = i;
|
|
|
|
cb->args[1] = rqstp_index;
|
|
|
|
ret = skb->len;
|
|
|
|
out:
|
|
|
|
rcu_read_unlock();
|
2024-06-17 14:26:26 +00:00
|
|
|
out_unlock:
|
2023-09-11 12:49:46 +00:00
|
|
|
mutex_unlock(&nfsd_mutex);
|
|
|
|
|
2024-06-17 14:26:26 +00:00
|
|
|
return ret;
|
2023-09-11 12:49:44 +00:00
|
|
|
}
|
|
|
|
|
2024-04-23 13:25:40 +00:00
|
|
|
/**
|
|
|
|
* nfsd_nl_threads_set_doit - set the number of running threads
|
|
|
|
* @skb: reply buffer
|
|
|
|
* @info: netlink metadata and command arguments
|
|
|
|
*
|
|
|
|
* Return 0 on success or a negative errno.
|
|
|
|
*/
|
|
|
|
int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
2024-06-13 18:34:32 +00:00
|
|
|
int *nthreads, count = 0, nrpools, i, ret = -EOPNOTSUPP, rem;
|
2024-04-23 13:25:40 +00:00
|
|
|
struct net *net = genl_info_net(info);
|
|
|
|
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
|
|
|
const struct nlattr *attr;
|
|
|
|
const char *scope = NULL;
|
|
|
|
|
|
|
|
if (GENL_REQ_ATTR_CHECK(info, NFSD_A_SERVER_THREADS))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* count number of SERVER_THREADS values */
|
|
|
|
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
|
|
|
|
if (nla_type(attr) == NFSD_A_SERVER_THREADS)
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_lock(&nfsd_mutex);
|
|
|
|
|
2024-06-13 18:34:32 +00:00
|
|
|
nrpools = max(count, nfsd_nrpools(net));
|
|
|
|
nthreads = kcalloc(nrpools, sizeof(int), GFP_KERNEL);
|
|
|
|
if (!nthreads) {
|
|
|
|
ret = -ENOMEM;
|
2024-04-23 13:25:40 +00:00
|
|
|
goto out_unlock;
|
2024-06-13 18:34:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
|
|
|
|
if (nla_type(attr) == NFSD_A_SERVER_THREADS) {
|
|
|
|
nthreads[i++] = nla_get_u32(attr);
|
|
|
|
if (i >= nrpools)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2024-04-23 13:25:40 +00:00
|
|
|
|
|
|
|
if (info->attrs[NFSD_A_SERVER_GRACETIME] ||
|
|
|
|
info->attrs[NFSD_A_SERVER_LEASETIME] ||
|
|
|
|
info->attrs[NFSD_A_SERVER_SCOPE]) {
|
|
|
|
ret = -EBUSY;
|
|
|
|
if (nn->nfsd_serv && nn->nfsd_serv->sv_nrthreads)
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
ret = -EINVAL;
|
|
|
|
attr = info->attrs[NFSD_A_SERVER_GRACETIME];
|
|
|
|
if (attr) {
|
|
|
|
u32 gracetime = nla_get_u32(attr);
|
|
|
|
|
|
|
|
if (gracetime < 10 || gracetime > 3600)
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
nn->nfsd4_grace = gracetime;
|
|
|
|
}
|
|
|
|
|
|
|
|
attr = info->attrs[NFSD_A_SERVER_LEASETIME];
|
|
|
|
if (attr) {
|
|
|
|
u32 leasetime = nla_get_u32(attr);
|
|
|
|
|
|
|
|
if (leasetime < 10 || leasetime > 3600)
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
nn->nfsd4_lease = leasetime;
|
|
|
|
}
|
|
|
|
|
|
|
|
attr = info->attrs[NFSD_A_SERVER_SCOPE];
|
|
|
|
if (attr)
|
|
|
|
scope = nla_data(attr);
|
|
|
|
}
|
|
|
|
|
2024-06-13 18:34:32 +00:00
|
|
|
ret = nfsd_svc(nrpools, nthreads, net, get_current_cred(), scope);
|
|
|
|
if (ret > 0)
|
|
|
|
ret = 0;
|
2024-04-23 13:25:40 +00:00
|
|
|
out_unlock:
|
|
|
|
mutex_unlock(&nfsd_mutex);
|
2024-06-13 18:34:32 +00:00
|
|
|
kfree(nthreads);
|
|
|
|
return ret;
|
2024-04-23 13:25:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nfsd_nl_threads_get_doit - get the number of running threads
|
|
|
|
* @skb: reply buffer
|
|
|
|
* @info: netlink metadata and command arguments
|
|
|
|
*
|
|
|
|
* Return 0 on success or a negative errno.
|
|
|
|
*/
|
|
|
|
int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct net *net = genl_info_net(info);
|
|
|
|
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
|
|
|
void *hdr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!skb)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_iput(skb, info);
|
|
|
|
if (!hdr) {
|
|
|
|
err = -EMSGSIZE;
|
|
|
|
goto err_free_msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_lock(&nfsd_mutex);
|
|
|
|
|
|
|
|
err = nla_put_u32(skb, NFSD_A_SERVER_GRACETIME,
|
|
|
|
nn->nfsd4_grace) ||
|
|
|
|
nla_put_u32(skb, NFSD_A_SERVER_LEASETIME,
|
|
|
|
nn->nfsd4_lease) ||
|
|
|
|
nla_put_string(skb, NFSD_A_SERVER_SCOPE,
|
|
|
|
nn->nfsd_name);
|
|
|
|
if (err)
|
|
|
|
goto err_unlock;
|
|
|
|
|
|
|
|
if (nn->nfsd_serv) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < nfsd_nrpools(net); ++i) {
|
|
|
|
struct svc_pool *sp = &nn->nfsd_serv->sv_pools[i];
|
|
|
|
|
|
|
|
err = nla_put_u32(skb, NFSD_A_SERVER_THREADS,
|
2024-07-15 07:14:18 +00:00
|
|
|
sp->sp_nrthreads);
|
2024-04-23 13:25:40 +00:00
|
|
|
if (err)
|
|
|
|
goto err_unlock;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
err = nla_put_u32(skb, NFSD_A_SERVER_THREADS, 0);
|
|
|
|
if (err)
|
|
|
|
goto err_unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(&nfsd_mutex);
|
|
|
|
|
|
|
|
genlmsg_end(skb, hdr);
|
|
|
|
|
|
|
|
return genlmsg_reply(skb, info);
|
|
|
|
|
|
|
|
err_unlock:
|
|
|
|
mutex_unlock(&nfsd_mutex);
|
|
|
|
err_free_msg:
|
|
|
|
nlmsg_free(skb);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2024-04-23 13:25:41 +00:00
|
|
|
/**
|
|
|
|
* nfsd_nl_version_set_doit - set the nfs enabled versions
|
|
|
|
* @skb: reply buffer
|
|
|
|
* @info: netlink metadata and command arguments
|
|
|
|
*
|
|
|
|
* Return 0 on success or a negative errno.
|
|
|
|
*/
|
|
|
|
int nfsd_nl_version_set_doit(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
const struct nlattr *attr;
|
|
|
|
struct nfsd_net *nn;
|
|
|
|
int i, rem;
|
|
|
|
|
|
|
|
if (GENL_REQ_ATTR_CHECK(info, NFSD_A_SERVER_PROTO_VERSION))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
mutex_lock(&nfsd_mutex);
|
|
|
|
|
|
|
|
nn = net_generic(genl_info_net(info), nfsd_net_id);
|
|
|
|
if (nn->nfsd_serv) {
|
|
|
|
mutex_unlock(&nfsd_mutex);
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clear current supported versions. */
|
|
|
|
nfsd_vers(nn, 2, NFSD_CLEAR);
|
|
|
|
nfsd_vers(nn, 3, NFSD_CLEAR);
|
|
|
|
for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++)
|
|
|
|
nfsd_minorversion(nn, i, NFSD_CLEAR);
|
|
|
|
|
|
|
|
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
|
|
|
|
struct nlattr *tb[NFSD_A_VERSION_MAX + 1];
|
|
|
|
u32 major, minor = 0;
|
|
|
|
bool enabled;
|
|
|
|
|
|
|
|
if (nla_type(attr) != NFSD_A_SERVER_PROTO_VERSION)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (nla_parse_nested(tb, NFSD_A_VERSION_MAX, attr,
|
|
|
|
nfsd_version_nl_policy, info->extack) < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!tb[NFSD_A_VERSION_MAJOR])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
major = nla_get_u32(tb[NFSD_A_VERSION_MAJOR]);
|
|
|
|
if (tb[NFSD_A_VERSION_MINOR])
|
|
|
|
minor = nla_get_u32(tb[NFSD_A_VERSION_MINOR]);
|
|
|
|
|
|
|
|
enabled = nla_get_flag(tb[NFSD_A_VERSION_ENABLED]);
|
|
|
|
|
|
|
|
switch (major) {
|
|
|
|
case 4:
|
|
|
|
nfsd_minorversion(nn, minor, enabled ? NFSD_SET : NFSD_CLEAR);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
case 2:
|
|
|
|
if (!minor)
|
|
|
|
nfsd_vers(nn, major, enabled ? NFSD_SET : NFSD_CLEAR);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(&nfsd_mutex);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nfsd_nl_version_get_doit - get the enabled status for all supported nfs versions
|
|
|
|
* @skb: reply buffer
|
|
|
|
* @info: netlink metadata and command arguments
|
|
|
|
*
|
|
|
|
* Return 0 on success or a negative errno.
|
|
|
|
*/
|
|
|
|
int nfsd_nl_version_get_doit(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nfsd_net *nn;
|
|
|
|
int i, err;
|
|
|
|
void *hdr;
|
|
|
|
|
|
|
|
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!skb)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_iput(skb, info);
|
|
|
|
if (!hdr) {
|
|
|
|
err = -EMSGSIZE;
|
|
|
|
goto err_free_msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_lock(&nfsd_mutex);
|
|
|
|
nn = net_generic(genl_info_net(info), nfsd_net_id);
|
|
|
|
|
|
|
|
for (i = 2; i <= 4; i++) {
|
|
|
|
int j;
|
|
|
|
|
|
|
|
for (j = 0; j <= NFSD_SUPPORTED_MINOR_VERSION; j++) {
|
|
|
|
struct nlattr *attr;
|
|
|
|
|
|
|
|
/* Don't record any versions the kernel doesn't have
|
|
|
|
* compiled in
|
|
|
|
*/
|
|
|
|
if (!nfsd_support_version(i))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* NFSv{2,3} does not support minor numbers */
|
|
|
|
if (i < 4 && j)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
attr = nla_nest_start(skb,
|
|
|
|
NFSD_A_SERVER_PROTO_VERSION);
|
|
|
|
if (!attr) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto err_nfsd_unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nla_put_u32(skb, NFSD_A_VERSION_MAJOR, i) ||
|
|
|
|
nla_put_u32(skb, NFSD_A_VERSION_MINOR, j)) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto err_nfsd_unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the enabled flag if the version is enabled */
|
|
|
|
if (nfsd_vers(nn, i, NFSD_TEST) &&
|
|
|
|
(i < 4 || nfsd_minorversion(nn, j, NFSD_TEST)) &&
|
|
|
|
nla_put_flag(skb, NFSD_A_VERSION_ENABLED)) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto err_nfsd_unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
nla_nest_end(skb, attr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(&nfsd_mutex);
|
|
|
|
genlmsg_end(skb, hdr);
|
|
|
|
|
|
|
|
return genlmsg_reply(skb, info);
|
|
|
|
|
|
|
|
err_nfsd_unlock:
|
|
|
|
mutex_unlock(&nfsd_mutex);
|
|
|
|
err_free_msg:
|
|
|
|
nlmsg_free(skb);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2024-04-23 13:25:44 +00:00
|
|
|
/**
|
|
|
|
* nfsd_nl_listener_set_doit - set the nfs running sockets
|
|
|
|
* @skb: reply buffer
|
|
|
|
* @info: netlink metadata and command arguments
|
|
|
|
*
|
|
|
|
* Return 0 on success or a negative errno.
|
|
|
|
*/
|
|
|
|
int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct net *net = genl_info_net(info);
|
|
|
|
struct svc_xprt *xprt, *tmp;
|
|
|
|
const struct nlattr *attr;
|
|
|
|
struct svc_serv *serv;
|
|
|
|
LIST_HEAD(permsocks);
|
|
|
|
struct nfsd_net *nn;
|
|
|
|
int err, rem;
|
|
|
|
|
|
|
|
mutex_lock(&nfsd_mutex);
|
|
|
|
|
|
|
|
err = nfsd_create_serv(net);
|
|
|
|
if (err) {
|
|
|
|
mutex_unlock(&nfsd_mutex);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
nn = net_generic(net, nfsd_net_id);
|
|
|
|
serv = nn->nfsd_serv;
|
|
|
|
|
|
|
|
spin_lock_bh(&serv->sv_lock);
|
|
|
|
|
|
|
|
/* Move all of the old listener sockets to a temp list */
|
|
|
|
list_splice_init(&serv->sv_permsocks, &permsocks);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Walk the list of server_socks from userland and move any that match
|
|
|
|
* back to sv_permsocks
|
|
|
|
*/
|
|
|
|
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
|
|
|
|
struct nlattr *tb[NFSD_A_SOCK_MAX + 1];
|
|
|
|
const char *xcl_name;
|
|
|
|
struct sockaddr *sa;
|
|
|
|
|
|
|
|
if (nla_type(attr) != NFSD_A_SERVER_SOCK_ADDR)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (nla_parse_nested(tb, NFSD_A_SOCK_MAX, attr,
|
|
|
|
nfsd_sock_nl_policy, info->extack) < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!tb[NFSD_A_SOCK_ADDR] || !tb[NFSD_A_SOCK_TRANSPORT_NAME])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (nla_len(tb[NFSD_A_SOCK_ADDR]) < sizeof(*sa))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
xcl_name = nla_data(tb[NFSD_A_SOCK_TRANSPORT_NAME]);
|
|
|
|
sa = nla_data(tb[NFSD_A_SOCK_ADDR]);
|
|
|
|
|
|
|
|
/* Put back any matching sockets */
|
|
|
|
list_for_each_entry_safe(xprt, tmp, &permsocks, xpt_list) {
|
|
|
|
/* This shouldn't be possible */
|
|
|
|
if (WARN_ON_ONCE(xprt->xpt_net != net)) {
|
|
|
|
list_move(&xprt->xpt_list, &serv->sv_permsocks);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If everything matches, put it back */
|
|
|
|
if (!strcmp(xprt->xpt_class->xcl_name, xcl_name) &&
|
|
|
|
rpc_cmp_addr_port(sa, (struct sockaddr *)&xprt->xpt_local)) {
|
|
|
|
list_move(&xprt->xpt_list, &serv->sv_permsocks);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* For now, no removing old sockets while server is running */
|
|
|
|
if (serv->sv_nrthreads && !list_empty(&permsocks)) {
|
|
|
|
list_splice_init(&permsocks, &serv->sv_permsocks);
|
|
|
|
spin_unlock_bh(&serv->sv_lock);
|
|
|
|
err = -EBUSY;
|
|
|
|
goto out_unlock_mtx;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Close the remaining sockets on the permsocks list */
|
|
|
|
while (!list_empty(&permsocks)) {
|
|
|
|
xprt = list_first_entry(&permsocks, struct svc_xprt, xpt_list);
|
|
|
|
list_move(&xprt->xpt_list, &serv->sv_permsocks);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Newly-created sockets are born with the BUSY bit set. Clear
|
|
|
|
* it if there are no threads, since nothing can pick it up
|
|
|
|
* in that case.
|
|
|
|
*/
|
|
|
|
if (!serv->sv_nrthreads)
|
|
|
|
clear_bit(XPT_BUSY, &xprt->xpt_flags);
|
|
|
|
|
|
|
|
set_bit(XPT_CLOSE, &xprt->xpt_flags);
|
|
|
|
spin_unlock_bh(&serv->sv_lock);
|
|
|
|
svc_xprt_close(xprt);
|
|
|
|
spin_lock_bh(&serv->sv_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_unlock_bh(&serv->sv_lock);
|
|
|
|
|
|
|
|
/* walk list of addrs again, open any that still don't exist */
|
|
|
|
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
|
|
|
|
struct nlattr *tb[NFSD_A_SOCK_MAX + 1];
|
|
|
|
const char *xcl_name;
|
|
|
|
struct sockaddr *sa;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (nla_type(attr) != NFSD_A_SERVER_SOCK_ADDR)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (nla_parse_nested(tb, NFSD_A_SOCK_MAX, attr,
|
|
|
|
nfsd_sock_nl_policy, info->extack) < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!tb[NFSD_A_SOCK_ADDR] || !tb[NFSD_A_SOCK_TRANSPORT_NAME])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (nla_len(tb[NFSD_A_SOCK_ADDR]) < sizeof(*sa))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
xcl_name = nla_data(tb[NFSD_A_SOCK_TRANSPORT_NAME]);
|
|
|
|
sa = nla_data(tb[NFSD_A_SOCK_ADDR]);
|
|
|
|
|
|
|
|
xprt = svc_find_listener(serv, xcl_name, net, sa);
|
|
|
|
if (xprt) {
|
|
|
|
svc_xprt_put(xprt);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-07-19 18:55:53 +00:00
|
|
|
ret = svc_xprt_create_from_sa(serv, xcl_name, net, sa, 0,
|
2024-04-23 13:25:44 +00:00
|
|
|
get_current_cred());
|
|
|
|
/* always save the latest error */
|
|
|
|
if (ret < 0)
|
|
|
|
err = ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!serv->sv_nrthreads && list_empty(&nn->nfsd_serv->sv_permsocks))
|
|
|
|
nfsd_destroy_serv(net);
|
|
|
|
|
|
|
|
out_unlock_mtx:
|
|
|
|
mutex_unlock(&nfsd_mutex);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nfsd_nl_listener_get_doit - get the nfs running listeners
|
|
|
|
* @skb: reply buffer
|
|
|
|
* @info: netlink metadata and command arguments
|
|
|
|
*
|
|
|
|
* Return 0 on success or a negative errno.
|
|
|
|
*/
|
|
|
|
int nfsd_nl_listener_get_doit(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct svc_xprt *xprt;
|
|
|
|
struct svc_serv *serv;
|
|
|
|
struct nfsd_net *nn;
|
|
|
|
void *hdr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!skb)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_iput(skb, info);
|
|
|
|
if (!hdr) {
|
|
|
|
err = -EMSGSIZE;
|
|
|
|
goto err_free_msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_lock(&nfsd_mutex);
|
|
|
|
nn = net_generic(genl_info_net(info), nfsd_net_id);
|
|
|
|
|
|
|
|
/* no nfs server? Just send empty socket list */
|
|
|
|
if (!nn->nfsd_serv)
|
|
|
|
goto out_unlock_mtx;
|
|
|
|
|
|
|
|
serv = nn->nfsd_serv;
|
|
|
|
spin_lock_bh(&serv->sv_lock);
|
|
|
|
list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
|
|
|
|
struct nlattr *attr;
|
|
|
|
|
|
|
|
attr = nla_nest_start(skb, NFSD_A_SERVER_SOCK_ADDR);
|
|
|
|
if (!attr) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto err_serv_unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nla_put_string(skb, NFSD_A_SOCK_TRANSPORT_NAME,
|
|
|
|
xprt->xpt_class->xcl_name) ||
|
|
|
|
nla_put(skb, NFSD_A_SOCK_ADDR,
|
|
|
|
sizeof(struct sockaddr_storage),
|
|
|
|
&xprt->xpt_local)) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto err_serv_unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
nla_nest_end(skb, attr);
|
|
|
|
}
|
|
|
|
spin_unlock_bh(&serv->sv_lock);
|
|
|
|
out_unlock_mtx:
|
|
|
|
mutex_unlock(&nfsd_mutex);
|
|
|
|
genlmsg_end(skb, hdr);
|
|
|
|
|
|
|
|
return genlmsg_reply(skb, info);
|
|
|
|
|
|
|
|
err_serv_unlock:
|
|
|
|
spin_unlock_bh(&serv->sv_lock);
|
|
|
|
mutex_unlock(&nfsd_mutex);
|
|
|
|
err_free_msg:
|
|
|
|
nlmsg_free(skb);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2024-06-14 12:59:10 +00:00
|
|
|
/**
|
|
|
|
* nfsd_nl_pool_mode_set_doit - set the number of running threads
|
|
|
|
* @skb: reply buffer
|
|
|
|
* @info: netlink metadata and command arguments
|
|
|
|
*
|
|
|
|
* Return 0 on success or a negative errno.
|
|
|
|
*/
|
|
|
|
int nfsd_nl_pool_mode_set_doit(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
const struct nlattr *attr;
|
|
|
|
|
|
|
|
if (GENL_REQ_ATTR_CHECK(info, NFSD_A_POOL_MODE_MODE))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
attr = info->attrs[NFSD_A_POOL_MODE_MODE];
|
|
|
|
return sunrpc_set_pool_mode(nla_data(attr));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nfsd_nl_pool_mode_get_doit - get info about pool_mode
|
|
|
|
* @skb: reply buffer
|
|
|
|
* @info: netlink metadata and command arguments
|
|
|
|
*
|
|
|
|
* Return 0 on success or a negative errno.
|
|
|
|
*/
|
|
|
|
int nfsd_nl_pool_mode_get_doit(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct net *net = genl_info_net(info);
|
|
|
|
char buf[16];
|
|
|
|
void *hdr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (sunrpc_get_pool_mode(buf, ARRAY_SIZE(buf)) >= ARRAY_SIZE(buf))
|
|
|
|
return -ERANGE;
|
|
|
|
|
|
|
|
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!skb)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
err = -EMSGSIZE;
|
|
|
|
hdr = genlmsg_iput(skb, info);
|
|
|
|
if (!hdr)
|
|
|
|
goto err_free_msg;
|
|
|
|
|
|
|
|
err = nla_put_string(skb, NFSD_A_POOL_MODE_MODE, buf) |
|
|
|
|
nla_put_u32(skb, NFSD_A_POOL_MODE_NPOOLS, nfsd_nrpools(net));
|
|
|
|
if (err)
|
|
|
|
goto err_free_msg;
|
|
|
|
|
|
|
|
genlmsg_end(skb, hdr);
|
|
|
|
return genlmsg_reply(skb, info);
|
|
|
|
|
|
|
|
err_free_msg:
|
|
|
|
nlmsg_free(skb);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-06-17 03:10:53 +00:00
|
|
|
/**
|
|
|
|
* nfsd_net_init - Prepare the nfsd_net portion of a new net namespace
|
|
|
|
* @net: a freshly-created network namespace
|
|
|
|
*
|
|
|
|
* This information stays around as long as the network namespace is
|
|
|
|
* alive whether or not there is an NFSD instance running in the
|
|
|
|
* namespace.
|
|
|
|
*
|
|
|
|
* Returns zero on success, or a negative errno otherwise.
|
|
|
|
*/
|
|
|
|
static __net_init int nfsd_net_init(struct net *net)
|
2012-04-11 11:13:35 +00:00
|
|
|
{
|
2012-11-27 11:11:44 +00:00
|
|
|
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
2024-08-07 01:11:32 +00:00
|
|
|
int retval;
|
|
|
|
int i;
|
2012-04-11 11:13:35 +00:00
|
|
|
|
|
|
|
retval = nfsd_export_init(net);
|
|
|
|
if (retval)
|
|
|
|
goto out_export_error;
|
2012-04-11 13:33:05 +00:00
|
|
|
retval = nfsd_idmap_init(net);
|
|
|
|
if (retval)
|
|
|
|
goto out_idmap_error;
|
2024-03-25 13:21:39 +00:00
|
|
|
retval = percpu_counter_init_many(nn->counter, 0, GFP_KERNEL,
|
|
|
|
NFSD_STATS_COUNTERS_NUM);
|
2023-06-16 21:51:34 +00:00
|
|
|
if (retval)
|
|
|
|
goto out_repcache_error;
|
2024-01-26 15:39:49 +00:00
|
|
|
memset(&nn->nfsd_svcstats, 0, sizeof(nn->nfsd_svcstats));
|
2024-09-05 19:09:47 +00:00
|
|
|
nn->nfsd_svcstats.program = &nfsd_programs[0];
|
2024-08-07 01:11:32 +00:00
|
|
|
for (i = 0; i < sizeof(nn->nfsd_versions); i++)
|
|
|
|
nn->nfsd_versions[i] = nfsd_support_version(i);
|
|
|
|
for (i = 0; i < sizeof(nn->nfsd4_minorversions); i++)
|
|
|
|
nn->nfsd4_minorversions[i] = nfsd_support_version(4);
|
2024-06-24 23:04:56 +00:00
|
|
|
nn->nfsd_info.mutex = &nfsd_mutex;
|
|
|
|
nn->nfsd_serv = NULL;
|
2023-01-11 20:17:09 +00:00
|
|
|
nfsd4_init_leases_net(nn);
|
2021-12-29 19:43:16 +00:00
|
|
|
get_random_bytes(&nn->siphash_key, sizeof(nn->siphash_key));
|
|
|
|
seqlock_init(&nn->writeverf_lock);
|
2024-01-26 15:39:46 +00:00
|
|
|
nfsd_proc_stat_init(net);
|
2024-09-05 19:09:50 +00:00
|
|
|
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
|
|
|
|
INIT_LIST_HEAD(&nn->local_clients);
|
|
|
|
#endif
|
2012-04-11 11:13:35 +00:00
|
|
|
return 0;
|
|
|
|
|
2023-06-16 21:51:34 +00:00
|
|
|
out_repcache_error:
|
|
|
|
nfsd_idmap_shutdown(net);
|
2012-04-11 13:33:05 +00:00
|
|
|
out_idmap_error:
|
|
|
|
nfsd_export_shutdown(net);
|
2012-04-11 11:13:35 +00:00
|
|
|
out_export_error:
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2024-09-05 19:09:50 +00:00
|
|
|
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
|
|
|
|
/**
|
|
|
|
* nfsd_net_pre_exit - Disconnect localio clients from net namespace
|
|
|
|
* @net: a network namespace that is about to be destroyed
|
|
|
|
*
|
|
|
|
* This invalidated ->net pointers held by localio clients
|
|
|
|
* while they can still safely access nn->counter.
|
|
|
|
*/
|
|
|
|
static __net_exit void nfsd_net_pre_exit(struct net *net)
|
|
|
|
{
|
|
|
|
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
|
|
|
|
|
|
|
nfs_uuid_invalidate_clients(&nn->local_clients);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2023-06-17 03:10:53 +00:00
|
|
|
/**
|
|
|
|
* nfsd_net_exit - Release the nfsd_net portion of a net namespace
|
|
|
|
* @net: a network namespace that is about to be destroyed
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static __net_exit void nfsd_net_exit(struct net *net)
|
2012-04-11 11:13:35 +00:00
|
|
|
{
|
2023-06-16 21:51:34 +00:00
|
|
|
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
|
|
|
|
2024-01-26 15:39:46 +00:00
|
|
|
nfsd_proc_stat_shutdown(net);
|
2024-03-25 13:21:39 +00:00
|
|
|
percpu_counter_destroy_many(nn->counter, NFSD_STATS_COUNTERS_NUM);
|
2012-04-11 13:33:05 +00:00
|
|
|
nfsd_idmap_shutdown(net);
|
2012-04-11 11:13:35 +00:00
|
|
|
nfsd_export_shutdown(net);
|
|
|
|
}
|
|
|
|
|
2012-03-21 13:52:05 +00:00
|
|
|
static struct pernet_operations nfsd_net_ops = {
|
2023-06-17 03:10:53 +00:00
|
|
|
.init = nfsd_net_init,
|
2024-09-05 19:09:50 +00:00
|
|
|
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
|
|
|
|
.pre_exit = nfsd_net_pre_exit,
|
|
|
|
#endif
|
2023-06-17 03:10:53 +00:00
|
|
|
.exit = nfsd_net_exit,
|
2012-03-21 13:52:05 +00:00
|
|
|
.id = &nfsd_net_id,
|
|
|
|
.size = sizeof(struct nfsd_net),
|
|
|
|
};
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
static int __init init_nfsd(void)
|
|
|
|
{
|
|
|
|
int retval;
|
|
|
|
|
2015-04-20 16:00:08 +00:00
|
|
|
retval = nfsd4_init_slabs();
|
|
|
|
if (retval)
|
2021-12-07 14:00:39 +00:00
|
|
|
return retval;
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 11:11:59 +00:00
|
|
|
retval = nfsd4_init_pnfs();
|
2011-11-01 17:35:21 +00:00
|
|
|
if (retval)
|
|
|
|
goto out_free_slabs;
|
2020-06-01 21:44:45 +00:00
|
|
|
retval = nfsd_drc_slab_create();
|
|
|
|
if (retval)
|
2024-01-26 15:39:47 +00:00
|
|
|
goto out_free_pnfs;
|
2005-04-16 22:20:36 +00:00
|
|
|
nfsd_lockd_init(); /* lockd->nfsd callbacks */
|
2007-11-12 22:32:21 +00:00
|
|
|
retval = create_proc_exports_entry();
|
|
|
|
if (retval)
|
2012-04-11 13:33:05 +00:00
|
|
|
goto out_free_lockd;
|
2021-02-03 16:42:13 +00:00
|
|
|
retval = register_pernet_subsys(&nfsd_net_ops);
|
|
|
|
if (retval < 0)
|
2022-05-21 04:08:45 +00:00
|
|
|
goto out_free_exports;
|
2021-12-07 14:00:39 +00:00
|
|
|
retval = register_cld_notifier();
|
2022-05-02 21:19:23 +00:00
|
|
|
if (retval)
|
2022-05-21 04:08:44 +00:00
|
|
|
goto out_free_subsys;
|
2022-05-02 21:19:23 +00:00
|
|
|
retval = nfsd4_create_laundry_wq();
|
2022-05-21 04:08:45 +00:00
|
|
|
if (retval)
|
|
|
|
goto out_free_cld;
|
|
|
|
retval = register_filesystem(&nfsd_fs_type);
|
2021-12-07 14:00:39 +00:00
|
|
|
if (retval)
|
2007-11-09 18:44:06 +00:00
|
|
|
goto out_free_all;
|
2023-09-11 12:49:46 +00:00
|
|
|
retval = genl_register_family(&nfsd_nl_family);
|
|
|
|
if (retval)
|
|
|
|
goto out_free_all;
|
2024-09-05 19:09:50 +00:00
|
|
|
nfsd_localio_ops_init();
|
2023-09-11 12:49:46 +00:00
|
|
|
|
2007-11-09 18:44:06 +00:00
|
|
|
return 0;
|
|
|
|
out_free_all:
|
2022-05-21 04:08:45 +00:00
|
|
|
nfsd4_destroy_laundry_wq();
|
|
|
|
out_free_cld:
|
2022-05-21 04:08:44 +00:00
|
|
|
unregister_cld_notifier();
|
|
|
|
out_free_subsys:
|
2021-12-07 14:00:39 +00:00
|
|
|
unregister_pernet_subsys(&nfsd_net_ops);
|
2021-02-03 16:42:13 +00:00
|
|
|
out_free_exports:
|
2007-11-09 18:44:06 +00:00
|
|
|
remove_proc_entry("fs/nfs/exports", NULL);
|
|
|
|
remove_proc_entry("fs/nfs", NULL);
|
2007-11-08 22:20:34 +00:00
|
|
|
out_free_lockd:
|
2007-11-09 18:44:06 +00:00
|
|
|
nfsd_lockd_shutdown();
|
2020-06-01 21:44:45 +00:00
|
|
|
nfsd_drc_slab_free();
|
2021-01-06 07:52:35 +00:00
|
|
|
out_free_pnfs:
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 11:11:59 +00:00
|
|
|
nfsd4_exit_pnfs();
|
2011-11-01 17:35:21 +00:00
|
|
|
out_free_slabs:
|
2007-11-09 18:44:06 +00:00
|
|
|
nfsd4_free_slabs();
|
2005-04-16 22:20:36 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit exit_nfsd(void)
|
|
|
|
{
|
2023-09-11 12:49:46 +00:00
|
|
|
genl_unregister_family(&nfsd_nl_family);
|
2022-05-21 04:08:45 +00:00
|
|
|
unregister_filesystem(&nfsd_fs_type);
|
2022-05-02 21:19:23 +00:00
|
|
|
nfsd4_destroy_laundry_wq();
|
2021-12-07 14:00:39 +00:00
|
|
|
unregister_cld_notifier();
|
2021-02-03 16:42:13 +00:00
|
|
|
unregister_pernet_subsys(&nfsd_net_ops);
|
2020-06-01 21:44:45 +00:00
|
|
|
nfsd_drc_slab_free();
|
2005-04-16 22:20:36 +00:00
|
|
|
remove_proc_entry("fs/nfs/exports", NULL);
|
|
|
|
remove_proc_entry("fs/nfs", NULL);
|
|
|
|
nfsd_lockd_shutdown();
|
2007-08-01 19:30:59 +00:00
|
|
|
nfsd4_free_slabs();
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 11:11:59 +00:00
|
|
|
nfsd4_exit_pnfs();
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
|
2023-07-20 13:34:53 +00:00
|
|
|
MODULE_DESCRIPTION("In-kernel NFS server");
|
2005-04-16 22:20:36 +00:00
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
module_init(init_nfsd)
|
|
|
|
module_exit(exit_nfsd)
|