linux
Network interface will fail to go up when !ZONE_DMA
If !ZONE_DMA, __alloc_pages_nodemask() will return NULL when asked for DMA memory, resulting in a driver failure.
Bug fixed by commit 1f758a4341a
Type | BehaviorViolation |
Config | "EP93XX_ETH && !ZONE_DMA" (2nd degree) |
Fix-in | code |
Location | drivers/net/arm/ |
#define ENOMEM 12 /* Out of memory */ #define NULL (void*)0 #define ___GFP_WAIT 0x10u #define ___GFP_IO 0x40u #define ___GFP_FS 0x80u #define __GFP_WAIT ((int)___GFP_WAIT) /* Can wait and reschedule? */ #define __GFP_IO ((int)___GFP_IO) /* Can start physical IO? */ #define __GFP_FS ((int)___GFP_FS) /* Can call down to low-level FS? */ #define GFP_KERNEL (__GFP_WAIT | __GFP_IO | __GFP_FS) #define ___GFP_DMA 0x01u #define __GFP_DMA ((int)___GFP_DMA) #define GFP_DMA __GFP_DMA static int some_int = 0; int* __alloc_pages_nodemask(int gfp_mask) { #ifndef CONFIG_ZONE_DMA if (gfp_mask & __GFP_DMA) return NULL; // (4) #endif return &some_int; } #ifdef CONFIG_EP93XX_ETH int ep93xx_alloc_buffers() { int *descs = __alloc_pages_nodemask(GFP_KERNEL | GFP_DMA); // (3) if (descs == NULL) return 1; // (5) } int ep93xx_open() { if (ep93xx_alloc_buffers()) // (2) return -ENOMEM; // (6) ERROR } #endif int main(void) { #ifdef CONFIG_EP93XX_ETH ep93xx_open(); // (1) #endif return 0; }
diff --git a/simple/1f758a4.c b/simple/1f758a4.c --- a/simple/1f758a4.c +++ b/simple/1f758a4.c @@ -29,7 +29,7 @@ #ifdef CONFIG_EP93XX_ETH int ep93xx_alloc_buffers() { - int *descs = __alloc_pages_nodemask(GFP_KERNEL | GFP_DMA); // (3) + int *descs = __alloc_pages_nodemask(GFP_KERNEL); // (3) if (descs == NULL) return 1; // (5) }
#include <errno.h> #include <stdlib.h> #define ___GFP_WAIT 0x10u #define ___GFP_IO 0x40u #define ___GFP_FS 0x80u #define __GFP_WAIT ((gfp_t)___GFP_WAIT) /* Can wait and reschedule? */ #define __GFP_IO ((gfp_t)___GFP_IO) /* Can start physical IO? */ #define __GFP_FS ((gfp_t)___GFP_FS) /* Can call down to low-level FS? */ #define GFP_KERNEL (__GFP_WAIT | __GFP_IO | __GFP_FS) #define ___GFP_DMA 0x01u #define __GFP_DMA ((gfp_t)___GFP_DMA) #define GFP_DMA __GFP_DMA typedef int gfp_t; static int some_int = 0; int main(int argc, char** argv) { #ifdef CONFIG_EP93XX_ETH // ep93xx_open(); #ifndef CONFIG_ZONE_DMA if ((GFP_KERNEL | GFP_DMA) & __GFP_DMA) return NULL; #endif int *descs = &some_int; if (descs == NULL) return -ENOMEM; // ERROR #endif return 0; }
// ref a197b59ae6e8bee56fcef37ea2482dc08414e2ac . call drivers/net/arm/ep93xx_eth.c:650:ep93xx_open() . 655: if (ep93xx_alloc_buffers(ep)) .. call drivers/net/arm/ep93xx_eth.c:492:ep93xx_alloc_buffers() .. 496: ep->descs = dma_alloc_coherent(dev, sizeof(struct ep93xx_descs), &ep->descs_dma_addr, GFP_KERNEL | GFP_DMA); ... call mm/page_alloc.c:2234:__alloc_pages_nodemask() ... [ZONE_DMA] 2251: if (WARN_ON_ONCE(gfp_mask & __GFP_DMA)) ... [ZONE_DMA] 2252: return NULL; .. 498: if (ep->descs == NULL) .. 499: return 1; . ERROR 656: return -ENOMEM;