• M
    mm: make page pfmemalloc check more robust · 2f064f34
    Michal Hocko 提交于
    Commit c48a11c7 ("netvm: propagate page->pfmemalloc to skb") added
    checks for page->pfmemalloc to __skb_fill_page_desc():
    
            if (page->pfmemalloc && !page->mapping)
                    skb->pfmemalloc = true;
    
    It assumes page->mapping == NULL implies that page->pfmemalloc can be
    trusted.  However, __delete_from_page_cache() can set set page->mapping
    to NULL and leave page->index value alone.  Due to being in union, a
    non-zero page->index will be interpreted as true page->pfmemalloc.
    
    So the assumption is invalid if the networking code can see such a page.
    And it seems it can.  We have encountered this with a NFS over loopback
    setup when such a page is attached to a new skbuf.  There is no copying
    going on in this case so the page confuses __skb_fill_page_desc which
    interprets the index as pfmemalloc flag and the network stack drops
    packets that have been allocated using the reserves unless they are to
    be queued on sockets handling the swapping which is the case here and
    that leads to hangs when the nfs client waits for a response from the
    server which has been dropped and thus never arrive.
    
    The struct page is already heavily packed so rather than finding another
    hole to put it in, let's do a trick instead.  We can reuse the index
    again but define it to an impossible value (-1UL).  This is the page
    index so it should never see the value that large.  Replace all direct
    users of page->pfmemalloc by page_is_pfmemalloc which will hide this
    nastiness from unspoiled eyes.
    
    The information will get lost if somebody wants to use page->index
    obviously but that was the case before and the original code expected
    that the information should be persisted somewhere else if that is
    really needed (e.g.  what SLAB and SLUB do).
    
    [akpm@linux-foundation.org: fix blooper in slub]
    Fixes: c48a11c7 ("netvm: propagate page->pfmemalloc to skb")
    Signed-off-by: NMichal Hocko <mhocko@suse.com>
    Debugged-by: NVlastimil Babka <vbabka@suse.com>
    Debugged-by: NJiri Bohac <jbohac@suse.com>
    Cc: Eric Dumazet <eric.dumazet@gmail.com>
    Cc: David Miller <davem@davemloft.net>
    Acked-by: NMel Gorman <mgorman@suse.de>
    Cc: <stable@vger.kernel.org>	[3.6+]
    Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
    2f064f34
page_alloc.c 193.1 KB