Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/compat/linuxkpi/common/src/linux_shrinker.c
39586 views
1
/*-
2
* Copyright (c) 2020 Emmanuel Vadot <[email protected]>
3
*
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
6
* are met:
7
* 1. Redistributions of source code must retain the above copyright
8
* notice, this list of conditions and the following disclaimer.
9
* 2. Redistributions in binary form must reproduce the above copyright
10
* notice, this list of conditions and the following disclaimer in the
11
* documentation and/or other materials provided with the distribution.
12
*
13
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23
* SUCH DAMAGE.
24
*/
25
26
#include <sys/param.h>
27
#include <sys/systm.h>
28
#include <sys/kernel.h>
29
#include <sys/queue.h>
30
#include <sys/eventhandler.h>
31
#include <sys/sx.h>
32
33
#include <linux/compat.h>
34
#include <linux/shrinker.h>
35
#include <linux/slab.h>
36
37
TAILQ_HEAD(, shrinker) lkpi_shrinkers = TAILQ_HEAD_INITIALIZER(lkpi_shrinkers);
38
static struct sx sx_shrinker;
39
40
struct shrinker *
41
linuxkpi_shrinker_alloc(unsigned int flags, const char *fmt, ...)
42
{
43
struct shrinker *shrinker;
44
45
shrinker = kzalloc(sizeof(*shrinker), GFP_KERNEL);
46
if (shrinker == NULL)
47
return (NULL);
48
49
shrinker->flags = flags | SHRINKER_ALLOCATED;
50
shrinker->seeks = DEFAULT_SEEKS;
51
52
return (shrinker);
53
}
54
55
int
56
linuxkpi_register_shrinker(struct shrinker *s)
57
{
58
59
KASSERT(s != NULL, ("NULL shrinker"));
60
KASSERT(s->count_objects != NULL, ("NULL shrinker"));
61
KASSERT(s->scan_objects != NULL, ("NULL shrinker"));
62
sx_xlock(&sx_shrinker);
63
s->flags |= SHRINKER_REGISTERED;
64
TAILQ_INSERT_TAIL(&lkpi_shrinkers, s, next);
65
sx_xunlock(&sx_shrinker);
66
return (0);
67
}
68
69
void
70
linuxkpi_unregister_shrinker(struct shrinker *s)
71
{
72
73
sx_xlock(&sx_shrinker);
74
TAILQ_REMOVE(&lkpi_shrinkers, s, next);
75
s->flags &= ~SHRINKER_REGISTERED;
76
sx_xunlock(&sx_shrinker);
77
}
78
79
void
80
linuxkpi_shrinker_free(struct shrinker *shrinker)
81
{
82
83
if (shrinker->flags & SHRINKER_REGISTERED)
84
unregister_shrinker(shrinker);
85
86
kfree(shrinker);
87
}
88
89
void
90
linuxkpi_synchronize_shrinkers(void)
91
{
92
93
sx_xlock(&sx_shrinker);
94
sx_xunlock(&sx_shrinker);
95
}
96
97
#define SHRINKER_BATCH 512
98
99
static void
100
shrinker_shrink(struct shrinker *s)
101
{
102
struct shrink_control sc;
103
unsigned long can_free;
104
unsigned long batch;
105
unsigned long scanned = 0;
106
unsigned long ret;
107
108
can_free = s->count_objects(s, &sc);
109
if (can_free <= 0)
110
return;
111
112
batch = s->batch ? s->batch : SHRINKER_BATCH;
113
while (scanned <= can_free) {
114
sc.nr_to_scan = batch;
115
ret = s->scan_objects(s, &sc);
116
if (ret == SHRINK_STOP)
117
break;
118
scanned += batch;
119
}
120
}
121
122
static void
123
linuxkpi_vm_lowmem(void *arg __unused, int flags __unused)
124
{
125
struct shrinker *s;
126
127
sx_xlock(&sx_shrinker);
128
TAILQ_FOREACH(s, &lkpi_shrinkers, next) {
129
shrinker_shrink(s);
130
}
131
sx_xunlock(&sx_shrinker);
132
}
133
134
static eventhandler_tag lowmem_tag;
135
136
static void
137
linuxkpi_sysinit_shrinker(void *arg __unused)
138
{
139
140
sx_init(&sx_shrinker, "lkpi-shrinker");
141
lowmem_tag = EVENTHANDLER_REGISTER(vm_lowmem, linuxkpi_vm_lowmem,
142
NULL, EVENTHANDLER_PRI_FIRST);
143
}
144
145
static void
146
linuxkpi_sysuninit_shrinker(void *arg __unused)
147
{
148
149
sx_destroy(&sx_shrinker);
150
EVENTHANDLER_DEREGISTER(vm_lowmem, lowmem_tag);
151
}
152
153
SYSINIT(linuxkpi_shrinker, SI_SUB_DRIVERS, SI_ORDER_ANY,
154
linuxkpi_sysinit_shrinker, NULL);
155
SYSUNINIT(linuxkpi_shrinker, SI_SUB_DRIVERS, SI_ORDER_ANY,
156
linuxkpi_sysuninit_shrinker, NULL);
157
158