~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/nfs_common/nfslocalio.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /fs/nfs_common/nfslocalio.c (Architecture i386) and /fs/nfs_common/nfslocalio.c (Architecture sparc)


  1 // SPDX-License-Identifier: GPL-2.0-only            1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*                                                  2 /*
  3  * Copyright (C) 2024 Mike Snitzer <snitzer@ha      3  * Copyright (C) 2024 Mike Snitzer <snitzer@hammerspace.com>
  4  * Copyright (C) 2024 NeilBrown <neilb@suse.de      4  * Copyright (C) 2024 NeilBrown <neilb@suse.de>
  5  */                                                 5  */
  6                                                     6 
  7 #include <linux/module.h>                           7 #include <linux/module.h>
  8 #include <linux/list.h>                             8 #include <linux/list.h>
  9 #include <linux/nfslocalio.h>                       9 #include <linux/nfslocalio.h>
 10 #include <net/netns/generic.h>                     10 #include <net/netns/generic.h>
 11                                                    11 
 12 MODULE_LICENSE("GPL");                             12 MODULE_LICENSE("GPL");
 13 MODULE_DESCRIPTION("NFS localio protocol bypas     13 MODULE_DESCRIPTION("NFS localio protocol bypass support");
 14                                                    14 
 15 static DEFINE_SPINLOCK(nfs_uuid_lock);             15 static DEFINE_SPINLOCK(nfs_uuid_lock);
 16                                                    16 
 17 /*                                                 17 /*
 18  * Global list of nfs_uuid_t instances             18  * Global list of nfs_uuid_t instances
 19  * that is protected by nfs_uuid_lock.             19  * that is protected by nfs_uuid_lock.
 20  */                                                20  */
 21 static LIST_HEAD(nfs_uuids);                       21 static LIST_HEAD(nfs_uuids);
 22                                                    22 
 23 void nfs_uuid_init(nfs_uuid_t *nfs_uuid)           23 void nfs_uuid_init(nfs_uuid_t *nfs_uuid)
 24 {                                                  24 {
 25         nfs_uuid->net = NULL;                      25         nfs_uuid->net = NULL;
 26         nfs_uuid->dom = NULL;                      26         nfs_uuid->dom = NULL;
 27         INIT_LIST_HEAD(&nfs_uuid->list);           27         INIT_LIST_HEAD(&nfs_uuid->list);
 28 }                                                  28 }
 29 EXPORT_SYMBOL_GPL(nfs_uuid_init);                  29 EXPORT_SYMBOL_GPL(nfs_uuid_init);
 30                                                    30 
 31 bool nfs_uuid_begin(nfs_uuid_t *nfs_uuid)          31 bool nfs_uuid_begin(nfs_uuid_t *nfs_uuid)
 32 {                                                  32 {
 33         spin_lock(&nfs_uuid_lock);                 33         spin_lock(&nfs_uuid_lock);
 34         /* Is this nfs_uuid already in use? */     34         /* Is this nfs_uuid already in use? */
 35         if (!list_empty(&nfs_uuid->list)) {        35         if (!list_empty(&nfs_uuid->list)) {
 36                 spin_unlock(&nfs_uuid_lock);       36                 spin_unlock(&nfs_uuid_lock);
 37                 return false;                      37                 return false;
 38         }                                          38         }
 39         uuid_gen(&nfs_uuid->uuid);                 39         uuid_gen(&nfs_uuid->uuid);
 40         list_add_tail(&nfs_uuid->list, &nfs_uu     40         list_add_tail(&nfs_uuid->list, &nfs_uuids);
 41         spin_unlock(&nfs_uuid_lock);               41         spin_unlock(&nfs_uuid_lock);
 42                                                    42 
 43         return true;                               43         return true;
 44 }                                                  44 }
 45 EXPORT_SYMBOL_GPL(nfs_uuid_begin);                 45 EXPORT_SYMBOL_GPL(nfs_uuid_begin);
 46                                                    46 
 47 void nfs_uuid_end(nfs_uuid_t *nfs_uuid)            47 void nfs_uuid_end(nfs_uuid_t *nfs_uuid)
 48 {                                                  48 {
 49         if (nfs_uuid->net == NULL) {               49         if (nfs_uuid->net == NULL) {
 50                 spin_lock(&nfs_uuid_lock);         50                 spin_lock(&nfs_uuid_lock);
 51                 if (nfs_uuid->net == NULL)         51                 if (nfs_uuid->net == NULL)
 52                         list_del_init(&nfs_uui     52                         list_del_init(&nfs_uuid->list);
 53                 spin_unlock(&nfs_uuid_lock);       53                 spin_unlock(&nfs_uuid_lock);
 54         }                                          54         }
 55 }                                                  55 }
 56 EXPORT_SYMBOL_GPL(nfs_uuid_end);                   56 EXPORT_SYMBOL_GPL(nfs_uuid_end);
 57                                                    57 
 58 static nfs_uuid_t * nfs_uuid_lookup_locked(con     58 static nfs_uuid_t * nfs_uuid_lookup_locked(const uuid_t *uuid)
 59 {                                                  59 {
 60         nfs_uuid_t *nfs_uuid;                      60         nfs_uuid_t *nfs_uuid;
 61                                                    61 
 62         list_for_each_entry(nfs_uuid, &nfs_uui     62         list_for_each_entry(nfs_uuid, &nfs_uuids, list)
 63                 if (uuid_equal(&nfs_uuid->uuid     63                 if (uuid_equal(&nfs_uuid->uuid, uuid))
 64                         return nfs_uuid;           64                         return nfs_uuid;
 65                                                    65 
 66         return NULL;                               66         return NULL;
 67 }                                                  67 }
 68                                                    68 
 69 static struct module *nfsd_mod;                    69 static struct module *nfsd_mod;
 70                                                    70 
 71 void nfs_uuid_is_local(const uuid_t *uuid, str     71 void nfs_uuid_is_local(const uuid_t *uuid, struct list_head *list,
 72                        struct net *net, struct     72                        struct net *net, struct auth_domain *dom,
 73                        struct module *mod)         73                        struct module *mod)
 74 {                                                  74 {
 75         nfs_uuid_t *nfs_uuid;                      75         nfs_uuid_t *nfs_uuid;
 76                                                    76 
 77         spin_lock(&nfs_uuid_lock);                 77         spin_lock(&nfs_uuid_lock);
 78         nfs_uuid = nfs_uuid_lookup_locked(uuid     78         nfs_uuid = nfs_uuid_lookup_locked(uuid);
 79         if (nfs_uuid) {                            79         if (nfs_uuid) {
 80                 kref_get(&dom->ref);               80                 kref_get(&dom->ref);
 81                 nfs_uuid->dom = dom;               81                 nfs_uuid->dom = dom;
 82                 /*                                 82                 /*
 83                  * We don't hold a ref on the      83                  * We don't hold a ref on the net, but instead put
 84                  * ourselves on a list so the      84                  * ourselves on a list so the net pointer can be
 85                  * invalidated.                    85                  * invalidated.
 86                  */                                86                  */
 87                 list_move(&nfs_uuid->list, lis     87                 list_move(&nfs_uuid->list, list);
 88                 rcu_assign_pointer(nfs_uuid->n     88                 rcu_assign_pointer(nfs_uuid->net, net);
 89                                                    89 
 90                 __module_get(mod);                 90                 __module_get(mod);
 91                 nfsd_mod = mod;                    91                 nfsd_mod = mod;
 92         }                                          92         }
 93         spin_unlock(&nfs_uuid_lock);               93         spin_unlock(&nfs_uuid_lock);
 94 }                                                  94 }
 95 EXPORT_SYMBOL_GPL(nfs_uuid_is_local);              95 EXPORT_SYMBOL_GPL(nfs_uuid_is_local);
 96                                                    96 
 97 static void nfs_uuid_put_locked(nfs_uuid_t *nf     97 static void nfs_uuid_put_locked(nfs_uuid_t *nfs_uuid)
 98 {                                                  98 {
 99         if (nfs_uuid->net) {                       99         if (nfs_uuid->net) {
100                 module_put(nfsd_mod);             100                 module_put(nfsd_mod);
101                 nfs_uuid->net = NULL;             101                 nfs_uuid->net = NULL;
102         }                                         102         }
103         if (nfs_uuid->dom) {                      103         if (nfs_uuid->dom) {
104                 auth_domain_put(nfs_uuid->dom)    104                 auth_domain_put(nfs_uuid->dom);
105                 nfs_uuid->dom = NULL;             105                 nfs_uuid->dom = NULL;
106         }                                         106         }
107         list_del_init(&nfs_uuid->list);           107         list_del_init(&nfs_uuid->list);
108 }                                                 108 }
109                                                   109 
110 void nfs_uuid_invalidate_clients(struct list_h    110 void nfs_uuid_invalidate_clients(struct list_head *list)
111 {                                                 111 {
112         nfs_uuid_t *nfs_uuid, *tmp;               112         nfs_uuid_t *nfs_uuid, *tmp;
113                                                   113 
114         spin_lock(&nfs_uuid_lock);                114         spin_lock(&nfs_uuid_lock);
115         list_for_each_entry_safe(nfs_uuid, tmp    115         list_for_each_entry_safe(nfs_uuid, tmp, list, list)
116                 nfs_uuid_put_locked(nfs_uuid);    116                 nfs_uuid_put_locked(nfs_uuid);
117         spin_unlock(&nfs_uuid_lock);              117         spin_unlock(&nfs_uuid_lock);
118 }                                                 118 }
119 EXPORT_SYMBOL_GPL(nfs_uuid_invalidate_clients)    119 EXPORT_SYMBOL_GPL(nfs_uuid_invalidate_clients);
120                                                   120 
121 void nfs_uuid_invalidate_one_client(nfs_uuid_t    121 void nfs_uuid_invalidate_one_client(nfs_uuid_t *nfs_uuid)
122 {                                                 122 {
123         if (nfs_uuid->net) {                      123         if (nfs_uuid->net) {
124                 spin_lock(&nfs_uuid_lock);        124                 spin_lock(&nfs_uuid_lock);
125                 nfs_uuid_put_locked(nfs_uuid);    125                 nfs_uuid_put_locked(nfs_uuid);
126                 spin_unlock(&nfs_uuid_lock);      126                 spin_unlock(&nfs_uuid_lock);
127         }                                         127         }
128 }                                                 128 }
129 EXPORT_SYMBOL_GPL(nfs_uuid_invalidate_one_clie    129 EXPORT_SYMBOL_GPL(nfs_uuid_invalidate_one_client);
130                                                   130 
131 struct nfsd_file *nfs_open_local_fh(nfs_uuid_t    131 struct nfsd_file *nfs_open_local_fh(nfs_uuid_t *uuid,
132                    struct rpc_clnt *rpc_clnt,     132                    struct rpc_clnt *rpc_clnt, const struct cred *cred,
133                    const struct nfs_fh *nfs_fh    133                    const struct nfs_fh *nfs_fh, const fmode_t fmode)
134 {                                                 134 {
135         struct net *net;                          135         struct net *net;
136         struct nfsd_file *localio;                136         struct nfsd_file *localio;
137                                                   137 
138         /*                                        138         /*
139          * Not running in nfsd context, so mus    139          * Not running in nfsd context, so must safely get reference on nfsd_serv.
140          * But the server may already be shutt    140          * But the server may already be shutting down, if so disallow new localio.
141          * uuid->net is NOT a counted referenc    141          * uuid->net is NOT a counted reference, but rcu_read_lock() ensures that
142          * if uuid->net is not NULL, then call    142          * if uuid->net is not NULL, then calling nfsd_serv_try_get() is safe
143          * and if it succeeds we will have an     143          * and if it succeeds we will have an implied reference to the net.
144          *                                        144          *
145          * Otherwise NFS may not have ref on N    145          * Otherwise NFS may not have ref on NFSD and therefore cannot safely
146          * make 'nfs_to' calls.                   146          * make 'nfs_to' calls.
147          */                                       147          */
148         rcu_read_lock();                          148         rcu_read_lock();
149         net = rcu_dereference(uuid->net);         149         net = rcu_dereference(uuid->net);
150         if (!net || !nfs_to->nfsd_serv_try_get    150         if (!net || !nfs_to->nfsd_serv_try_get(net)) {
151                 rcu_read_unlock();                151                 rcu_read_unlock();
152                 return ERR_PTR(-ENXIO);           152                 return ERR_PTR(-ENXIO);
153         }                                         153         }
154         rcu_read_unlock();                        154         rcu_read_unlock();
155         /* We have an implied reference to net    155         /* We have an implied reference to net thanks to nfsd_serv_try_get */
156         localio = nfs_to->nfsd_open_local_fh(n    156         localio = nfs_to->nfsd_open_local_fh(net, uuid->dom, rpc_clnt,
157                                              c    157                                              cred, nfs_fh, fmode);
158         if (IS_ERR(localio)) {                    158         if (IS_ERR(localio)) {
159                 rcu_read_lock();                  159                 rcu_read_lock();
160                 nfs_to->nfsd_serv_put(net);       160                 nfs_to->nfsd_serv_put(net);
161                 rcu_read_unlock();                161                 rcu_read_unlock();
162         }                                         162         }
163         return localio;                           163         return localio;
164 }                                                 164 }
165 EXPORT_SYMBOL_GPL(nfs_open_local_fh);             165 EXPORT_SYMBOL_GPL(nfs_open_local_fh);
166                                                   166 
167 /*                                                167 /*
168  * The NFS LOCALIO code needs to call into NFS    168  * The NFS LOCALIO code needs to call into NFSD using various symbols,
169  * but cannot be statically linked, because th    169  * but cannot be statically linked, because that will make the NFS
170  * module always depend on the NFSD module.       170  * module always depend on the NFSD module.
171  *                                                171  *
172  * 'nfs_to' provides NFS access to NFSD functi    172  * 'nfs_to' provides NFS access to NFSD functions needed for LOCALIO,
173  * its lifetime is tightly coupled to the NFSD    173  * its lifetime is tightly coupled to the NFSD module and will always
174  * be available to NFS LOCALIO because any suc    174  * be available to NFS LOCALIO because any successful client<->server
175  * LOCALIO handshake results in a reference on    175  * LOCALIO handshake results in a reference on the NFSD module (above),
176  * so NFS implicitly holds a reference to the     176  * so NFS implicitly holds a reference to the NFSD module and its
177  * functions in the 'nfs_to' nfsd_localio_oper    177  * functions in the 'nfs_to' nfsd_localio_operations cannot disappear.
178  *                                                178  *
179  * If the last NFS client using LOCALIO discon    179  * If the last NFS client using LOCALIO disconnects (and its reference
180  * on NFSD dropped) then NFSD could be unloade    180  * on NFSD dropped) then NFSD could be unloaded, resulting in 'nfs_to'
181  * functions being invalid pointers. But if NF    181  * functions being invalid pointers. But if NFSD isn't loaded then NFS
182  * will not be able to handshake with NFSD and    182  * will not be able to handshake with NFSD and will have no cause to
183  * try to call 'nfs_to' function pointers. If/    183  * try to call 'nfs_to' function pointers. If/when NFSD is reloaded it
184  * will reinitialize the 'nfs_to' function poi    184  * will reinitialize the 'nfs_to' function pointers and make LOCALIO
185  * possible.                                      185  * possible.
186  */                                               186  */
187 const struct nfsd_localio_operations *nfs_to;     187 const struct nfsd_localio_operations *nfs_to;
188 EXPORT_SYMBOL_GPL(nfs_to);                        188 EXPORT_SYMBOL_GPL(nfs_to);
189                                                   189 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php