- 9p/xen racy double-free fix

- track 9p RPC waiting time as IO
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE/IPbcYBuWt0zoYhOq06b7GqY5nAFAmmRjJcACgkQq06b7GqY
 5nCUMA//WDifZs5ug0Zf/6pKJ3PIr/NmQf0XXPmn0YlR53Uz11X9CoXV0ZjQJsz6
 Dsp5DMgHpTBizBb+iS/0wTuNqB1Imx+r5opEi/+vgVdl53XxcurmmqfJBULLdOhj
 a02PKH3VBzpTel93mYpvJvxil6dpN/fqfpKm2dGOcz8U6d5KFYpjkMZoYBVQWhQx
 4Afyp71XHbuHamg68sw4UOmCTeWNGOxYPDrL/pVCl3usKC+6zX4vTADtS6ckjYtb
 7s45hJmYuRQ8IyZnXEJeUefm3OoxwSxXUERP3lotMEiImMLE6g/IK5hiQaLYkPwb
 aEyNGP2ReISXUdXy0jJA3ILUcYs1+fbq89Rs93LC/+EzjQm5b23yfsEB5DyIAZnw
 giOXAcBjm/3cC7czw8Rw6Aa6dGjjWDg//5hOzDbvdVH54j3MnKzLiwQylgsszBKX
 dY58SMDGPdn/Bcf+TDyu5Ahr4GDARX0vVSLFot3xEULt9x90Sdd89GQffujIKx3v
 bIcGj0Ql/BRMnPVB5gZD2c8K+HeIIYrv/l4tlVLpOeKIepBw0yNnFMBDp+yQxbSf
 gkJxajkcjd9hEjaK1U4znJeX3cQzhgj0cpPRJq7b9SSC1+4c6PThL8PSDrmzCPJV
 DGBSFMHQR6g+zFy4xpbc5ErBReNZVXN1FqvCGo6TM0fTPvTNcV0=
 =ew5K
 -----END PGP SIGNATURE-----

Merge tag '9p-for-7.0-rc1' of https://github.com/martinetd/linux

Pull 9p updates from Dominique Martinet:

 - 9p/xen racy double-free fix

 - track 9p RPC waiting time as IO

* tag '9p-for-7.0-rc1' of https://github.com/martinetd/linux:
  9p/xen: protect xen_9pfs_front_free against concurrent calls
  9p: Track 9P RPC waiting time as IO
  wait: Introduce io_wait_event_killable()
This commit is contained in:
Linus Torvalds 2026-02-15 10:24:46 -08:00
commit 011af61b9f
4 changed files with 67 additions and 49 deletions

View file

@ -937,6 +937,21 @@ extern int do_wait_intr_irq(wait_queue_head_t *, wait_queue_entry_t *);
__ret; \
})
#define __io_wait_event_killable(wq, condition) \
___wait_event(wq, condition, TASK_KILLABLE, 0, 0, io_schedule())
/*
* wait_event_killable() - link wait_event_killable but with io_schedule()
*/
#define io_wait_event_killable(wq_head, condition) \
({ \
int __ret = 0; \
might_sleep(); \
if (!(condition)) \
__ret = __io_wait_event_killable(wq_head, condition); \
__ret; \
})
#define __wait_event_state(wq, condition, state) \
___wait_event(wq, condition, state, 0, 0, schedule())

View file

