1 /*
2  *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3  *  Copyright (C) 2007 The Regents of the University of California.
4  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5  *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
6  *  UCRL-CODE-235197
7  *
8  *  This file is part of the SPL, Solaris Porting Layer.
9  *
10  *  The SPL is free software; you can redistribute it and/or modify it
11  *  under the terms of the GNU General Public License as published by the
12  *  Free Software Foundation; either version 2 of the License, or (at your
13  *  option) any later version.
14  *
15  *  The SPL is distributed in the hope that it will be useful, but WITHOUT
16  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18  *  for more details.
19  *
20  *  You should have received a copy of the GNU General Public License along
21  *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  *  Solaris Porting Layer (SPL) Shrinker Implementation.
24  */
25 
26 #include <sys/kmem.h>
27 #include <sys/shrinker.h>
28 
29 #ifdef HAVE_SINGLE_SHRINKER_CALLBACK
30 /* 3.0-3.11: single shrink() callback, which we wrap to carry both functions */
31 struct spl_shrinker_wrap {
32 	struct shrinker shrinker;
33 	spl_shrinker_cb countfunc;
34 	spl_shrinker_cb scanfunc;
35 };
36 
37 static int
38 spl_shrinker_single_cb(struct shrinker *shrinker, struct shrink_control *sc)
39 {
40 	struct spl_shrinker_wrap *sw = (struct spl_shrinker_wrap *)shrinker;
41 
42 	if (sc->nr_to_scan != 0)
43 		(void) sw->scanfunc(&sw->shrinker, sc);
44 	return (sw->countfunc(&sw->shrinker, sc));
45 }
46 #endif
47 
48 struct shrinker *
49 spl_register_shrinker(const char *name, spl_shrinker_cb countfunc,
50     spl_shrinker_cb scanfunc, int seek_cost)
51 {
52 	struct shrinker *shrinker;
53 
54 	/* allocate shrinker */
55 #if defined(HAVE_SHRINKER_REGISTER)
56 	/* 6.7: kernel will allocate the shrinker for us */
57 	shrinker = shrinker_alloc(0, name);
58 #elif defined(HAVE_SPLIT_SHRINKER_CALLBACK)
59 	/* 3.12-6.6: we allocate the shrinker  */
60 	shrinker = kmem_zalloc(sizeof (struct shrinker), KM_SLEEP);
61 #elif defined(HAVE_SINGLE_SHRINKER_CALLBACK)
62 	/* 3.0-3.11: allocate a wrapper */
63 	struct spl_shrinker_wrap *sw =
64 	    kmem_zalloc(sizeof (struct spl_shrinker_wrap), KM_SLEEP);
65 	shrinker = &sw->shrinker;
66 #else
67 	/* 2.x-2.6.22, or a newer shrinker API has been introduced. */
68 #error "Unknown shrinker API"
69 #endif
70 
71 	if (shrinker == NULL)
72 		return (NULL);
73 
74 	/* set callbacks */
75 #ifdef HAVE_SINGLE_SHRINKER_CALLBACK
76 	sw->countfunc = countfunc;
77 	sw->scanfunc = scanfunc;
78 	shrinker->shrink = spl_shrinker_single_cb;
79 #else
80 	shrinker->count_objects = countfunc;
81 	shrinker->scan_objects = scanfunc;
82 #endif
83 
84 	/* set params */
85 	shrinker->seeks = seek_cost;
86 
87 	/* register with kernel */
88 #if defined(HAVE_SHRINKER_REGISTER)
89 	shrinker_register(shrinker);
90 #elif defined(HAVE_REGISTER_SHRINKER_VARARG)
91 	register_shrinker(shrinker, name);
92 #else
93 	register_shrinker(shrinker);
94 #endif
95 
96 	return (shrinker);
97 }
98 EXPORT_SYMBOL(spl_register_shrinker);
99 
100 void
101 spl_unregister_shrinker(struct shrinker *shrinker)
102 {
103 #if defined(HAVE_SHRINKER_REGISTER)
104 	shrinker_free(shrinker);
105 #elif defined(HAVE_SPLIT_SHRINKER_CALLBACK)
106 	unregister_shrinker(shrinker);
107 	kmem_free(shrinker, sizeof (struct shrinker));
108 #elif defined(HAVE_SINGLE_SHRINKER_CALLBACK)
109 	unregister_shrinker(shrinker);
110 	kmem_free(shrinker, sizeof (struct spl_shrinker_wrap));
111 #else
112 #error "Unknown shrinker API"
113 #endif
114 }
115 EXPORT_SYMBOL(spl_unregister_shrinker);
116