Skip to content

Commit fa49838

Browse files
westonandrosadamsonAnna Schumaker
authored andcommitted
nfsd: add LOCALIO support
Add server support for bypassing NFS for localhost reads, writes, and commits. This is only useful when both the client and server are running on the same host. If nfsd_open_local_fh() fails then the NFS client will both retry and fallback to normal network-based read, write and commit operations if localio is no longer supported. Care is taken to ensure the same NFS security mechanisms are used (authentication, etc) regardless of whether localio or regular NFS access is used. The auth_domain established as part of the traditional NFS client access to the NFS server is also used for localio. Store auth_domain for localio in nfsd_uuid_t and transfer it to the client if it is local to the server. Relative to containers, localio gives the client access to the network namespace the server has. This is required to allow the client to access the server's per-namespace nfsd_net struct. This commit also introduces the use of NFSD's percpu_ref to interlock nfsd_destroy_serv and nfsd_open_local_fh, to ensure nn->nfsd_serv is not destroyed while in use by nfsd_open_local_fh and other LOCALIO client code. CONFIG_NFS_LOCALIO enables NFS server support for LOCALIO. Signed-off-by: Weston Andros Adamson <[email protected]> Signed-off-by: Trond Myklebust <[email protected]> Co-developed-by: Mike Snitzer <[email protected]> Signed-off-by: Mike Snitzer <[email protected]> Co-developed-by: NeilBrown <[email protected]> Signed-off-by: NeilBrown <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Acked-by: Chuck Lever <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent a61e147 commit fa49838

File tree

8 files changed

+134
-3
lines changed

8 files changed

+134
-3
lines changed

fs/nfsd/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ nfsd-$(CONFIG_NFSD_PNFS) += nfs4layouts.o
2323
nfsd-$(CONFIG_NFSD_BLOCKLAYOUT) += blocklayout.o blocklayoutxdr.o
2424
nfsd-$(CONFIG_NFSD_SCSILAYOUT) += blocklayout.o blocklayoutxdr.o
2525
nfsd-$(CONFIG_NFSD_FLEXFILELAYOUT) += flexfilelayout.o flexfilelayoutxdr.o
26+
nfsd-$(CONFIG_NFS_LOCALIO) += localio.o

fs/nfsd/filecache.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
#define NFSD_FILE_CACHE_UP (0)
5353

5454
/* We only care about NFSD_MAY_READ/WRITE for this cache */
55-
#define NFSD_FILE_MAY_MASK (NFSD_MAY_READ|NFSD_MAY_WRITE)
55+
#define NFSD_FILE_MAY_MASK (NFSD_MAY_READ|NFSD_MAY_WRITE|NFSD_MAY_LOCALIO)
5656

5757
static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits);
5858
static DEFINE_PER_CPU(unsigned long, nfsd_file_acquisitions);

