diff mbox series

[3/3] sunrpc: Add a sysfs file for adding a new xprt

Message ID 20250108213632.260498-4-anna@kernel.org (mailing list archive)
State Handled Elsewhere
Headers show
Series NFS & SUNRPC Sysfs Improvements | expand

Commit Message

Anna Schumaker Jan. 8, 2025, 9:36 p.m. UTC
From: Anna Schumaker <anna.schumaker@oracle.com>

Writing to this file will clone the 'main' xprt of an xprt_switch and
add it to be used as an additional connection.

Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
---
 include/linux/sunrpc/xprtmultipath.h |  1 +
 net/sunrpc/sysfs.c                   | 54 ++++++++++++++++++++++++++++
 net/sunrpc/xprtmultipath.c           | 21 +++++++++++
 3 files changed, 76 insertions(+)

Comments

Benjamin Coddington Jan. 9, 2025, 3:10 p.m. UTC | #1
On 8 Jan 2025, at 16:36, Anna Schumaker wrote:

> From: Anna Schumaker <anna.schumaker@oracle.com>
>
> Writing to this file will clone the 'main' xprt of an xprt_switch and
> add it to be used as an additional connection.

I like this too!  I'd prefer it was ./add_xprt instead of
./xprt_switch_add_xprt, since the directory already gives the context that
you're operating on the xprt_switch.

After happily adding a bunch of xprts, I did have to look up the source to
re-learn how to remove them which wasn't obvious from the sysfs structure.
You have to write "offline", then "remove" to the xprt_state file.  This
made me wish there was just a ./xprt-N-tcp/del_xprt that would do both of
those..

.. and in stark contrast to my previous preference on less dynamic sysfs, I
think that the ./del_xprt shouldn't appear for the "main" xprt (since you
can't remove/delete them).

.. all just thoughts, these look good!

>
> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
> ---
>  include/linux/sunrpc/xprtmultipath.h |  1 +
>  net/sunrpc/sysfs.c                   | 54 ++++++++++++++++++++++++++++
>  net/sunrpc/xprtmultipath.c           | 21 +++++++++++
>  3 files changed, 76 insertions(+)
>
> diff --git a/include/linux/sunrpc/xprtmultipath.h b/include/linux/sunrpc/xprtmultipath.h
> index c0514c684b2c..c827c6ef0bc5 100644
> --- a/include/linux/sunrpc/xprtmultipath.h
> +++ b/include/linux/sunrpc/xprtmultipath.h
> @@ -56,6 +56,7 @@ extern void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps,
>  		struct rpc_xprt *xprt);
>  extern void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
>  		struct rpc_xprt *xprt, bool offline);
> +extern struct rpc_xprt *rpc_xprt_switch_get_main_xprt(struct rpc_xprt_switch *xps);
>
>  extern void xprt_iter_init(struct rpc_xprt_iter *xpi,
>  		struct rpc_xprt_switch *xps);
> diff --git a/net/sunrpc/sysfs.c b/net/sunrpc/sysfs.c
> index dc3b7cd70000..ce7dae140770 100644
> --- a/net/sunrpc/sysfs.c
> +++ b/net/sunrpc/sysfs.c
> @@ -250,6 +250,55 @@ static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
>  	return ret;
>  }
>
> +static ssize_t rpc_sysfs_xprt_switch_add_xprt_show(struct kobject *kobj,
> +						   struct kobj_attribute *attr,
> +						   char *buf)
> +{
> +	return sprintf(buf, "# add one xprt to this xprt_switch\n");
> +}
> +
> +static ssize_t rpc_sysfs_xprt_switch_add_xprt_store(struct kobject *kobj,
> +						    struct kobj_attribute *attr,
> +						    const char *buf, size_t count)
> +{
> +	struct rpc_xprt_switch *xprt_switch =
> +		rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
> +	struct xprt_create xprt_create_args;
> +	struct rpc_xprt *xprt, *new;
> +
> +	if (!xprt_switch)
> +		return 0;
> +
> +	xprt = rpc_xprt_switch_get_main_xprt(xprt_switch);
> +	if (!xprt)
> +		goto out;
> +
> +	xprt_create_args.ident = xprt->xprt_class->ident;
> +	xprt_create_args.net = xprt->xprt_net;
> +	xprt_create_args.dstaddr = (struct sockaddr *)&xprt->addr;
> +	xprt_create_args.addrlen = xprt->addrlen;
> +	xprt_create_args.servername = xprt->servername;
> +	xprt_create_args.bc_xprt = xprt->bc_xprt;
> +	xprt_create_args.xprtsec = xprt->xprtsec;
> +	xprt_create_args.connect_timeout = xprt->connect_timeout;
> +	xprt_create_args.reconnect_timeout = xprt->max_reconnect_timeout;
> +
> +	new = xprt_create_transport(&xprt_create_args);
> +	if (IS_ERR_OR_NULL(new)) {
> +		count = PTR_ERR(new);
> +		goto out_put_xprt;
> +	}
> +
> +	rpc_xprt_switch_add_xprt(xprt_switch, new);
> +	xprt_put(new);
> +
> +out_put_xprt:
> +	xprt_put(xprt);
> +out:
> +	xprt_switch_put(xprt_switch);
> +	return count;
> +}
> +
>  static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
>  					    struct kobj_attribute *attr,
>  					    const char *buf, size_t count)
> @@ -451,8 +500,13 @@ ATTRIBUTE_GROUPS(rpc_sysfs_xprt);
>  static struct kobj_attribute rpc_sysfs_xprt_switch_info =
>  	__ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
>
> +static struct kobj_attribute rpc_sysfs_xprt_switch_add_xprt =
> +	__ATTR(xprt_switch_add_xprt, 0644, rpc_sysfs_xprt_switch_add_xprt_show,
> +		rpc_sysfs_xprt_switch_add_xprt_store);
> +
>  static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
>  	&rpc_sysfs_xprt_switch_info.attr,
> +	&rpc_sysfs_xprt_switch_add_xprt.attr,
>  	NULL,
>  };
>  ATTRIBUTE_GROUPS(rpc_sysfs_xprt_switch);
> diff --git a/net/sunrpc/xprtmultipath.c b/net/sunrpc/xprtmultipath.c
> index 720d3ba742ec..a07b81ce93c3 100644
> --- a/net/sunrpc/xprtmultipath.c
> +++ b/net/sunrpc/xprtmultipath.c
> @@ -92,6 +92,27 @@ void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
>  	xprt_put(xprt);
>  }
>
> +/**
> + * rpc_xprt_switch_get_main_xprt - Get the 'main' xprt for an xprt switch.
> + * @xps: pointer to struct rpc_xprt_switch.
> + */
> +struct rpc_xprt *rpc_xprt_switch_get_main_xprt(struct rpc_xprt_switch *xps)
> +{
> +	struct rpc_xprt_iter xpi;
> +	struct rpc_xprt *xprt;
> +
> +	xprt_iter_init_listall(&xpi, xps);
> +
> +	xprt = xprt_iter_get_xprt(&xpi);
> +	while (xprt && !xprt->main) {
> +		xprt_put(xprt);
> +		xprt = xprt_iter_get_next(&xpi);
> +	}
> +
> +	xprt_iter_destroy(&xpi);
> +	return xprt;
> +}
> +
>  static DEFINE_IDA(rpc_xprtswitch_ids);
>
>  void xprt_multipath_cleanup_ids(void)
> -- 
> 2.47.1
Anna Schumaker Jan. 9, 2025, 8:54 p.m. UTC | #2
On 1/9/25 10:10 AM, Benjamin Coddington wrote:
> On 8 Jan 2025, at 16:36, Anna Schumaker wrote:
> 
>> From: Anna Schumaker <anna.schumaker@oracle.com>
>>
>> Writing to this file will clone the 'main' xprt of an xprt_switch and
>> add it to be used as an additional connection.
> 
> I like this too!  I'd prefer it was ./add_xprt instead of
> ./xprt_switch_add_xprt, since the directory already gives the context that
> you're operating on the xprt_switch.

