diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-05-17 11:36:59 -0400 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-05-17 11:36:59 -0400 |
| commit | dd504ea16f34a29da4aa933ae7ab917fcfd25fd7 (patch) | |
| tree | 0502645dc159be29c33c992e9e56dc3156074279 /mm/slob.c | |
| parent | 5cf4cf65a8ccca44ec9b357ebdb2b517269d7e8a (diff) | |
| parent | 0479ea0eab197b3e5d4c731f526c02e5e3fbfbd0 (diff) | |
Merge branch 'master' of /home/trondmy/repositories/git/linux-2.6/
Diffstat (limited to 'mm/slob.c')
| -rw-r--r-- | mm/slob.c | 53 |
1 files changed, 43 insertions, 10 deletions
| @@ -35,6 +35,7 @@ | |||
| 35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
| 36 | #include <linux/module.h> | 36 | #include <linux/module.h> |
| 37 | #include <linux/timer.h> | 37 | #include <linux/timer.h> |
| 38 | #include <linux/rcupdate.h> | ||
| 38 | 39 | ||
| 39 | struct slob_block { | 40 | struct slob_block { |
| 40 | int units; | 41 | int units; |
| @@ -53,6 +54,16 @@ struct bigblock { | |||
| 53 | }; | 54 | }; |
| 54 | typedef struct bigblock bigblock_t; | 55 | typedef struct bigblock bigblock_t; |
| 55 | 56 | ||
| 57 | /* | ||
| 58 | * struct slob_rcu is inserted at the tail of allocated slob blocks, which | ||
| 59 | * were created with a SLAB_DESTROY_BY_RCU slab. slob_rcu is used to free | ||
| 60 | * the block using call_rcu. | ||
| 61 | */ | ||
| 62 | struct slob_rcu { | ||
| 63 | struct rcu_head head; | ||
| 64 | int size; | ||
| 65 | }; | ||
| 66 | |||
| 56 | static slob_t arena = { .next = &arena, .units = 1 }; | 67 | static slob_t arena = { .next = &arena, .units = 1 }; |
| 57 | static slob_t *slobfree = &arena; | 68 | static slob_t *slobfree = &arena; |
| 58 | static bigblock_t *bigblocks; | 69 | static bigblock_t *bigblocks; |
| @@ -266,9 +277,9 @@ size_t ksize(const void *block) | |||
| 266 | 277 | ||
| 267 | struct kmem_cache { | 278 | struct kmem_cache { |
| 268 | unsigned int size, align; | 279 | unsigned int size, align; |
| 280 | unsigned long flags; | ||
| 269 | const char *name; | 281 | const char *name; |
| 270 | void (*ctor)(void *, struct kmem_cache *, unsigned long); | 282 | void (*ctor)(void *, struct kmem_cache *, unsigned long); |
| 271 | void (*dtor)(void *, struct kmem_cache *, unsigned long); | ||
| 272 | }; | 283 | }; |
| 273 | 284 | ||
| 274 | struct kmem_cache *kmem_cache_create(const char *name, size_t size, | 285 | struct kmem_cache *kmem_cache_create(const char *name, size_t size, |
| @@ -283,8 +294,12 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, | |||
| 283 | if (c) { | 294 | if (c) { |
| 284 | c->name = name; | 295 | c->name = name; |
| 285 | c->size = size; | 296 | c->size = size; |
| 297 | if (flags & SLAB_DESTROY_BY_RCU) { | ||
| 298 | /* leave room for rcu footer at the end of object */ | ||
| 299 | c->size += sizeof(struct slob_rcu); | ||
| 300 | } | ||
| 301 | c->flags = flags; | ||
| 286 | c->ctor = ctor; | 302 | c->ctor = ctor; |
| 287 | c->dtor = dtor; | ||
| 288 | /* ignore alignment unless it's forced */ | 303 | /* ignore alignment unless it's forced */ |
| 289 | c->align = (flags & SLAB_HWCACHE_ALIGN) ? SLOB_ALIGN : 0; | 304 | c->align = (flags & SLAB_HWCACHE_ALIGN) ? SLOB_ALIGN : 0; |
| 290 | if (c->align < align) | 305 | if (c->align < align) |
| @@ -312,7 +327,7 @@ void *kmem_cache_alloc(struct kmem_cache *c, gfp_t flags) | |||
| 312 | b = (void *)__get_free_pages(flags, get_order(c->size)); | 327 | b = (void *)__get_free_pages(flags, get_order(c->size)); |
| 313 | 328 | ||
| 314 | if (c->ctor) | 329 | if (c->ctor) |
| 315 | c->ctor(b, c, SLAB_CTOR_CONSTRUCTOR); | 330 | c->ctor(b, c, 0); |
| 316 | 331 | ||
| 317 | return b; | 332 | return b; |
| 318 | } | 333 | } |
| @@ -328,15 +343,33 @@ void *kmem_cache_zalloc(struct kmem_cache *c, gfp_t flags) | |||
| 328 | } | 343 | } |
| 329 | EXPORT_SYMBOL(kmem_cache_zalloc); | 344 | EXPORT_SYMBOL(kmem_cache_zalloc); |
| 330 | 345 | ||
| 331 | void kmem_cache_free(struct kmem_cache *c, void *b) | 346 | static void __kmem_cache_free(void *b, int size) |
| 332 | { | 347 | { |
| 333 | if (c->dtor) | 348 | if (size < PAGE_SIZE) |
| 334 | c->dtor(b, c, 0); | 349 | slob_free(b, size); |
| 335 | |||
| 336 | if (c->size < PAGE_SIZE) | ||
| 337 | slob_free(b, c->size); | ||
| 338 | else | 350 | else |
| 339 | free_pages((unsigned long)b, get_order(c->size)); | 351 | free_pages((unsigned long)b, get_order(size)); |
| 352 | } | ||
| 353 | |||
| 354 | static void kmem_rcu_free(struct rcu_head *head) | ||
| 355 | { | ||
| 356 | struct slob_rcu *slob_rcu = (struct slob_rcu *)head; | ||
| 357 | void *b = (void *)slob_rcu - (slob_rcu->size - sizeof(struct slob_rcu)); | ||
| 358 | |||
| 359 | __kmem_cache_free(b, slob_rcu->size); | ||
| 360 | } | ||
| 361 | |||
| 362 | void kmem_cache_free(struct kmem_cache *c, void *b) | ||
| 363 | { | ||
| 364 | if (unlikely(c->flags & SLAB_DESTROY_BY_RCU)) { | ||
| 365 | struct slob_rcu *slob_rcu; | ||
| 366 | slob_rcu = b + (c->size - sizeof(struct slob_rcu)); | ||
| 367 | INIT_RCU_HEAD(&slob_rcu->head); | ||
| 368 | slob_rcu->size = c->size; | ||
| 369 | call_rcu(&slob_rcu->head, kmem_rcu_free); | ||
| 370 | } else { | ||
| 371 | __kmem_cache_free(b, c->size); | ||
| 372 | } | ||
| 340 | } | 373 | } |
| 341 | EXPORT_SYMBOL(kmem_cache_free); | 374 | EXPORT_SYMBOL(kmem_cache_free); |
| 342 | 375 | ||
