Last active
August 26, 2024 15:43
-
-
Save thejh/d61b75722489d23d2ed41593b00f4fb9 to your computer and use it in GitHub Desktop.
perf addrinfo patch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/include/linux/slab.h b/include/linux/slab.h | |
index b5f5ee8308d0..aad7ffe6c45a 100644 | |
--- a/include/linux/slab.h | |
+++ b/include/linux/slab.h | |
@@ -778,4 +778,6 @@ size_t kmalloc_size_roundup(size_t size); | |
void __init kmem_cache_init_late(void); | |
+const char *folio_cache_name(const struct folio *folio); | |
+ | |
#endif /* _LINUX_SLAB_H */ | |
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h | |
index 3a64499b0f5d..c92b750a9489 100644 | |
--- a/include/uapi/linux/perf_event.h | |
+++ b/include/uapi/linux/perf_event.h | |
@@ -132,6 +132,27 @@ enum perf_sw_ids { | |
PERF_COUNT_SW_MAX, /* non-ABI */ | |
}; | |
+enum perf_addrinfo_memtype { | |
+ MEMTYPE_INVALID, | |
+ MEMTYPE_USER, | |
+ MEMTYPE_KERNEL, | |
+ MEMTYPE_KERNEL_LINEAR_MAPPING, | |
+ MEMTYPE_KERNEL_TEXT, | |
+ MEMTYPE_KERNEL_VMALLOC, | |
+ MEMTYPE_KERNEL_OWN_TASK_STACK, | |
+ MEMTYPE_KERNEL_MODULE, | |
+ MEMTYPE_KERNEL_SLAB, | |
+}; | |
+ | |
+struct perf_addrinfo { | |
+ enum perf_addrinfo_memtype type; | |
+ union { | |
+ struct { | |
+ char name[32]; | |
+ } slab; | |
+ }; | |
+} __attribute__((aligned(8))); | |
+ | |
/* | |
* Bits that can be set in attr.sample_type to request information | |
* in the overflow packets. | |
@@ -162,8 +183,9 @@ enum perf_event_sample_format { | |
PERF_SAMPLE_DATA_PAGE_SIZE = 1U << 22, | |
PERF_SAMPLE_CODE_PAGE_SIZE = 1U << 23, | |
PERF_SAMPLE_WEIGHT_STRUCT = 1U << 24, | |
+ PERF_SAMPLE_ADDRINFO = 1U << 25, | |
- PERF_SAMPLE_MAX = 1U << 25, /* non-ABI */ | |
+ PERF_SAMPLE_MAX = 1U << 26, /* non-ABI */ | |
}; | |
#define PERF_SAMPLE_WEIGHT_TYPE (PERF_SAMPLE_WEIGHT | PERF_SAMPLE_WEIGHT_STRUCT) | |
diff --git a/kernel/events/core.c b/kernel/events/core.c | |
index f0f0f71213a1..208622d55855 100644 | |
--- a/kernel/events/core.c | |
+++ b/kernel/events/core.c | |
@@ -1855,6 +1855,9 @@ static void __perf_event_header_size(struct perf_event *event, u64 sample_type) | |
if (sample_type & PERF_SAMPLE_ADDR) | |
size += sizeof(data->addr); | |
+ if (sample_type & PERF_SAMPLE_ADDRINFO) | |
+ size += sizeof(struct perf_addrinfo); | |
+ | |
if (sample_type & PERF_SAMPLE_PERIOD) | |
size += sizeof(data->period); | |
@@ -7330,6 +7333,49 @@ void perf_output_sample(struct perf_output_handle *handle, | |
if (sample_type & PERF_SAMPLE_ADDR) | |
perf_output_put(handle, data->addr); | |
+ if (sample_type & PERF_SAMPLE_ADDRINFO) { | |
+ struct perf_addrinfo addrinfo; | |
+ unsigned long addr = untagged_addr(data->addr); | |
+ | |
+ memset(&addrinfo, '\0', sizeof(addrinfo)); | |
+ | |
+ // TODO: assumes that user/kernel address space is shared | |
+ // TODO: x86-specific code below | |
+ if (addr < TASK_SIZE_MAX) { | |
+ addrinfo.type = MEMTYPE_USER; | |
+ } else if (addr - (unsigned long)task_stack_page(current) < THREAD_SIZE) { | |
+ addrinfo.type = MEMTYPE_KERNEL_OWN_TASK_STACK; | |
+ } else if (addr >= PAGE_OFFSET && addr < VMALLOC_START && virt_addr_valid(addr)) { | |
+ const struct page *page = virt_to_page(addr); | |
+ /* page_folio() is allowed without holding a reference */ | |
+ const struct folio *folio = page_folio(page); | |
+ struct folio copied_folio_start = {}; | |
+ | |
+ // TODO dirty hacks relying on struct layouts | |
+ rcu_read_lock(); | |
+ *(u128*)&copied_folio_start = cmpxchg128((u128*)folio, 0, 0); | |
+ if (folio_test_slab(&copied_folio_start)) { | |
+ // very dirty, passing in a partially initialized copied folio struct | |
+ const char *slab_name = folio_cache_name(&copied_folio_start); | |
+ | |
+ addrinfo.type = MEMTYPE_KERNEL_SLAB; | |
+ strscpy(addrinfo.slab.name, slab_name, sizeof(addrinfo.slab.name)); | |
+ } else { | |
+ addrinfo.type = MEMTYPE_KERNEL_LINEAR_MAPPING; | |
+ } | |
+ rcu_read_unlock(); | |
+ } else if (addr >= VMALLOC_START && addr < VMALLOC_END) { | |
+ addrinfo.type = MEMTYPE_KERNEL_VMALLOC; | |
+ } else if (addr >= __START_KERNEL_map && addr < MODULES_VADDR) { | |
+ addrinfo.type = MEMTYPE_KERNEL_TEXT; | |
+ } else if (addr >= MODULES_VADDR && addr < MODULES_END) { | |
+ addrinfo.type = MEMTYPE_KERNEL_MODULE; | |
+ } else { | |
+ addrinfo.type = MEMTYPE_KERNEL; | |
+ } | |
+ perf_output_put(handle, addrinfo); | |
+ } | |
+ | |
if (sample_type & PERF_SAMPLE_ID) | |
perf_output_put(handle, data->id); | |
diff --git a/mm/slab_common.c b/mm/slab_common.c | |
index 238293b1dbe1..9fec6e90b534 100644 | |
--- a/mm/slab_common.c | |
+++ b/mm/slab_common.c | |
@@ -468,8 +468,9 @@ static int shutdown_cache(struct kmem_cache *s) | |
void slab_kmem_cache_release(struct kmem_cache *s) | |
{ | |
__kmem_cache_release(s); | |
- kfree_const(s->name); | |
- kmem_cache_free(kmem_cache, s); | |
+ if (!is_kernel_rodata(s->name)) | |
+ kfree_rcu_mightsleep(s->name); | |
+ kfree_rcu_mightsleep(s); | |
} | |
void kmem_cache_destroy(struct kmem_cache *s) | |
@@ -1087,6 +1088,15 @@ static int slab_show(struct seq_file *m, void *p) | |
return 0; | |
} | |
+const char *folio_cache_name(const struct folio *folio) | |
+{ | |
+ struct slab *s = folio_slab(folio); | |
+ struct kmem_cache *cache = s->slab_cache; | |
+ | |
+ // TODO unclean annotation | |
+ return rcu_dereference(cache->name); | |
+} | |
+ | |
void dump_unreclaimable_slab(void) | |
{ | |
struct kmem_cache *s; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment