linux/fs/xfs/kmem.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
   3 * All Rights Reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it would be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write the Free Software Foundation,
  16 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17 */
  18#include <linux/mm.h>
  19#include <linux/highmem.h>
  20#include <linux/slab.h>
  21#include <linux/swap.h>
  22#include <linux/blkdev.h>
  23#include <linux/backing-dev.h>
  24#include "kmem.h"
  25#include "xfs_message.h"
  26
  27/*
  28 * Greedy allocation.  May fail and may return vmalloced memory.
  29 */
  30void *
  31kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize)
  32{
  33        void            *ptr;
  34        size_t          kmsize = maxsize;
  35
  36        while (!(ptr = vzalloc(kmsize))) {
  37                if ((kmsize >>= 1) <= minsize)
  38                        kmsize = minsize;
  39        }
  40        if (ptr)
  41                *size = kmsize;
  42        return ptr;
  43}
  44
  45void *
  46kmem_alloc(size_t size, xfs_km_flags_t flags)
  47{
  48        int     retries = 0;
  49        gfp_t   lflags = kmem_flags_convert(flags);
  50        void    *ptr;
  51
  52        do {
  53                ptr = kmalloc(size, lflags);
  54                if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP)))
  55                        return ptr;
  56                if (!(++retries % 100))
  57                        xfs_err(NULL,
  58                "possible memory allocation deadlock in %s (mode:0x%x)",
  59                                        __func__, lflags);
  60                congestion_wait(BLK_RW_ASYNC, HZ/50);
  61        } while (1);
  62}
  63
  64void *
  65kmem_zalloc_large(size_t size, xfs_km_flags_t flags)
  66{
  67        unsigned noio_flag = 0;
  68        void    *ptr;
  69        gfp_t   lflags;
  70
  71        ptr = kmem_zalloc(size, flags | KM_MAYFAIL);
  72        if (ptr)
  73                return ptr;
  74
  75        /*
  76         * __vmalloc() will allocate data pages and auxillary structures (e.g.
  77         * pagetables) with GFP_KERNEL, yet we may be under GFP_NOFS context
  78         * here. Hence we need to tell memory reclaim that we are in such a
  79         * context via PF_MEMALLOC_NOIO to prevent memory reclaim re-entering
  80         * the filesystem here and potentially deadlocking.
  81         */
  82        if ((current->flags & PF_FSTRANS) || (flags & KM_NOFS))
  83                noio_flag = memalloc_noio_save();
  84
  85        lflags = kmem_flags_convert(flags);
  86        ptr = __vmalloc(size, lflags | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL);
  87
  88        if ((current->flags & PF_FSTRANS) || (flags & KM_NOFS))
  89                memalloc_noio_restore(noio_flag);
  90
  91        return ptr;
  92}
  93
  94void *
  95kmem_realloc(const void *ptr, size_t newsize, size_t oldsize,
  96             xfs_km_flags_t flags)
  97{
  98        void    *new;
  99
 100        new = kmem_alloc(newsize, flags);
 101        if (ptr) {
 102                if (new)
 103                        memcpy(new, ptr,
 104                                ((oldsize < newsize) ? oldsize : newsize));
 105                kmem_free(ptr);
 106        }
 107        return new;
 108}
 109
 110void *
 111kmem_zone_alloc(kmem_zone_t *zone, xfs_km_flags_t flags)
 112{
 113        int     retries = 0;
 114        gfp_t   lflags = kmem_flags_convert(flags);
 115        void    *ptr;
 116
 117        do {
 118                ptr = kmem_cache_alloc(zone, lflags);
 119                if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP)))
 120                        return ptr;
 121                if (!(++retries % 100))
 122                        xfs_err(NULL,
 123                "possible memory allocation deadlock in %s (mode:0x%x)",
 124                                        __func__, lflags);
 125                congestion_wait(BLK_RW_ASYNC, HZ/50);
 126        } while (1);
 127}
 128