I'd prefer that too, actually. I don't know what I was thinking going with the longer name, and I've made that change for v2.

> 
> After happily adding a bunch of xprts, I did have to look up the source to
> re-learn how to remove them which wasn't obvious from the sysfs structure.
> You have to write "offline", then "remove" to the xprt_state file.  This
> made me wish there was just a ./xprt-N-tcp/del_xprt that would do both of
> those..

`rpcctl xprt remove` will already do both of those in one step, if that helps. But I can look at adding in 'del_xprt' if you still think it would help.

> 
> .. and in stark contrast to my previous preference on less dynamic sysfs, I
> think that the ./del_xprt shouldn't appear for the "main" xprt (since you
> can't remove/delete them).
> 
> .. all just thoughts, these look good!

Thanks!
Anna

> 
>>
>> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
>> ---
>>  include/linux/sunrpc/xprtmultipath.h |  1 +
>>  net/sunrpc/sysfs.c                   | 54 ++++++++++++++++++++++++++++
>>  net/sunrpc/xprtmultipath.c           | 21 +++++++++++
>>  3 files changed, 76 insertions(+)
>>
>> diff --git a/include/linux/sunrpc/xprtmultipath.h b/include/linux/sunrpc/xprtmultipath.h
>> index c0514c684b2c..c827c6ef0bc5 100644
>> --- a/include/linux/sunrpc/xprtmultipath.h
>> +++ b/include/linux/sunrpc/xprtmultipath.h
>> @@ -56,6 +56,7 @@ extern void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps,
>>  		struct rpc_xprt *xprt);
>>  extern void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
>>  		struct rpc_xprt *xprt, bool offline);
>> +extern struct rpc_xprt *rpc_xprt_switch_get_main_xprt(struct rpc_xprt_switch *xps);
>>
>>  extern void xprt_iter_init(struct rpc_xprt_iter *xpi,
>>  		struct rpc_xprt_switch *xps);
>> diff --git a/net/sunrpc/sysfs.c b/net/sunrpc/sysfs.c
>> index dc3b7cd70000..ce7dae140770 100644
>> --- a/net/sunrpc/sysfs.c
>> +++ b/net/sunrpc/sysfs.c
>> @@ -250,6 +250,55 @@ static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
>>  	return ret;
>>  }
>>
>> +static ssize_t rpc_sysfs_xprt_switch_add_xprt_show(struct kobject *kobj,
>> +						   struct kobj_attribute *attr,
>> +						   char *buf)
>> +{
>> +	return sprintf(buf, "# add one xprt to this xprt_switch\n");
>> +}
>> +
>> +static ssize_t rpc_sysfs_xprt_switch_add_xprt_store(struct kobject *kobj,
>> +						    struct kobj_attribute *attr,
>> +						    const char *buf, size_t count)
>> +{
>> +	struct rpc_xprt_switch *xprt_switch =
>> +		rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
>> +	struct xprt_create xprt_create_args;
>> +	struct rpc_xprt *xprt, *new;
>> +
>> +	if (!xprt_switch)
>> +		return 0;
>> +
>> +	xprt = rpc_xprt_switch_get_main_xprt(xprt_switch);
>> +	if (!xprt)
>> +		goto out;
>> +
>> +	xprt_create_args.ident = xprt->xprt_class->ident;
>> +	xprt_create_args.net = xprt->xprt_net;
>> +	xprt_create_args.dstaddr = (struct sockaddr *)&xprt->addr;
>> +	xprt_create_args.addrlen = xprt->addrlen;
>> +	xprt_create_args.servername = xprt->servername;
>> +	xprt_create_args.bc_xprt = xprt->bc_xprt;
>> +	xprt_create_args.xprtsec = xprt->xprtsec;
>> +	xprt_create_args.connect_timeout = xprt->connect_timeout;
>> +	xprt_create_args.reconnect_timeout = xprt->max_reconnect_timeout;
>> +
>> +	new = xprt_create_transport(&xprt_create_args);
>> +	if (IS_ERR_OR_NULL(new)) {
>> +		count = PTR_ERR(new);
>> +		goto out_put_xprt;
>> +	}
>> +
>> +	rpc_xprt_switch_add_xprt(xprt_switch, new);
>> +	xprt_put(new);
>> +
>> +out_put_xprt:
>> +	xprt_put(xprt);
>> +out:
>> +	xprt_switch_put(xprt_switch);
>> +	return count;
>> +}
>> +
>>  static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
>>  					    struct kobj_attribute *attr,
>>  					    const char *buf, size_t count)
>> @@ -451,8 +500,13 @@ ATTRIBUTE_GROUPS(rpc_sysfs_xprt);
>>  static struct kobj_attribute rpc_sysfs_xprt_switch_info =
>>  	__ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
>>
>> +static struct kobj_attribute rpc_sysfs_xprt_switch_add_xprt =
>> +	__ATTR(xprt_switch_add_xprt, 0644, rpc_sysfs_xprt_switch_add_xprt_show,
>> +		rpc_sysfs_xprt_switch_add_xprt_store);
>> +
>>  static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
>>  	&rpc_sysfs_xprt_switch_info.attr,
>> +	&rpc_sysfs_xprt_switch_add_xprt.attr,
>>  	NULL,
>>  };
>>  ATTRIBUTE_GROUPS(rpc_sysfs_xprt_switch);
>> diff --git a/net/sunrpc/xprtmultipath.c b/net/sunrpc/xprtmultipath.c
>> index 720d3ba742ec..a07b81ce93c3 100644
>> --- a/net/sunrpc/xprtmultipath.c
>> +++ b/net/sunrpc/xprtmultipath.c
>> @@ -92,6 +92,27 @@ void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
>>  	xprt_put(xprt);
>>  }
>>
>> +/**
>> + * rpc_xprt_switch_get_main_xprt - Get the 'main' xprt for an xprt switch.
>> + * @xps: pointer to struct rpc_xprt_switch.
>> + */
>> +struct rpc_xprt *rpc_xprt_switch_get_main_xprt(struct rpc_xprt_switch *xps)
>> +{
>> +	struct rpc_xprt_iter xpi;
>> +	struct rpc_xprt *xprt;
>> +
>> +	xprt_iter_init_listall(&xpi, xps);
>> +
>> +	xprt = xprt_iter_get_xprt(&xpi);
>> +	while (xprt && !xprt->main) {
>> +		xprt_put(xprt);
>> +		xprt = xprt_iter_get_next(&xpi);
>> +	}
>> +
>> +	xprt_iter_destroy(&xpi);
>> +	return xprt;
>> +}
>> +
>>  static DEFINE_IDA(rpc_xprtswitch_ids);
>>
>>  void xprt_multipath_cleanup_ids(void)
>> -- 
>> 2.47.1
>
Olga Kornievskaia Jan. 13, 2025, 2:10 p.m. UTC | #3
On Wed, Jan 8, 2025 at 4:36 PM Anna Schumaker <anna@kernel.org> wrote:
>
> From: Anna Schumaker <anna.schumaker@oracle.com>
>
> Writing to this file will clone the 'main' xprt of an xprt_switch and
> add it to be used as an additional connection.
>
> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
> ---
>  include/linux/sunrpc/xprtmultipath.h |  1 +
>  net/sunrpc/sysfs.c                   | 54 ++++++++++++++++++++++++++++
>  net/sunrpc/xprtmultipath.c           | 21 +++++++++++
>  3 files changed, 76 insertions(+)
>
> diff --git a/include/linux/sunrpc/xprtmultipath.h b/include/linux/sunrpc/xprtmultipath.h
> index c0514c684b2c..c827c6ef0bc5 100644
> --- a/include/linux/sunrpc/xprtmultipath.h
> +++ b/include/linux/sunrpc/xprtmultipath.h
> @@ -56,6 +56,7 @@ extern void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps,
>                 struct rpc_xprt *xprt);
>  extern void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
>                 struct rpc_xprt *xprt, bool offline);
> +extern struct rpc_xprt *rpc_xprt_switch_get_main_xprt(struct rpc_xprt_switch *xps);
>
>  extern void xprt_iter_init(struct rpc_xprt_iter *xpi,
>                 struct rpc_xprt_switch *xps);
> diff --git a/net/sunrpc/sysfs.c b/net/sunrpc/sysfs.c
> index dc3b7cd70000..ce7dae140770 100644
> --- a/net/sunrpc/sysfs.c
> +++ b/net/sunrpc/sysfs.c
> @@ -250,6 +250,55 @@ static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
>         return ret;
>  }
>
> +static ssize_t rpc_sysfs_xprt_switch_add_xprt_show(struct kobject *kobj,
> +                                                  struct kobj_attribute *attr,
> +                                                  char *buf)
> +{
> +       return sprintf(buf, "# add one xprt to this xprt_switch\n");
> +}
> +
> +static ssize_t rpc_sysfs_xprt_switch_add_xprt_store(struct kobject *kobj,
> +                                                   struct kobj_attribute *attr,
> +                                                   const char *buf, size_t count)
> +{
> +       struct rpc_xprt_switch *xprt_switch =
> +               rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
> +       struct xprt_create xprt_create_args;
> +       struct rpc_xprt *xprt, *new;
> +
> +       if (!xprt_switch)
> +               return 0;
> +
> +       xprt = rpc_xprt_switch_get_main_xprt(xprt_switch);
> +       if (!xprt)
> +               goto out;
> +
> +       xprt_create_args.ident = xprt->xprt_class->ident;
> +       xprt_create_args.net = xprt->xprt_net;
> +       xprt_create_args.dstaddr = (struct sockaddr *)&xprt->addr;
> +       xprt_create_args.addrlen = xprt->addrlen;
> +       xprt_create_args.servername = xprt->servername;
> +       xprt_create_args.bc_xprt = xprt->bc_xprt;
> +       xprt_create_args.xprtsec = xprt->xprtsec;
> +       xprt_create_args.connect_timeout = xprt->connect_timeout;
> +       xprt_create_args.reconnect_timeout = xprt->max_reconnect_timeout;
> +
> +       new = xprt_create_transport(&xprt_create_args);
> +       if (IS_ERR_OR_NULL(new)) {
> +               count = PTR_ERR(new);
> +               goto out_put_xprt;
> +       }
> +
> +       rpc_xprt_switch_add_xprt(xprt_switch, new);

Before adding a new transport don't we need to check that we are not
at or over the limit of how many connections we currently have (not
over nconnect limit and/or over the session trunking limit)?

> +       xprt_put(new);
> +
> +out_put_xprt:
> +       xprt_put(xprt);
> +out:
> +       xprt_switch_put(xprt_switch);
> +       return count;
> +}
> +
>  static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
>                                             struct kobj_attribute *attr,
>                                             const char *buf, size_t count)
> @@ -451,8 +500,13 @@ ATTRIBUTE_GROUPS(rpc_sysfs_xprt);
>  static struct kobj_attribute rpc_sysfs_xprt_switch_info =
>         __ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
>
> +static struct kobj_attribute rpc_sysfs_xprt_switch_add_xprt =
> +       __ATTR(xprt_switch_add_xprt, 0644, rpc_sysfs_xprt_switch_add_xprt_show,
> +               rpc_sysfs_xprt_switch_add_xprt_store);
> +
>  static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
>         &rpc_sysfs_xprt_switch_info.attr,
> +       &rpc_sysfs_xprt_switch_add_xprt.attr,
>         NULL,
>  };
>  ATTRIBUTE_GROUPS(rpc_sysfs_xprt_switch);
> diff --git a/net/sunrpc/xprtmultipath.c b/net/sunrpc/xprtmultipath.c
> index 720d3ba742ec..a07b81ce93c3 100644
> --- a/net/sunrpc/xprtmultipath.c
> +++ b/net/sunrpc/xprtmultipath.c
> @@ -92,6 +92,27 @@ void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
>         xprt_put(xprt);
>  }
>
> +/**
> + * rpc_xprt_switch_get_main_xprt - Get the 'main' xprt for an xprt switch.
> + * @xps: pointer to struct rpc_xprt_switch.
> + */
> +struct rpc_xprt *rpc_xprt_switch_get_main_xprt(struct rpc_xprt_switch *xps)
> +{
> +       struct rpc_xprt_iter xpi;
> +       struct rpc_xprt *xprt;
> +
> +       xprt_iter_init_listall(&xpi, xps);
> +
> +       xprt = xprt_iter_get_xprt(&xpi);
> +       while (xprt && !xprt->main) {
> +               xprt_put(xprt);
> +               xprt = xprt_iter_get_next(&xpi);
> +       }
> +
> +       xprt_iter_destroy(&xpi);
> +       return xprt;
> +}
> +
>  static DEFINE_IDA(rpc_xprtswitch_ids);
>
>  void xprt_multipath_cleanup_ids(void)
> --
> 2.47.1
>
>
Anna Schumaker Jan. 13, 2025, 9:52 p.m. UTC | #4
Hi Olga,

