nfslocalio.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2024 Mike Snitzer <snitzer@hammerspace.com>
  4. * Copyright (C) 2024 NeilBrown <neilb@suse.de>
  5. */
  6. #include <linux/module.h>
  7. #include <linux/list.h>
  8. #include <linux/nfslocalio.h>
  9. #include <linux/nfs3.h>
  10. #include <linux/nfs4.h>
  11. #include <linux/nfs_fs.h>
  12. #include <net/netns/generic.h>
  13. #include "localio_trace.h"
  14. MODULE_LICENSE("GPL");
  15. MODULE_DESCRIPTION("NFS localio protocol bypass support");
  16. static DEFINE_SPINLOCK(nfs_uuids_lock);
  17. /*
  18. * Global list of nfs_uuid_t instances
  19. * that is protected by nfs_uuids_lock.
  20. */
  21. static LIST_HEAD(nfs_uuids);
  22. /*
  23. * Lock ordering:
  24. * 1: nfs_uuid->lock
  25. * 2: nfs_uuids_lock
  26. * 3: nfs_uuid->list_lock (aka nn->local_clients_lock)
  27. *
  28. * May skip locks in select cases, but never hold multiple
  29. * locks out of order.
  30. */
  31. void nfs_uuid_init(nfs_uuid_t *nfs_uuid)
  32. {
  33. RCU_INIT_POINTER(nfs_uuid->net, NULL);
  34. nfs_uuid->dom = NULL;
  35. nfs_uuid->list_lock = NULL;
  36. INIT_LIST_HEAD(&nfs_uuid->list);
  37. INIT_LIST_HEAD(&nfs_uuid->files);
  38. spin_lock_init(&nfs_uuid->lock);
  39. nfs_uuid->nfs3_localio_probe_count = 0;
  40. }
  41. EXPORT_SYMBOL_GPL(nfs_uuid_init);
  42. bool nfs_uuid_begin(nfs_uuid_t *nfs_uuid)
  43. {
  44. spin_lock(&nfs_uuid->lock);
  45. if (rcu_access_pointer(nfs_uuid->net)) {
  46. /* This nfs_uuid is already in use */
  47. spin_unlock(&nfs_uuid->lock);
  48. return false;
  49. }
  50. spin_lock(&nfs_uuids_lock);
  51. if (!list_empty(&nfs_uuid->list)) {
  52. /* This nfs_uuid is already in use */
  53. spin_unlock(&nfs_uuids_lock);
  54. spin_unlock(&nfs_uuid->lock);
  55. return false;
  56. }
  57. list_add_tail(&nfs_uuid->list, &nfs_uuids);
  58. spin_unlock(&nfs_uuids_lock);
  59. uuid_gen(&nfs_uuid->uuid);
  60. spin_unlock(&nfs_uuid->lock);
  61. return true;
  62. }
  63. EXPORT_SYMBOL_GPL(nfs_uuid_begin);
  64. void nfs_uuid_end(nfs_uuid_t *nfs_uuid)
  65. {
  66. if (!rcu_access_pointer(nfs_uuid->net)) {
  67. spin_lock(&nfs_uuid->lock);
  68. if (!rcu_access_pointer(nfs_uuid->net)) {
  69. /* Not local, remove from nfs_uuids */
  70. spin_lock(&nfs_uuids_lock);
  71. list_del_init(&nfs_uuid->list);
  72. spin_unlock(&nfs_uuids_lock);
  73. }
  74. spin_unlock(&nfs_uuid->lock);
  75. }
  76. }
  77. EXPORT_SYMBOL_GPL(nfs_uuid_end);
  78. static nfs_uuid_t * nfs_uuid_lookup_locked(const uuid_t *uuid)
  79. {
  80. nfs_uuid_t *nfs_uuid;
  81. list_for_each_entry(nfs_uuid, &nfs_uuids, list)
  82. if (uuid_equal(&nfs_uuid->uuid, uuid))
  83. return nfs_uuid;
  84. return NULL;
  85. }
  86. static struct module *nfsd_mod;
  87. void nfs_uuid_is_local(const uuid_t *uuid, struct list_head *list,
  88. spinlock_t *list_lock, struct net *net,
  89. struct auth_domain *dom, struct module *mod)
  90. {
  91. nfs_uuid_t *nfs_uuid;
  92. spin_lock(&nfs_uuids_lock);
  93. nfs_uuid = nfs_uuid_lookup_locked(uuid);
  94. if (!nfs_uuid) {
  95. spin_unlock(&nfs_uuids_lock);
  96. return;
  97. }
  98. /*
  99. * We don't hold a ref on the net, but instead put
  100. * ourselves on @list (nn->local_clients) so the net
  101. * pointer can be invalidated.
  102. */
  103. spin_lock(list_lock); /* list_lock is nn->local_clients_lock */
  104. list_move(&nfs_uuid->list, list);
  105. spin_unlock(list_lock);
  106. spin_unlock(&nfs_uuids_lock);
  107. /* Once nfs_uuid is parented to @list, avoid global nfs_uuids_lock */
  108. spin_lock(&nfs_uuid->lock);
  109. __module_get(mod);
  110. nfsd_mod = mod;
  111. nfs_uuid->list_lock = list_lock;
  112. kref_get(&dom->ref);
  113. nfs_uuid->dom = dom;
  114. rcu_assign_pointer(nfs_uuid->net, net);
  115. spin_unlock(&nfs_uuid->lock);
  116. }
  117. EXPORT_SYMBOL_GPL(nfs_uuid_is_local);
  118. void nfs_localio_enable_client(struct nfs_client *clp)
  119. {
  120. /* nfs_uuid_is_local() does the actual enablement */
  121. trace_nfs_localio_enable_client(clp);
  122. }
  123. EXPORT_SYMBOL_GPL(nfs_localio_enable_client);
  124. /*
  125. * Cleanup the nfs_uuid_t embedded in an nfs_client.
  126. * This is the long-form of nfs_uuid_init().
  127. */
  128. static bool nfs_uuid_put(nfs_uuid_t *nfs_uuid)
  129. {
  130. struct nfs_file_localio *nfl;
  131. spin_lock(&nfs_uuid->lock);
  132. if (unlikely(!rcu_access_pointer(nfs_uuid->net))) {
  133. spin_unlock(&nfs_uuid->lock);
  134. return false;
  135. }
  136. RCU_INIT_POINTER(nfs_uuid->net, NULL);
  137. if (nfs_uuid->dom) {
  138. auth_domain_put(nfs_uuid->dom);
  139. nfs_uuid->dom = NULL;
  140. }
  141. /* Walk list of files and ensure their last references dropped */
  142. while ((nfl = list_first_entry_or_null(&nfs_uuid->files,
  143. struct nfs_file_localio,
  144. list)) != NULL) {
  145. /* If nfs_uuid is already NULL, nfs_close_local_fh is
  146. * closing and we must wait, else we unlink and close.
  147. */
  148. if (rcu_access_pointer(nfl->nfs_uuid) == NULL) {
  149. /* nfs_close_local_fh() is doing the
  150. * close and we must wait. until it unlinks
  151. */
  152. wait_var_event_spinlock(nfs_uuid,
  153. list_first_entry_or_null(
  154. &nfs_uuid->files,
  155. struct nfs_file_localio,
  156. list) != nfl,
  157. &nfs_uuid->lock);
  158. continue;
  159. }
  160. /* Remove nfl from nfs_uuid->files list */
  161. list_del_init(&nfl->list);
  162. spin_unlock(&nfs_uuid->lock);
  163. nfs_to_nfsd_file_put_local(&nfl->ro_file);
  164. nfs_to_nfsd_file_put_local(&nfl->rw_file);
  165. cond_resched();
  166. spin_lock(&nfs_uuid->lock);
  167. /* Now we can allow racing nfs_close_local_fh() to
  168. * skip the locking.
  169. */
  170. store_release_wake_up(&nfl->nfs_uuid, RCU_INITIALIZER(NULL));
  171. }
  172. /* Remove client from nn->local_clients */
  173. if (nfs_uuid->list_lock) {
  174. spin_lock(nfs_uuid->list_lock);
  175. BUG_ON(list_empty(&nfs_uuid->list));
  176. list_del_init(&nfs_uuid->list);
  177. spin_unlock(nfs_uuid->list_lock);
  178. nfs_uuid->list_lock = NULL;
  179. }
  180. module_put(nfsd_mod);
  181. spin_unlock(&nfs_uuid->lock);
  182. return true;
  183. }
  184. void nfs_localio_disable_client(struct nfs_client *clp)
  185. {
  186. if (nfs_uuid_put(&clp->cl_uuid))
  187. trace_nfs_localio_disable_client(clp);
  188. }
  189. EXPORT_SYMBOL_GPL(nfs_localio_disable_client);
  190. void nfs_localio_invalidate_clients(struct list_head *nn_local_clients,
  191. spinlock_t *nn_local_clients_lock)
  192. {
  193. LIST_HEAD(local_clients);
  194. nfs_uuid_t *nfs_uuid, *tmp;
  195. struct nfs_client *clp;
  196. spin_lock(nn_local_clients_lock);
  197. list_splice_init(nn_local_clients, &local_clients);
  198. spin_unlock(nn_local_clients_lock);
  199. list_for_each_entry_safe(nfs_uuid, tmp, &local_clients, list) {
  200. if (WARN_ON(nfs_uuid->list_lock != nn_local_clients_lock))
  201. break;
  202. clp = container_of(nfs_uuid, struct nfs_client, cl_uuid);
  203. nfs_localio_disable_client(clp);
  204. }
  205. }
  206. EXPORT_SYMBOL_GPL(nfs_localio_invalidate_clients);
  207. static int nfs_uuid_add_file(nfs_uuid_t *nfs_uuid, struct nfs_file_localio *nfl)
  208. {
  209. int ret = 0;
  210. /* Add nfl to nfs_uuid->files if it isn't already */
  211. spin_lock(&nfs_uuid->lock);
  212. if (rcu_access_pointer(nfs_uuid->net) == NULL) {
  213. ret = -ENXIO;
  214. } else if (list_empty(&nfl->list)) {
  215. rcu_assign_pointer(nfl->nfs_uuid, nfs_uuid);
  216. list_add_tail(&nfl->list, &nfs_uuid->files);
  217. }
  218. spin_unlock(&nfs_uuid->lock);
  219. return ret;
  220. }
  221. /*
  222. * Caller is responsible for calling nfsd_net_put and
  223. * nfsd_file_put (via nfs_to_nfsd_file_put_local).
  224. */
  225. struct nfsd_file *nfs_open_local_fh(nfs_uuid_t *uuid,
  226. struct rpc_clnt *rpc_clnt, const struct cred *cred,
  227. const struct nfs_fh *nfs_fh, struct nfs_file_localio *nfl,
  228. struct nfsd_file __rcu **pnf,
  229. const fmode_t fmode)
  230. {
  231. struct net *net;
  232. struct nfsd_file *localio;
  233. /*
  234. * Not running in nfsd context, so must safely get reference on nfsd_serv.
  235. * But the server may already be shutting down, if so disallow new localio.
  236. * uuid->net is NOT a counted reference, but rcu_read_lock() ensures that
  237. * if uuid->net is not NULL, then calling nfsd_net_try_get() is safe
  238. * and if it succeeds we will have an implied reference to the net.
  239. *
  240. * Otherwise NFS may not have ref on NFSD and therefore cannot safely
  241. * make 'nfs_to' calls.
  242. */
  243. rcu_read_lock();
  244. net = rcu_dereference(uuid->net);
  245. if (!net || !nfs_to->nfsd_net_try_get(net)) {
  246. rcu_read_unlock();
  247. return ERR_PTR(-ENXIO);
  248. }
  249. rcu_read_unlock();
  250. /* We have an implied reference to net thanks to nfsd_net_try_get */
  251. localio = nfs_to->nfsd_open_local_fh(net, uuid->dom, rpc_clnt, cred,
  252. nfs_fh, pnf, fmode);
  253. if (!IS_ERR(localio) && nfs_uuid_add_file(uuid, nfl) < 0) {
  254. /* Delete the cached file when racing with nfs_uuid_put() */
  255. nfs_to_nfsd_file_put_local(pnf);
  256. }
  257. nfs_to_nfsd_net_put(net);
  258. return localio;
  259. }
  260. EXPORT_SYMBOL_GPL(nfs_open_local_fh);
  261. void nfs_close_local_fh(struct nfs_file_localio *nfl)
  262. {
  263. nfs_uuid_t *nfs_uuid;
  264. rcu_read_lock();
  265. nfs_uuid = rcu_dereference(nfl->nfs_uuid);
  266. if (!nfs_uuid) {
  267. /* regular (non-LOCALIO) NFS will hammer this */
  268. rcu_read_unlock();
  269. return;
  270. }
  271. spin_lock(&nfs_uuid->lock);
  272. if (!rcu_access_pointer(nfl->nfs_uuid)) {
  273. /* nfs_uuid_put has finished here */
  274. spin_unlock(&nfs_uuid->lock);
  275. rcu_read_unlock();
  276. return;
  277. }
  278. if (list_empty(&nfl->list)) {
  279. /* nfs_uuid_put() has started closing files, wait for it
  280. * to finished
  281. */
  282. spin_unlock(&nfs_uuid->lock);
  283. rcu_read_unlock();
  284. wait_var_event(&nfl->nfs_uuid,
  285. rcu_access_pointer(nfl->nfs_uuid) == NULL);
  286. return;
  287. }
  288. /* tell nfs_uuid_put() to wait for us */
  289. RCU_INIT_POINTER(nfl->nfs_uuid, NULL);
  290. spin_unlock(&nfs_uuid->lock);
  291. rcu_read_unlock();
  292. nfs_to_nfsd_file_put_local(&nfl->ro_file);
  293. nfs_to_nfsd_file_put_local(&nfl->rw_file);
  294. /* Remove nfl from nfs_uuid->files list and signal nfs_uuid_put()
  295. * that we are done. The moment we drop the spinlock the
  296. * nfs_uuid could be freed.
  297. */
  298. spin_lock(&nfs_uuid->lock);
  299. list_del_init(&nfl->list);
  300. wake_up_var_locked(nfs_uuid, &nfs_uuid->lock);
  301. spin_unlock(&nfs_uuid->lock);
  302. }
  303. EXPORT_SYMBOL_GPL(nfs_close_local_fh);
  304. /*
  305. * The NFS LOCALIO code needs to call into NFSD using various symbols,
  306. * but cannot be statically linked, because that will make the NFS
  307. * module always depend on the NFSD module.
  308. *
  309. * 'nfs_to' provides NFS access to NFSD functions needed for LOCALIO,
  310. * its lifetime is tightly coupled to the NFSD module and will always
  311. * be available to NFS LOCALIO because any successful client<->server
  312. * LOCALIO handshake results in a reference on the NFSD module (above),
  313. * so NFS implicitly holds a reference to the NFSD module and its
  314. * functions in the 'nfs_to' nfsd_localio_operations cannot disappear.
  315. *
  316. * If the last NFS client using LOCALIO disconnects (and its reference
  317. * on NFSD dropped) then NFSD could be unloaded, resulting in 'nfs_to'
  318. * functions being invalid pointers. But if NFSD isn't loaded then NFS
  319. * will not be able to handshake with NFSD and will have no cause to
  320. * try to call 'nfs_to' function pointers. If/when NFSD is reloaded it
  321. * will reinitialize the 'nfs_to' function pointers and make LOCALIO
  322. * possible.
  323. */
  324. const struct nfsd_localio_operations *nfs_to;
  325. EXPORT_SYMBOL_GPL(nfs_to);