fs/nfsd/localio.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* NFS server support for local clients to bypass network stack
4+
*
5+
* Copyright (C) 2014 Weston Andros Adamson <[email protected]>
6+
* Copyright (C) 2019 Trond Myklebust <[email protected]>
7+
* Copyright (C) 2024 Mike Snitzer <[email protected]>
8+
* Copyright (C) 2024 NeilBrown <[email protected]>
9+
*/
10+
11+
#include <linux/exportfs.h>
12+
#include <linux/sunrpc/svcauth.h>
13+
#include <linux/sunrpc/clnt.h>
14+
#include <linux/nfs.h>
15+
#include <linux/nfs_common.h>
16+
#include <linux/nfslocalio.h>
17+
#include <linux/string.h>
18+
19+
#include "nfsd.h"
20+
#include "vfs.h"
21+
#include "netns.h"
22+
#include "filecache.h"
23+
24+
static const struct nfsd_localio_operations nfsd_localio_ops = {
25+
.nfsd_serv_try_get = nfsd_serv_try_get,
26+
.nfsd_serv_put = nfsd_serv_put,
27+
.nfsd_open_local_fh = nfsd_open_local_fh,
28+
.nfsd_file_put_local = nfsd_file_put_local,
29+
.nfsd_file_file = nfsd_file_file,
30+
};
31+
32+
void nfsd_localio_ops_init(void)
33+
{
34+
nfs_to = &nfsd_localio_ops;
35+
}
36+
37+
/**
38+
* nfsd_open_local_fh - lookup a local filehandle @nfs_fh and map to nfsd_file
39+
*
40+
* @net: 'struct net' to get the proper nfsd_net required for LOCALIO access
41+
* @dom: 'struct auth_domain' required for LOCALIO access
42+
* @rpc_clnt: rpc_clnt that the client established
43+
* @cred: cred that the client established
44+
* @nfs_fh: filehandle to lookup
45+
* @fmode: fmode_t to use for open
46+
*
47+
* This function maps a local fh to a path on a local filesystem.
48+
* This is useful when the nfs client has the local server mounted - it can
49+
* avoid all the NFS overhead with reads, writes and commits.
50+
*
51+
* On successful return, returned nfsd_file will have its nf_net member
52+
* set. Caller (NFS client) is responsible for calling nfsd_serv_put and
53+
* nfsd_file_put (via nfs_to->nfsd_file_put_local).
54+
*/
55+
struct nfsd_file *
56+
nfsd_open_local_fh(struct net *net, struct auth_domain *dom,
57+
struct rpc_clnt *rpc_clnt, const struct cred *cred,
58+
const struct nfs_fh *nfs_fh, const fmode_t fmode)
59+
{
60+
int mayflags = NFSD_MAY_LOCALIO;
61+
struct svc_cred rq_cred;
62+
struct svc_fh fh;
63+
struct nfsd_file *localio;
64+
__be32 beres;
65+
66+
if (nfs_fh->size > NFS4_FHSIZE)
67+
return ERR_PTR(-EINVAL);
68+
69+
/* nfs_fh -> svc_fh */
70+
fh_init(&fh, NFS4_FHSIZE);
71+
fh.fh_handle.fh_size = nfs_fh->size;
72+
memcpy(fh.fh_handle.fh_raw, nfs_fh->data, nfs_fh->size);
73+
74+
if (fmode & FMODE_READ)
75+
mayflags |= NFSD_MAY_READ;
76+
if (fmode & FMODE_WRITE)
77+
mayflags |= NFSD_MAY_WRITE;
78+
79+
svcauth_map_clnt_to_svc_cred_local(rpc_clnt, cred, &rq_cred);
80+
81+
beres = nfsd_file_acquire_local(net, &rq_cred, dom,
82+
&fh, mayflags, &localio);
83+
if (beres)
84+
localio = ERR_PTR(nfs_stat_to_errno(be32_to_cpu(beres)));
85+
86+
fh_put(&fh);
87+
if (rq_cred.cr_group_info)
88+
put_group_info(rq_cred.cr_group_info);
89+
90+
return localio;
91+
}
92+
EXPORT_SYMBOL_GPL(nfsd_open_local_fh);

fs/nfsd/netns.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,10 @@ struct nfsd_net {
217217
/* last time an admin-revoke happened for NFSv4.0 */
218218
time64_t nfs40_last_revoke;
219219

220+
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
221+
/* Local clients to be invalidated when net is shut down */
222+
struct list_head local_clients;
223+
#endif
220224
};
221225

222226
/* Simple check to find out if a given net was properly initialized */

fs/nfsd/nfsctl.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/sunrpc/svc.h>
1919
#include <linux/module.h>
2020
#include <linux/fsnotify.h>
21+
#include <linux/nfslocalio.h>
2122