@ -590,8 +590,8 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
}
again:
/* Wait for the response */
err = wait_event_killable(req->wq,
READ_ONCE(req->status) >= REQ_STATUS_RCVD);
err = io_wait_event_killable(req->wq,
READ_ONCE(req->status) >= REQ_STATUS_RCVD);
/* Make sure our req is coherent with regard to updates in other
* threads - echoes to wmb() in the callback

View file

@ -284,8 +284,8 @@ req_retry:
if (err == -ENOSPC) {
chan->ring_bufs_avail = 0;
spin_unlock_irqrestore(&chan->lock, flags);
err = wait_event_killable(*chan->vc_wq,
chan->ring_bufs_avail);
err = io_wait_event_killable(*chan->vc_wq,
chan->ring_bufs_avail);
if (err == -ERESTARTSYS)
return err;
@ -325,7 +325,7 @@ static int p9_get_mapped_pages(struct virtio_chan *chan,
* Other zc request to finish here
*/
if (atomic_read(&vp_pinned) >= chan->p9_max_pages) {
err = wait_event_killable(vp_wq,
err = io_wait_event_killable(vp_wq,
(atomic_read(&vp_pinned) < chan->p9_max_pages));
if (err == -ERESTARTSYS)
return err;
@ -512,8 +512,8 @@ req_retry_pinned:
if (err == -ENOSPC) {
chan->ring_bufs_avail = 0;
spin_unlock_irqrestore(&chan->lock, flags);
err = wait_event_killable(*chan->vc_wq,
chan->ring_bufs_avail);
err = io_wait_event_killable(*chan->vc_wq,
chan->ring_bufs_avail);
if (err == -ERESTARTSYS)
goto err_out;
@ -531,8 +531,8 @@ req_retry_pinned:
spin_unlock_irqrestore(&chan->lock, flags);
kicked = 1;
p9_debug(P9_DEBUG_TRANS, "virtio request kicked\n");
err = wait_event_killable(req->wq,
READ_ONCE(req->status) >= REQ_STATUS_RCVD);
err = io_wait_event_killable(req->wq,
READ_ONCE(req->status) >= REQ_STATUS_RCVD);
// RERROR needs reply (== error string) in static data
if (READ_ONCE(req->status) == REQ_STATUS_RCVD &&
unlikely(req->rc.sdata[4] == P9_RERROR))

View file

@ -136,8 +136,8 @@ static int p9_xen_request(struct p9_client *client, struct p9_req_t *p9_req)
ring = &priv->rings[num];
again:
while (wait_event_killable(ring->wq,
p9_xen_write_todo(ring, size)) != 0)
while (io_wait_event_killable(ring->wq,
p9_xen_write_todo(ring, size)) != 0)
;
spin_lock_irqsave(&ring->lock, flags);
@ -277,45 +277,52 @@ static void xen_9pfs_front_free(struct xen_9pfs_front_priv *priv)
{
int i, j;
write_lock(&xen_9pfs_lock);
list_del(&priv->list);
write_unlock(&xen_9pfs_lock);
if (priv->rings) {
for (i = 0; i < XEN_9PFS_NUM_RINGS; i++) {
struct xen_9pfs_dataring *ring = &priv->rings[i];
for (i = 0; i < XEN_9PFS_NUM_RINGS; i++) {
struct xen_9pfs_dataring *ring = &priv->rings[i];
cancel_work_sync(&ring->work);
cancel_work_sync(&ring->work);
if (!priv->rings[i].intf)
break;
if (priv->rings[i].irq > 0)
unbind_from_irqhandler(priv->rings[i].irq, ring);
if (priv->rings[i].data.in) {
for (j = 0;
j < (1 << priv->rings[i].intf->ring_order);
j++) {
grant_ref_t ref;
if (!priv->rings[i].intf)
break;
if (priv->rings[i].irq > 0)
unbind_from_irqhandler(priv->rings[i].irq, ring);
if (priv->rings[i].data.in) {
for (j = 0;
j < (1 << priv->rings[i].intf->ring_order);
j++) {
grant_ref_t ref;
ref = priv->rings[i].intf->ref[j];
gnttab_end_foreign_access(ref, NULL);
}
free_pages_exact(priv->rings[i].data.in,
ref = priv->rings[i].intf->ref[j];
gnttab_end_foreign_access(ref, NULL);
}
free_pages_exact(priv->rings[i].data.in,
1UL << (priv->rings[i].intf->ring_order +
XEN_PAGE_SHIFT));
}
gnttab_end_foreign_access(priv->rings[i].ref, NULL);
free_page((unsigned long)priv->rings[i].intf);
}
gnttab_end_foreign_access(priv->rings[i].ref, NULL);
free_page((unsigned long)priv->rings[i].intf);
kfree(priv->rings);
}
kfree(priv->rings);
kfree(priv->tag);
kfree(priv);
}
static void xen_9pfs_front_remove(struct xenbus_device *dev)
{
struct xen_9pfs_front_priv *priv = dev_get_drvdata(&dev->dev);
struct xen_9pfs_front_priv *priv;
write_lock(&xen_9pfs_lock);
priv = dev_get_drvdata(&dev->dev);
if (priv == NULL) {
write_unlock(&xen_9pfs_lock);
return;
}
dev_set_drvdata(&dev->dev, NULL);
list_del(&priv->list);
write_unlock(&xen_9pfs_lock);
xen_9pfs_front_free(priv);
}
@ -382,7 +389,7 @@ static int xen_9pfs_front_init(struct xenbus_device *dev)
{
int ret, i;
struct xenbus_transaction xbt;
struct xen_9pfs_front_priv *priv = dev_get_drvdata(&dev->dev);
struct xen_9pfs_front_priv *priv;
char *versions, *v;
unsigned int max_rings, max_ring_order, len = 0;
@ -410,6 +417,10 @@ static int xen_9pfs_front_init(struct xenbus_device *dev)
if (p9_xen_trans.maxsize > XEN_FLEX_RING_SIZE(max_ring_order))
p9_xen_trans.maxsize = XEN_FLEX_RING_SIZE(max_ring_order) / 2;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dev = dev;
priv->rings = kcalloc(XEN_9PFS_NUM_RINGS, sizeof(*priv->rings),
GFP_KERNEL);
if (!priv->rings) {
@ -468,6 +479,11 @@ static int xen_9pfs_front_init(struct xenbus_device *dev)
goto error;
}
write_lock(&xen_9pfs_lock);
dev_set_drvdata(&dev->dev, priv);
list_add_tail(&priv->list, &xen_9pfs_devs);
write_unlock(&xen_9pfs_lock);
xenbus_switch_state(dev, XenbusStateInitialised);
return 0;
@ -482,19 +498,6 @@ static int xen_9pfs_front_init(struct xenbus_device *dev)
static int xen_9pfs_front_probe(struct xenbus_device *dev,
const struct xenbus_device_id *id)
{
struct xen_9pfs_front_priv *priv = NULL;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dev = dev;
dev_set_drvdata(&dev->dev, priv);
write_lock(&xen_9pfs_lock);
list_add_tail(&priv->list, &xen_9pfs_devs);
write_unlock(&xen_9pfs_lock);
return 0;
}