From patchwork Fri Jun 7 14:26:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Snitzer X-Patchwork-Id: 13690160 Received: from mail-qv1-f45.google.com (mail-qv1-f45.google.com [209.85.219.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 38B0C19753E for ; Fri, 7 Jun 2024 14:27:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717770445; cv=none; b=RAV8SEku26ZCwO/AfrzLUtFlHIa1kF6qACMOotN6XDrjI17w/sIy9lei71FUnYLDOXGxR5rrHHXg+qHMxTpSuBQOqiMJpAzGTFULCt1yZajLHFUJdACv9hX7FLgmNkkJyHZifOFaRzjDl4ovK71ntKqQO8rQDSX3renEb0JfbXY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717770445; c=relaxed/simple; bh=t7A997fnvfAEdGwlWaTKDBLxE3tEhr26ZdIrlHjW1Kw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oiOuk6P/UeWVmGeaG1lIZi564WmznPSvqMp6w0wd54Oj+FYfJ6to7C1Z8R6NesSTq47dIXqi6Rucr3MVAjbLnmd5jXgVbRK7hkAQdvAuHikse8B5ShUcq//LqUfyemV2Tf1O8e3ayHfO9hCo1c9YD4GiPhCmfM5IOd0cTaFy/D4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=kernel.org; spf=none smtp.mailfrom=snitzer.net; arc=none smtp.client-ip=209.85.219.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=kernel.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=snitzer.net Received: by mail-qv1-f45.google.com with SMTP id 6a1803df08f44-6adc63c2ee0so8638266d6.3 for ; Fri, 07 Jun 2024 07:27:24 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717770443; x=1718375243; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=0SuI9qnbje9+RuZ3p/ZW9C8cIJrwGibWJDVRAtyf3Ws=; b=dhEvcnlJsROBkemBsr/8GCHCgnu9xfUiaC6t09Qe20FTP9xFg+s6m7UtUKsD9x5oAf u3GtRhQ1k+wY/AI1QJ3H7w+hFnUs4I1oe5qK8nI8Aatdhb/XOrTe6NwRxZ7oLopk/QZU Fx9dftWlSwEcr0t7d4SsNTW9oFtf0Llz80CkJTwwryjz5oRKD3pQZlINUMpXb3t9bSk7 b9alv6LpFLQsto77u2f9NFRFWlI0zbmi8PgROBXhhZa3mx4hvv3DS94mjSpJ2zGk2/Fb 9ZRyCZ03htHy1AKIKEyqKtrjAtGt/5eHdFCMPsx+wSXiugqqeGIu2WxZ7GfJA6jGDSPN 7keg== X-Gm-Message-State: AOJu0YwfLXegHvH3jiozszOiMrRgimP+NfkHLwcOG5TdijCCFUAZVCYc s1vLm34AV+3TssQwVjJI+7pCEfn23uInZiW1dhQ7aqptTG6eUj2B+ZLtLaBJC26/Ri6liUSnrXK RbBU= X-Google-Smtp-Source: AGHT+IG46qIppImUcGDXysFCHH7c0fOUJcs7kEkMmvqCxXFG7SzWDDasG+kukg4Na46TSUbzzsm7zg== X-Received: by 2002:a05:6214:2c0d:b0:6af:8067:e423 with SMTP id 6a1803df08f44-6b059b3747fmr35643046d6.5.1717770442748; Fri, 07 Jun 2024 07:27:22 -0700 (PDT) Received: from localhost (pool-68-160-141-91.bstnma.fios.verizon.net. [68.160.141.91]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-6b04f98499fsm17586276d6.80.2024.06.07.07.27.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Jun 2024 07:27:22 -0700 (PDT) From: Mike Snitzer To: linux-nfs@vger.kernel.org Cc: Jeff Layton , Chuck Lever , Trond Myklebust , snitzer@hammerspace.com Subject: [for-6.11 PATCH 22/29] nfs: implement v3 client support for NFS_LOCALIO_PROGRAM Date: Fri, 7 Jun 2024 10:26:39 -0400 Message-ID: <20240607142646.20924-23-snitzer@kernel.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240607142646.20924-1-snitzer@kernel.org> References: <20240607142646.20924-1-snitzer@kernel.org> Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 LOCALIOPROC_GETUUID allows client to discover server's uuid. nfs_local_probe() will retrieve server's uuid via LOCALIO protocol and verify the server with that uuid it is known to be local. This ensures client and server 1: support localio 2: are local to each other. Signed-off-by: Mike Snitzer --- fs/nfs/client.c | 10 +++++-- fs/nfs/localio.c | 62 +++++++++++++++++++++++++++++++++++---- fs/nfs/nfs3_fs.h | 1 + fs/nfs/nfs3client.c | 42 ++++++++++++++++++++++++++ fs/nfs/nfs3proc.c | 3 ++ fs/nfs/nfs3xdr.c | 58 ++++++++++++++++++++++++++++++++++++ include/linux/nfs_fs_sb.h | 1 + include/linux/nfs_xdr.h | 9 ++++++ include/uapi/linux/nfs.h | 4 +++ 9 files changed, 181 insertions(+), 9 deletions(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index c42faaed508c..589aeba8ccbb 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -170,7 +170,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) } INIT_LIST_HEAD(&clp->cl_superblocks); - clp->cl_rpcclient = ERR_PTR(-EINVAL); + clp->cl_rpcclient = clp->cl_rpcclient_localio = ERR_PTR(-EINVAL); clp->cl_flags = cl_init->init_flags; clp->cl_proto = cl_init->proto; @@ -241,6 +241,8 @@ void nfs_free_client(struct nfs_client *clp) /* -EIO all pending I/O */ if (!IS_ERR(clp->cl_rpcclient)) rpc_shutdown_client(clp->cl_rpcclient); + if (!IS_ERR(clp->cl_rpcclient_localio)) + rpc_shutdown_client(clp->cl_rpcclient_localio); put_net(clp->cl_net); put_nfs_version(clp->cl_nfs_mod); @@ -429,8 +431,10 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init) list_add_tail(&new->cl_share_link, &nn->nfs_client_list); spin_unlock(&nn->nfs_client_lock); - nfs_local_probe(new); - return rpc_ops->init_client(new, cl_init); + new = rpc_ops->init_client(new, cl_init); + if (!IS_ERR(new)) + nfs_local_probe(new); + return new; } spin_unlock(&nn->nfs_client_lock); diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c index 96349b6e7585..145708444998 100644 --- a/fs/nfs/localio.c +++ b/fs/nfs/localio.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -227,16 +228,65 @@ nfs_local_disable(struct nfs_client *clp) } } +static bool nfs_local_server_getuuid(struct nfs_client *clp, uuid_t *nfsd_uuid) +{ + u8 uuid[UUID_SIZE]; + struct nfs_getuuidres res = { + uuid, + }; + struct rpc_message msg = { + .rpc_resp = &res, + }; + int status; + + clp->rpc_ops->init_localioclient(clp); + if (IS_ERR(clp->cl_rpcclient_localio)) + return false; + + dprintk("%s: NFS issuing getuuid\n", __func__); + msg.rpc_proc = &clp->cl_rpcclient_localio->cl_procinfo[LOCALIOPROC_GETUUID]; + status = rpc_call_sync(clp->cl_rpcclient_localio, &msg, 0); + dprintk("%s: NFS reply getuuid: status=%d uuid=%pU uuid_len=%u\n", + __func__, status, res.uuid, res.len); + if (status || res.len != UUID_SIZE) + return false; + + import_uuid(nfsd_uuid, res.uuid); + + return true; +} + /* - * nfs_local_probe - probe local i/o support for an nfs_client + * nfs_local_probe - probe local i/o support for an nfs_server and nfs_client + * - called after alloc_client and init_client (so cl_rpcclient exists) */ -void -nfs_local_probe(struct nfs_client *clp) +void nfs_local_probe(struct nfs_client *clp) { - bool enable = false; + uuid_t uuid; - if (enable) - nfs_local_enable(clp); + if (!localio_enabled) + return; + + switch (clp->cl_rpcclient->cl_vers) { + case 3: + /* + * Retrieve server's uuid via LOCALIO protocol and verify the + * server with that uuid it is known to be local. This ensures + * client and server 1: support localio 2: are local to each other. + */ + if (!nfs_local_server_getuuid(clp, &uuid)) + return; + /* Verify client's nfsd, with specififed uuid, is local */ + if (!nfsd_uuid_is_local(&uuid)) + return; + break; + case 4: + default: + return; /* localio not supported */ + } + + dprintk("%s: detected local server.\n", __func__); + nfs_local_enable(clp); } EXPORT_SYMBOL_GPL(nfs_local_probe); diff --git a/fs/nfs/nfs3_fs.h b/fs/nfs/nfs3_fs.h index b333ea119ef5..efdf2b6519e9 100644 --- a/fs/nfs/nfs3_fs.h +++ b/fs/nfs/nfs3_fs.h @@ -30,6 +30,7 @@ static inline int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, struct nfs_server *nfs3_create_server(struct fs_context *); struct nfs_server *nfs3_clone_server(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, rpc_authflavor_t); +void nfs3_init_localioclient(struct nfs_client *); /* nfs3super.c */ extern struct nfs_subversion nfs_v3; diff --git a/fs/nfs/nfs3client.c b/fs/nfs/nfs3client.c index b0c8a39c2bbd..c41122ee808c 100644 --- a/fs/nfs/nfs3client.c +++ b/fs/nfs/nfs3client.c @@ -7,6 +7,8 @@ #include "netns.h" #include "sysfs.h" +#define NFSDBG_FACILITY NFSDBG_CLIENT + #ifdef CONFIG_NFS_V3_ACL static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program }; static const struct rpc_version *nfsacl_version[] = { @@ -130,3 +132,43 @@ struct nfs_client *nfs3_set_ds_client(struct nfs_server *mds_srv, return clp; } EXPORT_SYMBOL_GPL(nfs3_set_ds_client); + +#if defined(CONFIG_NFS_V3_LOCALIO) +static struct rpc_stat nfslocalio_rpcstat = { &nfslocalio_program3 }; +static const struct rpc_version *nfslocalio_version[] = { + [3] = &nfslocalio_version3, +}; + +const struct rpc_program nfslocalio_program3 = { + .name = "nfslocalio", + .number = NFS_LOCALIO_PROGRAM, + .nrvers = ARRAY_SIZE(nfslocalio_version), + .version = nfslocalio_version, + .stats = &nfslocalio_rpcstat, +}; + +/* + * Initialise an NFSv3 localio client connection + */ +void nfs3_init_localioclient(struct nfs_client *clp) +{ + if (unlikely(!IS_ERR(clp->cl_rpcclient_localio))) + goto out; + + clp->cl_rpcclient_localio = rpc_bind_new_program(clp->cl_rpcclient, + &nfslocalio_program3, 3); + if (IS_ERR(clp->cl_rpcclient_localio)) { + dprintk_rcu("%s: server (%s) does not support NFS v3 LOCALIO\n", __func__, + rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)); + return; + } +out: + /* No errors! Assume that localio is supported */ + dprintk_rcu("%s: server (%s) supports NFS v3 LOCALIO\n", __func__, + rpc_peeraddr2str(clp->cl_rpcclient_localio, RPC_DISPLAY_ADDR)); +} +#else +void nfs3_init_localioclient(struct nfs_client *clp) +{ +} +#endif /* CONFIG_NFS_V3_LOCALIO */ diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 74bda639a7cf..40b6e4d1e7be 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -1067,4 +1067,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = { .free_client = nfs_free_client, .create_server = nfs3_create_server, .clone_server = nfs3_clone_server, +#if defined(CONFIG_NFS_V3_LOCALIO) + .init_localioclient = nfs3_init_localioclient, +#endif }; diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 60f032be805a..49689a9a2111 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -2579,3 +2579,61 @@ const struct rpc_version nfsacl_version3 = { .counts = nfs3_acl_counts, }; #endif /* CONFIG_NFS_V3_ACL */ + +#if defined(CONFIG_NFS_V3_LOCALIO) + +#define LOCALIO3_getuuidres_sz (1+NFS3_filename_sz) + +static void nfs3_xdr_enc_getuuidargs(struct rpc_rqst *req, + struct xdr_stream *xdr, + const void *data) +{ + /* void function */ +} + +static inline int nfs3_decode_getuuidresok(struct xdr_stream *xdr, + struct nfs_getuuidres *result) +{ + return decode_inline_filename3(xdr, &result->uuid, &result->len); +} + +static int nfs3_xdr_dec_getuuidres(struct rpc_rqst *req, + struct xdr_stream *xdr, + void *result) +{ + enum nfs_stat status; + int error; + + error = decode_nfsstat3(xdr, &status); + if (unlikely(error)) + goto out; + if (status != NFS3_OK) + goto out_default; + error = nfs3_decode_getuuidresok(xdr, result); +out: + return error; +out_default: + return nfs3_stat_to_errno(status); +} + +static const struct rpc_procinfo nfs3_localio_procedures[] = { + [LOCALIOPROC_GETUUID] = { + .p_proc = LOCALIOPROC_GETUUID, + .p_encode = nfs3_xdr_enc_getuuidargs, + .p_decode = nfs3_xdr_dec_getuuidres, + .p_arglen = 1, + .p_replen = LOCALIO3_getuuidres_sz, + .p_timer = 0, + .p_name = "GETUUID", + }, +}; + +static unsigned int nfs3_localio_counts[ARRAY_SIZE(nfs3_localio_procedures)]; +const struct rpc_version nfslocalio_version3 = { + .number = 3, + .nrprocs = ARRAY_SIZE(nfs3_localio_procedures), + .procs = nfs3_localio_procedures, + .counts = nfs3_localio_counts, +}; + +#endif /* CONFIG_NFS_V3_LOCALIO */ diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 00fe469bc72e..efcdb4d8e9de 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -130,6 +130,7 @@ struct nfs_client { /* localio */ struct timespec64 cl_nfssvc_boot; seqlock_t cl_boot_lock; + struct rpc_clnt * cl_rpcclient_localio; /* localio RPC client handle */ }; /* diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 764513a61601..9a030e9bd9cf 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1002,6 +1002,11 @@ struct nfs3_getaclres { struct posix_acl * acl_default; }; +struct nfs_getuuidres { + const char * uuid; + unsigned int len; +}; + #if IS_ENABLED(CONFIG_NFS_V4) typedef u64 clientid4; @@ -1819,6 +1824,7 @@ struct nfs_rpc_ops { int (*discover_trunking)(struct nfs_server *, struct nfs_fh *); void (*enable_swap)(struct inode *inode); void (*disable_swap)(struct inode *inode); + void (*init_localioclient)(struct nfs_client *); }; /* @@ -1834,4 +1840,7 @@ extern const struct rpc_version nfs_version4; extern const struct rpc_version nfsacl_version3; extern const struct rpc_program nfsacl_program; +extern const struct rpc_version nfslocalio_version3; +extern const struct rpc_program nfslocalio_program3; + #endif diff --git a/include/uapi/linux/nfs.h b/include/uapi/linux/nfs.h index f356f2ba3814..e72f5564bdc0 100644 --- a/include/uapi/linux/nfs.h +++ b/include/uapi/linux/nfs.h @@ -33,6 +33,10 @@ #define NFS_MNT_VERSION 1 #define NFS_MNT3_VERSION 3 +#define NFS_LOCALIO_PROGRAM 100229 +#define LOCALIOPROC_NULL 0 +#define LOCALIOPROC_GETUUID 1 + #define NFS_PIPE_DIRNAME "nfs" /*