.. | .. |
---|
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); |
---|