From patchwork Mon Apr 15 19:44:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 13630662 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E9E7415B54F; Mon, 15 Apr 2024 19:45:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713210311; cv=none; b=Ez2oXov68DUSqpZn/ePnMxZdVmmGBb3mJz6pQUnHccd6WJ2/DIdFFaprU31qmYnEWPYDiXdRJjo1hRybtjpqJ+769bJ0pptOr4Sg8xEimJ9J4H2ZUeRRowpEvDkJyAZHH9z8FVkfUR5XcIuR+Fkns3gwmvZwWeBZsHZ1EZUDiEY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713210311; c=relaxed/simple; bh=VeCGfQJrB1Z6yM2TCJpvnNTk1N6tpO2H3HeUgSVZWC0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MwhFzNGPLxqCFKxRokdvC+he5klwJgL4+E1jEDy00YWey+oDc/AJHEH2OVGbyYBv8I9sUh71zB6QdyLc4ecRNeG7av7MUyyQuymfUGV1iUiv9ybLXdQv9gAuelSMHtGP5iJuusmqJEXW+xXQvXeHOiqqXtIvFYbjU0JMtTTRvYU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=TUJc0mkx; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="TUJc0mkx" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 31D4BC113CC; Mon, 15 Apr 2024 19:45:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1713210310; bh=VeCGfQJrB1Z6yM2TCJpvnNTk1N6tpO2H3HeUgSVZWC0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TUJc0mkx9p7TA7/66cMoNEmPKNdCVvb/Pa7SSHg6zZCtHWHtiNXH25ZlU63fsfB0Y WRc3aE9X0ws/K7nD7h8kc1DOELWjdqypHpFJ6VrPkUrJJJl7JsW5IbJA09IVvZG04k DcGz3gzIyAW7slmvDUmFgvNVZvwi9Edgg2dVHVrKyM9pRwiw4pDQbAxUfV1AdrFjYm mxXAELYvNBdo45o5PsaXdd6+9oi/JH2ZNZ3n5dwgoCtvbSzDyxP7axYCjJXF/7xv1P kwsbBrwXMaBF8Stxe3zMX+r3TENYY5+4APWL3oWTya0ANpd8N0hDB/zvryueShDxXi 3AJBCcZfrcieA== From: Lorenzo Bianconi To: linux-nfs@vger.kernel.org Cc: lorenzo.bianconi@redhat.com, chuck.lever@oracle.com, neilb@suse.de, netdev@vger.kernel.org, kuba@kernel.org, jlayton@kernel.org Subject: [PATCH v8 1/6] nfsd: move nfsd_mutex handling into nfsd_svc callers Date: Mon, 15 Apr 2024 21:44:34 +0200 Message-ID: <2c5ff2829a27f29dd8a912fc9f62fbf214195e73.1713209938.git.lorenzo@kernel.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Jeff Layton Currently nfsd_svc holds the nfsd_mutex over the whole function. For some of the later netlink patches though, we want to do some other things to the server before starting it. Move the mutex handling into the callers. Signed-off-by: Jeff Layton Signed-off-by: Lorenzo Bianconi --- fs/nfsd/nfsctl.c | 2 ++ fs/nfsd/nfssvc.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 93c87587e646..f2e442d7fe16 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -406,7 +406,9 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) if (newthreads < 0) return -EINVAL; trace_nfsd_ctl_threads(net, newthreads); + mutex_lock(&nfsd_mutex); rv = nfsd_svc(newthreads, net, file->f_cred); + mutex_unlock(&nfsd_mutex); if (rv < 0) return rv; } else diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index c0d17b92b249..ca193f7ff0e1 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -775,7 +775,8 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred) struct nfsd_net *nn = net_generic(net, nfsd_net_id); struct svc_serv *serv; - mutex_lock(&nfsd_mutex); + lockdep_assert_held(&nfsd_mutex); + dprintk("nfsd: creating service\n"); nrservs = max(nrservs, 0); @@ -804,7 +805,6 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred) if (serv->sv_nrthreads == 0) nfsd_destroy_serv(net); out: - mutex_unlock(&nfsd_mutex); return error; } From patchwork Mon Apr 15 19:44:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 13630663 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8C29C156997; Mon, 15 Apr 2024 19:45:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713210314; cv=none; b=FhlgL4s2wG9yy7bAOpSlxpCjTcANugpVMxF1Jx49nprCDlQgFLfBkO6K+eZKO7fFpebZiRcpOlFKeZxFHeZSetw6+wohYNc5xLeReXbQTyEc78MliQEU5e6wkx1AVdvYFXDkIn8fvyynx1+CNLzMVouM6P907iOsEQ/U1iKhyEE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713210314; c=relaxed/simple; bh=c9appUypE9UwFM2sEKyJ8H+OyIHk9lowUrJlHVql6u0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iyqzQsiD9r9LikiMkWIvJ2JHLBq60WNT+wgt52hpPVEC52YqXA6F4Jysd44C/Rm8FqNFlj2sJ05XKWwQnrOaG4LpznnSma9Tp4bVzAskWW1FxXTGPs6OgIl/fvk0CLx7B6Jkj5h+Mgo5yk4PSJqO6OHFpyJk/gUNB2gdUc9XarQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WJJq0ioo; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="WJJq0ioo" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 03CF5C113CC; Mon, 15 Apr 2024 19:45:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1713210314; bh=c9appUypE9UwFM2sEKyJ8H+OyIHk9lowUrJlHVql6u0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WJJq0ioo7RTzKLMwDs6z06bd6imCptNi3cVb2fJVeRvW+PFB1MNIPNuIn57gj6TJI Xvbsk8rhJL/gNNgjDgy0zQXgOl7regZ5tb3BvYjaHFeXkJh/mAUwPNsUNC3ZrPnQpK kmwd9QP1eVgLyYanZ6/j3FDWabyiBkzs5pOWi1vzm36QMFO6VfguparZ3ZMm+odXHG Vn5EMDROfYpiFqDnBk/h0FPxU/kPmgvPnENjYJzEF79EG1JMSGSyGJ/S8LVnLnT7yQ 973cHRx+3AP6g13sDF8x92CtkWMLmQg5qshlv1RTUhW2iitS/cbqzIM8IWwMNmOuI+ mTYDL3EzseC1Q== From: Lorenzo Bianconi To: linux-nfs@vger.kernel.org Cc: lorenzo.bianconi@redhat.com, chuck.lever@oracle.com, neilb@suse.de, netdev@vger.kernel.org, kuba@kernel.org, jlayton@kernel.org Subject: [PATCH v8 2/6] NFSD: convert write_threads to netlink command Date: Mon, 15 Apr 2024 21:44:35 +0200 Message-ID: <4ff777ebb8652e31709bd91c3af50693edf86a26.1713209938.git.lorenzo@kernel.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Introduce write_threads netlink command similar to the one available through the procfs. Tested-by: Jeff Layton Reviewed-by: Jeff Layton Co-developed-by: Jeff Layton Signed-off-by: Jeff Layton Signed-off-by: Lorenzo Bianconi --- Documentation/netlink/specs/nfsd.yaml | 33 ++++++++ fs/nfsd/netlink.c | 19 +++++ fs/nfsd/netlink.h | 2 + fs/nfsd/nfsctl.c | 104 ++++++++++++++++++++++++++ include/uapi/linux/nfsd_netlink.h | 11 +++ 5 files changed, 169 insertions(+) diff --git a/Documentation/netlink/specs/nfsd.yaml b/Documentation/netlink/specs/nfsd.yaml index 05acc73e2e33..cbe6c5fd6c4d 100644 --- a/Documentation/netlink/specs/nfsd.yaml +++ b/Documentation/netlink/specs/nfsd.yaml @@ -62,6 +62,18 @@ attribute-sets: name: compound-ops type: u32 multi-attr: true + - + name: server-worker + attributes: + - + name: threads + type: u32 + - + name: gracetime + type: u32 + - + name: leasetime + type: u32 operations: list: @@ -87,3 +99,24 @@ operations: - sport - dport - compound-ops + - + name: threads-set + doc: set the number of running threads + attribute-set: server-worker + flags: [ admin-perm ] + do: + request: + attributes: + - threads + - gracetime + - leasetime + - + name: threads-get + doc: get the number of running threads + attribute-set: server-worker + do: + reply: + attributes: + - threads + - gracetime + - leasetime diff --git a/fs/nfsd/netlink.c b/fs/nfsd/netlink.c index 0e1d635ec5f9..20a646af0324 100644 --- a/fs/nfsd/netlink.c +++ b/fs/nfsd/netlink.c @@ -10,6 +10,13 @@ #include +/* NFSD_CMD_THREADS_SET - do */ +static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_WORKER_LEASETIME + 1] = { + [NFSD_A_SERVER_WORKER_THREADS] = { .type = NLA_U32, }, + [NFSD_A_SERVER_WORKER_GRACETIME] = { .type = NLA_U32, }, + [NFSD_A_SERVER_WORKER_LEASETIME] = { .type = NLA_U32, }, +}; + /* Ops table for nfsd */ static const struct genl_split_ops nfsd_nl_ops[] = { { @@ -19,6 +26,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = { .done = nfsd_nl_rpc_status_get_done, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = NFSD_CMD_THREADS_SET, + .doit = nfsd_nl_threads_set_doit, + .policy = nfsd_threads_set_nl_policy, + .maxattr = NFSD_A_SERVER_WORKER_LEASETIME, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = NFSD_CMD_THREADS_GET, + .doit = nfsd_nl_threads_get_doit, + .flags = GENL_CMD_CAP_DO, + }, }; struct genl_family nfsd_nl_family __ro_after_init = { diff --git a/fs/nfsd/netlink.h b/fs/nfsd/netlink.h index d83dd6bdee92..4137fac477e4 100644 --- a/fs/nfsd/netlink.h +++ b/fs/nfsd/netlink.h @@ -16,6 +16,8 @@ int nfsd_nl_rpc_status_get_done(struct netlink_callback *cb); int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info); +int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info); extern struct genl_family nfsd_nl_family; diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index f2e442d7fe16..38a5df03981b 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1653,6 +1653,110 @@ int nfsd_nl_rpc_status_get_done(struct netlink_callback *cb) return 0; } +/** + * nfsd_nl_threads_set_doit - set the number of running threads + * @skb: reply buffer + * @info: netlink metadata and command arguments + * + * Return 0 on success or a negative errno. + */ +int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info) +{ + struct net *net = genl_info_net(info); + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + int ret = -EBUSY; + u32 nthreads; + + if (GENL_REQ_ATTR_CHECK(info, NFSD_A_SERVER_WORKER_THREADS)) + return -EINVAL; + + nthreads = nla_get_u32(info->attrs[NFSD_A_SERVER_WORKER_THREADS]); + + mutex_lock(&nfsd_mutex); + if (info->attrs[NFSD_A_SERVER_WORKER_GRACETIME] || + info->attrs[NFSD_A_SERVER_WORKER_LEASETIME]) { + const struct nlattr *attr; + + if (nn->nfsd_serv && nn->nfsd_serv->sv_nrthreads) + goto out_unlock; + + ret = -EINVAL; + attr = info->attrs[NFSD_A_SERVER_WORKER_GRACETIME]; + if (attr) { + u32 gracetime = nla_get_u32(attr); + + if (gracetime < 10 || gracetime > 3600) + goto out_unlock; + + nn->nfsd4_grace = gracetime; + } + + attr = info->attrs[NFSD_A_SERVER_WORKER_LEASETIME]; + if (attr) { + u32 leasetime = nla_get_u32(attr); + + if (leasetime < 10 || leasetime > 3600) + goto out_unlock; + + nn->nfsd4_lease = leasetime; + } + } + + ret = nfsd_svc(nthreads, net, get_current_cred()); +out_unlock: + mutex_unlock(&nfsd_mutex); + + return ret == nthreads ? 0 : ret; +} + +/** + * nfsd_nl_threads_get_doit - get the number of running threads + * @skb: reply buffer + * @info: netlink metadata and command arguments + * + * Return 0 on success or a negative errno. + */ +int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info) +{ + struct net *net = genl_info_net(info); + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + void *hdr; + int err; + + skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + hdr = genlmsg_iput(skb, info); + if (!hdr) { + err = -EMSGSIZE; + goto err_free_msg; + } + + mutex_lock(&nfsd_mutex); + err = nla_put_u32(skb, NFSD_A_SERVER_WORKER_GRACETIME, + nn->nfsd4_grace) || + nla_put_u32(skb, NFSD_A_SERVER_WORKER_LEASETIME, + nn->nfsd4_lease) || + nla_put_u32(skb, NFSD_A_SERVER_WORKER_THREADS, + nn->nfsd_serv ? nn->nfsd_serv->sv_nrthreads : 0); + mutex_unlock(&nfsd_mutex); + + if (err) { + err = -EINVAL; + goto err_free_msg; + } + + genlmsg_end(skb, hdr); + + return genlmsg_reply(skb, info); + +err_free_msg: + nlmsg_free(skb); + + return err; +} + /** * nfsd_net_init - Prepare the nfsd_net portion of a new net namespace * @net: a freshly-created network namespace diff --git a/include/uapi/linux/nfsd_netlink.h b/include/uapi/linux/nfsd_netlink.h index 3cd044edee5d..ccc78a5ee650 100644 --- a/include/uapi/linux/nfsd_netlink.h +++ b/include/uapi/linux/nfsd_netlink.h @@ -29,8 +29,19 @@ enum { NFSD_A_RPC_STATUS_MAX = (__NFSD_A_RPC_STATUS_MAX - 1) }; +enum { + NFSD_A_SERVER_WORKER_THREADS = 1, + NFSD_A_SERVER_WORKER_GRACETIME, + NFSD_A_SERVER_WORKER_LEASETIME, + + __NFSD_A_SERVER_WORKER_MAX, + NFSD_A_SERVER_WORKER_MAX = (__NFSD_A_SERVER_WORKER_MAX - 1) +}; + enum { NFSD_CMD_RPC_STATUS_GET = 1, + NFSD_CMD_THREADS_SET, + NFSD_CMD_THREADS_GET, __NFSD_CMD_MAX, NFSD_CMD_MAX = (__NFSD_CMD_MAX - 1) From patchwork Mon Apr 15 19:44:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 13630664 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 128DA156997; Mon, 15 Apr 2024 19:45:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713210318; cv=none; b=MW2GoB+O+4oVl5Mk8Pm4XS0b5xrBGxbncWq/cFiic1kmL+KUZv5msdNGYETZCDDOtpevVXgpDQcMG04A2QELyrZnYk1VQEcV3b7kNhgfcs+2W+FKxsR37ShrO44NmisV1qT4wVg9pMGGGvQlNNd9LbewxP3Lwn5ZQ8by/wycL0I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713210318; c=relaxed/simple; bh=7XQ+0gdAhPhCGjjejaaS2vBfsMxwcog45cQabMq/kyc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eKW3+MYK4YFykmuzdHwRbuWj3PU06NnAfmxQoRoba/baYzT+jtmZgHpfOxc+Y3/iX9gl55pjLNa6UvP8oSqVVknh8qh0e+0Di3STP/SWcQo9jLha19b4EKUF7bDPwkaeAMOrlxqpP0rqXsGYDj2j7g39/CQHpMJcY5W3/5m/8cg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=K+tTi46M; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="K+tTi46M" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9376AC113CC; Mon, 15 Apr 2024 19:45:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1713210317; bh=7XQ+0gdAhPhCGjjejaaS2vBfsMxwcog45cQabMq/kyc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=K+tTi46MwcFcHkbjmGCZ4kunl1xHjFxR3tHH0fyjpXkeYhuhL626Tj0JnskBsf35H 7P0jbN2oP1snTJtJp1BACbu2f1yIfqdMjKYpfllHY2n6+sh0goYCi8agNEtKxOBvki yVi9mGl/PD7dbPaj/9hhEpTBbdz7EG2kwf/yo6lM5daqC7znbSdhsczFxKpkh4CL3E FrR41Bc9C1Lq6fhYkIzOB9KTLIBsr8fPYGh1vhOBLD1MlhNIhX0iZRUglmeJze4Ydc ugPi5sbgP2+eoZrDfhkFy6RyerwyxfA+Y67teDotdbJqaTd/3/DifMcH3B+nR9Gxqn j5TB2sYZkNogQ== From: Lorenzo Bianconi To: linux-nfs@vger.kernel.org Cc: lorenzo.bianconi@redhat.com, chuck.lever@oracle.com, neilb@suse.de, netdev@vger.kernel.org, kuba@kernel.org, jlayton@kernel.org Subject: [PATCH v8 3/6] NFSD: add write_version to netlink command Date: Mon, 15 Apr 2024 21:44:36 +0200 Message-ID: <1036367642228283184f85715edc0e3227a8e3ae.1713209938.git.lorenzo@kernel.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Introduce write_version netlink command through a "declarative" interface. This patch introduces a change in behavior since for version-set userspace is expected to provide a NFS major/minor version list it wants to enable while all the other ones will be disabled. (procfs write_version command implements imperative interface where the admin writes +3/-3 to enable/disable a single version. Reviewed-by: Jeff Layton Tested-by: Jeff Layton Signed-off-by: Lorenzo Bianconi --- Documentation/netlink/specs/nfsd.yaml | 37 +++++++ fs/nfsd/netlink.c | 24 +++++ fs/nfsd/netlink.h | 5 + fs/nfsd/netns.h | 1 + fs/nfsd/nfsctl.c | 150 ++++++++++++++++++++++++++ fs/nfsd/nfssvc.c | 3 +- include/uapi/linux/nfsd_netlink.h | 18 ++++ 7 files changed, 236 insertions(+), 2 deletions(-) diff --git a/Documentation/netlink/specs/nfsd.yaml b/Documentation/netlink/specs/nfsd.yaml index cbe6c5fd6c4d..0396e8b3ea1f 100644 --- a/Documentation/netlink/specs/nfsd.yaml +++ b/Documentation/netlink/specs/nfsd.yaml @@ -74,6 +74,26 @@ attribute-sets: - name: leasetime type: u32 + - + name: version + attributes: + - + name: major + type: u32 + - + name: minor + type: u32 + - + name: enabled + type: flag + - + name: server-proto + attributes: + - + name: version + type: nest + nested-attributes: version + multi-attr: true operations: list: @@ -120,3 +140,20 @@ operations: - threads - gracetime - leasetime + - + name: version-set + doc: set nfs enabled versions + attribute-set: server-proto + flags: [ admin-perm ] + do: + request: + attributes: + - version + - + name: version-get + doc: get nfs enabled versions + attribute-set: server-proto + do: + reply: + attributes: + - version diff --git a/fs/nfsd/netlink.c b/fs/nfsd/netlink.c index 20a646af0324..bf5df9597288 100644 --- a/fs/nfsd/netlink.c +++ b/fs/nfsd/netlink.c @@ -10,6 +10,13 @@ #include +/* Common nested types */ +const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1] = { + [NFSD_A_VERSION_MAJOR] = { .type = NLA_U32, }, + [NFSD_A_VERSION_MINOR] = { .type = NLA_U32, }, + [NFSD_A_VERSION_ENABLED] = { .type = NLA_FLAG, }, +}; + /* NFSD_CMD_THREADS_SET - do */ static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_WORKER_LEASETIME + 1] = { [NFSD_A_SERVER_WORKER_THREADS] = { .type = NLA_U32, }, @@ -17,6 +24,11 @@ static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_WORKER_L [NFSD_A_SERVER_WORKER_LEASETIME] = { .type = NLA_U32, }, }; +/* NFSD_CMD_VERSION_SET - do */ +static const struct nla_policy nfsd_version_set_nl_policy[NFSD_A_SERVER_PROTO_VERSION + 1] = { + [NFSD_A_SERVER_PROTO_VERSION] = NLA_POLICY_NESTED(nfsd_version_nl_policy), +}; + /* Ops table for nfsd */ static const struct genl_split_ops nfsd_nl_ops[] = { { @@ -38,6 +50,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = { .doit = nfsd_nl_threads_get_doit, .flags = GENL_CMD_CAP_DO, }, + { + .cmd = NFSD_CMD_VERSION_SET, + .doit = nfsd_nl_version_set_doit, + .policy = nfsd_version_set_nl_policy, + .maxattr = NFSD_A_SERVER_PROTO_VERSION, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = NFSD_CMD_VERSION_GET, + .doit = nfsd_nl_version_get_doit, + .flags = GENL_CMD_CAP_DO, + }, }; struct genl_family nfsd_nl_family __ro_after_init = { diff --git a/fs/nfsd/netlink.h b/fs/nfsd/netlink.h index 4137fac477e4..c7c0da275481 100644 --- a/fs/nfsd/netlink.h +++ b/fs/nfsd/netlink.h @@ -11,6 +11,9 @@ #include +/* Common nested types */ +extern const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1]; + int nfsd_nl_rpc_status_get_start(struct netlink_callback *cb); int nfsd_nl_rpc_status_get_done(struct netlink_callback *cb); @@ -18,6 +21,8 @@ int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info); int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info); +int nfsd_nl_version_set_doit(struct sk_buff *skb, struct genl_info *info); +int nfsd_nl_version_get_doit(struct sk_buff *skb, struct genl_info *info); extern struct genl_family nfsd_nl_family; diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index d4be519b5734..14ec15656320 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -218,6 +218,7 @@ struct nfsd_net { /* Simple check to find out if a given net was properly initialized */ #define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl) +extern bool nfsd_support_version(int vers); extern void nfsd_netns_free_versions(struct nfsd_net *nn); extern unsigned int nfsd_net_id; diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 38a5df03981b..2c8929ef79e9 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1757,6 +1757,156 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info) return err; } +/** + * nfsd_nl_version_set_doit - set the nfs enabled versions + * @skb: reply buffer + * @info: netlink metadata and command arguments + * + * Return 0 on success or a negative errno. + */ +int nfsd_nl_version_set_doit(struct sk_buff *skb, struct genl_info *info) +{ + const struct nlattr *attr; + struct nfsd_net *nn; + int i, rem; + + if (GENL_REQ_ATTR_CHECK(info, NFSD_A_SERVER_PROTO_VERSION)) + return -EINVAL; + + mutex_lock(&nfsd_mutex); + + nn = net_generic(genl_info_net(info), nfsd_net_id); + if (nn->nfsd_serv) { + mutex_unlock(&nfsd_mutex); + return -EBUSY; + } + + /* clear current supported versions. */ + nfsd_vers(nn, 2, NFSD_CLEAR); + nfsd_vers(nn, 3, NFSD_CLEAR); + for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++) + nfsd_minorversion(nn, i, NFSD_CLEAR); + + nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) { + struct nlattr *tb[NFSD_A_VERSION_MAX + 1]; + u32 major, minor = 0; + bool enabled; + + if (nla_type(attr) != NFSD_A_SERVER_PROTO_VERSION) + continue; + + if (nla_parse_nested(tb, NFSD_A_VERSION_MAX, attr, + nfsd_version_nl_policy, info->extack) < 0) + continue; + + if (!tb[NFSD_A_VERSION_MAJOR]) + continue; + + major = nla_get_u32(tb[NFSD_A_VERSION_MAJOR]); + if (tb[NFSD_A_VERSION_MINOR]) + minor = nla_get_u32(tb[NFSD_A_VERSION_MINOR]); + + enabled = nla_get_flag(tb[NFSD_A_VERSION_ENABLED]); + + switch (major) { + case 4: + nfsd_minorversion(nn, minor, enabled ? NFSD_SET : NFSD_CLEAR); + break; + case 3: + case 2: + if (!minor) + nfsd_vers(nn, major, enabled ? NFSD_SET : NFSD_CLEAR); + break; + default: + break; + } + } + + mutex_unlock(&nfsd_mutex); + + return 0; +} + +/** + * nfsd_nl_version_get_doit - get the nfs enabled versions + * @skb: reply buffer + * @info: netlink metadata and command arguments + * + * Return 0 on success or a negative errno. + */ +int nfsd_nl_version_get_doit(struct sk_buff *skb, struct genl_info *info) +{ + struct nfsd_net *nn; + int i, err; + void *hdr; + + skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + hdr = genlmsg_iput(skb, info); + if (!hdr) { + err = -EMSGSIZE; + goto err_free_msg; + } + + mutex_lock(&nfsd_mutex); + nn = net_generic(genl_info_net(info), nfsd_net_id); + + for (i = 2; i <= 4; i++) { + int j; + + for (j = 0; j <= NFSD_SUPPORTED_MINOR_VERSION; j++) { + struct nlattr *attr; + + /* Don't record any versions the kernel doesn't have + * compiled in + */ + if (!nfsd_support_version(i)) + continue; + + /* NFSv{2,3} does not support minor numbers */ + if (i < 4 && j) + continue; + + attr = nla_nest_start(skb, + NFSD_A_SERVER_PROTO_VERSION); + if (!attr) { + err = -EINVAL; + goto err_nfsd_unlock; + } + + if (nla_put_u32(skb, NFSD_A_VERSION_MAJOR, i) || + nla_put_u32(skb, NFSD_A_VERSION_MINOR, j)) { + err = -EINVAL; + goto err_nfsd_unlock; + } + + /* Set the enabled flag if the version is enabled */ + if (nfsd_vers(nn, i, NFSD_TEST) && + (i < 4 || nfsd_minorversion(nn, j, NFSD_TEST)) && + nla_put_flag(skb, NFSD_A_VERSION_ENABLED)) { + err = -EINVAL; + goto err_nfsd_unlock; + } + + nla_nest_end(skb, attr); + } + } + + mutex_unlock(&nfsd_mutex); + genlmsg_end(skb, hdr); + + return genlmsg_reply(skb, info); + +err_nfsd_unlock: + mutex_unlock(&nfsd_mutex); +err_free_msg: + nlmsg_free(skb); + + return err; +} + /** * nfsd_net_init - Prepare the nfsd_net portion of a new net namespace * @net: a freshly-created network namespace diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index ca193f7ff0e1..4fc91f50138a 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -133,8 +133,7 @@ struct svc_program nfsd_program = { .pg_rpcbind_set = nfsd_rpcbind_set, }; -static bool -nfsd_support_version(int vers) +bool nfsd_support_version(int vers) { if (vers >= NFSD_MINVERS && vers < NFSD_NRVERS) return nfsd_version[vers] != NULL; diff --git a/include/uapi/linux/nfsd_netlink.h b/include/uapi/linux/nfsd_netlink.h index ccc78a5ee650..8a0a2b344923 100644 --- a/include/uapi/linux/nfsd_netlink.h +++ b/include/uapi/linux/nfsd_netlink.h @@ -38,10 +38,28 @@ enum { NFSD_A_SERVER_WORKER_MAX = (__NFSD_A_SERVER_WORKER_MAX - 1) }; +enum { + NFSD_A_VERSION_MAJOR = 1, + NFSD_A_VERSION_MINOR, + NFSD_A_VERSION_ENABLED, + + __NFSD_A_VERSION_MAX, + NFSD_A_VERSION_MAX = (__NFSD_A_VERSION_MAX - 1) +}; + +enum { + NFSD_A_SERVER_PROTO_VERSION = 1, + + __NFSD_A_SERVER_PROTO_MAX, + NFSD_A_SERVER_PROTO_MAX = (__NFSD_A_SERVER_PROTO_MAX - 1) +}; + enum { NFSD_CMD_RPC_STATUS_GET = 1, NFSD_CMD_THREADS_SET, NFSD_CMD_THREADS_GET, + NFSD_CMD_VERSION_SET, + NFSD_CMD_VERSION_GET, __NFSD_CMD_MAX, NFSD_CMD_MAX = (__NFSD_CMD_MAX - 1) From patchwork Mon Apr 15 19:44:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 13630665 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 238B315B987; Mon, 15 Apr 2024 19:45:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713210322; cv=none; b=fRA6aBgeJmeC5oYdSB3nWwWTbcAJXBzbjt4/IB1RQqqIJLaIYptvym5hZAoIkDIDqTV/NSDcosc+FdRFe3DrLLMd5y/tpeW8E/mF2wta1rDuZCu5KrTqi32BYTjNDk37xhy+z+yfY1j7PSD5qXCQ/MaWLohR6QZl0+Gw9Hqj2ew= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713210322; c=relaxed/simple; bh=/DTZXF8udDvRjKg2a8s3S2ZTaSHcPM7bxXD0dLq6SFs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SqdwwgmQbS0y46E6kUiYFQQmu04LUfd+KAK4jgE06PTge436aGgldZof7BMHmugRTEZWJ/JMpZdJN50RMWuNidYlO/MuftcKbPXQRNP9p9kO2yj3c+4GqMGrDwTYS1e+ZPVNLa93yh9wntu5ftWjF/Kph3l0ZJeb4Rl2y7qDLWI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FQa5E2Lj; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="FQa5E2Lj" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6BDCEC113CC; Mon, 15 Apr 2024 19:45:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1713210321; bh=/DTZXF8udDvRjKg2a8s3S2ZTaSHcPM7bxXD0dLq6SFs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FQa5E2Lji6HHbdrBWGvxWqSI6Wo0gr+xZj6HSI/7SK5t1PI7JFXLji1VGtnqbsioC wMZxFnq970z1qRjQKRqMofTJ0LNePcY+xJBhYScLBN7MBJq6yLPgjVbKGJCGIg+8zu p5wtlg103x6NAx3e87Fx8Lhs+WkVzFVjKG8hqA7zo2z3D9CKf3dw5za55h1W6nhc1d zg+OM4p+asEvf5jur0/D4hwfa21Em0pNGzeH5173KstWrRYiEpW1mUt1Iew+2MKVkS u8Edi/Oxlf+SFlicjzPlNztMnJP3Yro75Wyaf9UstN8MCtp8F4mW2vkdzs4H/01AoQ epmEKr+jkVUhw== From: Lorenzo Bianconi To: linux-nfs@vger.kernel.org Cc: lorenzo.bianconi@redhat.com, chuck.lever@oracle.com, neilb@suse.de, netdev@vger.kernel.org, kuba@kernel.org, jlayton@kernel.org Subject: [PATCH v8 4/6] SUNRPC: introduce svc_xprt_create_from_sa utility routine Date: Mon, 15 Apr 2024 21:44:37 +0200 Message-ID: X-Mailer: git-send-email 2.44.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add svc_xprt_create_from_sa utility routine and refactor svc_xprt_create() codebase in order to introduce the capability to create a svc port from socket address. Reviewed-by: Jeff Layton Tested-by: Jeff Layton Signed-off-by: Lorenzo Bianconi --- include/linux/sunrpc/svc_xprt.h | 3 + net/sunrpc/svc_xprt.c | 133 ++++++++++++++++++-------------- 2 files changed, 78 insertions(+), 58 deletions(-) diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index 8e20cd60e2e7..0d9b10dbe07d 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -135,6 +135,9 @@ int svc_reg_xprt_class(struct svc_xprt_class *); void svc_unreg_xprt_class(struct svc_xprt_class *); void svc_xprt_init(struct net *, struct svc_xprt_class *, struct svc_xprt *, struct svc_serv *); +int svc_xprt_create_from_sa(struct svc_serv *serv, const char *xprt_name, + struct net *net, struct sockaddr *sap, + int flags, const struct cred *cred); int svc_xprt_create(struct svc_serv *serv, const char *xprt_name, struct net *net, const int family, const unsigned short port, int flags, diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index b4a85a227bd7..463fe544ae28 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -211,51 +211,6 @@ void svc_xprt_init(struct net *net, struct svc_xprt_class *xcl, } EXPORT_SYMBOL_GPL(svc_xprt_init); -static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl, - struct svc_serv *serv, - struct net *net, - const int family, - const unsigned short port, - int flags) -{ - struct sockaddr_in sin = { - .sin_family = AF_INET, - .sin_addr.s_addr = htonl(INADDR_ANY), - .sin_port = htons(port), - }; -#if IS_ENABLED(CONFIG_IPV6) - struct sockaddr_in6 sin6 = { - .sin6_family = AF_INET6, - .sin6_addr = IN6ADDR_ANY_INIT, - .sin6_port = htons(port), - }; -#endif - struct svc_xprt *xprt; - struct sockaddr *sap; - size_t len; - - switch (family) { - case PF_INET: - sap = (struct sockaddr *)&sin; - len = sizeof(sin); - break; -#if IS_ENABLED(CONFIG_IPV6) - case PF_INET6: - sap = (struct sockaddr *)&sin6; - len = sizeof(sin6); - break; -#endif - default: - return ERR_PTR(-EAFNOSUPPORT); - } - - xprt = xcl->xcl_ops->xpo_create(serv, net, sap, len, flags); - if (IS_ERR(xprt)) - trace_svc_xprt_create_err(serv->sv_program->pg_name, - xcl->xcl_name, sap, len, xprt); - return xprt; -} - /** * svc_xprt_received - start next receiver thread * @xprt: controlling transport @@ -294,9 +249,8 @@ void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *new) } static int _svc_xprt_create(struct svc_serv *serv, const char *xprt_name, - struct net *net, const int family, - const unsigned short port, int flags, - const struct cred *cred) + struct net *net, struct sockaddr *sap, + size_t len, int flags, const struct cred *cred) { struct svc_xprt_class *xcl; @@ -312,8 +266,11 @@ static int _svc_xprt_create(struct svc_serv *serv, const char *xprt_name, goto err; spin_unlock(&svc_xprt_class_lock); - newxprt = __svc_xpo_create(xcl, serv, net, family, port, flags); + newxprt = xcl->xcl_ops->xpo_create(serv, net, sap, len, flags); if (IS_ERR(newxprt)) { + trace_svc_xprt_create_err(serv->sv_program->pg_name, + xcl->xcl_name, sap, len, + newxprt); module_put(xcl->xcl_owner); return PTR_ERR(newxprt); } @@ -329,6 +286,48 @@ static int _svc_xprt_create(struct svc_serv *serv, const char *xprt_name, return -EPROTONOSUPPORT; } +/** + * svc_xprt_create_from_sa - Add a new listener to @serv from socket address + * @serv: target RPC service + * @xprt_name: transport class name + * @net: network namespace + * @sap: socket address pointer + * @flags: SVC_SOCK flags + * @cred: credential to bind to this transport + * + * Return local xprt port on success or %-EPROTONOSUPPORT on failure + */ +int svc_xprt_create_from_sa(struct svc_serv *serv, const char *xprt_name, + struct net *net, struct sockaddr *sap, + int flags, const struct cred *cred) +{ + size_t len; + int err; + + switch (sap->sa_family) { + case AF_INET: + len = sizeof(struct sockaddr_in); + break; +#if IS_ENABLED(CONFIG_IPV6) + case AF_INET6: + len = sizeof(struct sockaddr_in6); + break; +#endif + default: + return -EAFNOSUPPORT; + } + + err = _svc_xprt_create(serv, xprt_name, net, sap, len, flags, cred); + if (err == -EPROTONOSUPPORT) { + request_module("svc%s", xprt_name); + err = _svc_xprt_create(serv, xprt_name, net, sap, len, flags, + cred); + } + + return err; +} +EXPORT_SYMBOL_GPL(svc_xprt_create_from_sa); + /** * svc_xprt_create - Add a new listener to @serv * @serv: target RPC service @@ -339,23 +338,41 @@ static int _svc_xprt_create(struct svc_serv *serv, const char *xprt_name, * @flags: SVC_SOCK flags * @cred: credential to bind to this transport * - * Return values: - * %0: New listener added successfully - * %-EPROTONOSUPPORT: Requested transport type not supported + * Return local xprt port on success or %-EPROTONOSUPPORT on failure */ int svc_xprt_create(struct svc_serv *serv, const char *xprt_name, struct net *net, const int family, const unsigned short port, int flags, const struct cred *cred) { - int err; + struct sockaddr_in sin = { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl(INADDR_ANY), + .sin_port = htons(port), + }; +#if IS_ENABLED(CONFIG_IPV6) + struct sockaddr_in6 sin6 = { + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_ANY_INIT, + .sin6_port = htons(port), + }; +#endif + struct sockaddr *sap; - err = _svc_xprt_create(serv, xprt_name, net, family, port, flags, cred); - if (err == -EPROTONOSUPPORT) { - request_module("svc%s", xprt_name); - err = _svc_xprt_create(serv, xprt_name, net, family, port, flags, cred); + switch (family) { + case PF_INET: + sap = (struct sockaddr *)&sin; + break; +#if IS_ENABLED(CONFIG_IPV6) + case PF_INET6: + sap = (struct sockaddr *)&sin6; + break; +#endif + default: + return -EAFNOSUPPORT; } - return err; + + return svc_xprt_create_from_sa(serv, xprt_name, net, sap, flags, cred); } EXPORT_SYMBOL_GPL(svc_xprt_create); From patchwork Mon Apr 15 19:44:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 13630666 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 09A16156997; Mon, 15 Apr 2024 19:45:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713210326; cv=none; b=H5PXCkLj+KsmVrBATsPBJpMB0AuINZJku8FPHUaZnvK5waUV6LuXkav5+CTrBhzqYpviF5OeGhxycTRv+IOS3XH4Yk6ecUItPqcWnHDYtJdWLth+KHDGdXqA2FXY2Y/8cZy9uBxXtnLXbS6CIVLT31/YB5UPIgGHvBph4IK08FM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713210326; c=relaxed/simple; bh=u1MIVeEB9jfAKl7VCceRlD6fHf4D2LjW0+JisF5Qw84=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=F66ieZmnDgic+dia3BOaKpQUFVhDkot4znxIgNm0tBu/CMcixI2xuIaTu0JP/us80glBdf3dyw6xI7LLEamv1YM6KpOuKAhU9/z5OB9DtXRMbUMnd6OCa2R3oFDBmIxlldeUYZqbUJlmm+cc4Fp8mFeBmjKGiuseQPmt2u7ACAU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=uL1Qbw7D; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="uL1Qbw7D" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 498B4C113CC; Mon, 15 Apr 2024 19:45:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1713210325; bh=u1MIVeEB9jfAKl7VCceRlD6fHf4D2LjW0+JisF5Qw84=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uL1Qbw7D1Ia+IrOBHTci395fidsVWuJjfGeonpHEzyZ3NRvrMEjcArQ+Zcmt8Mndj dnOUpe1dGyejwQNj5FkJ/9HXWovplf8YNvrqvLNLpurnHOA9THB6vChlY8+58tiT7D FPcTDbFIF7q86zljCqIXy8qF73S7Z9beeldMo8IG8jDfwIRAq5GYWMDnXS7yYe81X1 LDsrIRuMKxzmOi4M/7jS+CAGNCP7aBTuQz18u+7cCaD5K8cve4xSVbkVgdIxYRG81S JtXrarU1mVpJCjfcRuvJVq8efITN4x+0HCiQxDIPoTrB4+6xYSqdwseqcyiVndf2cR LUJAQR61G5MDg== From: Lorenzo Bianconi To: linux-nfs@vger.kernel.org Cc: lorenzo.bianconi@redhat.com, chuck.lever@oracle.com, neilb@suse.de, netdev@vger.kernel.org, kuba@kernel.org, jlayton@kernel.org Subject: [PATCH v8 5/6] SUNRPC: add a new svc_find_listener helper Date: Mon, 15 Apr 2024 21:44:38 +0200 Message-ID: <00d60d4fb200e4d9762a03d0b561a61e92c7b071.1713209938.git.lorenzo@kernel.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Jeff Layton svc_find_listener will return the transport instance pointer for the endpoint accepting connections/peer traffic from the specified transport class, and matching sockaddr. Signed-off-by: Jeff Layton Signed-off-by: Lorenzo Bianconi --- include/linux/sunrpc/svc_xprt.h | 2 ++ net/sunrpc/svc_xprt.c | 34 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index 0d9b10dbe07d..0981e35a9fed 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -150,6 +150,8 @@ void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt); void svc_xprt_close(struct svc_xprt *xprt); int svc_port_is_privileged(struct sockaddr *sin); int svc_print_xprts(char *buf, int maxlen); +struct svc_xprt *svc_find_listener(struct svc_serv *serv, const char *xcl_name, + struct net *net, const struct sockaddr *sa); struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, struct net *net, const sa_family_t af, const unsigned short port); diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 463fe544ae28..34a3626c56b1 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -1276,6 +1276,40 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt) return dr; } +/** + * svc_find_listener - find an RPC transport instance + * @serv: pointer to svc_serv to search + * @xcl_name: C string containing transport's class name + * @net: owner net pointer + * @sa: sockaddr containing address + * + * Return the transport instance pointer for the endpoint accepting + * connections/peer traffic from the specified transport class, + * and matching sockaddr. + */ +struct svc_xprt *svc_find_listener(struct svc_serv *serv, const char *xcl_name, + struct net *net, const struct sockaddr *sa) +{ + struct svc_xprt *xprt; + struct svc_xprt *found = NULL; + + spin_lock_bh(&serv->sv_lock); + list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) { + if (xprt->xpt_net != net) + continue; + if (strcmp(xprt->xpt_class->xcl_name, xcl_name)) + continue; + if (!rpc_cmp_addr_port(sa, (struct sockaddr *)&xprt->xpt_local)) + continue; + found = xprt; + svc_xprt_get(xprt); + break; + } + spin_unlock_bh(&serv->sv_lock); + return found; +} +EXPORT_SYMBOL_GPL(svc_find_listener); + /** * svc_find_xprt - find an RPC transport instance * @serv: pointer to svc_serv to search From patchwork Mon Apr 15 19:44:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 13630667 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A7ECF156997; Mon, 15 Apr 2024 19:45:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713210329; cv=none; b=apRYSgPvOQ9tPcMW3zswvA11+S3gJ2cCJQTfJg23dGeUu7KorHyZTeQL2q5bWAH1vajDmXfFn+4UW7ERImBS+h7XNEU3ldzDHuJOBuOTb/xlO0G5rT9/VagFHs0dgioFhK8SrXa+rYWL3PxcirdQvzgnjTh9vgx3JNIamgrTuNQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1713210329; c=relaxed/simple; bh=YzZyTZ6laH16VDOPaBXcnHJFtK1KqYmNpuOjW9U82po=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JC/3fmfjnoy1gLKqBe0OZAaBG+EyFjnGNI6zINNFy25Z15+65K/B3cRl+8UmRccwzeCoX7zFPQrGTrQ5rTGpQtPOe/iYq5mwlIDbXlt2Qc1z+xHJcBcn+vWw471x7NVJd37f5CmwQ4lFa0DOIVWU1grZss3sUpFO4Jug45JxdOk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MOQGybru; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="MOQGybru" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D5685C113CC; Mon, 15 Apr 2024 19:45:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1713210329; bh=YzZyTZ6laH16VDOPaBXcnHJFtK1KqYmNpuOjW9U82po=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MOQGybru9rotjWM5PJ0QeYy2p82Im0ZSvKUGBWwMP590fAy+E3CpN9LS7hGpTXecD EyZr4+NCT39zfrJpn0sr3vpasWusXGa4Er0+y0Ai9V2seCHoVO1PrEhJw1t/ZP8J4m 3EwrpreUeWFR02mEJAIbBiwnE1nIN4L7VfPw8MEbVlq4s2UyYwtM0fc61CUXn//a9g fO28v1UFl9aJSIT8UCQm1B8zYtJS8SgColoFLblAbcAEm2YP+P71FfYL+Km7qEKRAa 3+qRBbkOcYwb+YU4uCeU5y1nugZC8hL7sC8cIKlMc9Qfp8G4afv5TRJ12t2P3WMabw BKXNnCw04VClA== From: Lorenzo Bianconi To: linux-nfs@vger.kernel.org Cc: lorenzo.bianconi@redhat.com, chuck.lever@oracle.com, neilb@suse.de, netdev@vger.kernel.org, kuba@kernel.org, jlayton@kernel.org Subject: [PATCH v8 6/6] NFSD: add listener-{set,get} netlink command Date: Mon, 15 Apr 2024 21:44:39 +0200 Message-ID: X-Mailer: git-send-email 2.44.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Introduce write_ports netlink command. For listener-set, userspace is expected to provide a NFS listeners list it wants enabled. All other sockets will be closed. Reviewed-by: Jeff Layton Co-developed-by: Jeff Layton Signed-off-by: Jeff Layton Signed-off-by: Lorenzo Bianconi --- Documentation/netlink/specs/nfsd.yaml | 34 ++++ fs/nfsd/netlink.c | 22 +++ fs/nfsd/netlink.h | 3 + fs/nfsd/nfsctl.c | 220 ++++++++++++++++++++++++++ include/uapi/linux/nfsd_netlink.h | 17 ++ 5 files changed, 296 insertions(+) diff --git a/Documentation/netlink/specs/nfsd.yaml b/Documentation/netlink/specs/nfsd.yaml index 0396e8b3ea1f..e5c1f9186fe8 100644 --- a/Documentation/netlink/specs/nfsd.yaml +++ b/Documentation/netlink/specs/nfsd.yaml @@ -94,6 +94,23 @@ attribute-sets: type: nest nested-attributes: version multi-attr: true + - + name: sock + attributes: + - + name: addr + type: binary + - + name: transport-name + type: string + - + name: server-sock + attributes: + - + name: addr + type: nest + nested-attributes: sock + multi-attr: true operations: list: @@ -157,3 +174,20 @@ operations: reply: attributes: - version + - + name: listener-set + doc: set nfs running sockets + attribute-set: server-sock + flags: [ admin-perm ] + do: + request: + attributes: + - addr + - + name: listener-get + doc: get nfs running listeners + attribute-set: server-sock + do: + reply: + attributes: + - addr diff --git a/fs/nfsd/netlink.c b/fs/nfsd/netlink.c index bf5df9597288..9450d691dae8 100644 --- a/fs/nfsd/netlink.c +++ b/fs/nfsd/netlink.c @@ -11,6 +11,11 @@ #include /* Common nested types */ +const struct nla_policy nfsd_sock_nl_policy[NFSD_A_SOCK_TRANSPORT_NAME + 1] = { + [NFSD_A_SOCK_ADDR] = { .type = NLA_BINARY, }, + [NFSD_A_SOCK_TRANSPORT_NAME] = { .type = NLA_NUL_STRING, }, +}; + const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1] = { [NFSD_A_VERSION_MAJOR] = { .type = NLA_U32, }, [NFSD_A_VERSION_MINOR] = { .type = NLA_U32, }, @@ -29,6 +34,11 @@ static const struct nla_policy nfsd_version_set_nl_policy[NFSD_A_SERVER_PROTO_VE [NFSD_A_SERVER_PROTO_VERSION] = NLA_POLICY_NESTED(nfsd_version_nl_policy), }; +/* NFSD_CMD_LISTENER_SET - do */ +static const struct nla_policy nfsd_listener_set_nl_policy[NFSD_A_SERVER_SOCK_ADDR + 1] = { + [NFSD_A_SERVER_SOCK_ADDR] = NLA_POLICY_NESTED(nfsd_sock_nl_policy), +}; + /* Ops table for nfsd */ static const struct genl_split_ops nfsd_nl_ops[] = { { @@ -62,6 +72,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = { .doit = nfsd_nl_version_get_doit, .flags = GENL_CMD_CAP_DO, }, + { + .cmd = NFSD_CMD_LISTENER_SET, + .doit = nfsd_nl_listener_set_doit, + .policy = nfsd_listener_set_nl_policy, + .maxattr = NFSD_A_SERVER_SOCK_ADDR, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = NFSD_CMD_LISTENER_GET, + .doit = nfsd_nl_listener_get_doit, + .flags = GENL_CMD_CAP_DO, + }, }; struct genl_family nfsd_nl_family __ro_after_init = { diff --git a/fs/nfsd/netlink.h b/fs/nfsd/netlink.h index c7c0da275481..e3724637d64d 100644 --- a/fs/nfsd/netlink.h +++ b/fs/nfsd/netlink.h @@ -12,6 +12,7 @@ #include /* Common nested types */ +extern const struct nla_policy nfsd_sock_nl_policy[NFSD_A_SOCK_TRANSPORT_NAME + 1]; extern const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1]; int nfsd_nl_rpc_status_get_start(struct netlink_callback *cb); @@ -23,6 +24,8 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info); int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info); int nfsd_nl_version_set_doit(struct sk_buff *skb, struct genl_info *info); int nfsd_nl_version_get_doit(struct sk_buff *skb, struct genl_info *info); +int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info); +int nfsd_nl_listener_get_doit(struct sk_buff *skb, struct genl_info *info); extern struct genl_family nfsd_nl_family; diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 2c8929ef79e9..2e8534113ce4 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1907,6 +1907,226 @@ int nfsd_nl_version_get_doit(struct sk_buff *skb, struct genl_info *info) return err; } +/** + * nfsd_nl_listener_set_doit - set the nfs running sockets + * @skb: reply buffer + * @info: netlink metadata and command arguments + * + * Return 0 on success or a negative errno. + */ +int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info) +{ + struct net *net = genl_info_net(info); + struct svc_xprt *xprt, *tmp; + const struct nlattr *attr; + struct svc_serv *serv; + LIST_HEAD(permsocks); + struct nfsd_net *nn; + int err, rem; + + mutex_lock(&nfsd_mutex); + + err = nfsd_create_serv(net); + if (err) { + mutex_unlock(&nfsd_mutex); + return err; + } + + nn = net_generic(net, nfsd_net_id); + serv = nn->nfsd_serv; + + spin_lock_bh(&serv->sv_lock); + + /* Move all of the old listener sockets to a temp list */ + list_splice_init(&serv->sv_permsocks, &permsocks); + + /* + * Walk the list of server_socks from userland and move any that match + * back to sv_permsocks + */ + nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) { + struct nlattr *tb[NFSD_A_SOCK_MAX + 1]; + const char *xcl_name; + struct sockaddr *sa; + + if (nla_type(attr) != NFSD_A_SERVER_SOCK_ADDR) + continue; + + if (nla_parse_nested(tb, NFSD_A_SOCK_MAX, attr, + nfsd_sock_nl_policy, info->extack) < 0) + continue; + + if (!tb[NFSD_A_SOCK_ADDR] || !tb[NFSD_A_SOCK_TRANSPORT_NAME]) + continue; + + if (nla_len(tb[NFSD_A_SOCK_ADDR]) < sizeof(*sa)) + continue; + + xcl_name = nla_data(tb[NFSD_A_SOCK_TRANSPORT_NAME]); + sa = nla_data(tb[NFSD_A_SOCK_ADDR]); + + /* Put back any matching sockets */ + list_for_each_entry_safe(xprt, tmp, &permsocks, xpt_list) { + /* This shouldn't be possible */ + if (WARN_ON_ONCE(xprt->xpt_net != net)) { + list_move(&xprt->xpt_list, &serv->sv_permsocks); + continue; + } + + /* If everything matches, put it back */ + if (!strcmp(xprt->xpt_class->xcl_name, xcl_name) && + rpc_cmp_addr_port(sa, (struct sockaddr *)&xprt->xpt_local)) { + list_move(&xprt->xpt_list, &serv->sv_permsocks); + break; + } + } + } + + /* For now, no removing old sockets while server is running */ + if (serv->sv_nrthreads && !list_empty(&permsocks)) { + list_splice_init(&permsocks, &serv->sv_permsocks); + spin_unlock_bh(&serv->sv_lock); + err = -EBUSY; + goto out_unlock_mtx; + } + + /* Close the remaining sockets on the permsocks list */ + while (!list_empty(&permsocks)) { + xprt = list_first_entry(&permsocks, struct svc_xprt, xpt_list); + list_move(&xprt->xpt_list, &serv->sv_permsocks); + + /* + * Newly-created sockets are born with the BUSY bit set. Clear + * it if there are no threads, since nothing can pick it up + * in that case. + */ + if (!serv->sv_nrthreads) + clear_bit(XPT_BUSY, &xprt->xpt_flags); + + set_bit(XPT_CLOSE, &xprt->xpt_flags); + spin_unlock_bh(&serv->sv_lock); + svc_xprt_close(xprt); + spin_lock_bh(&serv->sv_lock); + } + + spin_unlock_bh(&serv->sv_lock); + + /* walk list of addrs again, open any that still don't exist */ + nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) { + struct nlattr *tb[NFSD_A_SOCK_MAX + 1]; + const char *xcl_name; + struct sockaddr *sa; + int ret; + + if (nla_type(attr) != NFSD_A_SERVER_SOCK_ADDR) + continue; + + if (nla_parse_nested(tb, NFSD_A_SOCK_MAX, attr, + nfsd_sock_nl_policy, info->extack) < 0) + continue; + + if (!tb[NFSD_A_SOCK_ADDR] || !tb[NFSD_A_SOCK_TRANSPORT_NAME]) + continue; + + if (nla_len(tb[NFSD_A_SOCK_ADDR]) < sizeof(*sa)) + continue; + + xcl_name = nla_data(tb[NFSD_A_SOCK_TRANSPORT_NAME]); + sa = nla_data(tb[NFSD_A_SOCK_ADDR]); + + xprt = svc_find_listener(serv, xcl_name, net, sa); + if (xprt) { + svc_xprt_put(xprt); + continue; + } + + ret = svc_xprt_create_from_sa(serv, xcl_name, net, sa, + SVC_SOCK_ANONYMOUS, + get_current_cred()); + /* always save the latest error */ + if (ret < 0) + err = ret; + } + + if (!serv->sv_nrthreads && list_empty(&nn->nfsd_serv->sv_permsocks)) + nfsd_destroy_serv(net); + +out_unlock_mtx: + mutex_unlock(&nfsd_mutex); + + return err; +} + +/** + * nfsd_nl_listener_get_doit - get the nfs running listeners + * @skb: reply buffer + * @info: netlink metadata and command arguments + * + * Return 0 on success or a negative errno. + */ +int nfsd_nl_listener_get_doit(struct sk_buff *skb, struct genl_info *info) +{ + struct svc_xprt *xprt; + struct svc_serv *serv; + struct nfsd_net *nn; + void *hdr; + int err; + + skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + hdr = genlmsg_iput(skb, info); + if (!hdr) { + err = -EMSGSIZE; + goto err_free_msg; + } + + mutex_lock(&nfsd_mutex); + nn = net_generic(genl_info_net(info), nfsd_net_id); + + /* no nfs server? Just send empty socket list */ + if (!nn->nfsd_serv) + goto out_unlock_mtx; + + serv = nn->nfsd_serv; + spin_lock_bh(&serv->sv_lock); + list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) { + struct nlattr *attr; + + attr = nla_nest_start(skb, NFSD_A_SERVER_SOCK_ADDR); + if (!attr) { + err = -EINVAL; + goto err_serv_unlock; + } + + if (nla_put_string(skb, NFSD_A_SOCK_TRANSPORT_NAME, + xprt->xpt_class->xcl_name) || + nla_put(skb, NFSD_A_SOCK_ADDR, + sizeof(struct sockaddr_storage), + &xprt->xpt_local)) { + err = -EINVAL; + goto err_serv_unlock; + } + + nla_nest_end(skb, attr); + } + spin_unlock_bh(&serv->sv_lock); +out_unlock_mtx: + mutex_unlock(&nfsd_mutex); + genlmsg_end(skb, hdr); + + return genlmsg_reply(skb, info); + +err_serv_unlock: + spin_unlock_bh(&serv->sv_lock); + mutex_unlock(&nfsd_mutex); +err_free_msg: + nlmsg_free(skb); + + return err; +} + /** * nfsd_net_init - Prepare the nfsd_net portion of a new net namespace * @net: a freshly-created network namespace diff --git a/include/uapi/linux/nfsd_netlink.h b/include/uapi/linux/nfsd_netlink.h index 8a0a2b344923..ca9900f9d86f 100644 --- a/include/uapi/linux/nfsd_netlink.h +++ b/include/uapi/linux/nfsd_netlink.h @@ -54,12 +54,29 @@ enum { NFSD_A_SERVER_PROTO_MAX = (__NFSD_A_SERVER_PROTO_MAX - 1) }; +enum { + NFSD_A_SOCK_ADDR = 1, + NFSD_A_SOCK_TRANSPORT_NAME, + + __NFSD_A_SOCK_MAX, + NFSD_A_SOCK_MAX = (__NFSD_A_SOCK_MAX - 1) +}; + +enum { + NFSD_A_SERVER_SOCK_ADDR = 1, + + __NFSD_A_SERVER_SOCK_MAX, + NFSD_A_SERVER_SOCK_MAX = (__NFSD_A_SERVER_SOCK_MAX - 1) +}; + enum { NFSD_CMD_RPC_STATUS_GET = 1, NFSD_CMD_THREADS_SET, NFSD_CMD_THREADS_GET, NFSD_CMD_VERSION_SET, NFSD_CMD_VERSION_GET, + NFSD_CMD_LISTENER_SET, + NFSD_CMD_LISTENER_GET, __NFSD_CMD_MAX, NFSD_CMD_MAX = (__NFSD_CMD_MAX - 1)