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 "time.h" 25#include "kmem.h" 26 27/* 28 * Greedy allocation. May fail and may return vmalloced memory. 29 * 30 * Must be freed using kmem_free_large. 31 */ 32void * 33kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize) 34{ 35 void *ptr; 36 size_t kmsize = maxsize; 37 38 while (!(ptr = kmem_zalloc_large(kmsize))) { 39 if ((kmsize >>= 1) <= minsize) 40 kmsize = minsize; 41 } 42 if (ptr) 43 *size = kmsize; 44 return ptr; 45} 46 47void * 48kmem_alloc(size_t size, unsigned int __nocast flags) 49{ 50 int retries = 0; 51 gfp_t lflags = kmem_flags_convert(flags); 52 void *ptr; 53 54 do { 55 ptr = kmalloc(size, lflags); 56 if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP))) 57 return ptr; 58 if (!(++retries % 100)) 59 printk(KERN_ERR "XFS: possible memory allocation " 60 "deadlock in %s (mode:0x%x)\n", 61 __func__, lflags); 62 congestion_wait(BLK_RW_ASYNC, HZ/50); 63 } while (1); 64} 65 66void * 67kmem_zalloc(size_t size, unsigned int __nocast flags) 68{ 69 void *ptr; 70 71 ptr = kmem_alloc(size, flags); 72 if (ptr) 73 memset((char *)ptr, 0, (int)size); 74 return ptr; 75} 76 77void 78kmem_free(const void *ptr) 79{ 80 if (!is_vmalloc_addr(ptr)) { 81 kfree(ptr); 82 } else { 83 vfree(ptr); 84 } 85} 86 87void * 88kmem_realloc(const void *ptr, size_t newsize, size_t oldsize, 89 unsigned int __nocast flags) 90{ 91 void *new; 92 93 new = kmem_alloc(newsize, flags); 94 if (ptr) { 95 if (new) 96 memcpy(new, ptr, 97 ((oldsize < newsize) ? oldsize : newsize)); 98 kmem_free(ptr); 99 } 100 return new; 101} 102 103void * 104kmem_zone_alloc(kmem_zone_t *zone, unsigned int __nocast flags) 105{ 106 int retries = 0; 107 gfp_t lflags = kmem_flags_convert(flags); 108 void *ptr; 109 110 do { 111 ptr = kmem_cache_alloc(zone, lflags); 112 if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP))) 113 return ptr; 114 if (!(++retries % 100)) 115 printk(KERN_ERR "XFS: possible memory allocation " 116 "deadlock in %s (mode:0x%x)\n", 117 __func__, lflags); 118 congestion_wait(BLK_RW_ASYNC, HZ/50); 119 } while (1); 120} 121 122void * 123kmem_zone_zalloc(kmem_zone_t *zone, unsigned int __nocast flags) 124{ 125 void *ptr; 126 127 ptr = kmem_zone_alloc(zone, flags); 128 if (ptr) 129 memset((char *)ptr, 0, kmem_cache_size(zone)); 130 return ptr; 131} 132