On 1/13/25 9:10 AM, Olga Kornievskaia wrote:
> On Wed, Jan 8, 2025 at 4:36 PM Anna Schumaker <anna@kernel.org> wrote:
>>
>> From: Anna Schumaker <anna.schumaker@oracle.com>
>>
>> Writing to this file will clone the 'main' xprt of an xprt_switch and
>> add it to be used as an additional connection.
>>
>> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
>> ---
>>  include/linux/sunrpc/xprtmultipath.h |  1 +
>>  net/sunrpc/sysfs.c                   | 54 ++++++++++++++++++++++++++++
>>  net/sunrpc/xprtmultipath.c           | 21 +++++++++++
>>  3 files changed, 76 insertions(+)
>>
>> diff --git a/include/linux/sunrpc/xprtmultipath.h b/include/linux/sunrpc/xprtmultipath.h
>> index c0514c684b2c..c827c6ef0bc5 100644
>> --- a/include/linux/sunrpc/xprtmultipath.h
>> +++ b/include/linux/sunrpc/xprtmultipath.h
>> @@ -56,6 +56,7 @@ extern void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps,
>>                 struct rpc_xprt *xprt);
>>  extern void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
>>                 struct rpc_xprt *xprt, bool offline);
>> +extern struct rpc_xprt *rpc_xprt_switch_get_main_xprt(struct rpc_xprt_switch *xps);
>>
>>  extern void xprt_iter_init(struct rpc_xprt_iter *xpi,
>>                 struct rpc_xprt_switch *xps);
>> diff --git a/net/sunrpc/sysfs.c b/net/sunrpc/sysfs.c
>> index dc3b7cd70000..ce7dae140770 100644
>> --- a/net/sunrpc/sysfs.c
>> +++ b/net/sunrpc/sysfs.c
>> @@ -250,6 +250,55 @@ static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
>>         return ret;
>>  }
>>
>> +static ssize_t rpc_sysfs_xprt_switch_add_xprt_show(struct kobject *kobj,
>> +                                                  struct kobj_attribute *attr,
>> +                                                  char *buf)
>> +{
>> +       return sprintf(buf, "# add one xprt to this xprt_switch\n");
>> +}
>> +
>> +static ssize_t rpc_sysfs_xprt_switch_add_xprt_store(struct kobject *kobj,
>> +                                                   struct kobj_attribute *attr,
>> +                                                   const char *buf, size_t count)
>> +{
>> +       struct rpc_xprt_switch *xprt_switch =
>> +               rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
>> +       struct xprt_create xprt_create_args;
>> +       struct rpc_xprt *xprt, *new;
>> +
>> +       if (!xprt_switch)
>> +               return 0;
>> +
>> +       xprt = rpc_xprt_switch_get_main_xprt(xprt_switch);
>> +       if (!xprt)
>> +               goto out;
>> +
>> +       xprt_create_args.ident = xprt->xprt_class->ident;
>> +       xprt_create_args.net = xprt->xprt_net;
>> +       xprt_create_args.dstaddr = (struct sockaddr *)&xprt->addr;
>> +       xprt_create_args.addrlen = xprt->addrlen;
>> +       xprt_create_args.servername = xprt->servername;
>> +       xprt_create_args.bc_xprt = xprt->bc_xprt;
>> +       xprt_create_args.xprtsec = xprt->xprtsec;
>> +       xprt_create_args.connect_timeout = xprt->connect_timeout;
>> +       xprt_create_args.reconnect_timeout = xprt->max_reconnect_timeout;
>> +
>> +       new = xprt_create_transport(&xprt_create_args);
>> +       if (IS_ERR_OR_NULL(new)) {
>> +               count = PTR_ERR(new);
>> +               goto out_put_xprt;
>> +       }
>> +
>> +       rpc_xprt_switch_add_xprt(xprt_switch, new);
> 
> Before adding a new transport don't we need to check that we are not
> at or over the limit of how many connections we currently have (not
> over nconnect limit and/or over the session trunking limit)?

That's a good thought, but I'm not really seeing how to do that from inside the sunrpc code. Those are configuration values for the NFS client, and don't get passed down to sunrpc, so sunrpc has no knownledge of them. If you think that'll be a problem, I can look into adding those checks for the next posting.

Anna

> 
>> +       xprt_put(new);
>> +
>> +out_put_xprt:
>> +       xprt_put(xprt);
>> +out:
>> +       xprt_switch_put(xprt_switch);
>> +       return count;
>> +}
>> +
>>  static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
>>                                             struct kobj_attribute *attr,
>>                                             const char *buf, size_t count)
>> @@ -451,8 +500,13 @@ ATTRIBUTE_GROUPS(rpc_sysfs_xprt);
>>  static struct kobj_attribute rpc_sysfs_xprt_switch_info =
>>         __ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
>>
>> +static struct kobj_attribute rpc_sysfs_xprt_switch_add_xprt =
>> +       __ATTR(xprt_switch_add_xprt, 0644, rpc_sysfs_xprt_switch_add_xprt_show,
>> +               rpc_sysfs_xprt_switch_add_xprt_store);
>> +
>>  static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
>>         &rpc_sysfs_xprt_switch_info.attr,
>> +       &rpc_sysfs_xprt_switch_add_xprt.attr,
>>         NULL,
>>  };
>>  ATTRIBUTE_GROUPS(rpc_sysfs_xprt_switch);
>> diff --git a/net/sunrpc/xprtmultipath.c b/net/sunrpc/xprtmultipath.c
>> index 720d3ba742ec..a07b81ce93c3 100644
>> --- a/net/sunrpc/xprtmultipath.c
>> +++ b/net/sunrpc/xprtmultipath.c
>> @@ -92,6 +92,27 @@ void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
>>         xprt_put(xprt);
>>  }
>>
>> +/**
>> + * rpc_xprt_switch_get_main_xprt - Get the 'main' xprt for an xprt switch.
>> + * @xps: pointer to struct rpc_xprt_switch.
>> + */
>> +struct rpc_xprt *rpc_xprt_switch_get_main_xprt(struct rpc_xprt_switch *xps)
>> +{
>> +       struct rpc_xprt_iter xpi;
>> +       struct rpc_xprt *xprt;
>> +
>> +       xprt_iter_init_listall(&xpi, xps);
>> +
>> +       xprt = xprt_iter_get_xprt(&xpi);
>> +       while (xprt && !xprt->main) {
>> +               xprt_put(xprt);
>> +               xprt = xprt_iter_get_next(&xpi);
>> +       }
>> +
>> +       xprt_iter_destroy(&xpi);
>> +       return xprt;
>> +}
>> +
>>  static DEFINE_IDA(rpc_xprtswitch_ids);
>>
>>  void xprt_multipath_cleanup_ids(void)
>> --
>> 2.47.1
>>
>>
Olga Kornievskaia Jan. 14, 2025, 3:09 p.m. UTC | #5
On Mon, Jan 13, 2025 at 4:52 PM Anna Schumaker
<anna.schumaker@oracle.com> wrote:
>
> Hi Olga,
>
> On 1/13/25 9:10 AM, Olga Kornievskaia wrote:
> > On Wed, Jan 8, 2025 at 4:36 PM Anna Schumaker <anna@kernel.org> wrote:
> >>
> >> From: Anna Schumaker <anna.schumaker@oracle.com>
> >>
> >> Writing to this file will clone the 'main' xprt of an xprt_switch and
> >> add it to be used as an additional connection.
> >>
> >> Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
> >> ---
> >>  include/linux/sunrpc/xprtmultipath.h |  1 +
> >>  net/sunrpc/sysfs.c                   | 54 ++++++++++++++++++++++++++++
> >>  net/sunrpc/xprtmultipath.c           | 21 +++++++++++
> >>  3 files changed, 76 insertions(+)
> >>
> >> diff --git a/include/linux/sunrpc/xprtmultipath.h b/include/linux/sunrpc/xprtmultipath.h
> >> index c0514c684b2c..c827c6ef0bc5 100644
> >> --- a/include/linux/sunrpc/xprtmultipath.h
> >> +++ b/include/linux/sunrpc/xprtmultipath.h
> >> @@ -56,6 +56,7 @@ extern void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps,
> >>                 struct rpc_xprt *xprt);
> >>  extern void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
> >>                 struct rpc_xprt *xprt, bool offline);
> >> +extern struct rpc_xprt *rpc_xprt_switch_get_main_xprt(struct rpc_xprt_switch *xps);
> >>
> >>  extern void xprt_iter_init(struct rpc_xprt_iter *xpi,
> >>                 struct rpc_xprt_switch *xps);
> >> diff --git a/net/sunrpc/sysfs.c b/net/sunrpc/sysfs.c
> >> index dc3b7cd70000..ce7dae140770 100644
> >> --- a/net/sunrpc/sysfs.c
> >> +++ b/net/sunrpc/sysfs.c
> >> @@ -250,6 +250,55 @@ static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
> >>         return ret;
> >>  }
> >>
> >> +static ssize_t rpc_sysfs_xprt_switch_add_xprt_show(struct kobject *kobj,
> >> +                                                  struct kobj_attribute *attr,
> >> +                                                  char *buf)
> >> +{
> >> +       return sprintf(buf, "# add one xprt to this xprt_switch\n");
> >> +}
> >> +
> >> +static ssize_t rpc_sysfs_xprt_switch_add_xprt_store(struct kobject *kobj,
> >> +                                                   struct kobj_attribute *attr,
> >> +                                                   const char *buf, size_t count)
> >> +{
> >> +       struct rpc_xprt_switch *xprt_switch =
> >> +               rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
> >> +       struct xprt_create xprt_create_args;
> >> +       struct rpc_xprt *xprt, *new;
> >> +
> >> +       if (!xprt_switch)
> >> +               return 0;
> >> +
> >> +       xprt = rpc_xprt_switch_get_main_xprt(xprt_switch);
> >> +       if (!xprt)
> >> +               goto out;
> >> +
> >> +       xprt_create_args.ident = xprt->xprt_class->ident;
> >> +       xprt_create_args.net = xprt->xprt_net;
> >> +       xprt_create_args.dstaddr = (struct sockaddr *)&xprt->addr;
> >> +       xprt_create_args.addrlen = xprt->addrlen;
> >> +       xprt_create_args.servername = xprt->servername;
> >> +       xprt_create_args.bc_xprt = xprt->bc_xprt;
> >> +       xprt_create_args.xprtsec = xprt->xprtsec;
> >> +       xprt_create_args.connect_timeout = xprt->connect_timeout;
> >> +       xprt_create_args.reconnect_timeout = xprt->max_reconnect_timeout;
> >> +
> >> +       new = xprt_create_transport(&xprt_create_args);
> >> +       if (IS_ERR_OR_NULL(new)) {
> >> +               count = PTR_ERR(new);
> >> +               goto out_put_xprt;
> >> +       }
> >> +
> >> +       rpc_xprt_switch_add_xprt(xprt_switch, new);
> >
> > Before adding a new transport don't we need to check that we are not
> > at or over the limit of how many connections we currently have (not
> > over nconnect limit and/or over the session trunking limit)?
>
> That's a good thought, but I'm not really seeing how to do that from inside the sunrpc code. Those are configuration values for the NFS client, and don't get passed down to sunrpc, so sunrpc has no knownledge of them. If you think that'll be a problem, I can look into adding those checks for the next posting.

Seems incorrect to allow going over a limit we enforce at the nfs
layer? So I think it is a problem.

The other thing that sticks out. Given that this is version agnostic
what happens for v3/v4 and the bc_xprt?

>
> Anna
>
> >
> >> +       xprt_put(new);
> >> +
> >> +out_put_xprt:
> >> +       xprt_put(xprt);
> >> +out:
> >> +       xprt_switch_put(xprt_switch);
> >> +       return count;
> >> +}
> >> +
> >>  static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
> >>                                             struct kobj_attribute *attr,
> >>                                             const char *buf, size_t count)
> >> @@ -451,8 +500,13 @@ ATTRIBUTE_GROUPS(rpc_sysfs_xprt);
> >>  static struct kobj_attribute rpc_sysfs_xprt_switch_info =
> >>         __ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
> >>
> >> +static struct kobj_attribute rpc_sysfs_xprt_switch_add_xprt =
> >> +       __ATTR(xprt_switch_add_xprt, 0644, rpc_sysfs_xprt_switch_add_xprt_show,
> >> +               rpc_sysfs_xprt_switch_add_xprt_store);
> >> +
> >>  static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
> >>         &rpc_sysfs_xprt_switch_info.attr,
> >> +       &rpc_sysfs_xprt_switch_add_xprt.attr,
> >>         NULL,
> >>  };
> >>  ATTRIBUTE_GROUPS(rpc_sysfs_xprt_switch);
> >> diff --git a/net/sunrpc/xprtmultipath.c b/net/sunrpc/xprtmultipath.c
> >> index 720d3ba742ec..a07b81ce93c3 100644
> >> --- a/net/sunrpc/xprtmultipath.c
> >> +++ b/net/sunrpc/xprtmultipath.c
> >> @@ -92,6 +92,27 @@ void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
> >>         xprt_put(xprt);
> >>  }
> >>
> >> +/**
> >> + * rpc_xprt_switch_get_main_xprt - Get the 'main' xprt for an xprt switch.
> >> + * @xps: pointer to struct rpc_xprt_switch.
> >> + */
> >> +struct rpc_xprt *rpc_xprt_switch_get_main_xprt(struct rpc_xprt_switch *xps)
> >> +{
> >> +       struct rpc_xprt_iter xpi;
> >> +       struct rpc_xprt *xprt;
> >> +
> >> +       xprt_iter_init_listall(&xpi, xps);
> >> +
> >> +       xprt = xprt_iter_get_xprt(&xpi);
> >> +       while (xprt && !xprt->main) {
> >> +               xprt_put(xprt);
> >> +               xprt = xprt_iter_get_next(&xpi);
> >> +       }
> >> +
> >> +       xprt_iter_destroy(&xpi);
> >> +       return xprt;
> >> +}
> >> +
> >>  static DEFINE_IDA(rpc_xprtswitch_ids);
> >>
> >>  void xprt_multipath_cleanup_ids(void)
> >> --
> >> 2.47.1
> >>
> >>
>
Dan Carpenter Jan. 20, 2025, 7:26 a.m. UTC | #6
Hi Anna,

