diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-12-29 09:16:24 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-12-29 09:16:24 -0500 |
commit | 2ff9f9d9629bf9530fe2ab8d803d612761ffc059 (patch) | |
tree | b22e3fddffbc0f58b1e1974f4819896d58b7bdaf | |
parent | 0f01f07fad4ee11d98fe6faa442afbeb0328a378 (diff) | |
parent | a4900437f3d76761a1646cd90254ccb01714a9ed (diff) |
Merge branch 'topic/kmemtrace' of git://git.kernel.org/pub/scm/linux/kernel/git/penberg/slab-2.6 into tracing/kmemtrace
-rw-r--r-- | Documentation/ABI/testing/debugfs-kmemtrace | 71 | ||||
-rw-r--r-- | Documentation/kernel-parameters.txt | 10 | ||||
-rw-r--r-- | Documentation/vm/kmemtrace.txt | 126 | ||||
-rw-r--r-- | MAINTAINERS | 6 | ||||
-rw-r--r-- | include/linux/kmemtrace.h | 86 | ||||
-rw-r--r-- | include/linux/slab.h | 8 | ||||
-rw-r--r-- | include/linux/slab_def.h | 68 | ||||
-rw-r--r-- | include/linux/slob_def.h | 9 | ||||
-rw-r--r-- | include/linux/slub_def.h | 53 | ||||
-rw-r--r-- | init/main.c | 2 | ||||
-rw-r--r-- | lib/Kconfig.debug | 20 | ||||
-rw-r--r-- | mm/Makefile | 1 | ||||
-rw-r--r-- | mm/kmemtrace.c | 333 | ||||
-rw-r--r-- | mm/slab.c | 79 | ||||
-rw-r--r-- | mm/slob.c | 37 | ||||
-rw-r--r-- | mm/slub.c | 123 |
16 files changed, 967 insertions, 65 deletions
diff --git a/Documentation/ABI/testing/debugfs-kmemtrace b/Documentation/ABI/testing/debugfs-kmemtrace new file mode 100644 index 000000000000..5e6a92a02d85 --- /dev/null +++ b/Documentation/ABI/testing/debugfs-kmemtrace | |||
@@ -0,0 +1,71 @@ | |||
1 | What: /sys/kernel/debug/kmemtrace/ | ||
2 | Date: July 2008 | ||
3 | Contact: Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro> | ||
4 | Description: | ||
5 | |||
6 | In kmemtrace-enabled kernels, the following files are created: | ||
7 | |||
8 | /sys/kernel/debug/kmemtrace/ | ||
9 | cpu<n> (0400) Per-CPU tracing data, see below. (binary) | ||
10 | total_overruns (0400) Total number of bytes which were dropped from | ||
11 | cpu<n> files because of full buffer condition, | ||
12 | non-binary. (text) | ||
13 | abi_version (0400) Kernel's kmemtrace ABI version. (text) | ||
14 | |||
15 | Each per-CPU file should be read according to the relay interface. That is, | ||
16 | the reader should set affinity to that specific CPU and, as currently done by | ||
17 | the userspace application (though there are other methods), use poll() with | ||
18 | an infinite timeout before every read(). Otherwise, erroneous data may be | ||
19 | read. The binary data has the following _core_ format: | ||
20 | |||
21 | Event ID (1 byte) Unsigned integer, one of: | ||
22 | 0 - represents an allocation (KMEMTRACE_EVENT_ALLOC) | ||
23 | 1 - represents a freeing of previously allocated memory | ||
24 | (KMEMTRACE_EVENT_FREE) | ||
25 | Type ID (1 byte) Unsigned integer, one of: | ||
26 | 0 - this is a kmalloc() / kfree() | ||
27 | 1 - this is a kmem_cache_alloc() / kmem_cache_free() | ||
28 | 2 - this is a __get_free_pages() et al. | ||
29 | Event size (2 bytes) Unsigned integer representing the | ||
30 | size of this event. Used to extend | ||
31 | kmemtrace. Discard the bytes you | ||
32 | don't know about. | ||
33 | Sequence number (4 bytes) Signed integer used to reorder data | ||
34 | logged on SMP machines. Wraparound | ||
35 | must be taken into account, although | ||
36 | it is unlikely. | ||
37 | Caller address (8 bytes) Return address to the caller. | ||
38 | Pointer to mem (8 bytes) Pointer to target memory area. Can be | ||
39 | NULL, but not all such calls might be | ||
40 | recorded. | ||
41 | |||
42 | In case of KMEMTRACE_EVENT_ALLOC events, the next fields follow: | ||
43 | |||
44 | Requested bytes (8 bytes) Total number of requested bytes, | ||
45 | unsigned, must not be zero. | ||
46 | Allocated bytes (8 bytes) Total number of actually allocated | ||
47 | bytes, unsigned, must not be lower | ||
48 | than requested bytes. | ||
49 | Requested flags (4 bytes) GFP flags supplied by the caller. | ||
50 | Target CPU (4 bytes) Signed integer, valid for event id 1. | ||
51 | If equal to -1, target CPU is the same | ||
52 | as origin CPU, but the reverse might | ||
53 | not be true. | ||
54 | |||
55 | The data is made available in the same endianness the machine has. | ||
56 | |||
57 | Other event ids and type ids may be defined and added. Other fields may be | ||
58 | added by increasing event size, but see below for details. | ||
59 | Every modification to the ABI, including new id definitions, are followed | ||
60 | by bumping the ABI version by one. | ||
61 | |||
62 | Adding new data to the packet (features) is done at the end of the mandatory | ||
63 | data: | ||
64 | Feature size (2 byte) | ||
65 | Feature ID (1 byte) | ||
66 | Feature data (Feature size - 3 bytes) | ||
67 | |||
68 | |||
69 | Users: | ||
70 | kmemtrace-user - git://repo.or.cz/kmemtrace-user.git | ||
71 | |||
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a2d8805c03d5..af600c0fe0ec 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -49,6 +49,7 @@ parameter is applicable: | |||
49 | ISAPNP ISA PnP code is enabled. | 49 | ISAPNP ISA PnP code is enabled. |
50 | ISDN Appropriate ISDN support is enabled. | 50 | ISDN Appropriate ISDN support is enabled. |
51 | JOY Appropriate joystick support is enabled. | 51 | JOY Appropriate joystick support is enabled. |
52 | KMEMTRACE kmemtrace is enabled. | ||
52 | LIBATA Libata driver is enabled | 53 | LIBATA Libata driver is enabled |
53 | LP Printer support is enabled. | 54 | LP Printer support is enabled. |
54 | LOOP Loopback device support is enabled. | 55 | LOOP Loopback device support is enabled. |
@@ -1033,6 +1034,15 @@ and is between 256 and 4096 characters. It is defined in the file | |||
1033 | use the HighMem zone if it exists, and the Normal | 1034 | use the HighMem zone if it exists, and the Normal |
1034 | zone if it does not. | 1035 | zone if it does not. |
1035 | 1036 | ||
1037 | kmemtrace.enable= [KNL,KMEMTRACE] Format: { yes | no } | ||
1038 | Controls whether kmemtrace is enabled | ||
1039 | at boot-time. | ||
1040 | |||
1041 | kmemtrace.subbufs=n [KNL,KMEMTRACE] Overrides the number of | ||
1042 | subbufs kmemtrace's relay channel has. Set this | ||
1043 | higher than default (KMEMTRACE_N_SUBBUFS in code) if | ||
1044 | you experience buffer overruns. | ||
1045 | |||
1036 | movablecore=nn[KMG] [KNL,X86-32,IA-64,PPC,X86-64] This parameter | 1046 | movablecore=nn[KMG] [KNL,X86-32,IA-64,PPC,X86-64] This parameter |
1037 | is similar to kernelcore except it specifies the | 1047 | is similar to kernelcore except it specifies the |
1038 | amount of memory used for migratable allocations. | 1048 | amount of memory used for migratable allocations. |
diff --git a/Documentation/vm/kmemtrace.txt b/Documentation/vm/kmemtrace.txt new file mode 100644 index 000000000000..a956d9b7f943 --- /dev/null +++ b/Documentation/vm/kmemtrace.txt | |||
@@ -0,0 +1,126 @@ | |||
1 | kmemtrace - Kernel Memory Tracer | ||
2 | |||
3 | by Eduard - Gabriel Munteanu | ||
4 | <eduard.munteanu@linux360.ro> | ||
5 | |||
6 | I. Introduction | ||
7 | =============== | ||
8 | |||
9 | kmemtrace helps kernel developers figure out two things: | ||
10 | 1) how different allocators (SLAB, SLUB etc.) perform | ||
11 | 2) how kernel code allocates memory and how much | ||
12 | |||
13 | To do this, we trace every allocation and export information to the userspace | ||
14 | through the relay interface. We export things such as the number of requested | ||
15 | bytes, the number of bytes actually allocated (i.e. including internal | ||
16 | fragmentation), whether this is a slab allocation or a plain kmalloc() and so | ||
17 | on. | ||
18 | |||
19 | The actual analysis is performed by a userspace tool (see section III for | ||
20 | details on where to get it from). It logs the data exported by the kernel, | ||
21 | processes it and (as of writing this) can provide the following information: | ||
22 | - the total amount of memory allocated and fragmentation per call-site | ||
23 | - the amount of memory allocated and fragmentation per allocation | ||
24 | - total memory allocated and fragmentation in the collected dataset | ||
25 | - number of cross-CPU allocation and frees (makes sense in NUMA environments) | ||
26 | |||
27 | Moreover, it can potentially find inconsistent and erroneous behavior in | ||
28 | kernel code, such as using slab free functions on kmalloc'ed memory or | ||
29 | allocating less memory than requested (but not truly failed allocations). | ||
30 | |||
31 | kmemtrace also makes provisions for tracing on some arch and analysing the | ||
32 | data on another. | ||
33 | |||
34 | II. Design and goals | ||
35 | ==================== | ||
36 | |||
37 | kmemtrace was designed to handle rather large amounts of data. Thus, it uses | ||
38 | the relay interface to export whatever is logged to userspace, which then | ||
39 | stores it. Analysis and reporting is done asynchronously, that is, after the | ||
40 | data is collected and stored. By design, it allows one to log and analyse | ||
41 | on different machines and different arches. | ||
42 | |||
43 | As of writing this, the ABI is not considered stable, though it might not | ||
44 | change much. However, no guarantees are made about compatibility yet. When | ||
45 | deemed stable, the ABI should still allow easy extension while maintaining | ||
46 | backward compatibility. This is described further in Documentation/ABI. | ||
47 | |||
48 | Summary of design goals: | ||
49 | - allow logging and analysis to be done across different machines | ||
50 | - be fast and anticipate usage in high-load environments (*) | ||
51 | - be reasonably extensible | ||
52 | - make it possible for GNU/Linux distributions to have kmemtrace | ||
53 | included in their repositories | ||
54 | |||
55 | (*) - one of the reasons Pekka Enberg's original userspace data analysis | ||
56 | tool's code was rewritten from Perl to C (although this is more than a | ||
57 | simple conversion) | ||
58 | |||
59 | |||
60 | III. Quick usage guide | ||
61 | ====================== | ||
62 | |||
63 | 1) Get a kernel that supports kmemtrace and build it accordingly (i.e. enable | ||
64 | CONFIG_KMEMTRACE). | ||
65 | |||
66 | 2) Get the userspace tool and build it: | ||
67 | $ git-clone git://repo.or.cz/kmemtrace-user.git # current repository | ||
68 | $ cd kmemtrace-user/ | ||
69 | $ ./autogen.sh | ||
70 | $ ./configure | ||
71 | $ make | ||
72 | |||
73 | 3) Boot the kmemtrace-enabled kernel if you haven't, preferably in the | ||
74 | 'single' runlevel (so that relay buffers don't fill up easily), and run | ||
75 | kmemtrace: | ||
76 | # '$' does not mean user, but root here. | ||
77 | $ mount -t debugfs none /sys/kernel/debug | ||
78 | $ mount -t proc none /proc | ||
79 | $ cd path/to/kmemtrace-user/ | ||
80 | $ ./kmemtraced | ||
81 | Wait a bit, then stop it with CTRL+C. | ||
82 | $ cat /sys/kernel/debug/kmemtrace/total_overruns # Check if we didn't | ||
83 | # overrun, should | ||
84 | # be zero. | ||
85 | $ (Optionally) [Run kmemtrace_check separately on each cpu[0-9]*.out file to | ||
86 | check its correctness] | ||
87 | $ ./kmemtrace-report | ||
88 | |||
89 | Now you should have a nice and short summary of how the allocator performs. | ||
90 | |||
91 | IV. FAQ and known issues | ||
92 | ======================== | ||
93 | |||
94 | Q: 'cat /sys/kernel/debug/kmemtrace/total_overruns' is non-zero, how do I fix | ||
95 | this? Should I worry? | ||
96 | A: If it's non-zero, this affects kmemtrace's accuracy, depending on how | ||
97 | large the number is. You can fix it by supplying a higher | ||
98 | 'kmemtrace.subbufs=N' kernel parameter. | ||
99 | --- | ||
100 | |||
101 | Q: kmemtrace_check reports errors, how do I fix this? Should I worry? | ||
102 | A: This is a bug and should be reported. It can occur for a variety of | ||
103 | reasons: | ||
104 | - possible bugs in relay code | ||
105 | - possible misuse of relay by kmemtrace | ||
106 | - timestamps being collected unorderly | ||
107 | Or you may fix it yourself and send us a patch. | ||
108 | --- | ||
109 | |||
110 | Q: kmemtrace_report shows many errors, how do I fix this? Should I worry? | ||
111 | A: This is a known issue and I'm working on it. These might be true errors | ||
112 | in kernel code, which may have inconsistent behavior (e.g. allocating memory | ||
113 | with kmem_cache_alloc() and freeing it with kfree()). Pekka Enberg pointed | ||
114 | out this behavior may work with SLAB, but may fail with other allocators. | ||
115 | |||
116 | It may also be due to lack of tracing in some unusual allocator functions. | ||
117 | |||
118 | We don't want bug reports regarding this issue yet. | ||
119 | --- | ||
120 | |||
121 | V. See also | ||
122 | =========== | ||
123 | |||
124 | Documentation/kernel-parameters.txt | ||
125 | Documentation/ABI/testing/debugfs-kmemtrace | ||
126 | |||
diff --git a/MAINTAINERS b/MAINTAINERS index 08d0ab7fa161..857c877eee20 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -2566,6 +2566,12 @@ M: jason.wessel@windriver.com | |||
2566 | L: kgdb-bugreport@lists.sourceforge.net | 2566 | L: kgdb-bugreport@lists.sourceforge.net |
2567 | S: Maintained | 2567 | S: Maintained |
2568 | 2568 | ||
2569 | KMEMTRACE | ||
2570 | P: Eduard - Gabriel Munteanu | ||
2571 | M: eduard.munteanu@linux360.ro | ||
2572 | L: linux-kernel@vger.kernel.org | ||
2573 | S: Maintained | ||
2574 | |||
2569 | KPROBES | 2575 | KPROBES |
2570 | P: Ananth N Mavinakayanahalli | 2576 | P: Ananth N Mavinakayanahalli |
2571 | M: ananth@in.ibm.com | 2577 | M: ananth@in.ibm.com |
diff --git a/include/linux/kmemtrace.h b/include/linux/kmemtrace.h new file mode 100644 index 000000000000..5bea8ead6a6b --- /dev/null +++ b/include/linux/kmemtrace.h | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 Eduard - Gabriel Munteanu | ||
3 | * | ||
4 | * This file is released under GPL version 2. | ||
5 | */ | ||
6 | |||
7 | #ifndef _LINUX_KMEMTRACE_H | ||
8 | #define _LINUX_KMEMTRACE_H | ||
9 | |||
10 | #ifdef __KERNEL__ | ||
11 | |||
12 | #include <linux/types.h> | ||
13 | #include <linux/marker.h> | ||
14 | |||
15 | enum kmemtrace_type_id { | ||
16 | KMEMTRACE_TYPE_KMALLOC = 0, /* kmalloc() or kfree(). */ | ||
17 | KMEMTRACE_TYPE_CACHE, /* kmem_cache_*(). */ | ||
18 | KMEMTRACE_TYPE_PAGES, /* __get_free_pages() and friends. */ | ||
19 | }; | ||
20 | |||
21 | #ifdef CONFIG_KMEMTRACE | ||
22 | |||
23 | extern void kmemtrace_init(void); | ||
24 | |||
25 | static inline void kmemtrace_mark_alloc_node(enum kmemtrace_type_id type_id, | ||
26 | unsigned long call_site, | ||
27 | const void *ptr, | ||
28 | size_t bytes_req, | ||
29 | size_t bytes_alloc, | ||
30 | gfp_t gfp_flags, | ||
31 | int node) | ||
32 | { | ||
33 | trace_mark(kmemtrace_alloc, "type_id %d call_site %lu ptr %lu " | ||
34 | "bytes_req %lu bytes_alloc %lu gfp_flags %lu node %d", | ||
35 | type_id, call_site, (unsigned long) ptr, | ||
36 | (unsigned long) bytes_req, (unsigned long) bytes_alloc, | ||
37 | (unsigned long) gfp_flags, node); | ||
38 | } | ||
39 | |||
40 | static inline void kmemtrace_mark_free(enum kmemtrace_type_id type_id, | ||
41 | unsigned long call_site, | ||
42 | const void *ptr) | ||
43 | { | ||
44 | trace_mark(kmemtrace_free, "type_id %d call_site %lu ptr %lu", | ||
45 | type_id, call_site, (unsigned long) ptr); | ||
46 | } | ||
47 | |||
48 | #else /* CONFIG_KMEMTRACE */ | ||
49 | |||
50 | static inline void kmemtrace_init(void) | ||
51 | { | ||
52 | } | ||
53 | |||
54 | static inline void kmemtrace_mark_alloc_node(enum kmemtrace_type_id type_id, | ||
55 | unsigned long call_site, | ||
56 | const void *ptr, | ||
57 | size_t bytes_req, | ||
58 | size_t bytes_alloc, | ||
59 | gfp_t gfp_flags, | ||
60 | int node) | ||
61 | { | ||
62 | } | ||
63 | |||
64 | static inline void kmemtrace_mark_free(enum kmemtrace_type_id type_id, | ||
65 | unsigned long call_site, | ||
66 | const void *ptr) | ||
67 | { | ||
68 | } | ||
69 | |||
70 | #endif /* CONFIG_KMEMTRACE */ | ||
71 | |||
72 | static inline void kmemtrace_mark_alloc(enum kmemtrace_type_id type_id, | ||
73 | unsigned long call_site, | ||
74 | const void *ptr, | ||
75 | size_t bytes_req, | ||
76 | size_t bytes_alloc, | ||
77 | gfp_t gfp_flags) | ||
78 | { | ||
79 | kmemtrace_mark_alloc_node(type_id, call_site, ptr, | ||
80 | bytes_req, bytes_alloc, gfp_flags, -1); | ||
81 | } | ||
82 | |||
83 | #endif /* __KERNEL__ */ | ||
84 | |||
85 | #endif /* _LINUX_KMEMTRACE_H */ | ||
86 | |||
diff --git a/include/linux/slab.h b/include/linux/slab.h index 000da12b5cf0..c97ed28559ec 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h | |||
@@ -253,9 +253,9 @@ static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep, | |||
253 | * request comes from. | 253 | * request comes from. |
254 | */ | 254 | */ |
255 | #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) | 255 | #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) |
256 | extern void *__kmalloc_track_caller(size_t, gfp_t, void*); | 256 | extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long); |
257 | #define kmalloc_track_caller(size, flags) \ | 257 | #define kmalloc_track_caller(size, flags) \ |
258 | __kmalloc_track_caller(size, flags, __builtin_return_address(0)) | 258 | __kmalloc_track_caller(size, flags, _RET_IP_) |
259 | #else | 259 | #else |
260 | #define kmalloc_track_caller(size, flags) \ | 260 | #define kmalloc_track_caller(size, flags) \ |
261 | __kmalloc(size, flags) | 261 | __kmalloc(size, flags) |
@@ -271,10 +271,10 @@ extern void *__kmalloc_track_caller(size_t, gfp_t, void*); | |||
271 | * allocation request comes from. | 271 | * allocation request comes from. |
272 | */ | 272 | */ |
273 | #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) | 273 | #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) |
274 | extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, void *); | 274 | extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, unsigned long); |
275 | #define kmalloc_node_track_caller(size, flags, node) \ | 275 | #define kmalloc_node_track_caller(size, flags, node) \ |
276 | __kmalloc_node_track_caller(size, flags, node, \ | 276 | __kmalloc_node_track_caller(size, flags, node, \ |
277 | __builtin_return_address(0)) | 277 | _RET_IP_) |
278 | #else | 278 | #else |
279 | #define kmalloc_node_track_caller(size, flags, node) \ | 279 | #define kmalloc_node_track_caller(size, flags, node) \ |
280 | __kmalloc_node(size, flags, node) | 280 | __kmalloc_node(size, flags, node) |
diff --git a/include/linux/slab_def.h b/include/linux/slab_def.h index 39c3a5eb8ebe..7555ce99f6d2 100644 --- a/include/linux/slab_def.h +++ b/include/linux/slab_def.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <asm/page.h> /* kmalloc_sizes.h needs PAGE_SIZE */ | 14 | #include <asm/page.h> /* kmalloc_sizes.h needs PAGE_SIZE */ |
15 | #include <asm/cache.h> /* kmalloc_sizes.h needs L1_CACHE_BYTES */ | 15 | #include <asm/cache.h> /* kmalloc_sizes.h needs L1_CACHE_BYTES */ |
16 | #include <linux/compiler.h> | 16 | #include <linux/compiler.h> |
17 | #include <linux/kmemtrace.h> | ||
17 | 18 | ||
18 | /* Size description struct for general caches. */ | 19 | /* Size description struct for general caches. */ |
19 | struct cache_sizes { | 20 | struct cache_sizes { |
@@ -28,8 +29,26 @@ extern struct cache_sizes malloc_sizes[]; | |||
28 | void *kmem_cache_alloc(struct kmem_cache *, gfp_t); | 29 | void *kmem_cache_alloc(struct kmem_cache *, gfp_t); |
29 | void *__kmalloc(size_t size, gfp_t flags); | 30 | void *__kmalloc(size_t size, gfp_t flags); |
30 | 31 | ||
31 | static inline void *kmalloc(size_t size, gfp_t flags) | 32 | #ifdef CONFIG_KMEMTRACE |
33 | extern void *kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags); | ||
34 | extern size_t slab_buffer_size(struct kmem_cache *cachep); | ||
35 | #else | ||
36 | static __always_inline void * | ||
37 | kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags) | ||
32 | { | 38 | { |
39 | return kmem_cache_alloc(cachep, flags); | ||
40 | } | ||
41 | static inline size_t slab_buffer_size(struct kmem_cache *cachep) | ||
42 | { | ||
43 | return 0; | ||
44 | } | ||
45 | #endif | ||
46 | |||
47 | static __always_inline void *kmalloc(size_t size, gfp_t flags) | ||
48 | { | ||
49 | struct kmem_cache *cachep; | ||
50 | void *ret; | ||
51 | |||
33 | if (__builtin_constant_p(size)) { | 52 | if (__builtin_constant_p(size)) { |
34 | int i = 0; | 53 | int i = 0; |
35 | 54 | ||
@@ -50,10 +69,17 @@ static inline void *kmalloc(size_t size, gfp_t flags) | |||
50 | found: | 69 | found: |
51 | #ifdef CONFIG_ZONE_DMA | 70 | #ifdef CONFIG_ZONE_DMA |
52 | if (flags & GFP_DMA) | 71 | if (flags & GFP_DMA) |
53 | return kmem_cache_alloc(malloc_sizes[i].cs_dmacachep, | 72 | cachep = malloc_sizes[i].cs_dmacachep; |
54 | flags); | 73 | else |
55 | #endif | 74 | #endif |
56 | return kmem_cache_alloc(malloc_sizes[i].cs_cachep, flags); | 75 | cachep = malloc_sizes[i].cs_cachep; |
76 | |||
77 | ret = kmem_cache_alloc_notrace(cachep, flags); | ||
78 | |||
79 | kmemtrace_mark_alloc(KMEMTRACE_TYPE_KMALLOC, _THIS_IP_, ret, | ||
80 | size, slab_buffer_size(cachep), flags); | ||
81 | |||
82 | return ret; | ||
57 | } | 83 | } |
58 | return __kmalloc(size, flags); | 84 | return __kmalloc(size, flags); |
59 | } | 85 | } |
@@ -62,8 +88,25 @@ found: | |||
62 | extern void *__kmalloc_node(size_t size, gfp_t flags, int node); | 88 | extern void *__kmalloc_node(size_t size, gfp_t flags, int node); |
63 | extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); | 89 | extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); |
64 | 90 | ||
65 | static inline void *kmalloc_node(size_t size, gfp_t flags, int node) | 91 | #ifdef CONFIG_KMEMTRACE |
92 | extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *cachep, | ||
93 | gfp_t flags, | ||
94 | int nodeid); | ||
95 | #else | ||
96 | static __always_inline void * | ||
97 | kmem_cache_alloc_node_notrace(struct kmem_cache *cachep, | ||
98 | gfp_t flags, | ||
99 | int nodeid) | ||
100 | { | ||
101 | return kmem_cache_alloc_node(cachep, flags, nodeid); | ||
102 | } | ||
103 | #endif | ||
104 | |||
105 | static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node) | ||
66 | { | 106 | { |
107 | struct kmem_cache *cachep; | ||
108 | void *ret; | ||
109 | |||
67 | if (__builtin_constant_p(size)) { | 110 | if (__builtin_constant_p(size)) { |
68 | int i = 0; | 111 | int i = 0; |
69 | 112 | ||
@@ -84,11 +127,18 @@ static inline void *kmalloc_node(size_t size, gfp_t flags, int node) | |||
84 | found: | 127 | found: |
85 | #ifdef CONFIG_ZONE_DMA | 128 | #ifdef CONFIG_ZONE_DMA |
86 | if (flags & GFP_DMA) | 129 | if (flags & GFP_DMA) |
87 | return kmem_cache_alloc_node(malloc_sizes[i].cs_dmacachep, | 130 | cachep = malloc_sizes[i].cs_dmacachep; |
88 | flags, node); | 131 | else |
89 | #endif | 132 | #endif |
90 | return kmem_cache_alloc_node(malloc_sizes[i].cs_cachep, | 133 | cachep = malloc_sizes[i].cs_cachep; |
91 | flags, node); | 134 | |
135 | ret = kmem_cache_alloc_node_notrace(cachep, flags, node); | ||
136 | |||
137 | kmemtrace_mark_alloc_node(KMEMTRACE_TYPE_KMALLOC, _THIS_IP_, | ||
138 | ret, size, slab_buffer_size(cachep), | ||
139 | flags, node); | ||
140 | |||
141 | return ret; | ||
92 | } | 142 | } |
93 | return __kmalloc_node(size, flags, node); | 143 | return __kmalloc_node(size, flags, node); |
94 | } | 144 | } |
diff --git a/include/linux/slob_def.h b/include/linux/slob_def.h index 59a3fa476ab9..0ec00b39d006 100644 --- a/include/linux/slob_def.h +++ b/include/linux/slob_def.h | |||
@@ -3,14 +3,15 @@ | |||
3 | 3 | ||
4 | void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); | 4 | void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); |
5 | 5 | ||
6 | static inline void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags) | 6 | static __always_inline void *kmem_cache_alloc(struct kmem_cache *cachep, |
7 | gfp_t flags) | ||
7 | { | 8 | { |
8 | return kmem_cache_alloc_node(cachep, flags, -1); | 9 | return kmem_cache_alloc_node(cachep, flags, -1); |
9 | } | 10 | } |
10 | 11 | ||
11 | void *__kmalloc_node(size_t size, gfp_t flags, int node); | 12 | void *__kmalloc_node(size_t size, gfp_t flags, int node); |
12 | 13 | ||
13 | static inline void *kmalloc_node(size_t size, gfp_t flags, int node) | 14 | static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node) |
14 | { | 15 | { |
15 | return __kmalloc_node(size, flags, node); | 16 | return __kmalloc_node(size, flags, node); |
16 | } | 17 | } |
@@ -23,12 +24,12 @@ static inline void *kmalloc_node(size_t size, gfp_t flags, int node) | |||
23 | * kmalloc is the normal method of allocating memory | 24 | * kmalloc is the normal method of allocating memory |
24 | * in the kernel. | 25 | * in the kernel. |
25 | */ | 26 | */ |
26 | static inline void *kmalloc(size_t size, gfp_t flags) | 27 | static __always_inline void *kmalloc(size_t size, gfp_t flags) |
27 | { | 28 | { |
28 | return __kmalloc_node(size, flags, -1); | 29 | return __kmalloc_node(size, flags, -1); |
29 | } | 30 | } |
30 | 31 | ||
31 | static inline void *__kmalloc(size_t size, gfp_t flags) | 32 | static __always_inline void *__kmalloc(size_t size, gfp_t flags) |
32 | { | 33 | { |
33 | return kmalloc(size, flags); | 34 | return kmalloc(size, flags); |
34 | } | 35 | } |
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h index 2f5c16b1aacd..dc28432b5b9a 100644 --- a/include/linux/slub_def.h +++ b/include/linux/slub_def.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/gfp.h> | 10 | #include <linux/gfp.h> |
11 | #include <linux/workqueue.h> | 11 | #include <linux/workqueue.h> |
12 | #include <linux/kobject.h> | 12 | #include <linux/kobject.h> |
13 | #include <linux/kmemtrace.h> | ||
13 | 14 | ||
14 | enum stat_item { | 15 | enum stat_item { |
15 | ALLOC_FASTPATH, /* Allocation from cpu slab */ | 16 | ALLOC_FASTPATH, /* Allocation from cpu slab */ |
@@ -204,13 +205,31 @@ static __always_inline struct kmem_cache *kmalloc_slab(size_t size) | |||
204 | void *kmem_cache_alloc(struct kmem_cache *, gfp_t); | 205 | void *kmem_cache_alloc(struct kmem_cache *, gfp_t); |
205 | void *__kmalloc(size_t size, gfp_t flags); | 206 | void *__kmalloc(size_t size, gfp_t flags); |
206 | 207 | ||
208 | #ifdef CONFIG_KMEMTRACE | ||
209 | extern void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags); | ||
210 | #else | ||
211 | static __always_inline void * | ||
212 | kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags) | ||
213 | { | ||
214 | return kmem_cache_alloc(s, gfpflags); | ||
215 | } | ||
216 | #endif | ||
217 | |||
207 | static __always_inline void *kmalloc_large(size_t size, gfp_t flags) | 218 | static __always_inline void *kmalloc_large(size_t size, gfp_t flags) |
208 | { | 219 | { |
209 | return (void *)__get_free_pages(flags | __GFP_COMP, get_order(size)); | 220 | unsigned int order = get_order(size); |
221 | void *ret = (void *) __get_free_pages(flags | __GFP_COMP, order); | ||
222 | |||
223 | kmemtrace_mark_alloc(KMEMTRACE_TYPE_KMALLOC, _THIS_IP_, ret, | ||
224 | size, PAGE_SIZE << order, flags); | ||
225 | |||
226 | return ret; | ||
210 | } | 227 | } |
211 | 228 | ||
212 | static __always_inline void *kmalloc(size_t size, gfp_t flags) | 229 | static __always_inline void *kmalloc(size_t size, gfp_t flags) |
213 | { | 230 | { |
231 | void *ret; | ||
232 | |||
214 | if (__builtin_constant_p(size)) { | 233 | if (__builtin_constant_p(size)) { |
215 | if (size > PAGE_SIZE) | 234 | if (size > PAGE_SIZE) |
216 | return kmalloc_large(size, flags); | 235 | return kmalloc_large(size, flags); |
@@ -221,7 +240,13 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags) | |||
221 | if (!s) | 240 | if (!s) |
222 | return ZERO_SIZE_PTR; | 241 | return ZERO_SIZE_PTR; |
223 | 242 | ||
224 | return kmem_cache_alloc(s, flags); | 243 | ret = kmem_cache_alloc_notrace(s, flags); |
244 | |||
245 | kmemtrace_mark_alloc(KMEMTRACE_TYPE_KMALLOC, | ||
246 | _THIS_IP_, ret, | ||
247 | size, s->size, flags); | ||
248 | |||
249 | return ret; | ||
225 | } | 250 | } |
226 | } | 251 | } |
227 | return __kmalloc(size, flags); | 252 | return __kmalloc(size, flags); |
@@ -231,8 +256,24 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags) | |||
231 | void *__kmalloc_node(size_t size, gfp_t flags, int node); | 256 | void *__kmalloc_node(size_t size, gfp_t flags, int node); |
232 | void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); | 257 | void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); |
233 | 258 | ||
259 | #ifdef CONFIG_KMEMTRACE | ||
260 | extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *s, | ||
261 | gfp_t gfpflags, | ||
262 | int node); | ||
263 | #else | ||
264 | static __always_inline void * | ||
265 | kmem_cache_alloc_node_notrace(struct kmem_cache *s, | ||
266 | gfp_t gfpflags, | ||
267 | int node) | ||
268 | { | ||
269 | return kmem_cache_alloc_node(s, gfpflags, node); | ||
270 | } | ||
271 | #endif | ||
272 | |||
234 | static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node) | 273 | static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node) |
235 | { | 274 | { |
275 | void *ret; | ||
276 | |||
236 | if (__builtin_constant_p(size) && | 277 | if (__builtin_constant_p(size) && |
237 | size <= PAGE_SIZE && !(flags & SLUB_DMA)) { | 278 | size <= PAGE_SIZE && !(flags & SLUB_DMA)) { |
238 | struct kmem_cache *s = kmalloc_slab(size); | 279 | struct kmem_cache *s = kmalloc_slab(size); |
@@ -240,7 +281,13 @@ static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node) | |||
240 | if (!s) | 281 | if (!s) |
241 | return ZERO_SIZE_PTR; | 282 | return ZERO_SIZE_PTR; |
242 | 283 | ||
243 | return kmem_cache_alloc_node(s, flags, node); | 284 | ret = kmem_cache_alloc_node_notrace(s, flags, node); |
285 | |||
286 | kmemtrace_mark_alloc_node(KMEMTRACE_TYPE_KMALLOC, | ||
287 | _THIS_IP_, ret, | ||
288 | size, s->size, flags, node); | ||
289 | |||
290 | return ret; | ||
244 | } | 291 | } |
245 | return __kmalloc_node(size, flags, node); | 292 | return __kmalloc_node(size, flags, node); |
246 | } | 293 | } |
diff --git a/init/main.c b/init/main.c index 17e9757bfde2..9711586aa7c9 100644 --- a/init/main.c +++ b/init/main.c | |||
@@ -70,6 +70,7 @@ | |||
70 | #include <asm/setup.h> | 70 | #include <asm/setup.h> |
71 | #include <asm/sections.h> | 71 | #include <asm/sections.h> |
72 | #include <asm/cacheflush.h> | 72 | #include <asm/cacheflush.h> |
73 | #include <linux/kmemtrace.h> | ||
73 | 74 | ||
74 | #ifdef CONFIG_X86_LOCAL_APIC | 75 | #ifdef CONFIG_X86_LOCAL_APIC |
75 | #include <asm/smp.h> | 76 | #include <asm/smp.h> |
@@ -654,6 +655,7 @@ asmlinkage void __init start_kernel(void) | |||
654 | enable_debug_pagealloc(); | 655 | enable_debug_pagealloc(); |
655 | cpu_hotplug_init(); | 656 | cpu_hotplug_init(); |
656 | kmem_cache_init(); | 657 | kmem_cache_init(); |
658 | kmemtrace_init(); | ||
657 | debug_objects_mem_init(); | 659 | debug_objects_mem_init(); |
658 | idr_init_cache(); | 660 | idr_init_cache(); |
659 | setup_per_cpu_pageset(); | 661 | setup_per_cpu_pageset(); |
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index b0f239e443bc..b5417e23ba94 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
@@ -803,6 +803,26 @@ config FIREWIRE_OHCI_REMOTE_DMA | |||
803 | 803 | ||
804 | If unsure, say N. | 804 | If unsure, say N. |
805 | 805 | ||
806 | config KMEMTRACE | ||
807 | bool "Kernel memory tracer (kmemtrace)" | ||
808 | depends on RELAY && DEBUG_FS && MARKERS | ||
809 | help | ||
810 | kmemtrace provides tracing for slab allocator functions, such as | ||
811 | kmalloc, kfree, kmem_cache_alloc, kmem_cache_free etc.. Collected | ||
812 | data is then fed to the userspace application in order to analyse | ||
813 | allocation hotspots, internal fragmentation and so on, making it | ||
814 | possible to see how well an allocator performs, as well as debug | ||
815 | and profile kernel code. | ||
816 | |||
817 | This requires an userspace application to use. See | ||
818 | Documentation/vm/kmemtrace.txt for more information. | ||
819 | |||
820 | Saying Y will make the kernel somewhat larger and slower. However, | ||
821 | if you disable kmemtrace at run-time or boot-time, the performance | ||
822 | impact is minimal (depending on the arch the kernel is built for). | ||
823 | |||
824 | If unsure, say N. | ||
825 | |||
806 | menuconfig BUILD_DOCSRC | 826 | menuconfig BUILD_DOCSRC |
807 | bool "Build targets in Documentation/ tree" | 827 | bool "Build targets in Documentation/ tree" |
808 | depends on HEADERS_CHECK | 828 | depends on HEADERS_CHECK |
diff --git a/mm/Makefile b/mm/Makefile index c06b45a1ff5f..3782eb66d4b3 100644 --- a/mm/Makefile +++ b/mm/Makefile | |||
@@ -34,3 +34,4 @@ obj-$(CONFIG_MIGRATION) += migrate.o | |||
34 | obj-$(CONFIG_SMP) += allocpercpu.o | 34 | obj-$(CONFIG_SMP) += allocpercpu.o |
35 | obj-$(CONFIG_QUICKLIST) += quicklist.o | 35 | obj-$(CONFIG_QUICKLIST) += quicklist.o |
36 | obj-$(CONFIG_CGROUP_MEM_RES_CTLR) += memcontrol.o page_cgroup.o | 36 | obj-$(CONFIG_CGROUP_MEM_RES_CTLR) += memcontrol.o page_cgroup.o |
37 | obj-$(CONFIG_KMEMTRACE) += kmemtrace.o | ||
diff --git a/mm/kmemtrace.c b/mm/kmemtrace.c new file mode 100644 index 000000000000..2a70a805027c --- /dev/null +++ b/mm/kmemtrace.c | |||
@@ -0,0 +1,333 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 Pekka Enberg, Eduard - Gabriel Munteanu | ||
3 | * | ||
4 | * This file is released under GPL version 2. | ||
5 | */ | ||
6 | |||
7 | #include <linux/string.h> | ||
8 | #include <linux/debugfs.h> | ||
9 | #include <linux/relay.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/marker.h> | ||
12 | #include <linux/gfp.h> | ||
13 | #include <linux/kmemtrace.h> | ||
14 | |||
15 | #define KMEMTRACE_SUBBUF_SIZE 524288 | ||
16 | #define KMEMTRACE_DEF_N_SUBBUFS 20 | ||
17 | |||
18 | static struct rchan *kmemtrace_chan; | ||
19 | static u32 kmemtrace_buf_overruns; | ||
20 | |||
21 | static unsigned int kmemtrace_n_subbufs; | ||
22 | |||
23 | /* disabled by default */ | ||
24 | static unsigned int kmemtrace_enabled; | ||
25 | |||
26 | /* | ||
27 | * The sequence number is used for reordering kmemtrace packets | ||
28 | * in userspace, since they are logged as per-CPU data. | ||
29 | * | ||
30 | * atomic_t should always be a 32-bit signed integer. Wraparound is not | ||
31 | * likely to occur, but userspace can deal with it by expecting a certain | ||
32 | * sequence number in the next packet that will be read. | ||
33 | */ | ||
34 | static atomic_t kmemtrace_seq_num; | ||
35 | |||
36 | #define KMEMTRACE_ABI_VERSION 1 | ||
37 | |||
38 | static u32 kmemtrace_abi_version __read_mostly = KMEMTRACE_ABI_VERSION; | ||
39 | |||
40 | enum kmemtrace_event_id { | ||
41 | KMEMTRACE_EVENT_ALLOC = 0, | ||
42 | KMEMTRACE_EVENT_FREE, | ||
43 | }; | ||
44 | |||
45 | struct kmemtrace_event { | ||
46 | u8 event_id; | ||
47 | u8 type_id; | ||
48 | u16 event_size; | ||
49 | s32 seq_num; | ||
50 | u64 call_site; | ||
51 | u64 ptr; | ||
52 | } __attribute__ ((__packed__)); | ||
53 | |||
54 | struct kmemtrace_stats_alloc { | ||
55 | u64 bytes_req; | ||
56 | u64 bytes_alloc; | ||
57 | u32 gfp_flags; | ||
58 | s32 numa_node; | ||
59 | } __attribute__ ((__packed__)); | ||
60 | |||
61 | static void kmemtrace_probe_alloc(void *probe_data, void *call_data, | ||
62 | const char *format, va_list *args) | ||
63 | { | ||
64 | unsigned long flags; | ||
65 | struct kmemtrace_event *ev; | ||
66 | struct kmemtrace_stats_alloc *stats; | ||
67 | void *buf; | ||
68 | |||
69 | local_irq_save(flags); | ||
70 | |||
71 | buf = relay_reserve(kmemtrace_chan, | ||
72 | sizeof(struct kmemtrace_event) + | ||
73 | sizeof(struct kmemtrace_stats_alloc)); | ||
74 | if (!buf) | ||
75 | goto failed; | ||
76 | |||
77 | /* | ||
78 | * Don't convert this to use structure initializers, | ||
79 | * C99 does not guarantee the rvalues evaluation order. | ||
80 | */ | ||
81 | |||
82 | ev = buf; | ||
83 | ev->event_id = KMEMTRACE_EVENT_ALLOC; | ||
84 | ev->type_id = va_arg(*args, int); | ||
85 | ev->event_size = sizeof(struct kmemtrace_event) + | ||
86 | sizeof(struct kmemtrace_stats_alloc); | ||
87 | ev->seq_num = atomic_add_return(1, &kmemtrace_seq_num); | ||
88 | ev->call_site = va_arg(*args, unsigned long); | ||
89 | ev->ptr = va_arg(*args, unsigned long); | ||
90 | |||
91 | stats = buf + sizeof(struct kmemtrace_event); | ||
92 | stats->bytes_req = va_arg(*args, unsigned long); | ||
93 | stats->bytes_alloc = va_arg(*args, unsigned long); | ||
94 | stats->gfp_flags = va_arg(*args, unsigned long); | ||
95 | stats->numa_node = va_arg(*args, int); | ||
96 | |||
97 | failed: | ||
98 | local_irq_restore(flags); | ||
99 | } | ||
100 | |||
101 | static void kmemtrace_probe_free(void *probe_data, void *call_data, | ||
102 | const char *format, va_list *args) | ||
103 | { | ||
104 | unsigned long flags; | ||
105 | struct kmemtrace_event *ev; | ||
106 | |||
107 | local_irq_save(flags); | ||
108 | |||
109 | ev = relay_reserve(kmemtrace_chan, sizeof(struct kmemtrace_event)); | ||
110 | if (!ev) | ||
111 | goto failed; | ||
112 | |||
113 | /* | ||
114 | * Don't convert this to use structure initializers, | ||
115 | * C99 does not guarantee the rvalues evaluation order. | ||
116 | */ | ||
117 | ev->event_id = KMEMTRACE_EVENT_FREE; | ||
118 | ev->type_id = va_arg(*args, int); | ||
119 | ev->event_size = sizeof(struct kmemtrace_event); | ||
120 | ev->seq_num = atomic_add_return(1, &kmemtrace_seq_num); | ||
121 | ev->call_site = va_arg(*args, unsigned long); | ||
122 | ev->ptr = va_arg(*args, unsigned long); | ||
123 | |||
124 | failed: | ||
125 | local_irq_restore(flags); | ||
126 | } | ||
127 | |||
128 | static struct dentry * | ||
129 | kmemtrace_create_buf_file(const char *filename, struct dentry *parent, | ||
130 | int mode, struct rchan_buf *buf, int *is_global) | ||
131 | { | ||
132 | return debugfs_create_file(filename, mode, parent, buf, | ||
133 | &relay_file_operations); | ||
134 | } | ||
135 | |||
136 | static int kmemtrace_remove_buf_file(struct dentry *dentry) | ||
137 | { | ||
138 | debugfs_remove(dentry); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static int kmemtrace_subbuf_start(struct rchan_buf *buf, | ||
144 | void *subbuf, | ||
145 | void *prev_subbuf, | ||
146 | size_t prev_padding) | ||
147 | { | ||
148 | if (relay_buf_full(buf)) { | ||
149 | /* | ||
150 | * We know it's not SMP-safe, but neither | ||
151 | * debugfs_create_u32() is. | ||
152 | */ | ||
153 | kmemtrace_buf_overruns++; | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | return 1; | ||
158 | } | ||
159 | |||
160 | static struct rchan_callbacks relay_callbacks = { | ||
161 | .create_buf_file = kmemtrace_create_buf_file, | ||
162 | .remove_buf_file = kmemtrace_remove_buf_file, | ||
163 | .subbuf_start = kmemtrace_subbuf_start, | ||
164 | }; | ||
165 | |||
166 | static struct dentry *kmemtrace_dir; | ||
167 | static struct dentry *kmemtrace_overruns_dentry; | ||
168 | static struct dentry *kmemtrace_abi_version_dentry; | ||
169 | |||
170 | static struct dentry *kmemtrace_enabled_dentry; | ||
171 | |||
172 | static int kmemtrace_start_probes(void) | ||
173 | { | ||
174 | int err; | ||
175 | |||
176 | err = marker_probe_register("kmemtrace_alloc", "type_id %d " | ||
177 | "call_site %lu ptr %lu " | ||
178 | "bytes_req %lu bytes_alloc %lu " | ||
179 | "gfp_flags %lu node %d", | ||
180 | kmemtrace_probe_alloc, NULL); | ||
181 | if (err) | ||
182 | return err; | ||
183 | err = marker_probe_register("kmemtrace_free", "type_id %d " | ||
184 | "call_site %lu ptr %lu", | ||
185 | kmemtrace_probe_free, NULL); | ||
186 | |||
187 | return err; | ||
188 | } | ||
189 | |||
190 | static void kmemtrace_stop_probes(void) | ||
191 | { | ||
192 | marker_probe_unregister("kmemtrace_alloc", | ||
193 | kmemtrace_probe_alloc, NULL); | ||
194 | marker_probe_unregister("kmemtrace_free", | ||
195 | kmemtrace_probe_free, NULL); | ||
196 | } | ||
197 | |||
198 | static int kmemtrace_enabled_get(void *data, u64 *val) | ||
199 | { | ||
200 | *val = *((int *) data); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static int kmemtrace_enabled_set(void *data, u64 val) | ||
206 | { | ||
207 | u64 old_val = kmemtrace_enabled; | ||
208 | |||
209 | *((int *) data) = !!val; | ||
210 | |||
211 | if (old_val == val) | ||
212 | return 0; | ||
213 | if (val) | ||
214 | kmemtrace_start_probes(); | ||
215 | else | ||
216 | kmemtrace_stop_probes(); | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | DEFINE_SIMPLE_ATTRIBUTE(kmemtrace_enabled_fops, | ||
222 | kmemtrace_enabled_get, | ||
223 | kmemtrace_enabled_set, "%llu\n"); | ||
224 | |||
225 | static void kmemtrace_cleanup(void) | ||
226 | { | ||
227 | if (kmemtrace_enabled_dentry) | ||
228 | debugfs_remove(kmemtrace_enabled_dentry); | ||
229 | |||
230 | kmemtrace_stop_probes(); | ||
231 | |||
232 | if (kmemtrace_abi_version_dentry) | ||
233 | debugfs_remove(kmemtrace_abi_version_dentry); | ||
234 | if (kmemtrace_overruns_dentry) | ||
235 | debugfs_remove(kmemtrace_overruns_dentry); | ||
236 | |||
237 | relay_close(kmemtrace_chan); | ||
238 | kmemtrace_chan = NULL; | ||
239 | |||
240 | if (kmemtrace_dir) | ||
241 | debugfs_remove(kmemtrace_dir); | ||
242 | } | ||
243 | |||
244 | static int __init kmemtrace_setup_late(void) | ||
245 | { | ||
246 | if (!kmemtrace_chan) | ||
247 | goto failed; | ||
248 | |||
249 | kmemtrace_dir = debugfs_create_dir("kmemtrace", NULL); | ||
250 | if (!kmemtrace_dir) | ||
251 | goto cleanup; | ||
252 | |||
253 | kmemtrace_abi_version_dentry = | ||
254 | debugfs_create_u32("abi_version", S_IRUSR, | ||
255 | kmemtrace_dir, &kmemtrace_abi_version); | ||
256 | kmemtrace_overruns_dentry = | ||
257 | debugfs_create_u32("total_overruns", S_IRUSR, | ||
258 | kmemtrace_dir, &kmemtrace_buf_overruns); | ||
259 | if (!kmemtrace_overruns_dentry || !kmemtrace_abi_version_dentry) | ||
260 | goto cleanup; | ||
261 | |||
262 | kmemtrace_enabled_dentry = | ||
263 | debugfs_create_file("enabled", S_IRUSR | S_IWUSR, | ||
264 | kmemtrace_dir, &kmemtrace_enabled, | ||
265 | &kmemtrace_enabled_fops); | ||
266 | if (!kmemtrace_enabled_dentry) | ||
267 | goto cleanup; | ||
268 | |||
269 | if (relay_late_setup_files(kmemtrace_chan, "cpu", kmemtrace_dir)) | ||
270 | goto cleanup; | ||
271 | |||
272 | printk(KERN_INFO "kmemtrace: fully up.\n"); | ||
273 | |||
274 | return 0; | ||
275 | |||
276 | cleanup: | ||
277 | kmemtrace_cleanup(); | ||
278 | failed: | ||
279 | return 1; | ||
280 | } | ||
281 | late_initcall(kmemtrace_setup_late); | ||
282 | |||
283 | static int __init kmemtrace_set_boot_enabled(char *str) | ||
284 | { | ||
285 | if (!str) | ||
286 | return -EINVAL; | ||
287 | |||
288 | if (!strcmp(str, "yes")) | ||
289 | kmemtrace_enabled = 1; | ||
290 | else if (!strcmp(str, "no")) | ||
291 | kmemtrace_enabled = 0; | ||
292 | else | ||
293 | return -EINVAL; | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | early_param("kmemtrace.enable", kmemtrace_set_boot_enabled); | ||
298 | |||
299 | static int __init kmemtrace_set_subbufs(char *str) | ||
300 | { | ||
301 | get_option(&str, &kmemtrace_n_subbufs); | ||
302 | return 0; | ||
303 | } | ||
304 | early_param("kmemtrace.subbufs", kmemtrace_set_subbufs); | ||
305 | |||
306 | void kmemtrace_init(void) | ||
307 | { | ||
308 | if (!kmemtrace_n_subbufs) | ||
309 | kmemtrace_n_subbufs = KMEMTRACE_DEF_N_SUBBUFS; | ||
310 | |||
311 | kmemtrace_chan = relay_open(NULL, NULL, KMEMTRACE_SUBBUF_SIZE, | ||
312 | kmemtrace_n_subbufs, &relay_callbacks, | ||
313 | NULL); | ||
314 | if (!kmemtrace_chan) { | ||
315 | printk(KERN_ERR "kmemtrace: could not open relay channel.\n"); | ||
316 | return; | ||
317 | } | ||
318 | |||
319 | if (!kmemtrace_enabled) { | ||
320 | printk(KERN_INFO "kmemtrace: disabled. Pass " | ||
321 | "kemtrace.enable=yes as kernel parameter for " | ||
322 | "boot-time tracing.\n"); | ||
323 | return; | ||
324 | } | ||
325 | if (kmemtrace_start_probes()) { | ||
326 | printk(KERN_ERR "kmemtrace: could not register marker probes!\n"); | ||
327 | kmemtrace_cleanup(); | ||
328 | return; | ||
329 | } | ||
330 | |||
331 | printk(KERN_INFO "kmemtrace: enabled.\n"); | ||
332 | } | ||
333 | |||
@@ -112,6 +112,7 @@ | |||
112 | #include <linux/rtmutex.h> | 112 | #include <linux/rtmutex.h> |
113 | #include <linux/reciprocal_div.h> | 113 | #include <linux/reciprocal_div.h> |
114 | #include <linux/debugobjects.h> | 114 | #include <linux/debugobjects.h> |
115 | #include <linux/kmemtrace.h> | ||
115 | 116 | ||
116 | #include <asm/cacheflush.h> | 117 | #include <asm/cacheflush.h> |
117 | #include <asm/tlbflush.h> | 118 | #include <asm/tlbflush.h> |
@@ -568,6 +569,14 @@ static void **dbg_userword(struct kmem_cache *cachep, void *objp) | |||
568 | 569 | ||
569 | #endif | 570 | #endif |
570 | 571 | ||
572 | #ifdef CONFIG_KMEMTRACE | ||
573 | size_t slab_buffer_size(struct kmem_cache *cachep) | ||
574 | { | ||
575 | return cachep->buffer_size; | ||
576 | } | ||
577 | EXPORT_SYMBOL(slab_buffer_size); | ||
578 | #endif | ||
579 | |||
571 | /* | 580 | /* |
572 | * Do not go above this order unless 0 objects fit into the slab. | 581 | * Do not go above this order unless 0 objects fit into the slab. |
573 | */ | 582 | */ |
@@ -3613,10 +3622,23 @@ static inline void __cache_free(struct kmem_cache *cachep, void *objp) | |||
3613 | */ | 3622 | */ |
3614 | void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags) | 3623 | void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags) |
3615 | { | 3624 | { |
3616 | return __cache_alloc(cachep, flags, __builtin_return_address(0)); | 3625 | void *ret = __cache_alloc(cachep, flags, __builtin_return_address(0)); |
3626 | |||
3627 | kmemtrace_mark_alloc(KMEMTRACE_TYPE_CACHE, _RET_IP_, ret, | ||
3628 | obj_size(cachep), cachep->buffer_size, flags); | ||
3629 | |||
3630 | return ret; | ||
3617 | } | 3631 | } |
3618 | EXPORT_SYMBOL(kmem_cache_alloc); | 3632 | EXPORT_SYMBOL(kmem_cache_alloc); |
3619 | 3633 | ||
3634 | #ifdef CONFIG_KMEMTRACE | ||
3635 | void *kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags) | ||
3636 | { | ||
3637 | return __cache_alloc(cachep, flags, __builtin_return_address(0)); | ||
3638 | } | ||
3639 | EXPORT_SYMBOL(kmem_cache_alloc_notrace); | ||
3640 | #endif | ||
3641 | |||
3620 | /** | 3642 | /** |
3621 | * kmem_ptr_validate - check if an untrusted pointer might be a slab entry. | 3643 | * kmem_ptr_validate - check if an untrusted pointer might be a slab entry. |
3622 | * @cachep: the cache we're checking against | 3644 | * @cachep: the cache we're checking against |
@@ -3661,23 +3683,47 @@ out: | |||
3661 | #ifdef CONFIG_NUMA | 3683 | #ifdef CONFIG_NUMA |
3662 | void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid) | 3684 | void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid) |
3663 | { | 3685 | { |
3664 | return __cache_alloc_node(cachep, flags, nodeid, | 3686 | void *ret = __cache_alloc_node(cachep, flags, nodeid, |
3665 | __builtin_return_address(0)); | 3687 | __builtin_return_address(0)); |
3688 | |||
3689 | kmemtrace_mark_alloc_node(KMEMTRACE_TYPE_CACHE, _RET_IP_, ret, | ||
3690 | obj_size(cachep), cachep->buffer_size, | ||
3691 | flags, nodeid); | ||
3692 | |||
3693 | return ret; | ||
3666 | } | 3694 | } |
3667 | EXPORT_SYMBOL(kmem_cache_alloc_node); | 3695 | EXPORT_SYMBOL(kmem_cache_alloc_node); |
3668 | 3696 | ||
3697 | #ifdef CONFIG_KMEMTRACE | ||
3698 | void *kmem_cache_alloc_node_notrace(struct kmem_cache *cachep, | ||
3699 | gfp_t flags, | ||
3700 | int nodeid) | ||
3701 | { | ||
3702 | return __cache_alloc_node(cachep, flags, nodeid, | ||
3703 | __builtin_return_address(0)); | ||
3704 | } | ||
3705 | EXPORT_SYMBOL(kmem_cache_alloc_node_notrace); | ||
3706 | #endif | ||
3707 | |||
3669 | static __always_inline void * | 3708 | static __always_inline void * |
3670 | __do_kmalloc_node(size_t size, gfp_t flags, int node, void *caller) | 3709 | __do_kmalloc_node(size_t size, gfp_t flags, int node, void *caller) |
3671 | { | 3710 | { |
3672 | struct kmem_cache *cachep; | 3711 | struct kmem_cache *cachep; |
3712 | void *ret; | ||
3673 | 3713 | ||
3674 | cachep = kmem_find_general_cachep(size, flags); | 3714 | cachep = kmem_find_general_cachep(size, flags); |
3675 | if (unlikely(ZERO_OR_NULL_PTR(cachep))) | 3715 | if (unlikely(ZERO_OR_NULL_PTR(cachep))) |
3676 | return cachep; | 3716 | return cachep; |
3677 | return kmem_cache_alloc_node(cachep, flags, node); | 3717 | ret = kmem_cache_alloc_node_notrace(cachep, flags, node); |
3718 | |||
3719 | kmemtrace_mark_alloc_node(KMEMTRACE_TYPE_KMALLOC, | ||
3720 | (unsigned long) caller, ret, | ||
3721 | size, cachep->buffer_size, flags, node); | ||
3722 | |||
3723 | return ret; | ||
3678 | } | 3724 | } |
3679 | 3725 | ||
3680 | #ifdef CONFIG_DEBUG_SLAB | 3726 | #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_KMEMTRACE) |
3681 | void *__kmalloc_node(size_t size, gfp_t flags, int node) | 3727 | void *__kmalloc_node(size_t size, gfp_t flags, int node) |
3682 | { | 3728 | { |
3683 | return __do_kmalloc_node(size, flags, node, | 3729 | return __do_kmalloc_node(size, flags, node, |
@@ -3686,9 +3732,9 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node) | |||
3686 | EXPORT_SYMBOL(__kmalloc_node); | 3732 | EXPORT_SYMBOL(__kmalloc_node); |
3687 | 3733 | ||
3688 | void *__kmalloc_node_track_caller(size_t size, gfp_t flags, | 3734 | void *__kmalloc_node_track_caller(size_t size, gfp_t flags, |
3689 | int node, void *caller) | 3735 | int node, unsigned long caller) |
3690 | { | 3736 | { |
3691 | return __do_kmalloc_node(size, flags, node, caller); | 3737 | return __do_kmalloc_node(size, flags, node, (void *)caller); |
3692 | } | 3738 | } |
3693 | EXPORT_SYMBOL(__kmalloc_node_track_caller); | 3739 | EXPORT_SYMBOL(__kmalloc_node_track_caller); |
3694 | #else | 3740 | #else |
@@ -3710,6 +3756,7 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags, | |||
3710 | void *caller) | 3756 | void *caller) |
3711 | { | 3757 | { |
3712 | struct kmem_cache *cachep; | 3758 | struct kmem_cache *cachep; |
3759 | void *ret; | ||
3713 | 3760 | ||
3714 | /* If you want to save a few bytes .text space: replace | 3761 | /* If you want to save a few bytes .text space: replace |
3715 | * __ with kmem_. | 3762 | * __ with kmem_. |
@@ -3719,20 +3766,26 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags, | |||
3719 | cachep = __find_general_cachep(size, flags); | 3766 | cachep = __find_general_cachep(size, flags); |
3720 | if (unlikely(ZERO_OR_NULL_PTR(cachep))) | 3767 | if (unlikely(ZERO_OR_NULL_PTR(cachep))) |
3721 | return cachep; | 3768 | return cachep; |
3722 | return __cache_alloc(cachep, flags, caller); | 3769 | ret = __cache_alloc(cachep, flags, caller); |
3770 | |||
3771 | kmemtrace_mark_alloc(KMEMTRACE_TYPE_KMALLOC, | ||
3772 | (unsigned long) caller, ret, | ||
3773 | size, cachep->buffer_size, flags); | ||
3774 | |||
3775 | return ret; | ||
3723 | } | 3776 | } |
3724 | 3777 | ||
3725 | 3778 | ||
3726 | #ifdef CONFIG_DEBUG_SLAB | 3779 | #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_KMEMTRACE) |
3727 | void *__kmalloc(size_t size, gfp_t flags) | 3780 | void *__kmalloc(size_t size, gfp_t flags) |
3728 | { | 3781 | { |
3729 | return __do_kmalloc(size, flags, __builtin_return_address(0)); | 3782 | return __do_kmalloc(size, flags, __builtin_return_address(0)); |
3730 | } | 3783 | } |
3731 | EXPORT_SYMBOL(__kmalloc); | 3784 | EXPORT_SYMBOL(__kmalloc); |
3732 | 3785 | ||
3733 | void *__kmalloc_track_caller(size_t size, gfp_t flags, void *caller) | 3786 | void *__kmalloc_track_caller(size_t size, gfp_t flags, unsigned long caller) |
3734 | { | 3787 | { |
3735 | return __do_kmalloc(size, flags, caller); | 3788 | return __do_kmalloc(size, flags, (void *)caller); |
3736 | } | 3789 | } |
3737 | EXPORT_SYMBOL(__kmalloc_track_caller); | 3790 | EXPORT_SYMBOL(__kmalloc_track_caller); |
3738 | 3791 | ||
@@ -3762,6 +3815,8 @@ void kmem_cache_free(struct kmem_cache *cachep, void *objp) | |||
3762 | debug_check_no_obj_freed(objp, obj_size(cachep)); | 3815 | debug_check_no_obj_freed(objp, obj_size(cachep)); |
3763 | __cache_free(cachep, objp); | 3816 | __cache_free(cachep, objp); |
3764 | local_irq_restore(flags); | 3817 | local_irq_restore(flags); |
3818 | |||
3819 | kmemtrace_mark_free(KMEMTRACE_TYPE_CACHE, _RET_IP_, objp); | ||
3765 | } | 3820 | } |
3766 | EXPORT_SYMBOL(kmem_cache_free); | 3821 | EXPORT_SYMBOL(kmem_cache_free); |
3767 | 3822 | ||
@@ -3788,6 +3843,8 @@ void kfree(const void *objp) | |||
3788 | debug_check_no_obj_freed(objp, obj_size(c)); | 3843 | debug_check_no_obj_freed(objp, obj_size(c)); |
3789 | __cache_free(c, (void *)objp); | 3844 | __cache_free(c, (void *)objp); |
3790 | local_irq_restore(flags); | 3845 | local_irq_restore(flags); |
3846 | |||
3847 | kmemtrace_mark_free(KMEMTRACE_TYPE_KMALLOC, _RET_IP_, objp); | ||
3791 | } | 3848 | } |
3792 | EXPORT_SYMBOL(kfree); | 3849 | EXPORT_SYMBOL(kfree); |
3793 | 3850 | ||
@@ -65,6 +65,7 @@ | |||
65 | #include <linux/module.h> | 65 | #include <linux/module.h> |
66 | #include <linux/rcupdate.h> | 66 | #include <linux/rcupdate.h> |
67 | #include <linux/list.h> | 67 | #include <linux/list.h> |
68 | #include <linux/kmemtrace.h> | ||
68 | #include <asm/atomic.h> | 69 | #include <asm/atomic.h> |
69 | 70 | ||
70 | /* | 71 | /* |
@@ -463,27 +464,38 @@ void *__kmalloc_node(size_t size, gfp_t gfp, int node) | |||
463 | { | 464 | { |
464 | unsigned int *m; | 465 | unsigned int *m; |
465 | int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); | 466 | int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); |
467 | void *ret; | ||
466 | 468 | ||
467 | if (size < PAGE_SIZE - align) { | 469 | if (size < PAGE_SIZE - align) { |
468 | if (!size) | 470 | if (!size) |
469 | return ZERO_SIZE_PTR; | 471 | return ZERO_SIZE_PTR; |
470 | 472 | ||
471 | m = slob_alloc(size + align, gfp, align, node); | 473 | m = slob_alloc(size + align, gfp, align, node); |
474 | |||
472 | if (!m) | 475 | if (!m) |
473 | return NULL; | 476 | return NULL; |
474 | *m = size; | 477 | *m = size; |
475 | return (void *)m + align; | 478 | ret = (void *)m + align; |
479 | |||
480 | kmemtrace_mark_alloc_node(KMEMTRACE_TYPE_KMALLOC, | ||
481 | _RET_IP_, ret, | ||
482 | size, size + align, gfp, node); | ||
476 | } else { | 483 | } else { |
477 | void *ret; | 484 | unsigned int order = get_order(size); |
478 | 485 | ||
479 | ret = slob_new_page(gfp | __GFP_COMP, get_order(size), node); | 486 | ret = slob_new_page(gfp | __GFP_COMP, order, node); |
480 | if (ret) { | 487 | if (ret) { |
481 | struct page *page; | 488 | struct page *page; |
482 | page = virt_to_page(ret); | 489 | page = virt_to_page(ret); |
483 | page->private = size; | 490 | page->private = size; |
484 | } | 491 | } |
485 | return ret; | 492 | |
493 | kmemtrace_mark_alloc_node(KMEMTRACE_TYPE_KMALLOC, | ||
494 | _RET_IP_, ret, | ||
495 | size, PAGE_SIZE << order, gfp, node); | ||
486 | } | 496 | } |
497 | |||
498 | return ret; | ||
487 | } | 499 | } |
488 | EXPORT_SYMBOL(__kmalloc_node); | 500 | EXPORT_SYMBOL(__kmalloc_node); |
489 | 501 | ||
@@ -501,6 +513,8 @@ void kfree(const void *block) | |||
501 | slob_free(m, *m + align); | 513 | slob_free(m, *m + align); |
502 | } else | 514 | } else |
503 | put_page(&sp->page); | 515 | put_page(&sp->page); |
516 | |||
517 | kmemtrace_mark_free(KMEMTRACE_TYPE_KMALLOC, _RET_IP_, block); | ||
504 | } | 518 | } |
505 | EXPORT_SYMBOL(kfree); | 519 | EXPORT_SYMBOL(kfree); |
506 | 520 | ||
@@ -569,10 +583,19 @@ void *kmem_cache_alloc_node(struct kmem_cache *c, gfp_t flags, int node) | |||
569 | { | 583 | { |
570 | void *b; | 584 | void *b; |
571 | 585 | ||
572 | if (c->size < PAGE_SIZE) | 586 | if (c->size < PAGE_SIZE) { |
573 | b = slob_alloc(c->size, flags, c->align, node); | 587 | b = slob_alloc(c->size, flags, c->align, node); |
574 | else | 588 | kmemtrace_mark_alloc_node(KMEMTRACE_TYPE_CACHE, |
589 | _RET_IP_, b, c->size, | ||
590 | SLOB_UNITS(c->size) * SLOB_UNIT, | ||
591 | flags, node); | ||
592 | } else { | ||
575 | b = slob_new_page(flags, get_order(c->size), node); | 593 | b = slob_new_page(flags, get_order(c->size), node); |
594 | kmemtrace_mark_alloc_node(KMEMTRACE_TYPE_CACHE, | ||
595 | _RET_IP_, b, c->size, | ||
596 | PAGE_SIZE << get_order(c->size), | ||
597 | flags, node); | ||
598 | } | ||
576 | 599 | ||
577 | if (c->ctor) | 600 | if (c->ctor) |
578 | c->ctor(b); | 601 | c->ctor(b); |
@@ -608,6 +631,8 @@ void kmem_cache_free(struct kmem_cache *c, void *b) | |||
608 | } else { | 631 | } else { |
609 | __kmem_cache_free(b, c->size); | 632 | __kmem_cache_free(b, c->size); |
610 | } | 633 | } |
634 | |||
635 | kmemtrace_mark_free(KMEMTRACE_TYPE_CACHE, _RET_IP_, b); | ||
611 | } | 636 | } |
612 | EXPORT_SYMBOL(kmem_cache_free); | 637 | EXPORT_SYMBOL(kmem_cache_free); |
613 | 638 | ||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/kallsyms.h> | 24 | #include <linux/kallsyms.h> |
25 | #include <linux/memory.h> | 25 | #include <linux/memory.h> |
26 | #include <linux/math64.h> | 26 | #include <linux/math64.h> |
27 | #include <linux/kmemtrace.h> | ||
27 | 28 | ||
28 | /* | 29 | /* |
29 | * Lock order: | 30 | * Lock order: |
@@ -178,7 +179,7 @@ static LIST_HEAD(slab_caches); | |||
178 | * Tracking user of a slab. | 179 | * Tracking user of a slab. |
179 | */ | 180 | */ |
180 | struct track { | 181 | struct track { |
181 | void *addr; /* Called from address */ | 182 | unsigned long addr; /* Called from address */ |
182 | int cpu; /* Was running on cpu */ | 183 | int cpu; /* Was running on cpu */ |
183 | int pid; /* Pid context */ | 184 | int pid; /* Pid context */ |
184 | unsigned long when; /* When did the operation occur */ | 185 | unsigned long when; /* When did the operation occur */ |
@@ -367,7 +368,7 @@ static struct track *get_track(struct kmem_cache *s, void *object, | |||
367 | } | 368 | } |
368 | 369 | ||
369 | static void set_track(struct kmem_cache *s, void *object, | 370 | static void set_track(struct kmem_cache *s, void *object, |
370 | enum track_item alloc, void *addr) | 371 | enum track_item alloc, unsigned long addr) |
371 | { | 372 | { |
372 | struct track *p; | 373 | struct track *p; |
373 | 374 | ||
@@ -391,8 +392,8 @@ static void init_tracking(struct kmem_cache *s, void *object) | |||
391 | if (!(s->flags & SLAB_STORE_USER)) | 392 | if (!(s->flags & SLAB_STORE_USER)) |
392 | return; | 393 | return; |
393 | 394 | ||
394 | set_track(s, object, TRACK_FREE, NULL); | 395 | set_track(s, object, TRACK_FREE, 0UL); |
395 | set_track(s, object, TRACK_ALLOC, NULL); | 396 | set_track(s, object, TRACK_ALLOC, 0UL); |
396 | } | 397 | } |
397 | 398 | ||
398 | static void print_track(const char *s, struct track *t) | 399 | static void print_track(const char *s, struct track *t) |
@@ -401,7 +402,7 @@ static void print_track(const char *s, struct track *t) | |||
401 | return; | 402 | return; |
402 | 403 | ||
403 | printk(KERN_ERR "INFO: %s in %pS age=%lu cpu=%u pid=%d\n", | 404 | printk(KERN_ERR "INFO: %s in %pS age=%lu cpu=%u pid=%d\n", |
404 | s, t->addr, jiffies - t->when, t->cpu, t->pid); | 405 | s, (void *)t->addr, jiffies - t->when, t->cpu, t->pid); |
405 | } | 406 | } |
406 | 407 | ||
407 | static void print_tracking(struct kmem_cache *s, void *object) | 408 | static void print_tracking(struct kmem_cache *s, void *object) |
@@ -866,7 +867,7 @@ static void setup_object_debug(struct kmem_cache *s, struct page *page, | |||
866 | } | 867 | } |
867 | 868 | ||
868 | static int alloc_debug_processing(struct kmem_cache *s, struct page *page, | 869 | static int alloc_debug_processing(struct kmem_cache *s, struct page *page, |
869 | void *object, void *addr) | 870 | void *object, unsigned long addr) |
870 | { | 871 | { |
871 | if (!check_slab(s, page)) | 872 | if (!check_slab(s, page)) |
872 | goto bad; | 873 | goto bad; |
@@ -906,7 +907,7 @@ bad: | |||
906 | } | 907 | } |
907 | 908 | ||
908 | static int free_debug_processing(struct kmem_cache *s, struct page *page, | 909 | static int free_debug_processing(struct kmem_cache *s, struct page *page, |
909 | void *object, void *addr) | 910 | void *object, unsigned long addr) |
910 | { | 911 | { |
911 | if (!check_slab(s, page)) | 912 | if (!check_slab(s, page)) |
912 | goto fail; | 913 | goto fail; |
@@ -1029,10 +1030,10 @@ static inline void setup_object_debug(struct kmem_cache *s, | |||
1029 | struct page *page, void *object) {} | 1030 | struct page *page, void *object) {} |
1030 | 1031 | ||
1031 | static inline int alloc_debug_processing(struct kmem_cache *s, | 1032 | static inline int alloc_debug_processing(struct kmem_cache *s, |
1032 | struct page *page, void *object, void *addr) { return 0; } | 1033 | struct page *page, void *object, unsigned long addr) { return 0; } |
1033 | 1034 | ||
1034 | static inline int free_debug_processing(struct kmem_cache *s, | 1035 | static inline int free_debug_processing(struct kmem_cache *s, |
1035 | struct page *page, void *object, void *addr) { return 0; } | 1036 | struct page *page, void *object, unsigned long addr) { return 0; } |
1036 | 1037 | ||
1037 | static inline int slab_pad_check(struct kmem_cache *s, struct page *page) | 1038 | static inline int slab_pad_check(struct kmem_cache *s, struct page *page) |
1038 | { return 1; } | 1039 | { return 1; } |
@@ -1499,8 +1500,8 @@ static inline int node_match(struct kmem_cache_cpu *c, int node) | |||
1499 | * we need to allocate a new slab. This is the slowest path since it involves | 1500 | * we need to allocate a new slab. This is the slowest path since it involves |
1500 | * a call to the page allocator and the setup of a new slab. | 1501 | * a call to the page allocator and the setup of a new slab. |
1501 | */ | 1502 | */ |
1502 | static void *__slab_alloc(struct kmem_cache *s, | 1503 | static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, |
1503 | gfp_t gfpflags, int node, void *addr, struct kmem_cache_cpu *c) | 1504 | unsigned long addr, struct kmem_cache_cpu *c) |
1504 | { | 1505 | { |
1505 | void **object; | 1506 | void **object; |
1506 | struct page *new; | 1507 | struct page *new; |
@@ -1584,7 +1585,7 @@ debug: | |||
1584 | * Otherwise we can simply pick the next object from the lockless free list. | 1585 | * Otherwise we can simply pick the next object from the lockless free list. |
1585 | */ | 1586 | */ |
1586 | static __always_inline void *slab_alloc(struct kmem_cache *s, | 1587 | static __always_inline void *slab_alloc(struct kmem_cache *s, |
1587 | gfp_t gfpflags, int node, void *addr) | 1588 | gfp_t gfpflags, int node, unsigned long addr) |
1588 | { | 1589 | { |
1589 | void **object; | 1590 | void **object; |
1590 | struct kmem_cache_cpu *c; | 1591 | struct kmem_cache_cpu *c; |
@@ -1613,18 +1614,46 @@ static __always_inline void *slab_alloc(struct kmem_cache *s, | |||
1613 | 1614 | ||
1614 | void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags) | 1615 | void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags) |
1615 | { | 1616 | { |
1616 | return slab_alloc(s, gfpflags, -1, __builtin_return_address(0)); | 1617 | void *ret = slab_alloc(s, gfpflags, -1, _RET_IP_); |
1618 | |||
1619 | kmemtrace_mark_alloc(KMEMTRACE_TYPE_CACHE, _RET_IP_, ret, | ||
1620 | s->objsize, s->size, gfpflags); | ||
1621 | |||
1622 | return ret; | ||
1617 | } | 1623 | } |
1618 | EXPORT_SYMBOL(kmem_cache_alloc); | 1624 | EXPORT_SYMBOL(kmem_cache_alloc); |
1619 | 1625 | ||
1626 | #ifdef CONFIG_KMEMTRACE | ||
1627 | void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags) | ||
1628 | { | ||
1629 | return slab_alloc(s, gfpflags, -1, _RET_IP_); | ||
1630 | } | ||
1631 | EXPORT_SYMBOL(kmem_cache_alloc_notrace); | ||
1632 | #endif | ||
1633 | |||
1620 | #ifdef CONFIG_NUMA | 1634 | #ifdef CONFIG_NUMA |
1621 | void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node) | 1635 | void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node) |
1622 | { | 1636 | { |
1623 | return slab_alloc(s, gfpflags, node, __builtin_return_address(0)); | 1637 | void *ret = slab_alloc(s, gfpflags, node, _RET_IP_); |
1638 | |||
1639 | kmemtrace_mark_alloc_node(KMEMTRACE_TYPE_CACHE, _RET_IP_, ret, | ||
1640 | s->objsize, s->size, gfpflags, node); | ||
1641 | |||
1642 | return ret; | ||
1624 | } | 1643 | } |
1625 | EXPORT_SYMBOL(kmem_cache_alloc_node); | 1644 | EXPORT_SYMBOL(kmem_cache_alloc_node); |
1626 | #endif | 1645 | #endif |
1627 | 1646 | ||
1647 | #ifdef CONFIG_KMEMTRACE | ||
1648 | void *kmem_cache_alloc_node_notrace(struct kmem_cache *s, | ||
1649 | gfp_t gfpflags, | ||
1650 | int node) | ||
1651 | { | ||
1652 | return slab_alloc(s, gfpflags, node, _RET_IP_); | ||
1653 | } | ||
1654 | EXPORT_SYMBOL(kmem_cache_alloc_node_notrace); | ||
1655 | #endif | ||
1656 | |||
1628 | /* | 1657 | /* |
1629 | * Slow patch handling. This may still be called frequently since objects | 1658 | * Slow patch handling. This may still be called frequently since objects |
1630 | * have a longer lifetime than the cpu slabs in most processing loads. | 1659 | * have a longer lifetime than the cpu slabs in most processing loads. |
@@ -1634,7 +1663,7 @@ EXPORT_SYMBOL(kmem_cache_alloc_node); | |||
1634 | * handling required then we can return immediately. | 1663 | * handling required then we can return immediately. |
1635 | */ | 1664 | */ |
1636 | static void __slab_free(struct kmem_cache *s, struct page *page, | 1665 | static void __slab_free(struct kmem_cache *s, struct page *page, |
1637 | void *x, void *addr, unsigned int offset) | 1666 | void *x, unsigned long addr, unsigned int offset) |
1638 | { | 1667 | { |
1639 | void *prior; | 1668 | void *prior; |
1640 | void **object = (void *)x; | 1669 | void **object = (void *)x; |
@@ -1704,7 +1733,7 @@ debug: | |||
1704 | * with all sorts of special processing. | 1733 | * with all sorts of special processing. |
1705 | */ | 1734 | */ |
1706 | static __always_inline void slab_free(struct kmem_cache *s, | 1735 | static __always_inline void slab_free(struct kmem_cache *s, |
1707 | struct page *page, void *x, void *addr) | 1736 | struct page *page, void *x, unsigned long addr) |
1708 | { | 1737 | { |
1709 | void **object = (void *)x; | 1738 | void **object = (void *)x; |
1710 | struct kmem_cache_cpu *c; | 1739 | struct kmem_cache_cpu *c; |
@@ -1731,7 +1760,9 @@ void kmem_cache_free(struct kmem_cache *s, void *x) | |||
1731 | 1760 | ||
1732 | page = virt_to_head_page(x); | 1761 | page = virt_to_head_page(x); |
1733 | 1762 | ||
1734 | slab_free(s, page, x, __builtin_return_address(0)); | 1763 | slab_free(s, page, x, _RET_IP_); |
1764 | |||
1765 | kmemtrace_mark_free(KMEMTRACE_TYPE_CACHE, _RET_IP_, x); | ||
1735 | } | 1766 | } |
1736 | EXPORT_SYMBOL(kmem_cache_free); | 1767 | EXPORT_SYMBOL(kmem_cache_free); |
1737 | 1768 | ||
@@ -2650,6 +2681,7 @@ static struct kmem_cache *get_slab(size_t size, gfp_t flags) | |||
2650 | void *__kmalloc(size_t size, gfp_t flags) | 2681 | void *__kmalloc(size_t size, gfp_t flags) |
2651 | { | 2682 | { |
2652 | struct kmem_cache *s; | 2683 | struct kmem_cache *s; |
2684 | void *ret; | ||
2653 | 2685 | ||
2654 | if (unlikely(size > PAGE_SIZE)) | 2686 | if (unlikely(size > PAGE_SIZE)) |
2655 | return kmalloc_large(size, flags); | 2687 | return kmalloc_large(size, flags); |
@@ -2659,7 +2691,12 @@ void *__kmalloc(size_t size, gfp_t flags) | |||
2659 | if (unlikely(ZERO_OR_NULL_PTR(s))) | 2691 | if (unlikely(ZERO_OR_NULL_PTR(s))) |
2660 | return s; | 2692 | return s; |
2661 | 2693 | ||
2662 | return slab_alloc(s, flags, -1, __builtin_return_address(0)); | 2694 | ret = slab_alloc(s, flags, -1, _RET_IP_); |
2695 | |||
2696 | kmemtrace_mark_alloc(KMEMTRACE_TYPE_KMALLOC, _RET_IP_, ret, | ||
2697 | size, s->size, flags); | ||
2698 | |||
2699 | return ret; | ||
2663 | } | 2700 | } |
2664 | EXPORT_SYMBOL(__kmalloc); | 2701 | EXPORT_SYMBOL(__kmalloc); |
2665 | 2702 | ||
@@ -2678,16 +2715,30 @@ static void *kmalloc_large_node(size_t size, gfp_t flags, int node) | |||
2678 | void *__kmalloc_node(size_t size, gfp_t flags, int node) | 2715 | void *__kmalloc_node(size_t size, gfp_t flags, int node) |
2679 | { | 2716 | { |
2680 | struct kmem_cache *s; | 2717 | struct kmem_cache *s; |
2718 | void *ret; | ||
2681 | 2719 | ||
2682 | if (unlikely(size > PAGE_SIZE)) | 2720 | if (unlikely(size > PAGE_SIZE)) { |
2683 | return kmalloc_large_node(size, flags, node); | 2721 | ret = kmalloc_large_node(size, flags, node); |
2722 | |||
2723 | kmemtrace_mark_alloc_node(KMEMTRACE_TYPE_KMALLOC, | ||
2724 | _RET_IP_, ret, | ||
2725 | size, PAGE_SIZE << get_order(size), | ||
2726 | flags, node); | ||
2727 | |||
2728 | return ret; | ||
2729 | } | ||
2684 | 2730 | ||
2685 | s = get_slab(size, flags); | 2731 | s = get_slab(size, flags); |
2686 | 2732 | ||
2687 | if (unlikely(ZERO_OR_NULL_PTR(s))) | 2733 | if (unlikely(ZERO_OR_NULL_PTR(s))) |
2688 | return s; | 2734 | return s; |
2689 | 2735 | ||
2690 | return slab_alloc(s, flags, node, __builtin_return_address(0)); | 2736 | ret = slab_alloc(s, flags, node, _RET_IP_); |
2737 | |||
2738 | kmemtrace_mark_alloc_node(KMEMTRACE_TYPE_KMALLOC, _RET_IP_, ret, | ||
2739 | size, s->size, flags, node); | ||
2740 | |||
2741 | return ret; | ||
2691 | } | 2742 | } |
2692 | EXPORT_SYMBOL(__kmalloc_node); | 2743 | EXPORT_SYMBOL(__kmalloc_node); |
2693 | #endif | 2744 | #endif |
@@ -2744,7 +2795,9 @@ void kfree(const void *x) | |||
2744 | put_page(page); | 2795 | put_page(page); |
2745 | return; | 2796 | return; |
2746 | } | 2797 | } |
2747 | slab_free(page->slab, page, object, __builtin_return_address(0)); | 2798 | slab_free(page->slab, page, object, _RET_IP_); |
2799 | |||
2800 | kmemtrace_mark_free(KMEMTRACE_TYPE_KMALLOC, _RET_IP_, x); | ||
2748 | } | 2801 | } |
2749 | EXPORT_SYMBOL(kfree); | 2802 | EXPORT_SYMBOL(kfree); |
2750 | 2803 | ||
@@ -3202,9 +3255,10 @@ static struct notifier_block __cpuinitdata slab_notifier = { | |||
3202 | 3255 | ||
3203 | #endif | 3256 | #endif |
3204 | 3257 | ||
3205 | void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, void *caller) | 3258 | void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, unsigned long caller) |
3206 | { | 3259 | { |
3207 | struct kmem_cache *s; | 3260 | struct kmem_cache *s; |
3261 | void *ret; | ||
3208 | 3262 | ||
3209 | if (unlikely(size > PAGE_SIZE)) | 3263 | if (unlikely(size > PAGE_SIZE)) |
3210 | return kmalloc_large(size, gfpflags); | 3264 | return kmalloc_large(size, gfpflags); |
@@ -3214,13 +3268,20 @@ void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, void *caller) | |||
3214 | if (unlikely(ZERO_OR_NULL_PTR(s))) | 3268 | if (unlikely(ZERO_OR_NULL_PTR(s))) |
3215 | return s; | 3269 | return s; |
3216 | 3270 | ||
3217 | return slab_alloc(s, gfpflags, -1, caller); | 3271 | ret = slab_alloc(s, gfpflags, -1, caller); |
3272 | |||
3273 | /* Honor the call site pointer we recieved. */ | ||
3274 | kmemtrace_mark_alloc(KMEMTRACE_TYPE_KMALLOC, caller, ret, size, | ||
3275 | s->size, gfpflags); | ||
3276 | |||
3277 | return ret; | ||
3218 | } | 3278 | } |
3219 | 3279 | ||
3220 | void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags, | 3280 | void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags, |
3221 | int node, void *caller) | 3281 | int node, unsigned long caller) |
3222 | { | 3282 | { |
3223 | struct kmem_cache *s; | 3283 | struct kmem_cache *s; |
3284 | void *ret; | ||
3224 | 3285 | ||
3225 | if (unlikely(size > PAGE_SIZE)) | 3286 | if (unlikely(size > PAGE_SIZE)) |
3226 | return kmalloc_large_node(size, gfpflags, node); | 3287 | return kmalloc_large_node(size, gfpflags, node); |
@@ -3230,7 +3291,13 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags, | |||
3230 | if (unlikely(ZERO_OR_NULL_PTR(s))) | 3291 | if (unlikely(ZERO_OR_NULL_PTR(s))) |
3231 | return s; | 3292 | return s; |
3232 | 3293 | ||
3233 | return slab_alloc(s, gfpflags, node, caller); | 3294 | ret = slab_alloc(s, gfpflags, node, caller); |
3295 | |||
3296 | /* Honor the call site pointer we recieved. */ | ||
3297 | kmemtrace_mark_alloc_node(KMEMTRACE_TYPE_KMALLOC, caller, ret, | ||
3298 | size, s->size, gfpflags, node); | ||
3299 | |||
3300 | return ret; | ||
3234 | } | 3301 | } |
3235 | 3302 | ||
3236 | #ifdef CONFIG_SLUB_DEBUG | 3303 | #ifdef CONFIG_SLUB_DEBUG |
@@ -3429,7 +3496,7 @@ static void resiliency_test(void) {}; | |||
3429 | 3496 | ||
3430 | struct location { | 3497 | struct location { |
3431 | unsigned long count; | 3498 | unsigned long count; |
3432 | void *addr; | 3499 | unsigned long addr; |
3433 | long long sum_time; | 3500 | long long sum_time; |
3434 | long min_time; | 3501 | long min_time; |
3435 | long max_time; | 3502 | long max_time; |
@@ -3477,7 +3544,7 @@ static int add_location(struct loc_track *t, struct kmem_cache *s, | |||
3477 | { | 3544 | { |
3478 | long start, end, pos; | 3545 | long start, end, pos; |
3479 | struct location *l; | 3546 | struct location *l; |
3480 | void *caddr; | 3547 | unsigned long caddr; |
3481 | unsigned long age = jiffies - track->when; | 3548 | unsigned long age = jiffies - track->when; |
3482 | 3549 | ||
3483 | start = -1; | 3550 | start = -1; |