Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
[pandora-kernel.git] / fs / xfs / linux-2.6 / kmem.c
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  */
32 void *
33 kmem_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
47 void *
48 kmem_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
66 void *
67 kmem_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
77 void
78 kmem_free(const void *ptr)
79 {
80         if (!is_vmalloc_addr(ptr)) {
81                 kfree(ptr);
82         } else {
83                 vfree(ptr);
84         }
85 }
86
87 void *
88 kmem_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
103 void *
104 kmem_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
122 void *
123 kmem_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 }