2223
#include "idmap.h"
2324
#include "nfsd.h"
@@ -2257,7 +2258,9 @@ static __net_init int nfsd_net_init(struct net *net)
22572258
get_random_bytes(&nn->siphash_key, sizeof(nn->siphash_key));
22582259
seqlock_init(&nn->writeverf_lock);
22592260
nfsd_proc_stat_init(net);
2260-
2261+
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
2262+
INIT_LIST_HEAD(&nn->local_clients);
2263+
#endif
22612264
return 0;
22622265

22632266
out_repcache_error:
@@ -2268,6 +2271,22 @@ static __net_init int nfsd_net_init(struct net *net)
22682271
return retval;
22692272
}
22702273

2274+
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
2275+
/**
2276+
* nfsd_net_pre_exit - Disconnect localio clients from net namespace
2277+
* @net: a network namespace that is about to be destroyed
2278+
*
2279+
* This invalidated ->net pointers held by localio clients
2280+
* while they can still safely access nn->counter.
2281+
*/
2282+
static __net_exit void nfsd_net_pre_exit(struct net *net)
2283+
{
2284+
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
2285+
2286+
nfs_uuid_invalidate_clients(&nn->local_clients);
2287+
}
2288+
#endif
2289+
22712290
/**
22722291
* nfsd_net_exit - Release the nfsd_net portion of a net namespace
22732292
* @net: a network namespace that is about to be destroyed
@@ -2285,6 +2304,9 @@ static __net_exit void nfsd_net_exit(struct net *net)
22852304

22862305
static struct pernet_operations nfsd_net_ops = {
22872306
.init = nfsd_net_init,
2307+
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
2308+
.pre_exit = nfsd_net_pre_exit,
2309+
#endif
22882310
.exit = nfsd_net_exit,
22892311
.id = &nfsd_net_id,
22902312
.size = sizeof(struct nfsd_net),
@@ -2322,6 +2344,7 @@ static int __init init_nfsd(void)
23222344
retval = genl_register_family(&nfsd_nl_family);
23232345
if (retval)
23242346
goto out_free_all;
2347+
nfsd_localio_ops_init();
23252348

23262349
return 0;
23272350
out_free_all:

fs/nfsd/trace.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ DEFINE_NFSD_XDR_ERR_EVENT(cant_encode);
8686
{ NFSD_MAY_NOT_BREAK_LEASE, "NOT_BREAK_LEASE" }, \
8787
{ NFSD_MAY_BYPASS_GSS, "BYPASS_GSS" }, \
8888
{ NFSD_MAY_READ_IF_EXEC, "READ_IF_EXEC" }, \
89-
{ NFSD_MAY_64BIT_COOKIE, "64BIT_COOKIE" })
89+
{ NFSD_MAY_64BIT_COOKIE, "64BIT_COOKIE" }, \
90+
{ NFSD_MAY_LOCALIO, "LOCALIO" })
9091

9192
TRACE_EVENT(nfsd_compound,
9293
TP_PROTO(

fs/nfsd/vfs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333

3434
#define NFSD_MAY_64BIT_COOKIE 0x1000 /* 64 bit readdir cookies for >= NFSv3 */
3535

36+
#define NFSD_MAY_LOCALIO 0x2000 /* for tracing, reflects when localio used */
37+
3638
#define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE)
3739
#define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC)
3840

include/linux/nfslocalio.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#ifndef __LINUX_NFSLOCALIO_H
77
#define __LINUX_NFSLOCALIO_H
88

9+
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
10+
911
#include <linux/module.h>
1012
#include <linux/list.h>
1113
#include <linux/uuid.h>
@@ -58,4 +60,10 @@ struct nfsd_localio_operations {
5860
extern void nfsd_localio_ops_init(void);
5961
extern const struct nfsd_localio_operations *nfs_to;
6062

63+
#else /* CONFIG_NFS_LOCALIO */
64+
static inline void nfsd_localio_ops_init(void)
65+
{
66+
}
67+
#endif /* CONFIG_NFS_LOCALIO */
68+
6169
#endif /* __LINUX_NFSLOCALIO_H */

0 commit comments

Comments
 (0)