xref: /freebsd-src/sys/compat/linuxkpi/common/src/linux_shrinker.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
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