diff options
| -rw-r--r-- | include/linux/slab.h | 2 | ||||
| -rw-r--r-- | mm/slab.c | 2 | ||||
| -rw-r--r-- | mm/slab.h | 2 | ||||
| -rw-r--r-- | mm/slab_common.c | 6 | ||||
| -rw-r--r-- | mm/slob.c | 2 | ||||
| -rw-r--r-- | mm/slub.c | 244 |
6 files changed, 182 insertions, 76 deletions
diff --git a/include/linux/slab.h b/include/linux/slab.h index 96940772bb92..2037a861e367 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h | |||
| @@ -316,7 +316,7 @@ void kmem_cache_free(struct kmem_cache *, void *); | |||
| 316 | * Note that interrupts must be enabled when calling these functions. | 316 | * Note that interrupts must be enabled when calling these functions. |
| 317 | */ | 317 | */ |
| 318 | void kmem_cache_free_bulk(struct kmem_cache *, size_t, void **); | 318 | void kmem_cache_free_bulk(struct kmem_cache *, size_t, void **); |
| 319 | bool kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **); | 319 | int kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **); |
| 320 | 320 | ||
| 321 | #ifdef CONFIG_NUMA | 321 | #ifdef CONFIG_NUMA |
| 322 | void *__kmalloc_node(size_t size, gfp_t flags, int node) __assume_kmalloc_alignment; | 322 | void *__kmalloc_node(size_t size, gfp_t flags, int node) __assume_kmalloc_alignment; |
| @@ -3419,7 +3419,7 @@ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p) | |||
| 3419 | } | 3419 | } |
| 3420 | EXPORT_SYMBOL(kmem_cache_free_bulk); | 3420 | EXPORT_SYMBOL(kmem_cache_free_bulk); |
| 3421 | 3421 | ||
| 3422 | bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, | 3422 | int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, |
| 3423 | void **p) | 3423 | void **p) |
| 3424 | { | 3424 | { |
| 3425 | return __kmem_cache_alloc_bulk(s, flags, size, p); | 3425 | return __kmem_cache_alloc_bulk(s, flags, size, p); |
| @@ -170,7 +170,7 @@ ssize_t slabinfo_write(struct file *file, const char __user *buffer, | |||
| 170 | * may be allocated or freed using these operations. | 170 | * may be allocated or freed using these operations. |
| 171 | */ | 171 | */ |
| 172 | void __kmem_cache_free_bulk(struct kmem_cache *, size_t, void **); | 172 | void __kmem_cache_free_bulk(struct kmem_cache *, size_t, void **); |
| 173 | bool __kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **); | 173 | int __kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **); |
| 174 | 174 | ||
| 175 | #ifdef CONFIG_MEMCG_KMEM | 175 | #ifdef CONFIG_MEMCG_KMEM |
| 176 | /* | 176 | /* |
diff --git a/mm/slab_common.c b/mm/slab_common.c index d88e97c10a2e..3c6a86b4ec25 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c | |||
| @@ -112,7 +112,7 @@ void __kmem_cache_free_bulk(struct kmem_cache *s, size_t nr, void **p) | |||
| 112 | kmem_cache_free(s, p[i]); | 112 | kmem_cache_free(s, p[i]); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | bool __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t nr, | 115 | int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t nr, |
| 116 | void **p) | 116 | void **p) |
| 117 | { | 117 | { |
| 118 | size_t i; | 118 | size_t i; |
| @@ -121,10 +121,10 @@ bool __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t nr, | |||
| 121 | void *x = p[i] = kmem_cache_alloc(s, flags); | 121 | void *x = p[i] = kmem_cache_alloc(s, flags); |
| 122 | if (!x) { | 122 | if (!x) { |
| 123 | __kmem_cache_free_bulk(s, i, p); | 123 | __kmem_cache_free_bulk(s, i, p); |
| 124 | return false; | 124 | return 0; |
| 125 | } | 125 | } |
| 126 | } | 126 | } |
| 127 | return true; | 127 | return i; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | #ifdef CONFIG_MEMCG_KMEM | 130 | #ifdef CONFIG_MEMCG_KMEM |
| @@ -617,7 +617,7 @@ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p) | |||
| 617 | } | 617 | } |
| 618 | EXPORT_SYMBOL(kmem_cache_free_bulk); | 618 | EXPORT_SYMBOL(kmem_cache_free_bulk); |
| 619 | 619 | ||
| 620 | bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, | 620 | int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, |
| 621 | void **p) | 621 | void **p) |
| 622 | { | 622 | { |
| 623 | return __kmem_cache_alloc_bulk(s, flags, size, p); | 623 | return __kmem_cache_alloc_bulk(s, flags, size, p); |
| @@ -1065,11 +1065,15 @@ bad: | |||
| 1065 | return 0; | 1065 | return 0; |
| 1066 | } | 1066 | } |
| 1067 | 1067 | ||
| 1068 | /* Supports checking bulk free of a constructed freelist */ | ||
| 1068 | static noinline struct kmem_cache_node *free_debug_processing( | 1069 | static noinline struct kmem_cache_node *free_debug_processing( |
| 1069 | struct kmem_cache *s, struct page *page, void *object, | 1070 | struct kmem_cache *s, struct page *page, |
| 1071 | void *head, void *tail, int bulk_cnt, | ||
| 1070 | unsigned long addr, unsigned long *flags) | 1072 | unsigned long addr, unsigned long *flags) |
| 1071 | { | 1073 | { |
| 1072 | struct kmem_cache_node *n = get_node(s, page_to_nid(page)); | 1074 | struct kmem_cache_node *n = get_node(s, page_to_nid(page)); |
| 1075 | void *object = head; | ||
| 1076 | int cnt = 0; | ||
| 1073 | 1077 | ||
| 1074 | spin_lock_irqsave(&n->list_lock, *flags); | 1078 | spin_lock_irqsave(&n->list_lock, *flags); |
| 1075 | slab_lock(page); | 1079 | slab_lock(page); |
| @@ -1077,6 +1081,9 @@ static noinline struct kmem_cache_node *free_debug_processing( | |||
| 1077 | if (!check_slab(s, page)) | 1081 | if (!check_slab(s, page)) |
| 1078 | goto fail; | 1082 | goto fail; |
| 1079 | 1083 | ||
| 1084 | next_object: | ||
| 1085 | cnt++; | ||
| 1086 | |||
| 1080 | if (!check_valid_pointer(s, page, object)) { | 1087 | if (!check_valid_pointer(s, page, object)) { |
| 1081 | slab_err(s, page, "Invalid object pointer 0x%p", object); | 1088 | slab_err(s, page, "Invalid object pointer 0x%p", object); |
| 1082 | goto fail; | 1089 | goto fail; |
| @@ -1107,8 +1114,19 @@ static noinline struct kmem_cache_node *free_debug_processing( | |||
| 1107 | if (s->flags & SLAB_STORE_USER) | 1114 | if (s->flags & SLAB_STORE_USER) |
| 1108 | set_track(s, object, TRACK_FREE, addr); | 1115 | set_track(s, object, TRACK_FREE, addr); |
| 1109 | trace(s, page, object, 0); | 1116 | trace(s, page, object, 0); |
| 1117 | /* Freepointer not overwritten by init_object(), SLAB_POISON moved it */ | ||
| 1110 | init_object(s, object, SLUB_RED_INACTIVE); | 1118 | init_object(s, object, SLUB_RED_INACTIVE); |
| 1119 | |||
| 1120 | /* Reached end of constructed freelist yet? */ | ||
| 1121 | if (object != tail) { | ||
| 1122 | object = get_freepointer(s, object); | ||
| 1123 | goto next_object; | ||
| 1124 | } | ||
| 1111 | out: | 1125 | out: |
| 1126 | if (cnt != bulk_cnt) | ||
| 1127 | slab_err(s, page, "Bulk freelist count(%d) invalid(%d)\n", | ||
| 1128 | bulk_cnt, cnt); | ||
| 1129 | |||
| 1112 | slab_unlock(page); | 1130 | slab_unlock(page); |
| 1113 | /* | 1131 | /* |
| 1114 | * Keep node_lock to preserve integrity | 1132 | * Keep node_lock to preserve integrity |
| @@ -1212,7 +1230,8 @@ static inline int alloc_debug_processing(struct kmem_cache *s, | |||
| 1212 | struct page *page, void *object, unsigned long addr) { return 0; } | 1230 | struct page *page, void *object, unsigned long addr) { return 0; } |
| 1213 | 1231 | ||
| 1214 | static inline struct kmem_cache_node *free_debug_processing( | 1232 | static inline struct kmem_cache_node *free_debug_processing( |
| 1215 | struct kmem_cache *s, struct page *page, void *object, | 1233 | struct kmem_cache *s, struct page *page, |
| 1234 | void *head, void *tail, int bulk_cnt, | ||
| 1216 | unsigned long addr, unsigned long *flags) { return NULL; } | 1235 | unsigned long addr, unsigned long *flags) { return NULL; } |
| 1217 | 1236 | ||
| 1218 | static inline int slab_pad_check(struct kmem_cache *s, struct page *page) | 1237 | static inline int slab_pad_check(struct kmem_cache *s, struct page *page) |
| @@ -1273,14 +1292,21 @@ static inline struct kmem_cache *slab_pre_alloc_hook(struct kmem_cache *s, | |||
| 1273 | return memcg_kmem_get_cache(s, flags); | 1292 | return memcg_kmem_get_cache(s, flags); |
| 1274 | } | 1293 | } |
| 1275 | 1294 | ||
| 1276 | static inline void slab_post_alloc_hook(struct kmem_cache *s, | 1295 | static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags, |
| 1277 | gfp_t flags, void *object) | 1296 | size_t size, void **p) |
| 1278 | { | 1297 | { |
| 1298 | size_t i; | ||
| 1299 | |||
| 1279 | flags &= gfp_allowed_mask; | 1300 | flags &= gfp_allowed_mask; |
| 1280 | kmemcheck_slab_alloc(s, flags, object, slab_ksize(s)); | 1301 | for (i = 0; i < size; i++) { |
| 1281 | kmemleak_alloc_recursive(object, s->object_size, 1, s->flags, flags); | 1302 | void *object = p[i]; |
| 1303 | |||
| 1304 | kmemcheck_slab_alloc(s, flags, object, slab_ksize(s)); | ||
| 1305 | kmemleak_alloc_recursive(object, s->object_size, 1, | ||
| 1306 | s->flags, flags); | ||
| 1307 | kasan_slab_alloc(s, object); | ||
| 1308 | } | ||
| 1282 | memcg_kmem_put_cache(s); | 1309 | memcg_kmem_put_cache(s); |
| 1283 | kasan_slab_alloc(s, object); | ||
| 1284 | } | 1310 | } |
| 1285 | 1311 | ||
| 1286 | static inline void slab_free_hook(struct kmem_cache *s, void *x) | 1312 | static inline void slab_free_hook(struct kmem_cache *s, void *x) |
| @@ -1308,6 +1334,29 @@ static inline void slab_free_hook(struct kmem_cache *s, void *x) | |||
| 1308 | kasan_slab_free(s, x); | 1334 | kasan_slab_free(s, x); |
| 1309 | } | 1335 | } |
| 1310 | 1336 | ||
| 1337 | static inline void slab_free_freelist_hook(struct kmem_cache *s, | ||
| 1338 | void *head, void *tail) | ||
| 1339 | { | ||
| 1340 | /* | ||
| 1341 | * Compiler cannot detect this function can be removed if slab_free_hook() | ||
| 1342 | * evaluates to nothing. Thus, catch all relevant config debug options here. | ||
| 1343 | */ | ||
| 1344 | #if defined(CONFIG_KMEMCHECK) || \ | ||
| 1345 | defined(CONFIG_LOCKDEP) || \ | ||
| 1346 | defined(CONFIG_DEBUG_KMEMLEAK) || \ | ||
| 1347 | defined(CONFIG_DEBUG_OBJECTS_FREE) || \ | ||
| 1348 | defined(CONFIG_KASAN) | ||
| 1349 | |||
| 1350 | void *object = head; | ||
| 1351 | void *tail_obj = tail ? : head; | ||
| 1352 | |||
| 1353 | do { | ||
| 1354 | slab_free_hook(s, object); | ||
| 1355 | } while ((object != tail_obj) && | ||
| 1356 | (object = get_freepointer(s, object))); | ||
| 1357 | #endif | ||
| 1358 | } | ||
| 1359 | |||
| 1311 | static void setup_object(struct kmem_cache *s, struct page *page, | 1360 | static void setup_object(struct kmem_cache *s, struct page *page, |
| 1312 | void *object) | 1361 | void *object) |
| 1313 | { | 1362 | { |
| @@ -2433,7 +2482,7 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, | |||
