[PATCH v11 4/6] xen/blkback: Protect 'reclaim_memory()' with 'reclaim_lock'
From: SeongJae Park
Date: Tue Dec 17 2019 - 11:09:13 EST
From: SeongJae Park <sjpark@xxxxxxxxx>
The 'reclaim_memory()' callback of blkback could race with
'xen_blkbk_probe()' and 'xen_blkbk_remove()'. In the case, incompletely
linked 'backend_info' and 'blkif' might be exposed to the callback, thus
result in bad results including NULL dereference. This commit fixes the
problem by applying the 'reclaim_lock' protection to those.
Note that this commit is separated for review purpose only. As the
previous commit might result in race condition and might make bisect
confuse, please squash this commit into previous commit if possible.
Signed-off-by: SeongJae Park <sjpark@xxxxxxxxx>
---
drivers/block/xen-blkback/xenbus.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
index 4f6ea4feca79..20045827a391 100644
--- a/drivers/block/xen-blkback/xenbus.c
+++ b/drivers/block/xen-blkback/xenbus.c
@@ -492,6 +492,7 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle,
static int xen_blkbk_remove(struct xenbus_device *dev)
{
struct backend_info *be = dev_get_drvdata(&dev->dev);
+ unsigned long flags;
pr_debug("%s %p %d\n", __func__, dev, dev->otherend_id);
@@ -504,6 +505,7 @@ static int xen_blkbk_remove(struct xenbus_device *dev)
be->backend_watch.node = NULL;
}
+ spin_lock_irqsave(&dev->reclaim_lock, flags);
dev_set_drvdata(&dev->dev, NULL);
if (be->blkif) {
@@ -512,6 +514,7 @@ static int xen_blkbk_remove(struct xenbus_device *dev)
/* Put the reference we set in xen_blkif_alloc(). */
xen_blkif_put(be->blkif);
}
+ spin_unlock_irqrestore(&dev->reclaim_lock, flags);
return 0;
}
@@ -597,6 +600,7 @@ static int xen_blkbk_probe(struct xenbus_device *dev,
int err;
struct backend_info *be = kzalloc(sizeof(struct backend_info),
GFP_KERNEL);
+ unsigned long flags;
/* match the pr_debug in xen_blkbk_remove */
pr_debug("%s %p %d\n", __func__, dev, dev->otherend_id);
@@ -607,6 +611,7 @@ static int xen_blkbk_probe(struct xenbus_device *dev,
return -ENOMEM;
}
be->dev = dev;
+ spin_lock_irqsave(&dev->reclaim_lock, flags);
dev_set_drvdata(&dev->dev, be);
be->blkif = xen_blkif_alloc(dev->otherend_id);
@@ -614,8 +619,10 @@ static int xen_blkbk_probe(struct xenbus_device *dev,
err = PTR_ERR(be->blkif);
be->blkif = NULL;
xenbus_dev_fatal(dev, err, "creating block interface");
+ spin_unlock_irqrestore(&dev->reclaim_lock, flags);
goto fail;
}
+ spin_unlock_irqrestore(&dev->reclaim_lock, flags);
err = xenbus_printf(XBT_NIL, dev->nodename,
"feature-max-indirect-segments", "%u",
@@ -838,6 +845,10 @@ static void reclaim_memory(struct xenbus_device *dev)
{
struct backend_info *be = dev_get_drvdata(&dev->dev);
+ /* Device is registered but not probed yet */
+ if (!be)
+ return;
+
be->blkif->buffer_squeeze_end = jiffies +
msecs_to_jiffies(buffer_squeeze_duration_ms);
}
--
2.17.1