nfsd_nl_listener_set_doit() returns the raw errno from svc_xprt_create_from_sa() and sets no extack. A failed LISTENER_SET therefore tells userland only "Address already in use", or whatever else the transport returned. It never tells userland which entry failed. Record the attribute and the transport name of the entry whose errno the call returns, and report both after the loop. NL_SET_BAD_ATTR() names the entry, which the message alone cannot do: a request can carry several entries with the same transport name. The rejections in nfsd_nl_validate_listeners() other than -E2BIG and the unsupported transport name still carry no extack. This patch does not change them. Assisted-by: LLM Signed-off-by: Jeff Layton --- fs/nfsd/nfsctl.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index d8135f38e69f..6cbdcee4b733 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -2089,7 +2089,9 @@ static int nfsd_nl_validate_listeners(struct genl_info *info) int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info) { struct net *net = genl_info_net(info); + const struct nlattr *bad_attr = NULL; struct svc_xprt *xprt, *tmp; + const char *bad_xprt = NULL; const struct nlattr *attr; struct svc_serv *serv; LIST_HEAD(permsocks); @@ -2208,8 +2210,22 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info) ret = svc_xprt_create_from_sa(serv, xcl_name, net, sa, 0, current_cred()); /* always save the latest error */ - if (ret < 0) + if (ret < 0) { + bad_attr = attr; + bad_xprt = xcl_name; err = ret; + } + } + + /* + * The ack carries the errno of the last entry that failed. Point at + * that entry as well, since several entries can share a transport + * name and the errno alone cannot tell them apart. + */ + if (err) { + NL_SET_BAD_ATTR(info->extack, bad_attr); + NL_SET_ERR_MSG_FMT(info->extack, "cannot create %s listener", + bad_xprt); } if (!serv->sv_nrthreads && list_empty(&nn->nfsd_serv->sv_permsocks)) -- 2.55.0