kernel test robot noticed the following build warnings:

https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Anna-Schumaker/NFS-Add-implid-to-sysfs/20250109-053732
base:   git://git.linux-nfs.org/projects/trondmy/linux-nfs.git linux-next
patch link:    https://lore.kernel.org/r/20250108213632.260498-4-anna%40kernel.org
patch subject: [PATCH 3/3] sunrpc: Add a sysfs file for adding a new xprt
config: x86_64-randconfig-r073-20250119 (https://download.01.org/0day-ci/archive/20250120/202501200000.40Rg2rc6-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202501200000.40Rg2rc6-lkp@intel.com/

New smatch warnings:
net/sunrpc/sysfs.c:288 rpc_sysfs_xprt_switch_add_xprt_store() warn: passing zero to 'PTR_ERR'

vim +/PTR_ERR +288 net/sunrpc/sysfs.c

2b155d9a088aee Anna Schumaker 2025-01-08  260  static ssize_t rpc_sysfs_xprt_switch_add_xprt_store(struct kobject *kobj,
2b155d9a088aee Anna Schumaker 2025-01-08  261  						    struct kobj_attribute *attr,
2b155d9a088aee Anna Schumaker 2025-01-08  262  						    const char *buf, size_t count)
2b155d9a088aee Anna Schumaker 2025-01-08  263  {
2b155d9a088aee Anna Schumaker 2025-01-08  264  	struct rpc_xprt_switch *xprt_switch =
2b155d9a088aee Anna Schumaker 2025-01-08  265  		rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
2b155d9a088aee Anna Schumaker 2025-01-08  266  	struct xprt_create xprt_create_args;
2b155d9a088aee Anna Schumaker 2025-01-08  267  	struct rpc_xprt *xprt, *new;
2b155d9a088aee Anna Schumaker 2025-01-08  268  
2b155d9a088aee Anna Schumaker 2025-01-08  269  	if (!xprt_switch)
2b155d9a088aee Anna Schumaker 2025-01-08  270  		return 0;
2b155d9a088aee Anna Schumaker 2025-01-08  271  
2b155d9a088aee Anna Schumaker 2025-01-08  272  	xprt = rpc_xprt_switch_get_main_xprt(xprt_switch);
2b155d9a088aee Anna Schumaker 2025-01-08  273  	if (!xprt)
2b155d9a088aee Anna Schumaker 2025-01-08  274  		goto out;
2b155d9a088aee Anna Schumaker 2025-01-08  275  
2b155d9a088aee Anna Schumaker 2025-01-08  276  	xprt_create_args.ident = xprt->xprt_class->ident;
2b155d9a088aee Anna Schumaker 2025-01-08  277  	xprt_create_args.net = xprt->xprt_net;
2b155d9a088aee Anna Schumaker 2025-01-08  278  	xprt_create_args.dstaddr = (struct sockaddr *)&xprt->addr;
2b155d9a088aee Anna Schumaker 2025-01-08  279  	xprt_create_args.addrlen = xprt->addrlen;
2b155d9a088aee Anna Schumaker 2025-01-08  280  	xprt_create_args.servername = xprt->servername;
2b155d9a088aee Anna Schumaker 2025-01-08  281  	xprt_create_args.bc_xprt = xprt->bc_xprt;
2b155d9a088aee Anna Schumaker 2025-01-08  282  	xprt_create_args.xprtsec = xprt->xprtsec;
2b155d9a088aee Anna Schumaker 2025-01-08  283  	xprt_create_args.connect_timeout = xprt->connect_timeout;
2b155d9a088aee Anna Schumaker 2025-01-08  284  	xprt_create_args.reconnect_timeout = xprt->max_reconnect_timeout;
2b155d9a088aee Anna Schumaker 2025-01-08  285  
2b155d9a088aee Anna Schumaker 2025-01-08  286  	new = xprt_create_transport(&xprt_create_args);
2b155d9a088aee Anna Schumaker 2025-01-08  287  	if (IS_ERR_OR_NULL(new)) {

This should just be if (IS_ERR(new)) {, otherwise we end up with a
nonsense debate about whether impossible NULL returns should be handled
as a error or a success.

2b155d9a088aee Anna Schumaker 2025-01-08 @288  		count = PTR_ERR(new);
2b155d9a088aee Anna Schumaker 2025-01-08  289  		goto out_put_xprt;
2b155d9a088aee Anna Schumaker 2025-01-08  290  	}
2b155d9a088aee Anna Schumaker 2025-01-08  291  
2b155d9a088aee Anna Schumaker 2025-01-08  292  	rpc_xprt_switch_add_xprt(xprt_switch, new);
2b155d9a088aee Anna Schumaker 2025-01-08  293  	xprt_put(new);
2b155d9a088aee Anna Schumaker 2025-01-08  294  
2b155d9a088aee Anna Schumaker 2025-01-08  295  out_put_xprt:
2b155d9a088aee Anna Schumaker 2025-01-08  296  	xprt_put(xprt);
2b155d9a088aee Anna Schumaker 2025-01-08  297  out:
2b155d9a088aee Anna Schumaker 2025-01-08  298  	xprt_switch_put(xprt_switch);
2b155d9a088aee Anna Schumaker 2025-01-08  299  	return count;
2b155d9a088aee Anna Schumaker 2025-01-08  300  }
diff mbox series

Patch

diff --git a/include/linux/sunrpc/xprtmultipath.h b/include/linux/sunrpc/xprtmultipath.h
index c0514c684b2c..c827c6ef0bc5 100644
--- a/include/linux/sunrpc/xprtmultipath.h
+++ b/include/linux/sunrpc/xprtmultipath.h
@@ -56,6 +56,7 @@  extern void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps,
 		struct rpc_xprt *xprt);
 extern void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
 		struct rpc_xprt *xprt, bool offline);
