On Tue, 2025-05-13 at 12:08 -0400, Mike Snitzer wrote: > It was reported that NFS client mounts of AWS Elastic File System > (EFS) volumes is slow, this is because the AWS firewall disallows > LOCALIO (because it doesn't consider the use of NFS_LOCALIO_PROGRAM > valid), see: https://bugzilla.redhat.com/show_bug.cgi?id=2335129 > > Switch to performing the LOCALIO probe asynchronously to address the > potential for the NFS LOCALIO protocol being disallowed and/or slowed > by the remote server's response. > > While at it, fix nfs_local_probe_async() to always take/put a > reference on the nfs_client that is using the LOCALIO protocol. > Also, unexport the nfs_local_probe() symbol and make it private to > fs/nfs/localio.c > > This change has the side-effect of initially issuing reads, writes and > commits over the wire via SUNRPC until the LOCALIO probe completes. > Technically, this should only happen if you start doing I/O _right_ after creating the client. Usually there is a delay between mounting and I/O so hopefully this shouldn't happen much if at all. Either way, it's clearly a safe way to handle this, and it gets around the synchronous blocking when the localio protocol server isn't reachable. > Suggested-by: Jeff Layton <jlayton@xxxxxxxxxx> # to always probe async > Fixes: 76d4cb6345da ("nfs: probe for LOCALIO when v4 client reconnects to server") > Cc: stable@xxxxxxxxxxxxxxx # 6.14+ > Signed-off-by: Mike Snitzer <snitzer@xxxxxxxxxx> > --- > fs/nfs/client.c | 2 +- > fs/nfs/flexfilelayout/flexfilelayoutdev.c | 2 +- > fs/nfs/internal.h | 1 - > fs/nfs/localio.c | 6 ++++-- > 4 files changed, 6 insertions(+), 5 deletions(-) > > diff --git a/fs/nfs/client.c b/fs/nfs/client.c > index 6d63b958c4bb..d8fe7c0e7e05 100644 > --- a/fs/nfs/client.c > +++ b/fs/nfs/client.c > @@ -439,7 +439,7 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init) > spin_unlock(&nn->nfs_client_lock); > new = rpc_ops->init_client(new, cl_init); > if (!IS_ERR(new)) > - nfs_local_probe(new); > + nfs_local_probe_async(new); > return new; > } > > diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c > index 4a304cf17c4b..656d5c50bbce 100644 > --- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c > +++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c > @@ -400,7 +400,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, > * keep ds_clp even if DS is local, so that if local IO cannot > * proceed somehow, we can fall back to NFS whenever we want. > */ > - nfs_local_probe(ds->ds_clp); > + nfs_local_probe_async(ds->ds_clp); > max_payload = > nfs_block_size(rpc_max_payload(ds->ds_clp->cl_rpcclient), > NULL); > diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h > index 6655e5f32ec6..69c2c10ee658 100644 > --- a/fs/nfs/internal.h > +++ b/fs/nfs/internal.h > @@ -455,7 +455,6 @@ extern int nfs_wait_bit_killable(struct wait_bit_key *key, int mode); > > #if IS_ENABLED(CONFIG_NFS_LOCALIO) > /* localio.c */ > -extern void nfs_local_probe(struct nfs_client *); > extern void nfs_local_probe_async(struct nfs_client *); > extern void nfs_local_probe_async_work(struct work_struct *); > extern struct nfsd_file *nfs_local_open_fh(struct nfs_client *, > diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c > index 4ec952f9f47d..a4bacd9a5052 100644 > --- a/fs/nfs/localio.c > +++ b/fs/nfs/localio.c > @@ -171,7 +171,7 @@ static bool nfs_server_uuid_is_local(struct nfs_client *clp) > * - called after alloc_client and init_client (so cl_rpcclient exists) > * - this function is idempotent, it can be called for old or new clients > */ > -void nfs_local_probe(struct nfs_client *clp) > +static void nfs_local_probe(struct nfs_client *clp) > { > /* Disallow localio if disabled via sysfs or AUTH_SYS isn't used */ > if (!localio_enabled || > @@ -191,14 +191,16 @@ void nfs_local_probe(struct nfs_client *clp) > nfs_localio_enable_client(clp); > nfs_uuid_end(&clp->cl_uuid); > } > -EXPORT_SYMBOL_GPL(nfs_local_probe); > > void nfs_local_probe_async_work(struct work_struct *work) > { > struct nfs_client *clp = > container_of(work, struct nfs_client, cl_local_probe_work); > > + if (!refcount_inc_not_zero(&clp->cl_count)) > + return; > nfs_local_probe(clp); > + nfs_put_client(clp); > } > > void nfs_local_probe_async(struct nfs_client *clp) Reviewed-by: Jeff Layton <jlayton@xxxxxxxxxx>