Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1670947 > unrolled thread

Re: [PATCH v4 12/18] xen/pvcalls: implement poll command

Started byBoris Ostrovsky <boris.ostrovsky@oracle.com>
First post2017-06-20 18:50 +0200
Last post2017-06-21 23:50 +0200
Articles 4 — 2 participants

Back to article view | Back to linux.kernel

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: [PATCH v4 12/18] xen/pvcalls: implement poll command Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-06-20 18:50 +0200
    Re: [PATCH v4 12/18] xen/pvcalls: implement poll command Stefano Stabellini <sstabellini@kernel.org> - 2017-06-21 22:40 +0200
      Re: [PATCH v4 12/18] xen/pvcalls: implement poll command Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-06-21 23:00 +0200
        Re: [PATCH v4 12/18] xen/pvcalls: implement poll command Stefano Stabellini <sstabellini@kernel.org> - 2017-06-21 23:50 +0200

#1670947 — Re: [PATCH v4 12/18] xen/pvcalls: implement poll command

FromBoris Ostrovsky <boris.ostrovsky@oracle.com>
Date2017-06-20 18:50 +0200
SubjectRe: [PATCH v4 12/18] xen/pvcalls: implement poll command
Message-ID<tUuvN-2D0-35@gated-at.bofh.it>
> @@ -499,6 +521,55 @@ static int pvcalls_back_accept(struct xenbus_device *dev,
>  static int pvcalls_back_poll(struct xenbus_device *dev,
>  			     struct xen_pvcalls_request *req)
>  {
> +	struct pvcalls_fedata *fedata;
> +	struct sockpass_mapping *mappass;
> +	struct xen_pvcalls_response *rsp;
> +	struct inet_connection_sock *icsk;
> +	struct request_sock_queue *queue;
> +	unsigned long flags;
> +	int ret;
> +	bool data;
> +
> +	fedata = dev_get_drvdata(&dev->dev);
> +
> +	mappass = radix_tree_lookup(&fedata->socketpass_mappings, req->u.poll.id);
> +	if (mappass == NULL)
> +		return -EINVAL;
> +
> +	/*
> +	 * Limitation of the current implementation: only support one
> +	 * concurrent accept or poll call on one socket.
> +	 */
> +	spin_lock_irqsave(&mappass->copy_lock, flags);
> +	if (mappass->reqcopy.cmd != 0) {
> +		ret = -EINTR;
> +		goto out;
> +	}
> +
> +	mappass->reqcopy = *req;
> +	icsk = inet_csk(mappass->sock->sk);
> +	queue = &icsk->icsk_accept_queue;
> +	spin_lock(&queue->rskq_lock);
> +	data = queue->rskq_accept_head != NULL;
> +	spin_unlock(&queue->rskq_lock);

What is the purpose of the queue lock here?

-boris

> +	if (data) {
> +		mappass->reqcopy.cmd = 0;
> +		ret = 0;
> +		goto out;
> +	}
> +	spin_unlock_irqrestore(&mappass->copy_lock, flags);
> +
> +	/* Tell the caller we don't need to send back a notification yet */
> +	return -1;
>

[toc] | [next] | [standalone]


#1672016

FromStefano Stabellini <sstabellini@kernel.org>
Date2017-06-21 22:40 +0200
Message-ID<tUUzU-2OU-17@gated-at.bofh.it>
In reply to#1670947
On Tue, 20 Jun 2017, Boris Ostrovsky wrote:
> > @@ -499,6 +521,55 @@ static int pvcalls_back_accept(struct xenbus_device *dev,
> >  static int pvcalls_back_poll(struct xenbus_device *dev,
> >  			     struct xen_pvcalls_request *req)
> >  {
> > +	struct pvcalls_fedata *fedata;
> > +	struct sockpass_mapping *mappass;
> > +	struct xen_pvcalls_response *rsp;
> > +	struct inet_connection_sock *icsk;
> > +	struct request_sock_queue *queue;
> > +	unsigned long flags;
> > +	int ret;
> > +	bool data;
> > +
> > +	fedata = dev_get_drvdata(&dev->dev);
> > +
> > +	mappass = radix_tree_lookup(&fedata->socketpass_mappings, req->u.poll.id);
> > +	if (mappass == NULL)
> > +		return -EINVAL;
> > +
> > +	/*
> > +	 * Limitation of the current implementation: only support one
> > +	 * concurrent accept or poll call on one socket.
> > +	 */
> > +	spin_lock_irqsave(&mappass->copy_lock, flags);
> > +	if (mappass->reqcopy.cmd != 0) {
> > +		ret = -EINTR;
> > +		goto out;
> > +	}
> > +
> > +	mappass->reqcopy = *req;
> > +	icsk = inet_csk(mappass->sock->sk);
> > +	queue = &icsk->icsk_accept_queue;
> > +	spin_lock(&queue->rskq_lock);
> > +	data = queue->rskq_accept_head != NULL;
> > +	spin_unlock(&queue->rskq_lock);
> 
> What is the purpose of the queue lock here?

It is only there to protect accesses to rskq_accept_head. Functions that
change rskq_accept_head take this lock, see for example
net/ipv4/inet_connection_sock.c:inet_csk_reqsk_queue_add. I'll add an
in-code comment.


> > +	if (data) {
> > +		mappass->reqcopy.cmd = 0;
> > +		ret = 0;
> > +		goto out;
> > +	}
> > +	spin_unlock_irqrestore(&mappass->copy_lock, flags);
> > +
> > +	/* Tell the caller we don't need to send back a notification yet */
> > +	return -1;

[toc] | [prev] | [next] | [standalone]


#1672022

FromBoris Ostrovsky <boris.ostrovsky@oracle.com>
Date2017-06-21 23:00 +0200
Message-ID<tUUTf-2Wi-1@gated-at.bofh.it>
In reply to#1672016
>>> +
>>> +	mappass->reqcopy = *req;
>>> +	icsk = inet_csk(mappass->sock->sk);
>>> +	queue = &icsk->icsk_accept_queue;
>>> +	spin_lock(&queue->rskq_lock);
>>> +	data = queue->rskq_accept_head != NULL;
>>> +	spin_unlock(&queue->rskq_lock);
>> What is the purpose of the queue lock here?
> It is only there to protect accesses to rskq_accept_head. Functions that
> change rskq_accept_head take this lock, see for example
> net/ipv4/inet_connection_sock.c:inet_csk_reqsk_queue_add. I'll add an
> in-code comment.

I am not sure I follow. You are not changing rskq_accept_head, you are
simply reading it under the lock. It may be set by others to NULL as
soon as you drop the lock, at which point 'data' test below will be
obsolete.

In inet_csk_reqsk_queue_add() it is read and then, based on read result,
is written with a value so a lock is indeed need there.

-boris

>
>
>>> +	if (data) {
>>> +		mappass->reqcopy.cmd = 0;
>>> +		ret = 0;
>>> +		goto out;
>>> +	}
>>> +	spin_unlock_irqrestore(&mappass->copy_lock, flags);
>>> +
>>> +	/* Tell the caller we don't need to send back a notification yet */
>>> +	return -1;

[toc] | [prev] | [next] | [standalone]


#1672086

FromStefano Stabellini <sstabellini@kernel.org>
Date2017-06-21 23:50 +0200
Message-ID<tUVFD-3xy-3@gated-at.bofh.it>
In reply to#1672022
On Wed, 21 Jun 2017, Boris Ostrovsky wrote:
> >>> +
> >>> +	mappass->reqcopy = *req;
> >>> +	icsk = inet_csk(mappass->sock->sk);
> >>> +	queue = &icsk->icsk_accept_queue;
> >>> +	spin_lock(&queue->rskq_lock);
> >>> +	data = queue->rskq_accept_head != NULL;
> >>> +	spin_unlock(&queue->rskq_lock);
> >> What is the purpose of the queue lock here?
> > It is only there to protect accesses to rskq_accept_head. Functions that
> > change rskq_accept_head take this lock, see for example
> > net/ipv4/inet_connection_sock.c:inet_csk_reqsk_queue_add. I'll add an
> > in-code comment.
> 
> I am not sure I follow. You are not changing rskq_accept_head, you are
> simply reading it under the lock. It may be set by others to NULL as
> soon as you drop the lock, at which point 'data' test below will be
> obsolete.
> 
> In inet_csk_reqsk_queue_add() it is read and then, based on read result,
> is written with a value so a lock is indeed need there.

I think you are right. The only thing is that without the lock we might
read a transitory value as the rskq_accept_head reads/writes are not
guaranteed to be atomic. However, I don't think we care about it, since
this is just a != NULL test and, as you wrote, the result could be
obsolete immediately after. I'll drop the lock.



> >
> >
> >>> +	if (data) {
> >>> +		mappass->reqcopy.cmd = 0;
> >>> +		ret = 0;
> >>> +		goto out;
> >>> +	}
> >>> +	spin_unlock_irqrestore(&mappass->copy_lock, flags);
> >>> +
> >>> +	/* Tell the caller we don't need to send back a notification yet */
> >>> +	return -1;
> 

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web