diff mbox series

[RFC,v3,1/9] vsock: SO_RCVLOWAT transport set callback

Message ID 45822644-8e37-1625-5944-63fd5fc20dd3@sberdevices.ru (mailing list archive)
State New, archived
Headers show
Series vsock: updates for SO_RCVLOWAT handling | expand

Commit Message

Arseniy Krasnov Aug. 3, 2022, 1:51 p.m. UTC
This adds transport specific callback for SO_RCVLOWAT, because in some
transports it may be difficult to know current available number of bytes
ready to read. Thus, when SO_RCVLOWAT is set, transport may reject it.

Signed-off-by: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
---
 include/net/af_vsock.h   |  1 +
 net/vmw_vsock/af_vsock.c | 25 +++++++++++++++++++++++++
 2 files changed, 26 insertions(+)

Comments

Stefano Garzarella Aug. 8, 2022, 10:23 a.m. UTC | #1
On Wed, Aug 03, 2022 at 01:51:05PM +0000, Arseniy Krasnov wrote:
>This adds transport specific callback for SO_RCVLOWAT, because in some
>transports it may be difficult to know current available number of bytes
>ready to read. Thus, when SO_RCVLOWAT is set, transport may reject it.
>
>Signed-off-by: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
>---
> include/net/af_vsock.h   |  1 +
> net/vmw_vsock/af_vsock.c | 25 +++++++++++++++++++++++++
> 2 files changed, 26 insertions(+)
>
>diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h
>index f742e50207fb..eae5874bae35 100644
>--- a/include/net/af_vsock.h
>+++ b/include/net/af_vsock.h
>@@ -134,6 +134,7 @@ struct vsock_transport {
> 	u64 (*stream_rcvhiwat)(struct vsock_sock *);
> 	bool (*stream_is_active)(struct vsock_sock *);
> 	bool (*stream_allow)(u32 cid, u32 port);
>+	int (*set_rcvlowat)(struct vsock_sock *, int);

checkpatch suggests to add identifier names. For some we put them in, 
for others we didn't, but I suggest putting them in for the new ones 
because I think it's clearer too.

WARNING: function definition argument 'struct vsock_sock *' should also 
have an identifier name
#25: FILE: include/net/af_vsock.h:137:
+	int (*set_rcvlowat)(struct vsock_sock *, int);

WARNING: function definition argument 'int' should also have an identifier name
#25: FILE: include/net/af_vsock.h:137:
+	int (*set_rcvlowat)(struct vsock_sock *, int);

total: 0 errors, 2 warnings, 0 checks, 44 lines checked

>
> 	/* SEQ_PACKET. */
> 	ssize_t (*seqpacket_dequeue)(struct vsock_sock *vsk, struct msghdr *msg,
>diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
>index f04abf662ec6..016ad5ff78b7 100644
>--- a/net/vmw_vsock/af_vsock.c
>+++ b/net/vmw_vsock/af_vsock.c
>@@ -2129,6 +2129,30 @@ vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
> 	return err;
> }
>
>+static int vsock_set_rcvlowat(struct sock *sk, int val)
>+{
>+	const struct vsock_transport *transport;
>+	struct vsock_sock *vsk;
>+	int err = 0;
>+
>+	vsk = vsock_sk(sk);
>+
>+	if (val > vsk->buffer_size)
>+		return -EINVAL;
>+
>+	transport = vsk->transport;
>+
>+	if (!transport)
>+		return -EOPNOTSUPP;

I don't know whether it is better in this case to write it in 
sk->sk_rcvlowat, maybe we can return EOPNOTSUPP only when the trasport 
is assigned and set_rcvlowat is not defined. This is because usually the 
options are set just after creation, when the transport is practically 
unassigned.

I mean something like this:

         if (transport) {
                 if (transport->set_rcvlowat)
                         return transport->set_rcvlowat(vsk, val);
                 else
                         return -EOPNOTSUPP;
         }

         WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);

         return 0;

>+
>+	if (transport->set_rcvlowat)
>+		err = transport->set_rcvlowat(vsk, val);
>+	else
>+		WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
>+
>+	return err;
>+}
>+
> static const struct proto_ops vsock_stream_ops = {
> 	.family = PF_VSOCK,
> 	.owner = THIS_MODULE,
>@@ -2148,6 +2172,7 @@ static const struct proto_ops vsock_stream_ops = {
> 	.recvmsg = vsock_connectible_recvmsg,
> 	.mmap = sock_no_mmap,
> 	.sendpage = sock_no_sendpage,
>+	.set_rcvlowat = vsock_set_rcvlowat,
> };
>
> static const struct proto_ops vsock_seqpacket_ops = {
>-- 
>2.25.1
Stefano Garzarella Aug. 8, 2022, 10:30 a.m. UTC | #2
On Mon, Aug 8, 2022 at 12:23 PM Stefano Garzarella <sgarzare@redhat.com> wrote:
>
> On Wed, Aug 03, 2022 at 01:51:05PM +0000, Arseniy Krasnov wrote:
> >This adds transport specific callback for SO_RCVLOWAT, because in some
> >transports it may be difficult to know current available number of bytes
> >ready to read. Thus, when SO_RCVLOWAT is set, transport may reject it.
> >
> >Signed-off-by: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
> >---
> > include/net/af_vsock.h   |  1 +
> > net/vmw_vsock/af_vsock.c | 25 +++++++++++++++++++++++++
> > 2 files changed, 26 insertions(+)
> >
> >diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h
> >index f742e50207fb..eae5874bae35 100644
> >--- a/include/net/af_vsock.h
> >+++ b/include/net/af_vsock.h
> >@@ -134,6 +134,7 @@ struct vsock_transport {
> >       u64 (*stream_rcvhiwat)(struct vsock_sock *);
> >       bool (*stream_is_active)(struct vsock_sock *);
> >       bool (*stream_allow)(u32 cid, u32 port);
> >+      int (*set_rcvlowat)(struct vsock_sock *, int);
>
> checkpatch suggests to add identifier names. For some we put them in,
> for others we didn't, but I suggest putting them in for the new ones
> because I think it's clearer too.
>
> WARNING: function definition argument 'struct vsock_sock *' should also
> have an identifier name
> #25: FILE: include/net/af_vsock.h:137:
> +       int (*set_rcvlowat)(struct vsock_sock *, int);
>
> WARNING: function definition argument 'int' should also have an identifier name
> #25: FILE: include/net/af_vsock.h:137:
> +       int (*set_rcvlowat)(struct vsock_sock *, int);
>
> total: 0 errors, 2 warnings, 0 checks, 44 lines checked
>
> >
> >       /* SEQ_PACKET. */
> >       ssize_t (*seqpacket_dequeue)(struct vsock_sock *vsk, struct msghdr *msg,
> >diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
> >index f04abf662ec6..016ad5ff78b7 100644
> >--- a/net/vmw_vsock/af_vsock.c
> >+++ b/net/vmw_vsock/af_vsock.c
> >@@ -2129,6 +2129,30 @@ vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
> >       return err;
> > }
> >
> >+static int vsock_set_rcvlowat(struct sock *sk, int val)
> >+{
> >+      const struct vsock_transport *transport;
> >+      struct vsock_sock *vsk;
> >+      int err = 0;
> >+
> >+      vsk = vsock_sk(sk);
> >+
> >+      if (val > vsk->buffer_size)
> >+              return -EINVAL;
> >+
> >+      transport = vsk->transport;
> >+
> >+      if (!transport)
> >+              return -EOPNOTSUPP;
>
> I don't know whether it is better in this case to write it in
> sk->sk_rcvlowat, maybe we can return EOPNOTSUPP only when the trasport
> is assigned and set_rcvlowat is not defined. This is because usually the
> options are set just after creation, when the transport is practically
> unassigned.
>
> I mean something like this:
>
>          if (transport) {
>                  if (transport->set_rcvlowat)
>                          return transport->set_rcvlowat(vsk, val);
>                  else
>                          return -EOPNOTSUPP;
>          }
>
>          WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
>
>          return 0;

Since hv_sock implements `set_rcvlowat` to return EOPNOTSUPP. maybe we 
can just do the following:

        if (transport && transport->set_rcvlowat)
                return transport->set_rcvlowat(vsk, val);

        WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
        return 0;

That is, the default behavior is to set sk->sk_rcvlowat, but for 
transports that want a different behavior, they need to define 
set_rcvlowat() (like hv_sock).

Thanks,
Stefano
Arseniy Krasnov Aug. 9, 2022, 9:37 a.m. UTC | #3
On 08.08.2022 13:30, Stefano Garzarella wrote:
> On Mon, Aug 8, 2022 at 12:23 PM Stefano Garzarella <sgarzare@redhat.com> wrote:
>>
>> On Wed, Aug 03, 2022 at 01:51:05PM +0000, Arseniy Krasnov wrote:
>>> This adds transport specific callback for SO_RCVLOWAT, because in some
>>> transports it may be difficult to know current available number of bytes
>>> ready to read. Thus, when SO_RCVLOWAT is set, transport may reject it.
>>>
>>> Signed-off-by: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
>>> ---
>>> include/net/af_vsock.h   |  1 +
>>> net/vmw_vsock/af_vsock.c | 25 +++++++++++++++++++++++++
>>> 2 files changed, 26 insertions(+)
>>>
>>> diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h
>>> index f742e50207fb..eae5874bae35 100644
>>> --- a/include/net/af_vsock.h
>>> +++ b/include/net/af_vsock.h
>>> @@ -134,6 +134,7 @@ struct vsock_transport {
>>>       u64 (*stream_rcvhiwat)(struct vsock_sock *);
>>>       bool (*stream_is_active)(struct vsock_sock *);
>>>       bool (*stream_allow)(u32 cid, u32 port);
>>> +      int (*set_rcvlowat)(struct vsock_sock *, int);
>>
>> checkpatch suggests to add identifier names. For some we put them in,
>> for others we didn't, but I suggest putting them in for the new ones
>> because I think it's clearer too.
>>
>> WARNING: function definition argument 'struct vsock_sock *' should also
>> have an identifier name
>> #25: FILE: include/net/af_vsock.h:137:
>> +       int (*set_rcvlowat)(struct vsock_sock *, int);
>>
>> WARNING: function definition argument 'int' should also have an identifier name
>> #25: FILE: include/net/af_vsock.h:137:
>> +       int (*set_rcvlowat)(struct vsock_sock *, int);
>>
>> total: 0 errors, 2 warnings, 0 checks, 44 lines checked
>>
>>>
>>>       /* SEQ_PACKET. */
>>>       ssize_t (*seqpacket_dequeue)(struct vsock_sock *vsk, struct msghdr *msg,
>>> diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
>>> index f04abf662ec6..016ad5ff78b7 100644
>>> --- a/net/vmw_vsock/af_vsock.c
>>> +++ b/net/vmw_vsock/af_vsock.c
>>> @@ -2129,6 +2129,30 @@ vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
>>>       return err;
>>> }
>>>
>>> +static int vsock_set_rcvlowat(struct sock *sk, int val)
>>> +{
>>> +      const struct vsock_transport *transport;
>>> +      struct vsock_sock *vsk;
>>> +      int err = 0;
>>> +
>>> +      vsk = vsock_sk(sk);
>>> +
>>> +      if (val > vsk->buffer_size)
>>> +              return -EINVAL;
>>> +
>>> +      transport = vsk->transport;
>>> +
>>> +      if (!transport)
>>> +              return -EOPNOTSUPP;
>>
>> I don't know whether it is better in this case to write it in
>> sk->sk_rcvlowat, maybe we can return EOPNOTSUPP only when the trasport
>> is assigned and set_rcvlowat is not defined. This is because usually the
>> options are set just after creation, when the transport is practically
>> unassigned.
>>
>> I mean something like this:
>>
>>          if (transport) {
>>                  if (transport->set_rcvlowat)
>>                          return transport->set_rcvlowat(vsk, val);
>>                  else
>>                          return -EOPNOTSUPP;
>>          }
>>
>>          WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
>>
>>          return 0;
> 
> Since hv_sock implements `set_rcvlowat` to return EOPNOTSUPP. maybe we 
> can just do the following:
> 
>         if (transport && transport->set_rcvlowat)
>                 return transport->set_rcvlowat(vsk, val);
> 
>         WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
>         return 0;
> 
> That is, the default behavior is to set sk->sk_rcvlowat, but for 
> transports that want a different behavior, they need to define 
> set_rcvlowat() (like hv_sock).
Hm ok, i see. I've implemented logic when non-empty transport is required, because hyperv transport
forbids to set SO_RCVLOWAT, so user needs to call this setsockopt AFTER transport is assigned(to check
that transport allows it. Not after socket creation as You mentioned above). Otherwise there is no sense
in such callback - it will be never used. Also in code above - for hyperv we will have different behavior
depends on when set_rcvlowat is called: before or after transport assignment. Is it ok?
> 
> Thanks,
> Stefano
>
Arseniy Krasnov Aug. 9, 2022, 9:45 a.m. UTC | #4
On 09.08.2022 12:37, Arseniy Krasnov wrote:
> On 08.08.2022 13:30, Stefano Garzarella wrote:
>> On Mon, Aug 8, 2022 at 12:23 PM Stefano Garzarella <sgarzare@redhat.com> wrote:
>>>
>>> On Wed, Aug 03, 2022 at 01:51:05PM +0000, Arseniy Krasnov wrote:
>>>> This adds transport specific callback for SO_RCVLOWAT, because in some
>>>> transports it may be difficult to know current available number of bytes
>>>> ready to read. Thus, when SO_RCVLOWAT is set, transport may reject it.
>>>>
>>>> Signed-off-by: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
>>>> ---
>>>> include/net/af_vsock.h   |  1 +
>>>> net/vmw_vsock/af_vsock.c | 25 +++++++++++++++++++++++++
>>>> 2 files changed, 26 insertions(+)
>>>>
>>>> diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h
>>>> index f742e50207fb..eae5874bae35 100644
>>>> --- a/include/net/af_vsock.h
>>>> +++ b/include/net/af_vsock.h
>>>> @@ -134,6 +134,7 @@ struct vsock_transport {
>>>>       u64 (*stream_rcvhiwat)(struct vsock_sock *);
>>>>       bool (*stream_is_active)(struct vsock_sock *);
>>>>       bool (*stream_allow)(u32 cid, u32 port);
>>>> +      int (*set_rcvlowat)(struct vsock_sock *, int);
>>>
>>> checkpatch suggests to add identifier names. For some we put them in,
>>> for others we didn't, but I suggest putting them in for the new ones
>>> because I think it's clearer too.
>>>
>>> WARNING: function definition argument 'struct vsock_sock *' should also
>>> have an identifier name
>>> #25: FILE: include/net/af_vsock.h:137:
>>> +       int (*set_rcvlowat)(struct vsock_sock *, int);
>>>
>>> WARNING: function definition argument 'int' should also have an identifier name
>>> #25: FILE: include/net/af_vsock.h:137:
>>> +       int (*set_rcvlowat)(struct vsock_sock *, int);
>>>
>>> total: 0 errors, 2 warnings, 0 checks, 44 lines checked
>>>
>>>>
>>>>       /* SEQ_PACKET. */
>>>>       ssize_t (*seqpacket_dequeue)(struct vsock_sock *vsk, struct msghdr *msg,
>>>> diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
>>>> index f04abf662ec6..016ad5ff78b7 100644
>>>> --- a/net/vmw_vsock/af_vsock.c
>>>> +++ b/net/vmw_vsock/af_vsock.c
>>>> @@ -2129,6 +2129,30 @@ vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
>>>>       return err;
>>>> }
>>>>
>>>> +static int vsock_set_rcvlowat(struct sock *sk, int val)
>>>> +{
>>>> +      const struct vsock_transport *transport;
>>>> +      struct vsock_sock *vsk;
>>>> +      int err = 0;
>>>> +
>>>> +      vsk = vsock_sk(sk);
>>>> +
>>>> +      if (val > vsk->buffer_size)
>>>> +              return -EINVAL;
>>>> +
>>>> +      transport = vsk->transport;
>>>> +
>>>> +      if (!transport)
>>>> +              return -EOPNOTSUPP;
>>>
>>> I don't know whether it is better in this case to write it in
>>> sk->sk_rcvlowat, maybe we can return EOPNOTSUPP only when the trasport
>>> is assigned and set_rcvlowat is not defined. This is because usually the
>>> options are set just after creation, when the transport is practically
>>> unassigned.
>>>
>>> I mean something like this:
>>>
>>>          if (transport) {
>>>                  if (transport->set_rcvlowat)
>>>                          return transport->set_rcvlowat(vsk, val);
>>>                  else
>>>                          return -EOPNOTSUPP;
>>>          }
>>>
>>>          WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
>>>
>>>          return 0;
>>
>> Since hv_sock implements `set_rcvlowat` to return EOPNOTSUPP. maybe we 
>> can just do the following:
>>
>>         if (transport && transport->set_rcvlowat)
>>                 return transport->set_rcvlowat(vsk, val);
>>
>>         WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
>>         return 0;
>>
>> That is, the default behavior is to set sk->sk_rcvlowat, but for 
>> transports that want a different behavior, they need to define 
>> set_rcvlowat() (like hv_sock).
> Hm ok, i see. I've implemented logic when non-empty transport is required, because hyperv transport
> forbids to set SO_RCVLOWAT, so user needs to call this setsockopt AFTER transport is assigned(to check
> that transport allows it. Not after socket creation as You mentioned above). Otherwise there is no sense
> in such callback - it will be never used. Also in code above - for hyperv we will have different behavior
> depends on when set_rcvlowat is called: before or after transport assignment. Is it ok?
sorry, i mean: for hyperv, if user sets sk_rcvlowat before transport is assigned, it sees 0 - success, but in fact
hyperv transport forbids this option.
>>
>> Thanks,
>> Stefano
>>
>
Stefano Garzarella Aug. 9, 2022, 10:03 a.m. UTC | #5
On Tue, Aug 09, 2022 at 09:45:47AM +0000, Arseniy Krasnov wrote:
>On 09.08.2022 12:37, Arseniy Krasnov wrote:
>> On 08.08.2022 13:30, Stefano Garzarella wrote:
>>> On Mon, Aug 8, 2022 at 12:23 PM Stefano Garzarella <sgarzare@redhat.com> wrote:
>>>>
>>>> On Wed, Aug 03, 2022 at 01:51:05PM +0000, Arseniy Krasnov wrote:
>>>>> This adds transport specific callback for SO_RCVLOWAT, because in some
>>>>> transports it may be difficult to know current available number of bytes
>>>>> ready to read. Thus, when SO_RCVLOWAT is set, transport may reject it.
>>>>>
>>>>> Signed-off-by: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
>>>>> ---
>>>>> include/net/af_vsock.h   |  1 +
>>>>> net/vmw_vsock/af_vsock.c | 25 +++++++++++++++++++++++++
>>>>> 2 files changed, 26 insertions(+)
>>>>>
>>>>> diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h
>>>>> index f742e50207fb..eae5874bae35 100644
>>>>> --- a/include/net/af_vsock.h
>>>>> +++ b/include/net/af_vsock.h
>>>>> @@ -134,6 +134,7 @@ struct vsock_transport {
>>>>>       u64 (*stream_rcvhiwat)(struct vsock_sock *);
>>>>>       bool (*stream_is_active)(struct vsock_sock *);
>>>>>       bool (*stream_allow)(u32 cid, u32 port);
>>>>> +      int (*set_rcvlowat)(struct vsock_sock *, int);
>>>>
>>>> checkpatch suggests to add identifier names. For some we put them in,
>>>> for others we didn't, but I suggest putting them in for the new ones
>>>> because I think it's clearer too.
>>>>
>>>> WARNING: function definition argument 'struct vsock_sock *' should also
>>>> have an identifier name
>>>> #25: FILE: include/net/af_vsock.h:137:
>>>> +       int (*set_rcvlowat)(struct vsock_sock *, int);
>>>>
>>>> WARNING: function definition argument 'int' should also have an identifier name
>>>> #25: FILE: include/net/af_vsock.h:137:
>>>> +       int (*set_rcvlowat)(struct vsock_sock *, int);
>>>>
>>>> total: 0 errors, 2 warnings, 0 checks, 44 lines checked
>>>>
>>>>>
>>>>>       /* SEQ_PACKET. */
>>>>>       ssize_t (*seqpacket_dequeue)(struct vsock_sock *vsk, struct msghdr *msg,
>>>>> diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
>>>>> index f04abf662ec6..016ad5ff78b7 100644
>>>>> --- a/net/vmw_vsock/af_vsock.c
>>>>> +++ b/net/vmw_vsock/af_vsock.c
>>>>> @@ -2129,6 +2129,30 @@ vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
>>>>>       return err;
>>>>> }
>>>>>
>>>>> +static int vsock_set_rcvlowat(struct sock *sk, int val)
>>>>> +{
>>>>> +      const struct vsock_transport *transport;
>>>>> +      struct vsock_sock *vsk;
>>>>> +      int err = 0;
>>>>> +
>>>>> +      vsk = vsock_sk(sk);
>>>>> +
>>>>> +      if (val > vsk->buffer_size)
>>>>> +              return -EINVAL;
>>>>> +
>>>>> +      transport = vsk->transport;
>>>>> +
>>>>> +      if (!transport)
>>>>> +              return -EOPNOTSUPP;
>>>>
>>>> I don't know whether it is better in this case to write it in
>>>> sk->sk_rcvlowat, maybe we can return EOPNOTSUPP only when the trasport
>>>> is assigned and set_rcvlowat is not defined. This is because usually the
>>>> options are set just after creation, when the transport is practically
>>>> unassigned.
>>>>
>>>> I mean something like this:
>>>>
>>>>          if (transport) {
>>>>                  if (transport->set_rcvlowat)
>>>>                          return transport->set_rcvlowat(vsk, val);
>>>>                  else
>>>>                          return -EOPNOTSUPP;
>>>>          }
>>>>
>>>>          WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
>>>>
>>>>          return 0;
>>>
>>> Since hv_sock implements `set_rcvlowat` to return EOPNOTSUPP. maybe we
>>> can just do the following:
>>>
>>>         if (transport && transport->set_rcvlowat)
>>>                 return transport->set_rcvlowat(vsk, val);
>>>
>>>         WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
>>>         return 0;
>>>
>>> That is, the default behavior is to set sk->sk_rcvlowat, but for
>>> transports that want a different behavior, they need to define
>>> set_rcvlowat() (like hv_sock).
>> Hm ok, i see. I've implemented logic when non-empty transport is required, because hyperv transport
>> forbids to set SO_RCVLOWAT, so user needs to call this setsockopt AFTER transport is assigned(to check
>> that transport allows it. Not after socket creation as You mentioned above). Otherwise there is no sense
>> in such callback - it will be never used. Also in code above - for hyperv we will have different behavior
>> depends on when set_rcvlowat is called: before or after transport assignment. Is it ok?
>sorry, i mean: for hyperv, if user sets sk_rcvlowat before transport is assigned, it sees 0 - success, but in fact
>hyperv transport forbids this option.

I see, but I think it's better to set it and not respect in hyperv (as 
we've practically done until now with all transports) than to prevent 
the setting until we assign a transport.

At most when we use hyperv anyway we get notified per byte, so we should 
just get more notifications than we expect.

Thanks,
Stefano
Arseniy Krasnov Aug. 9, 2022, 10:13 a.m. UTC | #6
On 09.08.2022 13:03, Stefano Garzarella wrote:
> On Tue, Aug 09, 2022 at 09:45:47AM +0000, Arseniy Krasnov wrote:
>> On 09.08.2022 12:37, Arseniy Krasnov wrote:
>>> On 08.08.2022 13:30, Stefano Garzarella wrote:
>>>> On Mon, Aug 8, 2022 at 12:23 PM Stefano Garzarella <sgarzare@redhat.com> wrote:
>>>>>
>>>>> On Wed, Aug 03, 2022 at 01:51:05PM +0000, Arseniy Krasnov wrote:
>>>>>> This adds transport specific callback for SO_RCVLOWAT, because in some
>>>>>> transports it may be difficult to know current available number of bytes
>>>>>> ready to read. Thus, when SO_RCVLOWAT is set, transport may reject it.
>>>>>>
>>>>>> Signed-off-by: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
>>>>>> ---
>>>>>> include/net/af_vsock.h   |  1 +
>>>>>> net/vmw_vsock/af_vsock.c | 25 +++++++++++++++++++++++++
>>>>>> 2 files changed, 26 insertions(+)
>>>>>>
>>>>>> diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h
>>>>>> index f742e50207fb..eae5874bae35 100644
>>>>>> --- a/include/net/af_vsock.h
>>>>>> +++ b/include/net/af_vsock.h
>>>>>> @@ -134,6 +134,7 @@ struct vsock_transport {
>>>>>>       u64 (*stream_rcvhiwat)(struct vsock_sock *);
>>>>>>       bool (*stream_is_active)(struct vsock_sock *);
>>>>>>       bool (*stream_allow)(u32 cid, u32 port);
>>>>>> +      int (*set_rcvlowat)(struct vsock_sock *, int);
>>>>>
>>>>> checkpatch suggests to add identifier names. For some we put them in,
>>>>> for others we didn't, but I suggest putting them in for the new ones
>>>>> because I think it's clearer too.
>>>>>
>>>>> WARNING: function definition argument 'struct vsock_sock *' should also
>>>>> have an identifier name
>>>>> #25: FILE: include/net/af_vsock.h:137:
>>>>> +       int (*set_rcvlowat)(struct vsock_sock *, int);
>>>>>
>>>>> WARNING: function definition argument 'int' should also have an identifier name
>>>>> #25: FILE: include/net/af_vsock.h:137:
>>>>> +       int (*set_rcvlowat)(struct vsock_sock *, int);
>>>>>
>>>>> total: 0 errors, 2 warnings, 0 checks, 44 lines checked
>>>>>
>>>>>>
>>>>>>       /* SEQ_PACKET. */
>>>>>>       ssize_t (*seqpacket_dequeue)(struct vsock_sock *vsk, struct msghdr *msg,
>>>>>> diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
>>>>>> index f04abf662ec6..016ad5ff78b7 100644
>>>>>> --- a/net/vmw_vsock/af_vsock.c
>>>>>> +++ b/net/vmw_vsock/af_vsock.c
>>>>>> @@ -2129,6 +2129,30 @@ vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
>>>>>>       return err;
>>>>>> }
>>>>>>
>>>>>> +static int vsock_set_rcvlowat(struct sock *sk, int val)
>>>>>> +{
>>>>>> +      const struct vsock_transport *transport;
>>>>>> +      struct vsock_sock *vsk;
>>>>>> +      int err = 0;
>>>>>> +
>>>>>> +      vsk = vsock_sk(sk);
>>>>>> +
>>>>>> +      if (val > vsk->buffer_size)
>>>>>> +              return -EINVAL;
>>>>>> +
>>>>>> +      transport = vsk->transport;
>>>>>> +
>>>>>> +      if (!transport)
>>>>>> +              return -EOPNOTSUPP;
>>>>>
>>>>> I don't know whether it is better in this case to write it in
>>>>> sk->sk_rcvlowat, maybe we can return EOPNOTSUPP only when the trasport
>>>>> is assigned and set_rcvlowat is not defined. This is because usually the
>>>>> options are set just after creation, when the transport is practically
>>>>> unassigned.
>>>>>
>>>>> I mean something like this:
>>>>>
>>>>>          if (transport) {
>>>>>                  if (transport->set_rcvlowat)
>>>>>                          return transport->set_rcvlowat(vsk, val);
>>>>>                  else
>>>>>                          return -EOPNOTSUPP;
>>>>>          }
>>>>>
>>>>>          WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
>>>>>
>>>>>          return 0;
>>>>
>>>> Since hv_sock implements `set_rcvlowat` to return EOPNOTSUPP. maybe we
>>>> can just do the following:
>>>>
>>>>         if (transport && transport->set_rcvlowat)
>>>>                 return transport->set_rcvlowat(vsk, val);
>>>>
>>>>         WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
>>>>         return 0;
>>>>
>>>> That is, the default behavior is to set sk->sk_rcvlowat, but for
>>>> transports that want a different behavior, they need to define
>>>> set_rcvlowat() (like hv_sock).
>>> Hm ok, i see. I've implemented logic when non-empty transport is required, because hyperv transport
>>> forbids to set SO_RCVLOWAT, so user needs to call this setsockopt AFTER transport is assigned(to check
>>> that transport allows it. Not after socket creation as You mentioned above). Otherwise there is no sense
>>> in such callback - it will be never used. Also in code above - for hyperv we will have different behavior
>>> depends on when set_rcvlowat is called: before or after transport assignment. Is it ok?
>> sorry, i mean: for hyperv, if user sets sk_rcvlowat before transport is assigned, it sees 0 - success, but in fact
>> hyperv transport forbids this option.
> 
> I see, but I think it's better to set it and not respect in hyperv (as we've practically done until now with all transports) than to prevent the setting until we assign a transport.
> 
> At most when we use hyperv anyway we get notified per byte, so we should just get more notifications than we expect.
see it, ok, thanks
> 
> Thanks,
> Stefano
>
diff mbox series

Patch

diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h
index f742e50207fb..eae5874bae35 100644
--- a/include/net/af_vsock.h
+++ b/include/net/af_vsock.h
@@ -134,6 +134,7 @@  struct vsock_transport {
 	u64 (*stream_rcvhiwat)(struct vsock_sock *);
 	bool (*stream_is_active)(struct vsock_sock *);
 	bool (*stream_allow)(u32 cid, u32 port);
+	int (*set_rcvlowat)(struct vsock_sock *, int);
 
 	/* SEQ_PACKET. */
 	ssize_t (*seqpacket_dequeue)(struct vsock_sock *vsk, struct msghdr *msg,
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index f04abf662ec6..016ad5ff78b7 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -2129,6 +2129,30 @@  vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 	return err;
 }
 
+static int vsock_set_rcvlowat(struct sock *sk, int val)
+{
+	const struct vsock_transport *transport;
+	struct vsock_sock *vsk;
+	int err = 0;
+
+	vsk = vsock_sk(sk);
+
+	if (val > vsk->buffer_size)
+		return -EINVAL;
+
+	transport = vsk->transport;
+
+	if (!transport)
+		return -EOPNOTSUPP;
+
+	if (transport->set_rcvlowat)
+		err = transport->set_rcvlowat(vsk, val);
+	else
+		WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
+
+	return err;
+}
+
 static const struct proto_ops vsock_stream_ops = {
 	.family = PF_VSOCK,
 	.owner = THIS_MODULE,
@@ -2148,6 +2172,7 @@  static const struct proto_ops vsock_stream_ops = {
 	.recvmsg = vsock_connectible_recvmsg,
 	.mmap = sock_no_mmap,
 	.sendpage = sock_no_sendpage,
+	.set_rcvlowat = vsock_set_rcvlowat,
 };
 
 static const struct proto_ops vsock_seqpacket_ops = {