Whamcloud - gitweb
b5a6129e9ac9e8b7e19d702ce8c8fc716f2416ba
[fs/lustre-release.git] / libcfs / libcfs / linux / linux-mem.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36 #define DEBUG_SUBSYSTEM S_LNET
37
38 #include <linux/mm.h>
39 #include <linux/vmalloc.h>
40 #include <linux/slab.h>
41 #include <linux/highmem.h>
42 #include <libcfs/libcfs.h>
43
44 static unsigned int cfs_alloc_flags_to_gfp(u_int32_t flags)
45 {
46         unsigned int mflags = 0;
47
48 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
49         if (flags & CFS_ALLOC_ATOMIC)
50                 mflags |= __GFP_HIGH;
51         else if (flags & CFS_ALLOC_WAIT)
52                 mflags |= __GFP_WAIT;
53         else
54                 mflags |= (__GFP_HIGH | __GFP_WAIT);
55         if (flags & CFS_ALLOC_IO)
56                 mflags |= __GFP_IO | __GFP_HIGHIO;
57 #else
58         if (flags & CFS_ALLOC_ATOMIC)
59                 mflags |= __GFP_HIGH;
60         else
61                 mflags |= __GFP_WAIT;
62         if (flags & CFS_ALLOC_NOWARN)
63                 mflags |= __GFP_NOWARN;
64         if (flags & CFS_ALLOC_IO)
65                 mflags |= __GFP_IO;
66 #endif
67         if (flags & CFS_ALLOC_FS)
68                 mflags |= __GFP_FS;
69         if (flags & CFS_ALLOC_HIGH)
70                 mflags |= __GFP_HIGH;
71         return mflags;
72 }
73
74 void *
75 cfs_alloc(size_t nr_bytes, u_int32_t flags)
76 {
77         void *ptr = NULL;
78
79         ptr = kmalloc(nr_bytes, cfs_alloc_flags_to_gfp(flags));
80         if (ptr != NULL && (flags & CFS_ALLOC_ZERO))
81                 memset(ptr, 0, nr_bytes);
82         return ptr;
83 }
84
85 void
86 cfs_free(void *addr)
87 {
88         kfree(addr);
89 }
90
91 void *
92 cfs_alloc_large(size_t nr_bytes)
93 {
94         return vmalloc(nr_bytes);
95 }
96
97 void
98 cfs_free_large(void *addr)
99 {
100         vfree(addr);
101 }
102
103 cfs_page_t *cfs_alloc_pages(unsigned int flags, unsigned int order)
104 {
105         /*
106          * XXX nikita: do NOT call portals_debug_msg() (CDEBUG/ENTRY/EXIT)
107          * from here: this will lead to infinite recursion.
108          */
109         return alloc_pages(cfs_alloc_flags_to_gfp(flags), order);
110 }
111
112 void __cfs_free_pages(cfs_page_t *page, unsigned int order)
113 {
114         __free_pages(page, order);
115 }
116
117 cfs_mem_cache_t *
118 cfs_mem_cache_create (const char *name, size_t size, size_t offset,
119                       unsigned long flags)
120 {
121 #ifdef HAVE_KMEM_CACHE_CREATE_DTOR
122         return kmem_cache_create(name, size, offset, flags, NULL, NULL);
123 #else
124         return kmem_cache_create(name, size, offset, flags, NULL);
125 #endif
126 }
127
128 int
129 cfs_mem_cache_destroy (cfs_mem_cache_t * cachep)
130 {
131 #ifdef HAVE_KMEM_CACHE_DESTROY_INT
132         return kmem_cache_destroy(cachep);
133 #else
134         kmem_cache_destroy(cachep);
135         return 0;
136 #endif
137 }
138
139 void *
140 cfs_mem_cache_alloc(cfs_mem_cache_t *cachep, int flags)
141 {
142         return kmem_cache_alloc(cachep, cfs_alloc_flags_to_gfp(flags));
143 }
144
145 void
146 cfs_mem_cache_free(cfs_mem_cache_t *cachep, void *objp)
147 {
148         return kmem_cache_free(cachep, objp);
149 }
150
151 /**
152  * Returns true if \a addr is an address of an allocated object in a slab \a
153  * kmem. Used in assertions. This check is optimistically imprecise, i.e., it
154  * occasionally returns true for the incorrect addresses, but if it returns
155  * false, then the addresses is guaranteed to be incorrect.
156  */
157 int cfs_mem_is_in_cache(const void *addr, const cfs_mem_cache_t *kmem)
158 {
159 #ifdef CONFIG_SLAB
160         struct page *page;
161
162         /*
163          * XXX Copy of mm/slab.c:virt_to_cache(). It won't work with other
164          * allocators, like slub and slob.
165          */
166         page = virt_to_page(addr);
167         if (unlikely(PageCompound(page)))
168                 page = (struct page *)page->private;
169         return PageSlab(page) && ((void *)page->lru.next) == kmem;
170 #else
171         return 1;
172 #endif
173 }
174 EXPORT_SYMBOL(cfs_mem_is_in_cache);
175
176
177 EXPORT_SYMBOL(cfs_alloc);
178 EXPORT_SYMBOL(cfs_free);
179 EXPORT_SYMBOL(cfs_alloc_large);
180 EXPORT_SYMBOL(cfs_free_large);
181 EXPORT_SYMBOL(cfs_alloc_pages);
182 EXPORT_SYMBOL(__cfs_free_pages);
183 EXPORT_SYMBOL(cfs_mem_cache_create);
184 EXPORT_SYMBOL(cfs_mem_cache_destroy);
185 EXPORT_SYMBOL(cfs_mem_cache_alloc);
186 EXPORT_SYMBOL(cfs_mem_cache_free);