History

kprobes: unify insn caches

The current kpropes insn caches allocate memory areas for insn slots with module_alloc(). The assumption is that the kernel image and module area are both within the same +/- 2GB memory area. This however is not true for s390 where the kernel image resides within the first 2GB (DMA memory area), but the module area is far away in the vmalloc area, usually somewhere close below the 4TB area. For new pc relative instructions s390 needs insn slots that are within +/- 2GB of each area. That way we can patch displacements of pc-relative instructions within the insn slots just like x86 and powerpc. The module area works already with the normal insn slot allocator, however there is currently no way to get insn slots that are within the first 2GB on s390 (aka DMA area). Therefore this patch set modifies the kprobes insn slot cache code in order to allow to specify a custom allocator for the insn slot cache pages. In addition architecure can now have private insn slot caches withhout the need to modify common code. Patch 1 unifies and simplifies the current insn and optinsn caches implementation. This is a preparation which allows to add more insn caches in a simple way. Patch 2 adds the possibility to specify a custom allocator. Patch 3 makes s390 use the new insn slot mechanisms and adds support for pc-relative instructions with long displacements. This patch (of 3): The two insn caches (insn, and optinsn) each have an own mutex and alloc/free functions (get_[opt]insn_slot() / free_[opt]insn_slot()). Since there is the need for yet another insn cache which satifies dma allocations on s390, unify and simplify the current implementation: - Move the per insn cache mutex into struct kprobe_insn_cache. - Move the alloc/free functions to kprobe.h so they are simply wrappers for the generic __get_insn_slot/__free_insn_slot functions. The implementation is done with a DEFINE_INSN_CACHE_OPS() macro which provides the alloc/free functions for each cache if needed. - move the struct kprobe_insn_cache to kprobe.h which allows to generate architecture specific insn slot caches outside of the core kprobes code.

Heiko Carstens committed 13 years ago

Commit c802d641 parent ae797442 files · +49 −58Browse files

Showing the changes to kernel (1 of 2 files). Show all

Unified · Split

