1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Copyright (C) 2024 Mike Snitzer <[email protected]>
4  * Copyright (C) 2024 NeilBrown <[email protected]>
5  */
6 #ifndef __LINUX_NFSLOCALIO_H
7 #define __LINUX_NFSLOCALIO_H
8 
9 #if IS_ENABLED(CONFIG_NFS_LOCALIO)
10 
11 #include <linux/module.h>
12 #include <linux/list.h>
13 #include <linux/uuid.h>
14 #include <linux/sunrpc/clnt.h>
15 #include <linux/sunrpc/svcauth.h>
16 #include <linux/nfs.h>
17 #include <net/net_namespace.h>
18 
19 struct nfs_client;
20 struct nfs_file_localio;
21 
22 /*
23  * Useful to allow a client to negotiate if localio
24  * possible with its server.
25  *
26  * See Documentation/filesystems/nfs/localio.rst for more detail.
27  */
28 typedef struct {
29 	uuid_t uuid;
30 	unsigned nfs3_localio_probe_count;
31 	/* this struct is over a cacheline, avoid bouncing */
32 	spinlock_t ____cacheline_aligned lock;
33 	struct list_head list;
34 	spinlock_t *list_lock; /* nn->local_clients_lock */
35 	struct net __rcu *net; /* nfsd's network namespace */
36 	struct auth_domain *dom; /* auth_domain for localio */
37 	/* Local files to close when net is shut down or exports change */
38 	struct list_head files;
39 } nfs_uuid_t;
40 
41 void nfs_uuid_init(nfs_uuid_t *);
42 bool nfs_uuid_begin(nfs_uuid_t *);
43 void nfs_uuid_end(nfs_uuid_t *);
44 void nfs_uuid_is_local(const uuid_t *, struct list_head *, spinlock_t *,
45 		       struct net *, struct auth_domain *, struct module *);
46 
47 void nfs_localio_enable_client(struct nfs_client *clp);
48 void nfs_localio_disable_client(struct nfs_client *clp);
49 void nfs_localio_invalidate_clients(struct list_head *nn_local_clients,
50 				    spinlock_t *nn_local_clients_lock);
51 
52 /* localio needs to map filehandle -> struct nfsd_file */
53 extern struct nfsd_file *
54 nfsd_open_local_fh(struct net *, struct auth_domain *, struct rpc_clnt *,
55 		   const struct cred *, const struct nfs_fh *,
56 		   const fmode_t) __must_hold(rcu);
57 void nfs_close_local_fh(struct nfs_file_localio *);
58 
59 struct nfsd_localio_operations {
60 	bool (*nfsd_net_try_get)(struct net *);
61 	void (*nfsd_net_put)(struct net *);
62 	struct nfsd_file *(*nfsd_open_local_fh)(struct net *,
63 						struct auth_domain *,
64 						struct rpc_clnt *,
65 						const struct cred *,
66 						const struct nfs_fh *,
67 						const fmode_t);
68 	struct net *(*nfsd_file_put_local)(struct nfsd_file *);
69 	struct nfsd_file *(*nfsd_file_get)(struct nfsd_file *);
70 	void (*nfsd_file_put)(struct nfsd_file *);
71 	struct file *(*nfsd_file_file)(struct nfsd_file *);
72 } ____cacheline_aligned;
73 
74 extern void nfsd_localio_ops_init(void);
75 extern const struct nfsd_localio_operations *nfs_to;
76 
77 struct nfsd_file *nfs_open_local_fh(nfs_uuid_t *,
78 		   struct rpc_clnt *, const struct cred *,
79 		   const struct nfs_fh *, struct nfs_file_localio *,
80 		   const fmode_t);
81 
nfs_to_nfsd_net_put(struct net * net)82 static inline void nfs_to_nfsd_net_put(struct net *net)
83 {
84 	/*
85 	 * Once reference to net (and associated nfsd_serv) is dropped, NFSD
86 	 * could be unloaded, so ensure safe return from nfsd_net_put() by
87 	 * always taking RCU.
88 	 */
89 	rcu_read_lock();
90 	nfs_to->nfsd_net_put(net);
91 	rcu_read_unlock();
92 }
93 
nfs_to_nfsd_file_put_local(struct nfsd_file * localio)94 static inline void nfs_to_nfsd_file_put_local(struct nfsd_file *localio)
95 {
96 	/*
97 	 * Must not hold RCU otherwise nfsd_file_put() can easily trigger:
98 	 * "Voluntary context switch within RCU read-side critical section!"
99 	 * by scheduling deep in underlying filesystem (e.g. XFS).
100 	 */
101 	struct net *net = nfs_to->nfsd_file_put_local(localio);
102 
103 	nfs_to_nfsd_net_put(net);
104 }
105 
106 #else   /* CONFIG_NFS_LOCALIO */
107 
108 struct nfs_file_localio;
nfs_close_local_fh(struct nfs_file_localio * nfl)109 static inline void nfs_close_local_fh(struct nfs_file_localio *nfl)
110 {
111 }
nfsd_localio_ops_init(void)112 static inline void nfsd_localio_ops_init(void)
113 {
114 }
115 struct nfs_client;
nfs_localio_disable_client(struct nfs_client * clp)116 static inline void nfs_localio_disable_client(struct nfs_client *clp)
117 {
118 }
119 
120 #endif  /* CONFIG_NFS_LOCALIO */
121 
122 #endif  /* __LINUX_NFSLOCALIO_H */
123