| .. | .. |
|---|
| 112 | 112 | |
|---|
| 113 | 113 | static void set_slob_page_free(struct page *sp, struct list_head *list) |
|---|
| 114 | 114 | { |
|---|
| 115 | | - list_add(&sp->lru, list); |
|---|
| 115 | + list_add(&sp->slab_list, list); |
|---|
| 116 | 116 | __SetPageSlobFree(sp); |
|---|
| 117 | 117 | } |
|---|
| 118 | 118 | |
|---|
| 119 | 119 | static inline void clear_slob_page_free(struct page *sp) |
|---|
| 120 | 120 | { |
|---|
| 121 | | - list_del(&sp->lru); |
|---|
| 121 | + list_del(&sp->slab_list); |
|---|
| 122 | 122 | __ClearPageSlobFree(sp); |
|---|
| 123 | 123 | } |
|---|
| 124 | 124 | |
|---|
| .. | .. |
|---|
| 190 | 190 | |
|---|
| 191 | 191 | static void *slob_new_pages(gfp_t gfp, int order, int node) |
|---|
| 192 | 192 | { |
|---|
| 193 | | - void *page; |
|---|
| 193 | + struct page *page; |
|---|
| 194 | 194 | |
|---|
| 195 | 195 | #ifdef CONFIG_NUMA |
|---|
| 196 | 196 | if (node != NUMA_NO_NODE) |
|---|
| .. | .. |
|---|
| 202 | 202 | if (!page) |
|---|
| 203 | 203 | return NULL; |
|---|
| 204 | 204 | |
|---|
| 205 | + mod_node_page_state(page_pgdat(page), NR_SLAB_UNRECLAIMABLE_B, |
|---|
| 206 | + PAGE_SIZE << order); |
|---|
| 205 | 207 | return page_address(page); |
|---|
| 206 | 208 | } |
|---|
| 207 | 209 | |
|---|
| 208 | 210 | static void slob_free_pages(void *b, int order) |
|---|
| 209 | 211 | { |
|---|
| 212 | + struct page *sp = virt_to_page(b); |
|---|
| 213 | + |
|---|
| 210 | 214 | if (current->reclaim_state) |
|---|
| 211 | 215 | current->reclaim_state->reclaimed_slab += 1 << order; |
|---|
| 212 | | - free_pages((unsigned long)b, order); |
|---|
| 216 | + |
|---|
| 217 | + mod_node_page_state(page_pgdat(sp), NR_SLAB_UNRECLAIMABLE_B, |
|---|
| 218 | + -(PAGE_SIZE << order)); |
|---|
| 219 | + __free_pages(sp, order); |
|---|
| 213 | 220 | } |
|---|
| 214 | 221 | |
|---|
| 215 | 222 | /* |
|---|
| 216 | | - * Allocate a slob block within a given slob_page sp. |
|---|
| 223 | + * slob_page_alloc() - Allocate a slob block within a given slob_page sp. |
|---|
| 224 | + * @sp: Page to look in. |
|---|
| 225 | + * @size: Size of the allocation. |
|---|
| 226 | + * @align: Allocation alignment. |
|---|
| 227 | + * @align_offset: Offset in the allocated block that will be aligned. |
|---|
| 228 | + * @page_removed_from_list: Return parameter. |
|---|
| 229 | + * |
|---|
| 230 | + * Tries to find a chunk of memory at least @size bytes big within @page. |
|---|
| 231 | + * |
|---|
| 232 | + * Return: Pointer to memory if allocated, %NULL otherwise. If the |
|---|
| 233 | + * allocation fills up @page then the page is removed from the |
|---|
| 234 | + * freelist, in this case @page_removed_from_list will be set to |
|---|
| 235 | + * true (set to false otherwise). |
|---|
| 217 | 236 | */ |
|---|
| 218 | | -static void *slob_page_alloc(struct page *sp, size_t size, int align) |
|---|
| 237 | +static void *slob_page_alloc(struct page *sp, size_t size, int align, |
|---|
| 238 | + int align_offset, bool *page_removed_from_list) |
|---|
| 219 | 239 | { |
|---|
| 220 | 240 | slob_t *prev, *cur, *aligned = NULL; |
|---|
| 221 | 241 | int delta = 0, units = SLOB_UNITS(size); |
|---|
| 222 | 242 | |
|---|
| 243 | + *page_removed_from_list = false; |
|---|
| 223 | 244 | for (prev = NULL, cur = sp->freelist; ; prev = cur, cur = slob_next(cur)) { |
|---|
| 224 | 245 | slobidx_t avail = slob_units(cur); |
|---|
| 225 | 246 | |
|---|
| 247 | + /* |
|---|
| 248 | + * 'aligned' will hold the address of the slob block so that the |
|---|
| 249 | + * address 'aligned'+'align_offset' is aligned according to the |
|---|
| 250 | + * 'align' parameter. This is for kmalloc() which prepends the |
|---|
| 251 | + * allocated block with its size, so that the block itself is |
|---|
| 252 | + * aligned when needed. |
|---|
| 253 | + */ |
|---|
| 226 | 254 | if (align) { |
|---|
| 227 | | - aligned = (slob_t *)ALIGN((unsigned long)cur, align); |
|---|
| 255 | + aligned = (slob_t *) |
|---|
| 256 | + (ALIGN((unsigned long)cur + align_offset, align) |
|---|
| 257 | + - align_offset); |
|---|
| 228 | 258 | delta = aligned - cur; |
|---|
| 229 | 259 | } |
|---|
| 230 | 260 | if (avail >= units + delta) { /* room enough? */ |
|---|
| .. | .. |
|---|
| 254 | 284 | } |
|---|
| 255 | 285 | |
|---|
| 256 | 286 | sp->units -= units; |
|---|
| 257 | | - if (!sp->units) |
|---|
| 287 | + if (!sp->units) { |
|---|
| 258 | 288 | clear_slob_page_free(sp); |
|---|
| 289 | + *page_removed_from_list = true; |
|---|
| 290 | + } |
|---|
| 259 | 291 | return cur; |
|---|
| 260 | 292 | } |
|---|
| 261 | 293 | if (slob_last(cur)) |
|---|
| .. | .. |
|---|
| 266 | 298 | /* |
|---|
| 267 | 299 | * slob_alloc: entry point into the slob allocator. |
|---|
| 268 | 300 | */ |
|---|
| 269 | | -static void *slob_alloc(size_t size, gfp_t gfp, int align, int node) |
|---|
| 301 | +static void *slob_alloc(size_t size, gfp_t gfp, int align, int node, |
|---|
| 302 | + int align_offset) |
|---|
| 270 | 303 | { |
|---|
| 271 | 304 | struct page *sp; |
|---|
| 272 | | - struct list_head *prev; |
|---|
| 273 | 305 | struct list_head *slob_list; |
|---|
| 274 | 306 | slob_t *b = NULL; |
|---|
| 275 | 307 | unsigned long flags; |
|---|
| 308 | + bool _unused; |
|---|
| 276 | 309 | |
|---|
| 277 | 310 | if (size < SLOB_BREAK1) |
|---|
| 278 | 311 | slob_list = &free_slob_small; |
|---|
| .. | .. |
|---|
| 283 | 316 | |
|---|
| 284 | 317 | spin_lock_irqsave(&slob_lock, flags); |
|---|
| 285 | 318 | /* Iterate through each partially free page, try to find room */ |
|---|
| 286 | | - list_for_each_entry(sp, slob_list, lru) { |
|---|
| 319 | + list_for_each_entry(sp, slob_list, slab_list) { |
|---|
| 320 | + bool page_removed_from_list = false; |
|---|
| 287 | 321 | #ifdef CONFIG_NUMA |
|---|
| 288 | 322 | /* |
|---|
| 289 | 323 | * If there's a node specification, search for a partial |
|---|
| .. | .. |
|---|
| 296 | 330 | if (sp->units < SLOB_UNITS(size)) |
|---|
| 297 | 331 | continue; |
|---|
| 298 | 332 | |
|---|
| 299 | | - /* Attempt to alloc */ |
|---|
| 300 | | - prev = sp->lru.prev; |
|---|
| 301 | | - b = slob_page_alloc(sp, size, align); |
|---|
| 333 | + b = slob_page_alloc(sp, size, align, align_offset, &page_removed_from_list); |
|---|
| 302 | 334 | if (!b) |
|---|
| 303 | 335 | continue; |
|---|
| 304 | 336 | |
|---|
| 305 | | - /* Improve fragment distribution and reduce our average |
|---|
| 306 | | - * search time by starting our next search here. (see |
|---|
| 307 | | - * Knuth vol 1, sec 2.5, pg 449) */ |
|---|
| 308 | | - if (prev != slob_list->prev && |
|---|
| 309 | | - slob_list->next != prev->next) |
|---|
| 310 | | - list_move_tail(slob_list, prev->next); |
|---|
| 337 | + /* |
|---|
| 338 | + * If slob_page_alloc() removed sp from the list then we |
|---|
| 339 | + * cannot call list functions on sp. If so allocation |
|---|
| 340 | + * did not fragment the page anyway so optimisation is |
|---|
| 341 | + * unnecessary. |
|---|
| 342 | + */ |
|---|
| 343 | + if (!page_removed_from_list) { |
|---|
| 344 | + /* |
|---|
| 345 | + * Improve fragment distribution and reduce our average |
|---|
| 346 | + * search time by starting our next search here. (see |
|---|
| 347 | + * Knuth vol 1, sec 2.5, pg 449) |
|---|
| 348 | + */ |
|---|
| 349 | + if (!list_is_first(&sp->slab_list, slob_list)) |
|---|
| 350 | + list_rotate_to_front(&sp->slab_list, slob_list); |
|---|
| 351 | + } |
|---|
| 311 | 352 | break; |
|---|
| 312 | 353 | } |
|---|
| 313 | 354 | spin_unlock_irqrestore(&slob_lock, flags); |
|---|
| .. | .. |
|---|
| 323 | 364 | spin_lock_irqsave(&slob_lock, flags); |
|---|
| 324 | 365 | sp->units = SLOB_UNITS(PAGE_SIZE); |
|---|
| 325 | 366 | sp->freelist = b; |
|---|
| 326 | | - INIT_LIST_HEAD(&sp->lru); |
|---|
| 367 | + INIT_LIST_HEAD(&sp->slab_list); |
|---|
| 327 | 368 | set_slob(b, SLOB_UNITS(PAGE_SIZE), b + SLOB_UNITS(PAGE_SIZE)); |
|---|
| 328 | 369 | set_slob_page_free(sp, slob_list); |
|---|
| 329 | | - b = slob_page_alloc(sp, size, align); |
|---|
| 370 | + b = slob_page_alloc(sp, size, align, align_offset, &_unused); |
|---|
| 330 | 371 | BUG_ON(!b); |
|---|
| 331 | 372 | spin_unlock_irqrestore(&slob_lock, flags); |
|---|
| 332 | 373 | } |
|---|
| .. | .. |
|---|
| 428 | 469 | __do_kmalloc_node(size_t size, gfp_t gfp, int node, unsigned long caller) |
|---|
| 429 | 470 | { |
|---|
| 430 | 471 | unsigned int *m; |
|---|
| 431 | | - int align = max_t(size_t, ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); |
|---|
| 472 | + unsigned int minalign; |
|---|
| 432 | 473 | void *ret; |
|---|
| 433 | 474 | |
|---|
| 475 | + minalign = max_t(unsigned int, ARCH_KMALLOC_MINALIGN, |
|---|
| 476 | + arch_slab_minalign()); |
|---|
| 434 | 477 | gfp &= gfp_allowed_mask; |
|---|
| 435 | 478 | |
|---|
| 436 | 479 | fs_reclaim_acquire(gfp); |
|---|
| 437 | 480 | fs_reclaim_release(gfp); |
|---|
| 438 | 481 | |
|---|
| 439 | | - if (size < PAGE_SIZE - align) { |
|---|
| 482 | + if (size < PAGE_SIZE - minalign) { |
|---|
| 483 | + int align = minalign; |
|---|
| 484 | + |
|---|
| 485 | + /* |
|---|
| 486 | + * For power of two sizes, guarantee natural alignment for |
|---|
| 487 | + * kmalloc()'d objects. |
|---|
| 488 | + */ |
|---|
| 489 | + if (is_power_of_2(size)) |
|---|
| 490 | + align = max_t(unsigned int, minalign, size); |
|---|
| 491 | + |
|---|
| 440 | 492 | if (!size) |
|---|
| 441 | 493 | return ZERO_SIZE_PTR; |
|---|
| 442 | 494 | |
|---|
| 443 | | - m = slob_alloc(size + align, gfp, align, node); |
|---|
| 495 | + m = slob_alloc(size + minalign, gfp, align, node, minalign); |
|---|
| 444 | 496 | |
|---|
| 445 | 497 | if (!m) |
|---|
| 446 | 498 | return NULL; |
|---|
| 447 | 499 | *m = size; |
|---|
| 448 | | - ret = (void *)m + align; |
|---|
| 500 | + ret = (void *)m + minalign; |
|---|
| 449 | 501 | |
|---|
| 450 | 502 | trace_kmalloc_node(caller, ret, |
|---|
| 451 | | - size, size + align, gfp, node); |
|---|
| 503 | + size, size + minalign, gfp, node); |
|---|
| 452 | 504 | } else { |
|---|
| 453 | 505 | unsigned int order = get_order(size); |
|---|
| 454 | 506 | |
|---|
| .. | .. |
|---|
| 497 | 549 | |
|---|
| 498 | 550 | sp = virt_to_page(block); |
|---|
| 499 | 551 | if (PageSlab(sp)) { |
|---|
| 500 | | - int align = max_t(size_t, ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); |
|---|
| 552 | + unsigned int align = max_t(unsigned int, |
|---|
| 553 | + ARCH_KMALLOC_MINALIGN, |
|---|
| 554 | + arch_slab_minalign()); |
|---|
| 501 | 555 | unsigned int *m = (unsigned int *)(block - align); |
|---|
| 556 | + |
|---|
| 502 | 557 | slob_free(m, *m + align); |
|---|
| 503 | | - } else |
|---|
| 504 | | - __free_pages(sp, compound_order(sp)); |
|---|
| 558 | + } else { |
|---|
| 559 | + unsigned int order = compound_order(sp); |
|---|
| 560 | + mod_node_page_state(page_pgdat(sp), NR_SLAB_UNRECLAIMABLE_B, |
|---|
| 561 | + -(PAGE_SIZE << order)); |
|---|
| 562 | + __free_pages(sp, order); |
|---|
| 563 | + |
|---|
| 564 | + } |
|---|
| 505 | 565 | } |
|---|
| 506 | 566 | EXPORT_SYMBOL(kfree); |
|---|
| 507 | 567 | |
|---|
| 508 | 568 | /* can't use ksize for kmem_cache_alloc memory, only kmalloc */ |
|---|
| 509 | | -size_t ksize(const void *block) |
|---|
| 569 | +size_t __ksize(const void *block) |
|---|
| 510 | 570 | { |
|---|
| 511 | 571 | struct page *sp; |
|---|
| 512 | | - int align; |
|---|
| 572 | + unsigned int align; |
|---|
| 513 | 573 | unsigned int *m; |
|---|
| 514 | 574 | |
|---|
| 515 | 575 | BUG_ON(!block); |
|---|
| .. | .. |
|---|
| 518 | 578 | |
|---|
| 519 | 579 | sp = virt_to_page(block); |
|---|
| 520 | 580 | if (unlikely(!PageSlab(sp))) |
|---|
| 521 | | - return PAGE_SIZE << compound_order(sp); |
|---|
| 581 | + return page_size(sp); |
|---|
| 522 | 582 | |
|---|
| 523 | | - align = max_t(size_t, ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); |
|---|
| 583 | + align = max_t(unsigned int, ARCH_KMALLOC_MINALIGN, |
|---|
| 584 | + arch_slab_minalign()); |
|---|
| 524 | 585 | m = (unsigned int *)(block - align); |
|---|
| 525 | 586 | return SLOB_UNITS(*m) * SLOB_UNIT; |
|---|
| 526 | 587 | } |
|---|
| 527 | | -EXPORT_SYMBOL(ksize); |
|---|
| 588 | +EXPORT_SYMBOL(__ksize); |
|---|
| 528 | 589 | |
|---|
| 529 | 590 | int __kmem_cache_create(struct kmem_cache *c, slab_flags_t flags) |
|---|
| 530 | 591 | { |
|---|
| .. | .. |
|---|
| 546 | 607 | fs_reclaim_release(flags); |
|---|
| 547 | 608 | |
|---|
| 548 | 609 | if (c->size < PAGE_SIZE) { |
|---|
| 549 | | - b = slob_alloc(c->size, flags, c->align, node); |
|---|
| 610 | + b = slob_alloc(c->size, flags, c->align, node, 0); |
|---|
| 550 | 611 | trace_kmem_cache_alloc_node(_RET_IP_, b, c->object_size, |
|---|
| 551 | 612 | SLOB_UNITS(c->size) * SLOB_UNIT, |
|---|
| 552 | 613 | flags, node); |
|---|