RE: [External] Re: [PATCH 2/3] include/linux/gfp.h: use unsigned int in gfp_zone
From: Huaisheng HS1 Ye
Date: Sun May 06 2018 - 05:32:42 EST
> On Fri, May 04, 2018 at 03:35:33PM +0200, Michal Hocko wrote:
> > On Fri 04-05-18 14:52:08, Huaisheng Ye wrote:
> > > Suggest using unsigned int instead of int for bit within gfp_zone.
> > > @@ -401,7 +401,7 @@ static inline bool gfpflags_allow_blocking(const
> gfp_t gfp_flags)
> > > static inline enum zone_type gfp_zone(gfp_t flags)
> > > {
> > > enum zone_type z;
> > > - int bit = (__force int) (flags & GFP_ZONEMASK);
> > > + unsigned int bit = (__force unsigned int) (flags & GFP_ZONEMASK);
> > >
> > > z = (GFP_ZONE_TABLE >> (bit * GFP_ZONES_SHIFT)) &
> > > ((1 << GFP_ZONES_SHIFT) - 1);
>
> That reminds me. I wanted to talk about getting rid of GFP_ZONE_TABLE.
> Instead, we should encode the zone number in the bottom three bits of
> the gfp mask, while preserving the rules that ZONE_NORMAL gets encoded
> as zero (so GFP_KERNEL | GFP_HIGHMEM continues to work) and also leaving
> __GFP_MOVABLE in bit 3 so that it can continue to be used as a flag.
>
> So I was thinking ...
>
> -#define ___GFP_DMA 0x01u
> -#define ___GFP_HIGHMEM 0x02u
> -#define ___GFP_DMA32 0x04u
> +#define ___GFP_ZONE_MASK 0x07u
>
> #define __GFP_DMA ((__force gfp_t)OPT_ZONE_DMA ^ ZONE_NORMAL)
> #define __GFP_HIGHMEM ((__force gfp_t)OPT_ZONE_HIGHMEM ^
> ZONE_NORMAL)
> #define __GFP_DMA32 ((__force gfp_t)OPT_ZONE_DMA32 ^
> ZONE_NORMAL)
> #define __GFP_MOVABLE ((__force gfp_t)ZONE_MOVABLE ^ ZONE_NORMAL | \
> ___GFP_MOVABLE)
> #define GFP_ZONEMASK ((__force gfp_t)___GFP_ZONE_MASK |
> ___GFP_MOVABLE)
>
> Then we can delete GFP_ZONE_TABLE and GFP_ZONE_BAD.
> gfp_zone simply becomes:
>
> static inline enum zone_type gfp_zone(gfp_t flags)
> {
> return ((__force int)flags & ___GFP_ZONE_MASK) ^ ZONE_NORMAL;
> }
>
> Huaisheng Ye, would you have time to investigate this idea?
Dear Matthew and Michal,
This idea is great, we can replace GFP_ZONE_TABLE and GFP_ZONE_BAD with it.
I have realized it preliminarily based on your code and tested it on a 2 sockets platform. Fortunately, we got a positive test result.
I made some adjustments for __GFP_HIGHMEM, this flag is special than others, because the return result of gfp_zone has two possibilities, which depend on ___GFP_MOVABLE has been enabled or disabled.
When ___GFP_MOVABLE has been enabled, ZONE_MOVABLE shall be returned. When disabled, OPT_ZONE_HIGHMEM shall be used.
#define __GFP_DMA ((__force gfp_t)OPT_ZONE_DMA ^ ZONE_NORMAL)
#define __GFP_HIGHMEM ((__force gfp_t)ZONE_MOVABLE ^ ZONE_NORMAL)
#define __GFP_DMA32 ((__force gfp_t)OPT_ZONE_DMA32 ^ ZONE_NORMAL)
#define __GFP_MOVABLE ((__force gfp_t)___GFP_MOVABLE) /* ZONE_MOVABLE allowed */
#define GFP_ZONEMASK ((__force gfp_t)___GFP_ZONE_MASK | ___GFP_MOVABLE)
The present situation is that, based on this change, the bits of flags, __GFP_DMA and __GFP_HIGHMEM and __GFP_DMA32, have been encoded.
That is totally different from existing code, you know in kernel scope, there are many drivers or subsystems use these flags directly to realize bit manipulations like this below,
swiotlb-xen.c (drivers\xen): flags &= ~(__GFP_DMA | __GFP_HIGHMEM);
extent_io.c (fs\btrfs): mask &= ~(__GFP_DMA32|__GFP_HIGHMEM);
Because of these flags have been encoded, the above operations can cause problem.
I am trying to get a solution to resolve it. Any progress will be reported.
Sincerely,
Huaisheng Ye
Linux kernel | Lenovo