@@ -25,3 +25,13 @@ Description:
allocated without being in use. The time is in
seconds, 0 means indefinitely long.
The default is 60 seconds.
+
+What: /sys/module/xen_blkback/parameters/buffer_squeeze_duration_ms
+Date: December 2019
+KernelVersion: 5.5
+Contact: SeongJae Park <sjpark@amazon.de>
+Description:
+ When memory pressure is reported to blkback this option
+ controls the duration in milliseconds that blkback will not
+ cache any page not backed by a grant mapping.
+ The default is 10ms.
@@ -656,8 +656,11 @@ int xen_blkif_schedule(void *arg)
ring->next_lru = jiffies + msecs_to_jiffies(LRU_INTERVAL);
}
- /* Shrink if we have more than xen_blkif_max_buffer_pages */
- shrink_free_pagepool(ring, xen_blkif_max_buffer_pages);
+ /* Shrink the free pages pool if it is too large. */
+ if (time_before(jiffies, blkif->buffer_squeeze_end))
+ shrink_free_pagepool(ring, 0);
+ else
+ shrink_free_pagepool(ring, xen_blkif_max_buffer_pages);
if (log_stats && time_after(jiffies, ring->st_print))
print_stats(ring);
@@ -319,6 +319,7 @@ struct xen_blkif {
/* All rings for this device. */
struct xen_blkif_ring *rings;
unsigned int nr_rings;
+ unsigned long buffer_squeeze_end;
};
struct seg_buf {
@@ -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",
@@ -824,6 +831,28 @@ static void frontend_changed(struct xenbus_device *dev,
}
+/* Once a memory pressure is detected, squeeze free page pools for a while. */
+static unsigned int buffer_squeeze_duration_ms = 10;
+module_param_named(buffer_squeeze_duration_ms,
+ buffer_squeeze_duration_ms, int, 0644);
+MODULE_PARM_DESC(buffer_squeeze_duration_ms,
+"Duration in ms to squeeze pages buffer when a memory pressure is detected");
+
+/*
+ * Callback received when the memory pressure is detected.
+ */
+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);
+}
+
/* ** Connection ** */
@@ -1115,7 +1144,8 @@ static struct xenbus_driver xen_blkbk_driver = {
.ids = xen_blkbk_ids,
.probe = xen_blkbk_probe,
.remove = xen_blkbk_remove,
- .otherend_changed = frontend_changed
+ .otherend_changed = frontend_changed,
+ .reclaim_memory = reclaim_memory,
};
int xen_blkif_xenbus_init(void)