+extern struct rpc_xprt *rpc_xprt_switch_get_main_xprt(struct rpc_xprt_switch *xps);
 
 extern void xprt_iter_init(struct rpc_xprt_iter *xpi,
 		struct rpc_xprt_switch *xps);
diff --git a/net/sunrpc/sysfs.c b/net/sunrpc/sysfs.c
index dc3b7cd70000..ce7dae140770 100644
--- a/net/sunrpc/sysfs.c
+++ b/net/sunrpc/sysfs.c
@@ -250,6 +250,55 @@  static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
 	return ret;
 }
 
+static ssize_t rpc_sysfs_xprt_switch_add_xprt_show(struct kobject *kobj,
+						   struct kobj_attribute *attr,
+						   char *buf)
+{
+	return sprintf(buf, "# add one xprt to this xprt_switch\n");
+}
+
+static ssize_t rpc_sysfs_xprt_switch_add_xprt_store(struct kobject *kobj,
+						    struct kobj_attribute *attr,
+						    const char *buf, size_t count)
+{
+	struct rpc_xprt_switch *xprt_switch =
+		rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
+	struct xprt_create xprt_create_args;
+	struct rpc_xprt *xprt, *new;
+
+	if (!xprt_switch)
+		return 0;
+
+	xprt = rpc_xprt_switch_get_main_xprt(xprt_switch);
+	if (!xprt)
+		goto out;
+
+	xprt_create_args.ident = xprt->xprt_class->ident;
+	xprt_create_args.net = xprt->xprt_net;
+	xprt_create_args.dstaddr = (struct sockaddr *)&xprt->addr;
+	xprt_create_args.addrlen = xprt->addrlen;
+	xprt_create_args.servername = xprt->servername;
+	xprt_create_args.bc_xprt = xprt->bc_xprt;
+	xprt_create_args.xprtsec = xprt->xprtsec;
+	xprt_create_args.connect_timeout = xprt->connect_timeout;
+	xprt_create_args.reconnect_timeout = xprt->max_reconnect_timeout;
+
+	new = xprt_create_transport(&xprt_create_args);
+	if (IS_ERR_OR_NULL(new)) {
+		count = PTR_ERR(new);
+		goto out_put_xprt;
+	}
+
+	rpc_xprt_switch_add_xprt(xprt_switch, new);
+	xprt_put(new);
+
+out_put_xprt:
+	xprt_put(xprt);
+out:
+	xprt_switch_put(xprt_switch);
+	return count;
+}
+
 static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
 					    struct kobj_attribute *attr,
 					    const char *buf, size_t count)
