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