Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1700452 > unrolled thread
| Started by | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| First post | 2017-08-01 00:40 +0200 |
| Last post | 2017-08-01 18:10 +0200 |
| Articles | 4 — 3 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.
Re: [PATCH v2 11/13] xen/pvcalls: implement release command Stefano Stabellini <sstabellini@kernel.org> - 2017-08-01 00:40 +0200
Re: [PATCH v2 11/13] xen/pvcalls: implement release command Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-08-01 17:30 +0200
Re: [PATCH v2 11/13] xen/pvcalls: implement release command Juergen Gross <jgross@suse.com> - 2017-08-01 17:40 +0200
Re: [PATCH v2 11/13] xen/pvcalls: implement release command Boris Ostrovsky <boris.ostrovsky@oracle.com> - 2017-08-01 18:10 +0200
| From | Stefano Stabellini <sstabellini@kernel.org> |
|---|---|
| Date | 2017-08-01 00:40 +0200 |
| Subject | Re: [PATCH v2 11/13] xen/pvcalls: implement release command |
| Message-ID | <u9rvY-3zm-15@gated-at.bofh.it> |
On Thu, 27 Jul 2017, Boris Ostrovsky wrote:
> > +int pvcalls_front_release(struct socket *sock)
> > +{
> > + struct pvcalls_bedata *bedata;
> > + struct sock_mapping *map;
> > + int req_id, notify;
> > + struct xen_pvcalls_request *req;
> > +
> > + if (!pvcalls_front_dev)
> > + return -EIO;
> > + bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
> > + if (!bedata)
> > + return -EIO;
>
> Some (all?) other ops don't check bedata validity. Should they all do?
No, I don't think they should: dev_set_drvdata is called in the probe
function (pvcalls_front_probe). I'll remove it.
> > +
> > + if (sock->sk == NULL)
> > + return 0;
> > +
> > + map = (struct sock_mapping *) READ_ONCE(sock->sk->sk_send_head);
> > + if (map == NULL)
> > + return 0;
> > +
> > + spin_lock(&bedata->pvcallss_lock);
> > + req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1);
> > + if (RING_FULL(&bedata->ring) ||
> > + READ_ONCE(bedata->rsp[req_id].req_id) != PVCALLS_INVALID_ID) {
> > + spin_unlock(&bedata->pvcallss_lock);
> > + return -EAGAIN;
> > + }
> > + WRITE_ONCE(sock->sk->sk_send_head, NULL);
> > +
> > + req = RING_GET_REQUEST(&bedata->ring, req_id);
> > + req->req_id = req_id;
> > + req->cmd = PVCALLS_RELEASE;
> > + req->u.release.id = (uint64_t)sock;
> > +
> > + bedata->ring.req_prod_pvt++;
> > + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
> > + spin_unlock(&bedata->pvcallss_lock);
> > + if (notify)
> > + notify_remote_via_irq(bedata->irq);
> > +
> > + wait_event(bedata->inflight_req,
> > + READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
> > +
> > + if (map->active_socket) {
> > + /*
> > + * Set in_error and wake up inflight_conn_req to force
> > + * recvmsg waiters to exit.
> > + */
> > + map->active.ring->in_error = -EBADF;
> > + wake_up_interruptible(&map->active.inflight_conn_req);
> > +
> > + mutex_lock(&map->active.in_mutex);
> > + mutex_lock(&map->active.out_mutex);
> > + pvcalls_front_free_map(bedata, map);
> > + mutex_unlock(&map->active.out_mutex);
> > + mutex_unlock(&map->active.in_mutex);
> > + kfree(map);
>
> Since you are locking here I assume you expect that someone else might
> also be trying to lock the map. But you are freeing it immediately after
> unlocking. Wouldn't that mean that whoever is trying to grab the lock
> might then dereference freed memory?
The lock is to make sure there are no recvmsg or sendmsg in progress. We
are sure that no newer sendmsg or recvmsg are waiting for
pvcalls_front_release to release the lock because before send a message
to the backend we set sk_send_head to NULL.
> > + } else {
> > + spin_lock(&bedata->pvcallss_lock);
> > + list_del_init(&map->list);
> > + kfree(map);
> > + spin_unlock(&bedata->pvcallss_lock);
> > + }
> > + WRITE_ONCE(bedata->rsp[req_id].req_id, PVCALLS_INVALID_ID);
> > +
> > + return 0;
> > +}
> > +
> > static const struct xenbus_device_id pvcalls_front_ids[] = {
> > { "pvcalls" },
> > { "" }
> > diff --git a/drivers/xen/pvcalls-front.h b/drivers/xen/pvcalls-front.h
> > index 25e05b8..3332978 100644
> > --- a/drivers/xen/pvcalls-front.h
> > +++ b/drivers/xen/pvcalls-front.h
> > @@ -23,5 +23,6 @@ int pvcalls_front_recvmsg(struct socket *sock,
> > unsigned int pvcalls_front_poll(struct file *file,
> > struct socket *sock,
> > poll_table *wait);
> > +int pvcalls_front_release(struct socket *sock);
> >
> > #endif
[toc] | [next] | [standalone]
| From | Boris Ostrovsky <boris.ostrovsky@oracle.com> |
|---|---|
| Date | 2017-08-01 17:30 +0200 |
| Message-ID | <u9Hho-5Gd-33@gated-at.bofh.it> |
| In reply to | #1700452 |
On 07/31/2017 06:34 PM, Stefano Stabellini wrote:
> On Thu, 27 Jul 2017, Boris Ostrovsky wrote:
>>> +int pvcalls_front_release(struct socket *sock)
>>> +{
>>> + struct pvcalls_bedata *bedata;
>>> + struct sock_mapping *map;
>>> + int req_id, notify;
>>> + struct xen_pvcalls_request *req;
>>> +
>>> + if (!pvcalls_front_dev)
>>> + return -EIO;
>>> + bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
>>> + if (!bedata)
>>> + return -EIO;
>> Some (all?) other ops don't check bedata validity. Should they all do?
> No, I don't think they should: dev_set_drvdata is called in the probe
> function (pvcalls_front_probe). I'll remove it.
>
>
>>> +
>>> + if (sock->sk == NULL)
>>> + return 0;
>>> +
>>> + map = (struct sock_mapping *) READ_ONCE(sock->sk->sk_send_head);
>>> + if (map == NULL)
>>> + return 0;
>>> +
>>> + spin_lock(&bedata->pvcallss_lock);
>>> + req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1);
>>> + if (RING_FULL(&bedata->ring) ||
>>> + READ_ONCE(bedata->rsp[req_id].req_id) != PVCALLS_INVALID_ID) {
>>> + spin_unlock(&bedata->pvcallss_lock);
>>> + return -EAGAIN;
>>> + }
>>> + WRITE_ONCE(sock->sk->sk_send_head, NULL);
>>> +
>>> + req = RING_GET_REQUEST(&bedata->ring, req_id);
>>> + req->req_id = req_id;
>>> + req->cmd = PVCALLS_RELEASE;
>>> + req->u.release.id = (uint64_t)sock;
>>> +
>>> + bedata->ring.req_prod_pvt++;
>>> + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
>>> + spin_unlock(&bedata->pvcallss_lock);
>>> + if (notify)
>>> + notify_remote_via_irq(bedata->irq);
>>> +
>>> + wait_event(bedata->inflight_req,
>>> + READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
>>> +
>>> + if (map->active_socket) {
>>> + /*
>>> + * Set in_error and wake up inflight_conn_req to force
>>> + * recvmsg waiters to exit.
>>> + */
>>> + map->active.ring->in_error = -EBADF;
>>> + wake_up_interruptible(&map->active.inflight_conn_req);
>>> +
>>> + mutex_lock(&map->active.in_mutex);
>>> + mutex_lock(&map->active.out_mutex);
>>> + pvcalls_front_free_map(bedata, map);
>>> + mutex_unlock(&map->active.out_mutex);
>>> + mutex_unlock(&map->active.in_mutex);
>>> + kfree(map);
>> Since you are locking here I assume you expect that someone else might
>> also be trying to lock the map. But you are freeing it immediately after
>> unlocking. Wouldn't that mean that whoever is trying to grab the lock
>> might then dereference freed memory?
> The lock is to make sure there are no recvmsg or sendmsg in progress. We
> are sure that no newer sendmsg or recvmsg are waiting for
> pvcalls_front_release to release the lock because before send a message
> to the backend we set sk_send_head to NULL.
Is there a chance that whoever is potentially calling send/rcvmsg has
checked that sk_send_head is non-NULL but hasn't grabbed the lock yet?
Freeing a structure containing a lock right after releasing the lock
looks weird (to me). Is there any other way to synchronize with
sender/receiver? Any other lock?
BTW, I also noticed that in rcvmsg you are calling
wait_event_interruptible() while holding the lock. Have you tested with
CONFIG_DEBUG_ATOMIC_SLEEP? (or maybe it's some other config option that
would complain about those sorts of thing)
-boris
[toc] | [prev] | [next] | [standalone]
| From | Juergen Gross <jgross@suse.com> |
|---|---|
| Date | 2017-08-01 17:40 +0200 |
| Message-ID | <u9Hr4-5Jr-17@gated-at.bofh.it> |
| In reply to | #1701153 |
On 01/08/17 17:23, Boris Ostrovsky wrote:
> On 07/31/2017 06:34 PM, Stefano Stabellini wrote:
>> On Thu, 27 Jul 2017, Boris Ostrovsky wrote:
>>>> +int pvcalls_front_release(struct socket *sock)
>>>> +{
>>>> + struct pvcalls_bedata *bedata;
>>>> + struct sock_mapping *map;
>>>> + int req_id, notify;
>>>> + struct xen_pvcalls_request *req;
>>>> +
>>>> + if (!pvcalls_front_dev)
>>>> + return -EIO;
>>>> + bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
>>>> + if (!bedata)
>>>> + return -EIO;
>>> Some (all?) other ops don't check bedata validity. Should they all do?
>> No, I don't think they should: dev_set_drvdata is called in the probe
>> function (pvcalls_front_probe). I'll remove it.
>>
>>
>>>> +
>>>> + if (sock->sk == NULL)
>>>> + return 0;
>>>> +
>>>> + map = (struct sock_mapping *) READ_ONCE(sock->sk->sk_send_head);
>>>> + if (map == NULL)
>>>> + return 0;
>>>> +
>>>> + spin_lock(&bedata->pvcallss_lock);
>>>> + req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1);
>>>> + if (RING_FULL(&bedata->ring) ||
>>>> + READ_ONCE(bedata->rsp[req_id].req_id) != PVCALLS_INVALID_ID) {
>>>> + spin_unlock(&bedata->pvcallss_lock);
>>>> + return -EAGAIN;
>>>> + }
>>>> + WRITE_ONCE(sock->sk->sk_send_head, NULL);
>>>> +
>>>> + req = RING_GET_REQUEST(&bedata->ring, req_id);
>>>> + req->req_id = req_id;
>>>> + req->cmd = PVCALLS_RELEASE;
>>>> + req->u.release.id = (uint64_t)sock;
>>>> +
>>>> + bedata->ring.req_prod_pvt++;
>>>> + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
>>>> + spin_unlock(&bedata->pvcallss_lock);
>>>> + if (notify)
>>>> + notify_remote_via_irq(bedata->irq);
>>>> +
>>>> + wait_event(bedata->inflight_req,
>>>> + READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
>>>> +
>>>> + if (map->active_socket) {
>>>> + /*
>>>> + * Set in_error and wake up inflight_conn_req to force
>>>> + * recvmsg waiters to exit.
>>>> + */
>>>> + map->active.ring->in_error = -EBADF;
>>>> + wake_up_interruptible(&map->active.inflight_conn_req);
>>>> +
>>>> + mutex_lock(&map->active.in_mutex);
>>>> + mutex_lock(&map->active.out_mutex);
>>>> + pvcalls_front_free_map(bedata, map);
>>>> + mutex_unlock(&map->active.out_mutex);
>>>> + mutex_unlock(&map->active.in_mutex);
>>>> + kfree(map);
>>> Since you are locking here I assume you expect that someone else might
>>> also be trying to lock the map. But you are freeing it immediately after
>>> unlocking. Wouldn't that mean that whoever is trying to grab the lock
>>> might then dereference freed memory?
>> The lock is to make sure there are no recvmsg or sendmsg in progress. We
>> are sure that no newer sendmsg or recvmsg are waiting for
>> pvcalls_front_release to release the lock because before send a message
>> to the backend we set sk_send_head to NULL.
>
> Is there a chance that whoever is potentially calling send/rcvmsg has
> checked that sk_send_head is non-NULL but hasn't grabbed the lock yet?
>
> Freeing a structure containing a lock right after releasing the lock
> looks weird (to me). Is there any other way to synchronize with
> sender/receiver? Any other lock?
Right. This looks fishy. Either you don't need the locks or you can't
just free the area right after releasing the lock.
> BTW, I also noticed that in rcvmsg you are calling
> wait_event_interruptible() while holding the lock. Have you tested with
> CONFIG_DEBUG_ATOMIC_SLEEP? (or maybe it's some other config option that
> would complain about those sorts of thing)
I believe sleeping while holding a mutex is allowed. Sleeping in
spinlocked paths is bad.
BTW: You are looking for CONFIG_DEBUG_MUTEXES (see
Documentation/locking/mutex-design.txt ).
Juergen
[toc] | [prev] | [next] | [standalone]
| From | Boris Ostrovsky <boris.ostrovsky@oracle.com> |
|---|---|
| Date | 2017-08-01 18:10 +0200 |
| Message-ID | <u9HU6-68E-23@gated-at.bofh.it> |
| In reply to | #1701164 |
>> BTW, I also noticed that in rcvmsg you are calling >> wait_event_interruptible() while holding the lock. Have you tested with >> CONFIG_DEBUG_ATOMIC_SLEEP? (or maybe it's some other config option that >> would complain about those sorts of thing) > I believe sleeping while holding a mutex is allowed. Sleeping in > spinlocked paths is bad. Oh, right. I was thinking about spinlocks. Sorry. -boris > > BTW: You are looking for CONFIG_DEBUG_MUTEXES (see > Documentation/locking/mutex-design.txt ). > > > Juergen
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web