@@ -451,8 +500,13 @@  ATTRIBUTE_GROUPS(rpc_sysfs_xprt);
 static struct kobj_attribute rpc_sysfs_xprt_switch_info =
 	__ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
 
+static struct kobj_attribute rpc_sysfs_xprt_switch_add_xprt =
+	__ATTR(xprt_switch_add_xprt, 0644, rpc_sysfs_xprt_switch_add_xprt_show,
+		rpc_sysfs_xprt_switch_add_xprt_store);
+
 static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
 	&rpc_sysfs_xprt_switch_info.attr,
+	&rpc_sysfs_xprt_switch_add_xprt.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(rpc_sysfs_xprt_switch);
diff --git a/net/sunrpc/xprtmultipath.c b/net/sunrpc/xprtmultipath.c
index 720d3ba742ec..a07b81ce93c3 100644
--- a/net/sunrpc/xprtmultipath.c
+++ b/net/sunrpc/xprtmultipath.c
@@ -92,6 +92,27 @@  void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
 	xprt_put(xprt);
 }
 
+/**
+ * rpc_xprt_switch_get_main_xprt - Get the 'main' xprt for an xprt switch.
+ * @xps: pointer to struct rpc_xprt_switch.
+ */
+struct rpc_xprt *rpc_xprt_switch_get_main_xprt(struct rpc_xprt_switch *xps)
+{
+	struct rpc_xprt_iter xpi;
+	struct rpc_xprt *xprt;
+
+	xprt_iter_init_listall(&xpi, xps);
+
+	xprt = xprt_iter_get_xprt(&xpi);
+	while (xprt && !xprt->main) {
+		xprt_put(xprt);
+		xprt = xprt_iter_get_next(&xpi);
+	}
+
+	xprt_iter_destroy(&xpi);
+	return xprt;
+}
+
 static DEFINE_IDA(rpc_xprtswitch_ids);
 
 void xprt_multipath_cleanup_ids(void)