diff options
author | Joonsoo Kim <iamjoonsoo.kim@lge.com> | 2014-08-06 19:04:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-06 21:01:14 -0400 |
commit | 97654dfa20caa5e6c1b0a4af715aabaf5d070d69 (patch) | |
tree | 0b4b16ba910572e9068905cf12d587d888cc5ecb /mm/slab.c | |
parent | 25c063fbd5512eb7190bf5af88351109aededb3f (diff) |
slab: defer slab_destroy in free_block()
In free_block(), if freeing object makes new free slab and number of
free_objects exceeds free_limit, we start to destroy this new free slab
with holding the kmem_cache node lock. Holding the lock is useless and,
generally, holding a lock as least as possible is good thing. I never
measure performance effect of this, but we'd be better not to hold the
lock as much as possible.
Commented by Christoph:
This is also good because kmem_cache_free is no longer called while
holding the node lock. So we avoid one case of recursion.
Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Acked-by: Christoph Lameter <cl@linux.com>
Cc: Pekka Enberg <penberg@kernel.org>
Acked-by: David Rientjes <rientjes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/slab.c')
-rw-r--r-- | mm/slab.c | 60 |
1 files changed, 41 insertions, 19 deletions
@@ -242,7 +242,8 @@ static struct kmem_cache_node __initdata init_kmem_cache_node[NUM_INIT_LISTS]; | |||
242 | static int drain_freelist(struct kmem_cache *cache, | 242 | static int drain_freelist(struct kmem_cache *cache, |
243 | struct kmem_cache_node *n, int tofree); | 243 | struct kmem_cache_node *n, int tofree); |
244 | static void free_block(struct kmem_cache *cachep, void **objpp, int len, | 244 | static void free_block(struct kmem_cache *cachep, void **objpp, int len, |
245 | int node); | 245 | int node, struct list_head *list); |
246 | static void slabs_destroy(struct kmem_cache *cachep, struct list_head *list); | ||
246 | static int enable_cpucache(struct kmem_cache *cachep, gfp_t gfp); | 247 | static int enable_cpucache(struct kmem_cache *cachep, gfp_t gfp); |
247 | static void cache_reap(struct work_struct *unused); | 248 | static void cache_reap(struct work_struct *unused); |
248 | 249 | ||
@@ -1030,6 +1031,7 @@ static void __drain_alien_cache(struct kmem_cache *cachep, | |||
1030 | struct array_cache *ac, int node) | 1031 | struct array_cache *ac, int node) |
1031 | { | 1032 | { |
1032 | struct kmem_cache_node *n = get_node(cachep, node); | 1033 | struct kmem_cache_node *n = get_node(cachep, node); |
1034 | LIST_HEAD(list); | ||
1033 | 1035 | ||
1034 | if (ac->avail) { | 1036 | if (ac->avail) { |
1035 | spin_lock(&n->list_lock); | 1037 | spin_lock(&n->list_lock); |
@@ -1041,9 +1043,10 @@ static void __drain_alien_cache(struct kmem_cache *cachep, | |||
1041 | if (n->shared) | 1043 | if (n->shared) |
1042 | transfer_objects(n->shared, ac, ac->limit); | 1044 | transfer_objects(n->shared, ac, ac->limit); |
1043 | 1045 | ||
1044 | free_block(cachep, ac->entry, ac->avail, node); | 1046 | free_block(cachep, ac->entry, ac->avail, node, &list); |
1045 | ac->avail = 0; | 1047 | ac->avail = 0; |
1046 | spin_unlock(&n->list_lock); | 1048 | spin_unlock(&n->list_lock); |
1049 | slabs_destroy(cachep, &list); | ||
1047 | } | 1050 | } |
1048 | } | 1051 | } |
1049 | 1052 | ||
@@ -1087,6 +1090,7 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp) | |||
1087 | struct kmem_cache_node *n; | 1090 | struct kmem_cache_node *n; |
1088 | struct array_cache *alien = NULL; | 1091 | struct array_cache *alien = NULL; |
1089 | int node; | 1092 | int node; |
1093 | LIST_HEAD(list); | ||
1090 | 1094 | ||
1091 | node = numa_mem_id(); | 1095 | node = numa_mem_id(); |
1092 | 1096 | ||
@@ -1111,8 +1115,9 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp) | |||
1111 | } else { | 1115 | } else { |
1112 | n = get_node(cachep, nodeid); | 1116 | n = get_node(cachep, nodeid); |
1113 | spin_lock(&n->list_lock); | 1117 | spin_lock(&n->list_lock); |
1114 | free_block(cachep, &objp, 1, nodeid); | 1118 | free_block(cachep, &objp, 1, nodeid, &list); |
1115 | spin_unlock(&n->list_lock); | 1119 | spin_unlock(&n->list_lock); |
1120 | slabs_destroy(cachep, &list); | ||
1116 | } | 1121 | } |
1117 | return 1; | 1122 | return 1; |
1118 | } | 1123 | } |
@@ -1182,6 +1187,7 @@ static void cpuup_canceled(long cpu) | |||
1182 | struct array_cache *nc; | 1187 | struct array_cache *nc; |
1183 | struct array_cache *shared; | 1188 | struct array_cache *shared; |
1184 | struct array_cache **alien; | 1189 | struct array_cache **alien; |
1190 | LIST_HEAD(list); | ||
1185 | 1191 | ||
1186 | /* cpu is dead; no one can alloc from it. */ | 1192 | /* cpu is dead; no one can alloc from it. */ |
1187 | nc = cachep->array[cpu]; | 1193 | nc = cachep->array[cpu]; |
@@ -1196,7 +1202,7 @@ static void cpuup_canceled(long cpu) | |||
1196 | /* Free limit for this kmem_cache_node */ | 1202 | /* Free limit for this kmem_cache_node */ |
1197 | n->free_limit -= cachep->batchcount; | 1203 | n->free_limit -= cachep->batchcount; |
1198 | if (nc) | 1204 | if (nc) |
1199 | free_block(cachep, nc->entry, nc->avail, node); | 1205 | free_block(cachep, nc->entry, nc->avail, node, &list); |
1200 | 1206 | ||
1201 | if (!cpumask_empty(mask)) { | 1207 | if (!cpumask_empty(mask)) { |
1202 | spin_unlock_irq(&n->list_lock); | 1208 | spin_unlock_irq(&n->list_lock); |
@@ -1206,7 +1212,7 @@ static void cpuup_canceled(long cpu) | |||
1206 | shared = n->shared; | 1212 | shared = n->shared; |
1207 | if (shared) { | 1213 | if (shared) { |
1208 | free_block(cachep, shared->entry, | 1214 | free_block(cachep, shared->entry, |
1209 | shared->avail, node); | 1215 | shared->avail, node, &list); |
1210 | n->shared = NULL; | 1216 | n->shared = NULL; |
1211 | } | 1217 | } |
1212 | 1218 | ||
@@ -1221,6 +1227,7 @@ static void cpuup_canceled(long cpu) | |||
1221 | free_alien_cache(alien); | 1227 | free_alien_cache(alien); |
1222 | } | 1228 | } |
1223 | free_array_cache: | 1229 | free_array_cache: |
1230 | slabs_destroy(cachep, &list); | ||
1224 | kfree(nc); | 1231 | kfree(nc); |
1225 | } | 1232 | } |
1226 | /* | 1233 | /* |
@@ -2056,6 +2063,16 @@ static void slab_destroy(struct kmem_cache *cachep, struct page *page) | |||
2056 | kmem_cache_free(cachep->freelist_cache, freelist); | 2063 | kmem_cache_free(cachep->freelist_cache, freelist); |
2057 | } | 2064 | } |
2058 | 2065 | ||
2066 | static void slabs_destroy(struct kmem_cache *cachep, struct list_head *list) | ||
2067 | { | ||
2068 | struct page *page, *n; | ||
2069 | |||
2070 | list_for_each_entry_safe(page, n, list, lru) { | ||
2071 | list_del(&page->lru); | ||
2072 | slab_destroy(cachep, page); | ||
2073 | } | ||
2074 | } | ||
2075 | |||
2059 | /** | 2076 | /** |
2060 | * calculate_slab_order - calculate size (page order) of slabs | 2077 | * calculate_slab_order - calculate size (page order) of slabs |
2061 | * @cachep: pointer to the cache that is being created | 2078 | * @cachep: pointer to the cache that is being created |
@@ -2459,13 +2476,15 @@ static void do_drain(void *arg) | |||
2459 | struct array_cache *ac; | 2476 | struct array_cache *ac; |
2460 | int node = numa_mem_id(); | 2477 | int node = numa_mem_id(); |
2461 | struct kmem_cache_node *n; | 2478 | struct kmem_cache_node *n; |
2479 | LIST_HEAD(list); | ||
2462 | 2480 | ||
2463 | check_irq_off(); | 2481 | check_irq_off(); |
2464 | ac = cpu_cache_get(cachep); | 2482 | ac = cpu_cache_get(cachep); |
2465 | n = get_node(cachep, node); | 2483 | n = get_node(cachep, node); |
2466 | spin_lock(&n->list_lock); | 2484 | spin_lock(&n->list_lock); |
2467 | free_block(cachep, ac->entry, ac->avail, node); | 2485 | free_block(cachep, ac->entry, ac->avail, node, &list); |
2468 | spin_unlock(&n->list_lock); | 2486 | spin_unlock(&n->list_lock); |
2487 | slabs_destroy(cachep, &list); | ||
2469 | ac->avail = 0; | 2488 | ac->avail = 0; |
2470 | } | 2489 | } |
2471 | 2490 | ||
@@ -3393,9 +3412,10 @@ slab_alloc(struct kmem_cache *cachep, gfp_t flags, unsigned long caller) | |||
3393 | 3412 | ||
3394 | /* | 3413 | /* |
3395 | * Caller needs to acquire correct kmem_cache_node's list_lock | 3414 | * Caller needs to acquire correct kmem_cache_node's list_lock |
3415 | * @list: List of detached free slabs should be freed by caller | ||
3396 | */ | 3416 | */ |
3397 | static void free_block(struct kmem_cache *cachep, void **objpp, int nr_objects, | 3417 | static void free_block(struct kmem_cache *cachep, void **objpp, |
3398 | int node) | 3418 | int nr_objects, int node, struct list_head *list) |
3399 | { | 3419 | { |
3400 | int i; | 3420 | int i; |
3401 | struct kmem_cache_node *n = get_node(cachep, node); | 3421 | struct kmem_cache_node *n = get_node(cachep, node); |
@@ -3418,13 +3438,7 @@ static void free_block(struct kmem_cache *cachep, void **objpp, int nr_objects, | |||
3418 | if (page->active == 0) { | 3438 | if (page->active == 0) { |
3419 | if (n->free_objects > n->free_limit) { | 3439 | if (n->free_objects > n->free_limit) { |
3420 | n->free_objects -= cachep->num; | 3440 | n->free_objects -= cachep->num; |
3421 | /* No need to drop any previously held | 3441 | list_add_tail(&page->lru, list); |
3422 | * lock here, even if we have a off-slab slab | ||
3423 | * descriptor it is guaranteed to come from | ||
3424 | * a different cache, refer to comments before | ||
3425 | * alloc_slabmgmt. | ||
3426 | */ | ||
3427 | slab_destroy(cachep, page); | ||
3428 | } else { | 3442 | } else { |
3429 | list_add(&page->lru, &n->slabs_free); | 3443 | list_add(&page->lru, &n->slabs_free); |
3430 | } | 3444 | } |
@@ -3443,6 +3457,7 @@ static void cache_flusharray(struct kmem_cache *cachep, struct array_cache *ac) | |||
3443 | int batchcount; | 3457 | int batchcount; |
3444 | struct kmem_cache_node *n; | 3458 | struct kmem_cache_node *n; |
3445 | int node = numa_mem_id(); | 3459 | int node = numa_mem_id(); |
3460 | LIST_HEAD(list); | ||
3446 | 3461 | ||
3447 | batchcount = ac->batchcount; | 3462 | batchcount = ac->batchcount; |
3448 | #if DEBUG | 3463 | #if DEBUG |
@@ -3464,7 +3479,7 @@ static void cache_flusharray(struct kmem_cache *cachep, struct array_cache *ac) | |||
3464 | } | 3479 | } |
3465 | } | 3480 | } |
3466 | 3481 | ||
3467 | free_block(cachep, ac->entry, batchcount, node); | 3482 | free_block(cachep, ac->entry, batchcount, node, &list); |
3468 | free_done: | 3483 | free_done: |
3469 | #if STATS | 3484 | #if STATS |
3470 | { | 3485 | { |
@@ -3485,6 +3500,7 @@ free_done: | |||
3485 | } | 3500 | } |
3486 | #endif | 3501 | #endif |
3487 | spin_unlock(&n->list_lock); | 3502 | spin_unlock(&n->list_lock); |
3503 | slabs_destroy(cachep, &list); | ||
3488 | ac->avail -= batchcount; | 3504 | ac->avail -= batchcount; |
3489 | memmove(ac->entry, &(ac->entry[batchcount]), sizeof(void *)*ac->avail); | 3505 | memmove(ac->entry, &(ac->entry[batchcount]), sizeof(void *)*ac->avail); |
3490 | } | 3506 | } |
@@ -3765,12 +3781,13 @@ static int alloc_kmem_cache_node(struct kmem_cache *cachep, gfp_t gfp) | |||
3765 | n = get_node(cachep, node); | 3781 | n = get_node(cachep, node); |
3766 | if (n) { | 3782 | if (n) { |
3767 | struct array_cache *shared = n->shared; | 3783 | struct array_cache *shared = n->shared; |
3784 | LIST_HEAD(list); | ||
3768 | 3785 | ||
3769 | spin_lock_irq(&n->list_lock); | 3786 | spin_lock_irq(&n->list_lock); |
3770 | 3787 | ||
3771 | if (shared) | 3788 | if (shared) |
3772 | free_block(cachep, shared->entry, | 3789 | free_block(cachep, shared->entry, |
3773 | shared->avail, node); | 3790 | shared->avail, node, &list); |
3774 | 3791 | ||
3775 | n->shared = new_shared; | 3792 | n->shared = new_shared; |
3776 | if (!n->alien) { | 3793 | if (!n->alien) { |
@@ -3780,6 +3797,7 @@ static int alloc_kmem_cache_node(struct kmem_cache *cachep, gfp_t gfp) | |||
3780 | n->free_limit = (1 + nr_cpus_node(node)) * | 3797 | n->free_limit = (1 + nr_cpus_node(node)) * |
3781 | cachep->batchcount + cachep->num; | 3798 | cachep->batchcount + cachep->num; |
3782 | spin_unlock_irq(&n->list_lock); | 3799 | spin_unlock_irq(&n->list_lock); |
3800 | slabs_destroy(cachep, &list); | ||
3783 | kfree(shared); | 3801 | kfree(shared); |
3784 | free_alien_cache(new_alien); | 3802 | free_alien_cache(new_alien); |
3785 | continue; | 3803 | continue; |
@@ -3869,6 +3887,7 @@ static int __do_tune_cpucache(struct kmem_cache *cachep, int limit, | |||
3869 | cachep->shared = shared; | 3887 | cachep->shared = shared; |
3870 | 3888 | ||
3871 | for_each_online_cpu(i) { | 3889 | for_each_online_cpu(i) { |
3890 | LIST_HEAD(list); | ||
3872 | struct array_cache *ccold = new->new[i]; | 3891 | struct array_cache *ccold = new->new[i]; |
3873 | int node; | 3892 | int node; |
3874 | struct kmem_cache_node *n; | 3893 | struct kmem_cache_node *n; |
@@ -3879,8 +3898,9 @@ static int __do_tune_cpucache(struct kmem_cache *cachep, int limit, | |||
3879 | node = cpu_to_mem(i); | 3898 | node = cpu_to_mem(i); |
3880 | n = get_node(cachep, node); | 3899 | n = get_node(cachep, node); |
3881 | spin_lock_irq(&n->list_lock); | 3900 | spin_lock_irq(&n->list_lock); |
3882 | free_block(cachep, ccold->entry, ccold->avail, node); | 3901 | free_block(cachep, ccold->entry, ccold->avail, node, &list); |
3883 | spin_unlock_irq(&n->list_lock); | 3902 | spin_unlock_irq(&n->list_lock); |
3903 | slabs_destroy(cachep, &list); | ||
3884 | kfree(ccold); | 3904 | kfree(ccold); |
3885 | } | 3905 | } |
3886 | kfree(new); | 3906 | kfree(new); |
@@ -3988,6 +4008,7 @@ skip_setup: | |||
3988 | static void drain_array(struct kmem_cache *cachep, struct kmem_cache_node *n, | 4008 | static void drain_array(struct kmem_cache *cachep, struct kmem_cache_node *n, |
3989 | struct array_cache *ac, int force, int node) | 4009 | struct array_cache *ac, int force, int node) |
3990 | { | 4010 | { |
4011 | LIST_HEAD(list); | ||
3991 | int tofree; | 4012 | int tofree; |
3992 | 4013 | ||
3993 | if (!ac || !ac->avail) | 4014 | if (!ac || !ac->avail) |
@@ -4000,12 +4021,13 @@ static void drain_array(struct kmem_cache *cachep, struct kmem_cache_node *n, | |||
4000 | tofree = force ? ac->avail : (ac->limit + 4) / 5; | 4021 | tofree = force ? ac->avail : (ac->limit + 4) / 5; |
4001 | if (tofree > ac->avail) | 4022 | if (tofree > ac->avail) |
4002 | tofree = (ac->avail + 1) / 2; | 4023 | tofree = (ac->avail + 1) / 2; |
4003 | free_block(cachep, ac->entry, tofree, node); | 4024 | free_block(cachep, ac->entry, tofree, node, &list); |
4004 | ac->avail -= tofree; | 4025 | ac->avail -= tofree; |
4005 | memmove(ac->entry, &(ac->entry[tofree]), | 4026 | memmove(ac->entry, &(ac->entry[tofree]), |
4006 | sizeof(void *) * ac->avail); | 4027 | sizeof(void *) * ac->avail); |
4007 | } | 4028 | } |
4008 | spin_unlock_irq(&n->list_lock); | 4029 | spin_unlock_irq(&n->list_lock); |
4030 | slabs_destroy(cachep, &list); | ||
4009 | } | 4031 | } |
4010 | } | 4032 | } |
4011 | 4033 | ||