Add a shrinker to reclaim several pages used by bounce buffer in order to avoid memory pressures. Signed-off-by: Xie Yongji <xieyongji@xxxxxxxxxxxxx> --- drivers/vdpa/vdpa_user/vduse_dev.c | 51 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index c29b24a7e7e9..1bc2e627c476 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -1142,6 +1142,43 @@ static long vduse_ioctl(struct file *file, unsigned int cmd, return ret; } +static unsigned long vduse_shrink_scan(struct shrinker *shrinker, + struct shrink_control *sc) +{ + unsigned long freed = 0; + struct vduse_dev *dev; + + if (!mutex_trylock(&vduse_lock)) + return SHRINK_STOP; + + list_for_each_entry(dev, &vduse_devs, list) { + if (!dev->domain) + continue; + + freed = vduse_domain_reclaim(dev->domain); + if (!freed) + continue; + + list_move_tail(&dev->list, &vduse_devs); + break; + } + mutex_unlock(&vduse_lock); + + return freed ? freed : SHRINK_STOP; +} + +static unsigned long vduse_shrink_count(struct shrinker *shrink, + struct shrink_control *sc) +{ + return percpu_counter_read_positive(&vduse_total_bounce_pages); +} + +static struct shrinker vduse_bounce_pages_shrinker = { + .count_objects = vduse_shrink_count, + .scan_objects = vduse_shrink_scan, + .seeks = DEFAULT_SEEKS, +}; + static const struct file_operations vduse_fops = { .owner = THIS_MODULE, .unlocked_ioctl = vduse_ioctl, @@ -1292,12 +1329,24 @@ static int vduse_init(void) if (ret) goto err_irqfd; + ret = vduse_domain_init(); + if (ret) + goto err_domain; + + ret = register_shrinker(&vduse_bounce_pages_shrinker); + if (ret) + goto err_shrinker; + ret = vduse_parentdev_init(); if (ret) goto err_parentdev; return 0; err_parentdev: + unregister_shrinker(&vduse_bounce_pages_shrinker); +err_shrinker: + vduse_domain_exit(); +err_domain: vduse_virqfd_exit(); err_irqfd: destroy_workqueue(vduse_vdpa_wq); @@ -1309,8 +1358,10 @@ module_init(vduse_init); static void vduse_exit(void) { + unregister_shrinker(&vduse_bounce_pages_shrinker); misc_deregister(&vduse_misc); destroy_workqueue(vduse_vdpa_wq); + vduse_domain_exit(); vduse_virqfd_exit(); vduse_parentdev_exit(); } -- 2.11.0