12c95fb75SEmmanuel Vadot /*-
22c95fb75SEmmanuel Vadot * Copyright (c) 2020 Emmanuel Vadot <manu@FreeBSD.org>
32c95fb75SEmmanuel Vadot *
42c95fb75SEmmanuel Vadot * Redistribution and use in source and binary forms, with or without
52c95fb75SEmmanuel Vadot * modification, are permitted provided that the following conditions
62c95fb75SEmmanuel Vadot * are met:
72c95fb75SEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright
82c95fb75SEmmanuel Vadot * notice, this list of conditions and the following disclaimer.
92c95fb75SEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright
102c95fb75SEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the
112c95fb75SEmmanuel Vadot * documentation and/or other materials provided with the distribution.
122c95fb75SEmmanuel Vadot *
132c95fb75SEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
142c95fb75SEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
152c95fb75SEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
162c95fb75SEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
172c95fb75SEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
182c95fb75SEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
192c95fb75SEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
202c95fb75SEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
212c95fb75SEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
222c95fb75SEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
232c95fb75SEmmanuel Vadot * SUCH DAMAGE.
242c95fb75SEmmanuel Vadot */
252c95fb75SEmmanuel Vadot
262c95fb75SEmmanuel Vadot #include <sys/param.h>
272c95fb75SEmmanuel Vadot #include <sys/systm.h>
282c95fb75SEmmanuel Vadot #include <sys/kernel.h>
292c95fb75SEmmanuel Vadot #include <sys/queue.h>
302c95fb75SEmmanuel Vadot #include <sys/eventhandler.h>
3129d5f0c1SVladimir Kondratyev #include <sys/sx.h>
322c95fb75SEmmanuel Vadot
332fe9ea5dSVladimir Kondratyev #include <linux/compat.h>
342c95fb75SEmmanuel Vadot #include <linux/shrinker.h>
352c95fb75SEmmanuel Vadot
362c95fb75SEmmanuel Vadot TAILQ_HEAD(, shrinker) lkpi_shrinkers = TAILQ_HEAD_INITIALIZER(lkpi_shrinkers);
3729d5f0c1SVladimir Kondratyev static struct sx sx_shrinker;
382c95fb75SEmmanuel Vadot
392c95fb75SEmmanuel Vadot int
linuxkpi_register_shrinker(struct shrinker * s)402c95fb75SEmmanuel Vadot linuxkpi_register_shrinker(struct shrinker *s)
412c95fb75SEmmanuel Vadot {
422c95fb75SEmmanuel Vadot
432c95fb75SEmmanuel Vadot KASSERT(s != NULL, ("NULL shrinker"));
442c95fb75SEmmanuel Vadot KASSERT(s->count_objects != NULL, ("NULL shrinker"));
452c95fb75SEmmanuel Vadot KASSERT(s->scan_objects != NULL, ("NULL shrinker"));
4629d5f0c1SVladimir Kondratyev sx_xlock(&sx_shrinker);
472c95fb75SEmmanuel Vadot TAILQ_INSERT_TAIL(&lkpi_shrinkers, s, next);
4829d5f0c1SVladimir Kondratyev sx_xunlock(&sx_shrinker);
492c95fb75SEmmanuel Vadot return (0);
502c95fb75SEmmanuel Vadot }
512c95fb75SEmmanuel Vadot
522c95fb75SEmmanuel Vadot void
linuxkpi_unregister_shrinker(struct shrinker * s)532c95fb75SEmmanuel Vadot linuxkpi_unregister_shrinker(struct shrinker *s)
542c95fb75SEmmanuel Vadot {
552c95fb75SEmmanuel Vadot
5629d5f0c1SVladimir Kondratyev sx_xlock(&sx_shrinker);
572c95fb75SEmmanuel Vadot TAILQ_REMOVE(&lkpi_shrinkers, s, next);
5829d5f0c1SVladimir Kondratyev sx_xunlock(&sx_shrinker);
592c95fb75SEmmanuel Vadot }
602c95fb75SEmmanuel Vadot
61*83636727SJean-Sébastien Pédron void
linuxkpi_synchronize_shrinkers(void)62*83636727SJean-Sébastien Pédron linuxkpi_synchronize_shrinkers(void)
63*83636727SJean-Sébastien Pédron {
64*83636727SJean-Sébastien Pédron
65*83636727SJean-Sébastien Pédron sx_xlock(&sx_shrinker);
66*83636727SJean-Sébastien Pédron sx_xunlock(&sx_shrinker);
67*83636727SJean-Sébastien Pédron }
68*83636727SJean-Sébastien Pédron
692c95fb75SEmmanuel Vadot #define SHRINKER_BATCH 512
702c95fb75SEmmanuel Vadot
712c95fb75SEmmanuel Vadot static void
shrinker_shrink(struct shrinker * s)722c95fb75SEmmanuel Vadot shrinker_shrink(struct shrinker *s)
732c95fb75SEmmanuel Vadot {
742c95fb75SEmmanuel Vadot struct shrink_control sc;
752c95fb75SEmmanuel Vadot unsigned long can_free;
762c95fb75SEmmanuel Vadot unsigned long batch;
774af93235SMark Johnston unsigned long scanned = 0;
782c95fb75SEmmanuel Vadot unsigned long ret;
792c95fb75SEmmanuel Vadot
802c95fb75SEmmanuel Vadot can_free = s->count_objects(s, &sc);
812c95fb75SEmmanuel Vadot if (can_free <= 0)
822c95fb75SEmmanuel Vadot return;
832c95fb75SEmmanuel Vadot
842c95fb75SEmmanuel Vadot batch = s->batch ? s->batch : SHRINKER_BATCH;
854af93235SMark Johnston while (scanned <= can_free) {
862c95fb75SEmmanuel Vadot sc.nr_to_scan = batch;
872c95fb75SEmmanuel Vadot ret = s->scan_objects(s, &sc);
882c95fb75SEmmanuel Vadot if (ret == SHRINK_STOP)
892c95fb75SEmmanuel Vadot break;
904af93235SMark Johnston scanned += batch;
912c95fb75SEmmanuel Vadot }
922c95fb75SEmmanuel Vadot }
932c95fb75SEmmanuel Vadot
942c95fb75SEmmanuel Vadot static void
linuxkpi_vm_lowmem(void * arg __unused)952c95fb75SEmmanuel Vadot linuxkpi_vm_lowmem(void *arg __unused)
962c95fb75SEmmanuel Vadot {
972c95fb75SEmmanuel Vadot struct shrinker *s;
982c95fb75SEmmanuel Vadot
9929d5f0c1SVladimir Kondratyev sx_xlock(&sx_shrinker);
1002c95fb75SEmmanuel Vadot TAILQ_FOREACH(s, &lkpi_shrinkers, next) {
1012c95fb75SEmmanuel Vadot shrinker_shrink(s);
1022c95fb75SEmmanuel Vadot }
10329d5f0c1SVladimir Kondratyev sx_xunlock(&sx_shrinker);
1042c95fb75SEmmanuel Vadot }
1052c95fb75SEmmanuel Vadot
1062c95fb75SEmmanuel Vadot static eventhandler_tag lowmem_tag;
1072c95fb75SEmmanuel Vadot
1082c95fb75SEmmanuel Vadot static void
linuxkpi_sysinit_shrinker(void * arg __unused)1092c95fb75SEmmanuel Vadot linuxkpi_sysinit_shrinker(void *arg __unused)
1102c95fb75SEmmanuel Vadot {
1112c95fb75SEmmanuel Vadot
11229d5f0c1SVladimir Kondratyev sx_init(&sx_shrinker, "lkpi-shrinker");
1132c95fb75SEmmanuel Vadot lowmem_tag = EVENTHANDLER_REGISTER(vm_lowmem, linuxkpi_vm_lowmem,
1142c95fb75SEmmanuel Vadot NULL, EVENTHANDLER_PRI_FIRST);
1152c95fb75SEmmanuel Vadot }
1162c95fb75SEmmanuel Vadot
1172c95fb75SEmmanuel Vadot static void
linuxkpi_sysuninit_shrinker(void * arg __unused)1182c95fb75SEmmanuel Vadot linuxkpi_sysuninit_shrinker(void *arg __unused)
1192c95fb75SEmmanuel Vadot {
1202c95fb75SEmmanuel Vadot
12129d5f0c1SVladimir Kondratyev sx_destroy(&sx_shrinker);
1222c95fb75SEmmanuel Vadot EVENTHANDLER_DEREGISTER(vm_lowmem, lowmem_tag);
1232c95fb75SEmmanuel Vadot }
1242c95fb75SEmmanuel Vadot
1252c95fb75SEmmanuel Vadot SYSINIT(linuxkpi_shrinker, SI_SUB_DRIVERS, SI_ORDER_ANY,
1262c95fb75SEmmanuel Vadot linuxkpi_sysinit_shrinker, NULL);
1272c95fb75SEmmanuel Vadot SYSUNINIT(linuxkpi_shrinker, SI_SUB_DRIVERS, SI_ORDER_ANY,
1282c95fb75SEmmanuel Vadot linuxkpi_sysuninit_shrinker, NULL);
129