kernel/kprobes.c+21−54
@@ -121,12 +121,6 @@ struct kprobe_insn_page { · 120 unmodified lines
121121 (offsetof(struct kprobe_insn_page, slot_used) + \
122122 (sizeof(char) * (slots)))
123123
124−struct kprobe_insn_cache {
125− struct list_head pages; /* list of kprobe_insn_page */
126− size_t insn_size; /* size of instruction slot */
127− int nr_garbage;
128−};
129−
130124 static int slots_per_page(struct kprobe_insn_cache *c)
131125 {
132126 return PAGE_SIZE/(c->insn_size * sizeof(kprobe_opcode_t));
@@ -138,8 +132,8 @@ enum kprobe_slot_state { · 5 unmodified lines
138132 SLOT_USED = 2,
139133 };
140134
141−static DEFINE_MUTEX(kprobe_insn_mutex); /* Protects kprobe_insn_slots */
142−static struct kprobe_insn_cache kprobe_insn_slots = {
135+struct kprobe_insn_cache kprobe_insn_slots = {
136+ .mutex = __MUTEX_INITIALIZER(kprobe_insn_slots.mutex),
143137 .pages = LIST_HEAD_INIT(kprobe_insn_slots.pages),
144138 .insn_size = MAX_INSN_SIZE,
145139 .nr_garbage = 0,
@@ -150,10 +144,12 @@ static int __kprobes collect_garbage_slots(struct kprobe_insn_cache *c); · 4 unmodified lines
150144 * __get_insn_slot() - Find a slot on an executable page for an instruction.
151145 * We allocate an executable page if there's no room on existing ones.
152146 */
153−static kprobe_opcode_t __kprobes *__get_insn_slot(struct kprobe_insn_cache *c)
147+kprobe_opcode_t __kprobes *__get_insn_slot(struct kprobe_insn_cache *c)
154148 {
155149 struct kprobe_insn_page *kip;
150+ kprobe_opcode_t *slot = NULL;
156151
152+ mutex_lock(&c->mutex);
157153 retry:
158154 list_for_each_entry(kip, &c->pages, list) {
159155 if (kip->nused < slots_per_page(c)) {
@@ -162,7 +158,8 @@ static kprobe_opcode_t __kprobes *__get_insn_slot(struct kprobe_insn_cache *c) · 2 unmodified lines
162158 if (kip->slot_used[i] == SLOT_CLEAN) {
163159 kip->slot_used[i] = SLOT_USED;
164160 kip->nused++;
165− return kip->insns + (i * c->insn_size);
161+ slot = kip->insns + (i * c->insn_size);
162+ goto out;
166163 }
167164 }
168165 /* kip->nused is broken. Fix it. */
@@ -178,7 +175,7 @@ static kprobe_opcode_t __kprobes *__get_insn_slot(struct kprobe_insn_cache *c) · 9 unmodified lines
178175 /* All out of space. Need to allocate a new page. */
179176 kip = kmalloc(KPROBE_INSN_PAGE_SIZE(slots_per_page(c)), GFP_KERNEL);
180177 if (!kip)
181− return NULL;
178+ goto out;
182179
183180 /*
184181 * Use module_alloc so this page is within +/- 2GB of where the
@@ -188,7 +185,7 @@ static kprobe_opcode_t __kprobes *__get_insn_slot(struct kprobe_insn_cache *c) · 3 unmodified lines
188185 kip->insns = module_alloc(PAGE_SIZE);
189186 if (!kip->insns) {
190187 kfree(kip);
191− return NULL;
188+ goto out;
192189 }
193190 INIT_LIST_HEAD(&kip->list);
194191 memset(kip->slot_used, SLOT_CLEAN, slots_per_page(c));
@@ -196,19 +193,10 @@ static kprobe_opcode_t __kprobes *__get_insn_slot(struct kprobe_insn_cache *c) · 1 unmodified line
196193 kip->nused = 1;
197194 kip->ngarbage = 0;
198195 list_add(&kip->list, &c->pages);
199− return kip->insns;
200−}
201−
202−
203−kprobe_opcode_t __kprobes *get_insn_slot(void)
204−{
205− kprobe_opcode_t *ret = NULL;
206−
207− mutex_lock(&kprobe_insn_mutex);
208− ret = __get_insn_slot(&kprobe_insn_slots);
209− mutex_unlock(&kprobe_insn_mutex);
210−
211− return ret;
196+ slot = kip->insns;
197+out:
198+ mutex_unlock(&c->mutex);
199+ return slot;
212200 }
213201
214202 /* Return 1 if all garbages are collected, otherwise 0. */
@@ -255,11 +243,12 @@ static int __kprobes collect_garbage_slots(struct kprobe_insn_cache *c) · 40 unmodified lines
255243 return 0;
256244 }
257245
258−static void __kprobes __free_insn_slot(struct kprobe_insn_cache *c,
259− kprobe_opcode_t *slot, int dirty)
246+void __kprobes __free_insn_slot(struct kprobe_insn_cache *c,
247+ kprobe_opcode_t *slot, int dirty)
260248 {
261249 struct kprobe_insn_page *kip;
262250
251+ mutex_lock(&c->mutex);
263252 list_for_each_entry(kip, &c->pages, list) {
264253 long idx = ((long)slot - (long)kip->insns) /
265254 (c->insn_size * sizeof(kprobe_opcode_t));
@@ -272,45 +261,23 @@ static void __kprobes __free_insn_slot(struct kprobe_insn_cache *c, · 6 unmodified lines
272261 collect_garbage_slots(c);
273262 } else
274263 collect_one_slot(kip, idx);
275− return;
264+ goto out;
276265 }
277266 }
278267 /* Could not free this slot. */
279268 WARN_ON(1);
269+out:
270+ mutex_unlock(&c->mutex);
280271 }
281272
282−void __kprobes free_insn_slot(kprobe_opcode_t * slot, int dirty)
283−{
284− mutex_lock(&kprobe_insn_mutex);
285− __free_insn_slot(&kprobe_insn_slots, slot, dirty);
286− mutex_unlock(&kprobe_insn_mutex);
287−}
288273 #ifdef CONFIG_OPTPROBES
289274 /* For optimized_kprobe buffer */
290−static DEFINE_MUTEX(kprobe_optinsn_mutex); /* Protects kprobe_optinsn_slots */
291−static struct kprobe_insn_cache kprobe_optinsn_slots = {
275+struct kprobe_insn_cache kprobe_optinsn_slots = {
276+ .mutex = __MUTEX_INITIALIZER(kprobe_optinsn_slots.mutex),
292277 .pages = LIST_HEAD_INIT(kprobe_optinsn_slots.pages),
293278 /* .insn_size is initialized later */
294279 .nr_garbage = 0,
295280 };
296−/* Get a slot for optimized_kprobe buffer */
297−kprobe_opcode_t __kprobes *get_optinsn_slot(void)
298−{
299− kprobe_opcode_t *ret = NULL;
300−
301− mutex_lock(&kprobe_optinsn_mutex);
302− ret = __get_insn_slot(&kprobe_optinsn_slots);
303− mutex_unlock(&kprobe_optinsn_mutex);
304−
305− return ret;
306−}
307−
308−void __kprobes free_optinsn_slot(kprobe_opcode_t * slot, int dirty)
309−{
310− mutex_lock(&kprobe_optinsn_mutex);
311− __free_insn_slot(&kprobe_optinsn_slots, slot, dirty);
312− mutex_unlock(&kprobe_optinsn_mutex);
313−}
314281 #endif
315282 #endif
316283