aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2013-09-11 17:24:13 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-11 18:58:52 -0400
commitaf96397de8600232effbff43dc8b4ca20ddc02b1 (patch)
treed236fe3b4d37d5439ee41497a0d179a0b7614883
parentc802d64a356b5cf349121ac4c5e005f037ce548d (diff)
kprobes: allow to specify custom allocator for insn caches
The current two insn slot caches both use module_alloc/module_free to allocate and free insn slot cache pages. For s390 this is not sufficient since there is the need to allocate insn slots that are either within the vmalloc module area or within dma memory. Therefore add a mechanism which allows to specify an own allocator for an own insn slot cache. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/kprobes.h2
-rw-r--r--kernel/kprobes.c20
2 files changed, 20 insertions, 2 deletions
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index 077f65321b5e..925eaf28fca9 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -268,6 +268,8 @@ extern void kprobes_inc_nmissed_count(struct kprobe *p);
268 268
269struct kprobe_insn_cache { 269struct kprobe_insn_cache {
270 struct mutex mutex; 270 struct mutex mutex;
271 void *(*alloc)(void); /* allocate insn page */
272 void (*free)(void *); /* free insn page */
271 struct list_head pages; /* list of kprobe_insn_page */ 273 struct list_head pages; /* list of kprobe_insn_page */
272 size_t insn_size; /* size of instruction slot */ 274 size_t insn_size; /* size of instruction slot */
273 int nr_garbage; 275 int nr_garbage;
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 9e4912dc5559..a0d367a49122 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -112,6 +112,7 @@ static struct kprobe_blackpoint kprobe_blacklist[] = {
112struct kprobe_insn_page { 112struct kprobe_insn_page {
113 struct list_head list; 113 struct list_head list;
114 kprobe_opcode_t *insns; /* Page of instruction slots */ 114 kprobe_opcode_t *insns; /* Page of instruction slots */
115 struct kprobe_insn_cache *cache;
115 int nused; 116 int nused;
116 int ngarbage; 117 int ngarbage;
117 char slot_used[]; 118 char slot_used[];
@@ -132,8 +133,20 @@ enum kprobe_slot_state {
132 SLOT_USED = 2, 133 SLOT_USED = 2,
133}; 134};
134 135
136static void *alloc_insn_page(void)
137{
138 return module_alloc(PAGE_SIZE);
139}
140
141static void free_insn_page(void *page)
142{
143 module_free(NULL, page);
144}
145
135struct kprobe_insn_cache kprobe_insn_slots = { 146struct kprobe_insn_cache kprobe_insn_slots = {
136 .mutex = __MUTEX_INITIALIZER(kprobe_insn_slots.mutex), 147 .mutex = __MUTEX_INITIALIZER(kprobe_insn_slots.mutex),
148 .alloc = alloc_insn_page,
149 .free = free_insn_page,
137 .pages = LIST_HEAD_INIT(kprobe_insn_slots.pages), 150 .pages = LIST_HEAD_INIT(kprobe_insn_slots.pages),
138 .insn_size = MAX_INSN_SIZE, 151 .insn_size = MAX_INSN_SIZE,
139 .nr_garbage = 0, 152 .nr_garbage = 0,
@@ -182,7 +195,7 @@ kprobe_opcode_t __kprobes *__get_insn_slot(struct kprobe_insn_cache *c)
182 * kernel image and loaded module images reside. This is required 195 * kernel image and loaded module images reside. This is required
183 * so x86_64 can correctly handle the %rip-relative fixups. 196 * so x86_64 can correctly handle the %rip-relative fixups.
184 */ 197 */
185 kip->insns = module_alloc(PAGE_SIZE); 198 kip->insns = c->alloc();
186 if (!kip->insns) { 199 if (!kip->insns) {
187 kfree(kip); 200 kfree(kip);
188 goto out; 201 goto out;
@@ -192,6 +205,7 @@ kprobe_opcode_t __kprobes *__get_insn_slot(struct kprobe_insn_cache *c)
192 kip->slot_used[0] = SLOT_USED; 205 kip->slot_used[0] = SLOT_USED;
193 kip->nused = 1; 206 kip->nused = 1;
194 kip->ngarbage = 0; 207 kip->ngarbage = 0;
208 kip->cache = c;
195 list_add(&kip->list, &c->pages); 209 list_add(&kip->list, &c->pages);
196 slot = kip->insns; 210 slot = kip->insns;
197out: 211out:
@@ -213,7 +227,7 @@ static int __kprobes collect_one_slot(struct kprobe_insn_page *kip, int idx)
213 */ 227 */
214 if (!list_is_singular(&kip->list)) { 228 if (!list_is_singular(&kip->list)) {
215 list_del(&kip->list); 229 list_del(&kip->list);
216 module_free(NULL, kip->insns); 230 kip->cache->free(kip->insns);
217 kfree(kip); 231 kfree(kip);
218 } 232 }
219 return 1; 233 return 1;
@@ -274,6 +288,8 @@ out:
274/* For optimized_kprobe buffer */ 288/* For optimized_kprobe buffer */
275struct kprobe_insn_cache kprobe_optinsn_slots = { 289struct kprobe_insn_cache kprobe_optinsn_slots = {
276 .mutex = __MUTEX_INITIALIZER(kprobe_optinsn_slots.mutex), 290 .mutex = __MUTEX_INITIALIZER(kprobe_optinsn_slots.mutex),
291 .alloc = alloc_insn_page,
292 .free = free_insn_page,
277 .pages = LIST_HEAD_INIT(kprobe_optinsn_slots.pages), 293 .pages = LIST_HEAD_INIT(kprobe_optinsn_slots.pages),
278 /* .insn_size is initialized later */ 294 /* .insn_size is initialized later */
279 .nr_garbage = 0, 295 .nr_garbage = 0,