Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm: exclude ZONE_DEVICE from GFP_ZONE_TABLE

ZONE_DEVICE (merged in 4.3) and ZONE_CMA (proposed) are examples of new
mm zones that are bumping up against the current maximum limit of 4
zones, i.e. 2 bits in page->flags for the GFP_ZONE_TABLE.

The GFP_ZONE_TABLE poses an interesting constraint since
include/linux/gfp.h gets included by the 32-bit portion of a 64-bit
build. We need to be careful to only build the table for zones that
have a corresponding gfp_t flag. GFP_ZONES_SHIFT is introduced for this
purpose. This patch does not attempt to solve the problem of adding a
new zone that also has a corresponding GFP_ flag.

Vlastimil points out that ZONE_DEVICE, by depending on x86_64 and
SPARSEMEM_VMEMMAP implies that SECTIONS_WIDTH is zero. In other words
even though ZONE_DEVICE does not fit in GFP_ZONE_TABLE it is free to
consume another bit in page->flags (expand ZONES_WIDTH) with room to
spare.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=110931
Fixes: 033fbae988fc ("mm: ZONE_DEVICE for "device memory"")
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Reported-by: Mark <markk@clara.co.uk>
Reported-by: Vlastimil Babka <vbabka@suse.cz>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Rik van Riel <riel@redhat.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Dan Williams and committed by
Linus Torvalds
b11a7b94 d334c9bc

+22 -15
+20 -13
include/linux/gfp.h
··· 331 331 * 0xe => BAD (MOVABLE+DMA32+HIGHMEM) 332 332 * 0xf => BAD (MOVABLE+DMA32+HIGHMEM+DMA) 333 333 * 334 - * ZONES_SHIFT must be <= 2 on 32 bit platforms. 334 + * GFP_ZONES_SHIFT must be <= 2 on 32 bit platforms. 335 335 */ 336 336 337 - #if 16 * ZONES_SHIFT > BITS_PER_LONG 338 - #error ZONES_SHIFT too large to create GFP_ZONE_TABLE integer 337 + #if defined(CONFIG_ZONE_DEVICE) && (MAX_NR_ZONES-1) <= 4 338 + /* ZONE_DEVICE is not a valid GFP zone specifier */ 339 + #define GFP_ZONES_SHIFT 2 340 + #else 341 + #define GFP_ZONES_SHIFT ZONES_SHIFT 342 + #endif 343 + 344 + #if 16 * GFP_ZONES_SHIFT > BITS_PER_LONG 345 + #error GFP_ZONES_SHIFT too large to create GFP_ZONE_TABLE integer 339 346 #endif 340 347 341 348 #define GFP_ZONE_TABLE ( \ 342 - (ZONE_NORMAL << 0 * ZONES_SHIFT) \ 343 - | (OPT_ZONE_DMA << ___GFP_DMA * ZONES_SHIFT) \ 344 - | (OPT_ZONE_HIGHMEM << ___GFP_HIGHMEM * ZONES_SHIFT) \ 345 - | (OPT_ZONE_DMA32 << ___GFP_DMA32 * ZONES_SHIFT) \ 346 - | (ZONE_NORMAL << ___GFP_MOVABLE * ZONES_SHIFT) \ 347 - | (OPT_ZONE_DMA << (___GFP_MOVABLE | ___GFP_DMA) * ZONES_SHIFT) \ 348 - | (ZONE_MOVABLE << (___GFP_MOVABLE | ___GFP_HIGHMEM) * ZONES_SHIFT) \ 349 - | (OPT_ZONE_DMA32 << (___GFP_MOVABLE | ___GFP_DMA32) * ZONES_SHIFT) \ 349 + (ZONE_NORMAL << 0 * GFP_ZONES_SHIFT) \ 350 + | (OPT_ZONE_DMA << ___GFP_DMA * GFP_ZONES_SHIFT) \ 351 + | (OPT_ZONE_HIGHMEM << ___GFP_HIGHMEM * GFP_ZONES_SHIFT) \ 352 + | (OPT_ZONE_DMA32 << ___GFP_DMA32 * GFP_ZONES_SHIFT) \ 353 + | (ZONE_NORMAL << ___GFP_MOVABLE * GFP_ZONES_SHIFT) \ 354 + | (OPT_ZONE_DMA << (___GFP_MOVABLE | ___GFP_DMA) * GFP_ZONES_SHIFT) \ 355 + | (ZONE_MOVABLE << (___GFP_MOVABLE | ___GFP_HIGHMEM) * GFP_ZONES_SHIFT)\ 356 + | (OPT_ZONE_DMA32 << (___GFP_MOVABLE | ___GFP_DMA32) * GFP_ZONES_SHIFT)\ 350 357 ) 351 358 352 359 /* ··· 378 371 enum zone_type z; 379 372 int bit = (__force int) (flags & GFP_ZONEMASK); 380 373 381 - z = (GFP_ZONE_TABLE >> (bit * ZONES_SHIFT)) & 382 - ((1 << ZONES_SHIFT) - 1); 374 + z = (GFP_ZONE_TABLE >> (bit * GFP_ZONES_SHIFT)) & 375 + ((1 << GFP_ZONES_SHIFT) - 1); 383 376 VM_BUG_ON((GFP_ZONE_BAD >> bit) & 1); 384 377 return z; 385 378 }
+2
include/linux/page-flags-layout.h
··· 17 17 #define ZONES_SHIFT 1 18 18 #elif MAX_NR_ZONES <= 4 19 19 #define ZONES_SHIFT 2 20 + #elif MAX_NR_ZONES <= 8 21 + #define ZONES_SHIFT 3 20 22 #else 21 23 #error ZONES_SHIFT -- too many zones configured adjust calculation 22 24 #endif
-2
mm/Kconfig
··· 651 651 652 652 config ZONE_DEVICE 653 653 bool "Device memory (pmem, etc...) hotplug support" if EXPERT 654 - default !ZONE_DMA 655 - depends on !ZONE_DMA 656 654 depends on MEMORY_HOTPLUG 657 655 depends on MEMORY_HOTREMOVE 658 656 depends on X86_64 #arch_add_memory() comprehends device memory