aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2004-04-26 09:01:44 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-04-26 09:01:44 -0700
commit1b2569fb4487dda5216cc8c609bfe8668444b0e9 (patch)
treeffdf0f3e9f331134e8fca16803c84fd1781571d8 /mm
parentb3f25c2b2e31146b844042b50cff3bb46a9cf11c (diff)
downloadhistory-1b2569fb4487dda5216cc8c609bfe8668444b0e9.tar.gz
[PATCH] slab: use order 0 for vfs caches
We have interesting deadlocks when slab decides to use order-1 allocations for ext3_inode_cache. This is because ext3_alloc_inode() needs to perform a GFP_NOFS 1-order allocation. Sometimes the 1-order allocation needs to free a huge number of pages (tens of megabytes) before a 1-order grouping becomes available. But the GFP_NOFS allocator cannot free dcache (and hence icache) due to the deadlock problems identified in shrink_dcache_memory(). So change slab so that it will force 0-order allocations for shrinkable VFS objects. We can handle those OK.
Diffstat (limited to 'mm')
-rw-r--r--mm/slab.c74
1 files changed, 44 insertions, 30 deletions
diff --git a/mm/slab.c b/mm/slab.c
index e26a851b6108b6..6b3cedfc6b2dfa 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1220,41 +1220,55 @@ kmem_cache_create (const char *name, size_t size, size_t align,
size = ALIGN(size, align);
- /* Cal size (in pages) of slabs, and the num of objs per slab.
- * This could be made much more intelligent. For now, try to avoid
- * using high page-orders for slabs. When the gfp() funcs are more
- * friendly towards high-order requests, this should be changed.
- */
- do {
- unsigned int break_flag = 0;
-cal_wastage:
+ if ((flags & SLAB_RECLAIM_ACCOUNT) && size <= PAGE_SIZE) {
+ /*
+ * A VFS-reclaimable slab tends to have most allocations
+ * as GFP_NOFS and we really don't want to have to be allocating
+ * higher-order pages when we are unable to shrink dcache.
+ */
+ cachep->gfporder = 0;
cache_estimate(cachep->gfporder, size, align, flags,
- &left_over, &cachep->num);
- if (break_flag)
- break;
- if (cachep->gfporder >= MAX_GFP_ORDER)
- break;
- if (!cachep->num)
- goto next;
- if (flags & CFLGS_OFF_SLAB && cachep->num > offslab_limit) {
- /* Oops, this num of objs will cause problems. */
- cachep->gfporder--;
- break_flag++;
- goto cal_wastage;
- }
-
+ &left_over, &cachep->num);
+ } else {
/*
- * Large num of objs is good, but v. large slabs are currently
- * bad for the gfp()s.
+ * Calculate size (in pages) of slabs, and the num of objs per
+ * slab. This could be made much more intelligent. For now,
+ * try to avoid using high page-orders for slabs. When the
+ * gfp() funcs are more friendly towards high-order requests,
+ * this should be changed.
*/
- if (cachep->gfporder >= slab_break_gfp_order)
- break;
+ do {
+ unsigned int break_flag = 0;
+cal_wastage:
+ cache_estimate(cachep->gfporder, size, align, flags,
+ &left_over, &cachep->num);
+ if (break_flag)
+ break;
+ if (cachep->gfporder >= MAX_GFP_ORDER)
+ break;
+ if (!cachep->num)
+ goto next;
+ if (flags & CFLGS_OFF_SLAB &&
+ cachep->num > offslab_limit) {
+ /* This num of objs will cause problems. */
+ cachep->gfporder--;
+ break_flag++;
+ goto cal_wastage;
+ }
- if ((left_over*8) <= (PAGE_SIZE<<cachep->gfporder))
- break; /* Acceptable internal fragmentation. */
+ /*
+ * Large num of objs is good, but v. large slabs are
+ * currently bad for the gfp()s.
+ */
+ if (cachep->gfporder >= slab_break_gfp_order)
+ break;
+
+ if ((left_over*8) <= (PAGE_SIZE<<cachep->gfporder))
+ break; /* Acceptable internal fragmentation. */
next:
- cachep->gfporder++;
- } while (1);
+ cachep->gfporder++;
+ } while (1);
+ }
if (!cachep->num) {
printk("kmem_cache_create: couldn't create cache %s.\n", name);