4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
31 * This file is part of Lustre, http://www.lustre.org/
32 * Lustre is a trademark of Sun Microsystems, Inc.
34 * libcfs/libcfs/darwin/darwin-mem.c
36 * Author: Liang Zhen <liangzhen@clusterfs.com>
37 * Author: Nikita Danilov <nikita@clusterfs.com>
39 #define DEBUG_SUBSYSTEM S_LNET
41 #include <mach/mach_types.h>
43 #include <sys/malloc.h>
45 #include <libcfs/libcfs.h>
46 #include "darwin-internal.h"
48 #if CFS_INDIVIDUAL_ZONE
49 extern zone_t zinit( vm_size_t, vm_size_t, vm_size_t, const char *);
50 extern void * zalloc(zone_t zone);
51 extern void *zalloc_noblock(zone_t zone);
52 extern void zfree(zone_t zone, void *addr);
55 struct list_head *z_nob; /* Pointer to z_link */
56 struct list_head z_link; /* Do NOT access it directly */
59 static struct cfs_zone_nob cfs_zone_nob;
60 static spinlock_t cfs_zone_guard;
62 cfs_mem_cache_t *mem_cache_find(const char *name, size_t objsize)
64 cfs_mem_cache_t *walker = NULL;
66 LASSERT(cfs_zone_nob.z_nob != NULL);
68 spin_lock(&cfs_zone_guard);
69 list_for_each_entry(walker, cfs_zone_nob.z_nob, mc_link) {
70 if (!strcmp(walker->mc_name, name) && \
71 walker->mc_size == objsize)
74 spin_unlock(&cfs_zone_guard);
80 * our wrapper around kern/zalloc.c:zinit()
82 * Creates copy of name and calls zinit() to do real work. Needed because zone
83 * survives kext unloading, so that @name cannot be just static string
84 * embedded into kext image.
86 cfs_mem_cache_t *mem_cache_create(vm_size_t objsize, const char *name)
88 cfs_mem_cache_t *mc = NULL;
91 MALLOC(mc, cfs_mem_cache_t *, sizeof(cfs_mem_cache_t), M_TEMP, M_WAITOK|M_ZERO);
93 CERROR("cfs_mem_cache created fail!\n");
97 cname = _MALLOC(strlen(name) + 1, M_TEMP, M_WAITOK);
98 LASSERT(cname != NULL);
99 mc->mc_cache = zinit(objsize, (KMEM_MAX_ZONE * objsize), 0, strcpy(cname, name));
100 mc->mc_size = objsize;
101 CFS_INIT_LIST_HEAD(&mc->mc_link);
102 strncpy(mc->mc_name, name, 1 + strlen(name));
106 void mem_cache_destroy(cfs_mem_cache_t *mc)
109 * zone can NOT be destroyed after creating,
110 * so just keep it in list.
112 * We will not lost a zone after we unload
113 * libcfs, it can be found by from libcfs.zone
118 #define mem_cache_alloc(mc) zalloc((mc)->mc_cache)
120 # define mem_cache_alloc_nb(mc) zalloc((mc)->mc_cache)
122 /* XXX Liang: Tiger doesn't export zalloc_noblock() */
123 # define mem_cache_alloc_nb(mc) zalloc_noblock((mc)->mc_cache)
125 #define mem_cache_free(mc, p) zfree((mc)->mc_cache, p)
127 #else /* !CFS_INDIVIDUAL_ZONE */
130 mem_cache_find(const char *name, size_t objsize)
135 cfs_mem_cache_t *mem_cache_create(vm_size_t size, const char *name)
137 cfs_mem_cache_t *mc = NULL;
139 MALLOC(mc, cfs_mem_cache_t *, sizeof(cfs_mem_cache_t), M_TEMP, M_WAITOK|M_ZERO);
141 CERROR("cfs_mem_cache created fail!\n");
144 mc->mc_cache = OSMalloc_Tagalloc(name, OSMT_DEFAULT);
149 void mem_cache_destroy(cfs_mem_cache_t *mc)
151 OSMalloc_Tagfree(mc->mc_cache);
155 #define mem_cache_alloc(mc) OSMalloc((mc)->mc_size, (mc)->mc_cache)
156 #define mem_cache_alloc_nb(mc) OSMalloc_noblock((mc)->mc_size, (mc)->mc_cache)
157 #define mem_cache_free(mc, p) OSFree(p, (mc)->mc_size, (mc)->mc_cache)
159 #endif /* !CFS_INDIVIDUAL_ZONE */
162 cfs_mem_cache_create (const char *name,
163 size_t objsize, size_t off, unsigned long arg1)
167 mc = mem_cache_find(name, objsize);
170 mc = mem_cache_create(objsize, name);
174 int cfs_mem_cache_destroy (cfs_mem_cache_t *cachep)
176 mem_cache_destroy(cachep);
180 void *cfs_mem_cache_alloc (cfs_mem_cache_t *cachep, int flags)
184 /* zalloc_canblock() is not exported... Emulate it. */
185 if (flags & CFS_ALLOC_ATOMIC) {
186 result = (void *)mem_cache_alloc_nb(cachep);
188 LASSERT(get_preemption_level() == 0);
189 result = (void *)mem_cache_alloc(cachep);
191 if (result != NULL && (flags & CFS_ALLOC_ZERO))
192 memset(result, 0, cachep->mc_size);
197 void cfs_mem_cache_free (cfs_mem_cache_t *cachep, void *objp)
199 mem_cache_free(cachep, objp);
202 /* ---------------------------------------------------------------------------
205 * --------------------------------------------------------------------------- */
211 static unsigned int raw_pages = 0;
212 static cfs_mem_cache_t *raw_page_cache = NULL;
214 static struct xnu_page_ops raw_page_ops;
215 static struct xnu_page_ops *page_ops[XNU_PAGE_NTYPES] = {
216 [XNU_PAGE_RAW] = &raw_page_ops
219 #if defined(LIBCFS_DEBUG)
220 static int page_type_is_valid(cfs_page_t *page)
222 LASSERT(page != NULL);
223 return 0 <= page->type && page->type < XNU_PAGE_NTYPES;
226 static int page_is_raw(cfs_page_t *page)
228 return page->type == XNU_PAGE_RAW;
232 static struct xnu_raw_page *as_raw(cfs_page_t *page)
234 LASSERT(page_is_raw(page));
235 return list_entry(page, struct xnu_raw_page, header);
238 static void *raw_page_address(cfs_page_t *pg)
240 return (void *)as_raw(pg)->virtual;
243 static void *raw_page_map(cfs_page_t *pg)
245 return (void *)as_raw(pg)->virtual;
248 static void raw_page_unmap(cfs_page_t *pg)
252 static struct xnu_page_ops raw_page_ops = {
253 .page_map = raw_page_map,
254 .page_unmap = raw_page_unmap,
255 .page_address = raw_page_address
258 extern int get_preemption_level(void);
260 struct list_head page_death_row;
261 spinlock_t page_death_row_phylax;
263 static void raw_page_finish(struct xnu_raw_page *pg)
266 if (pg->virtual != NULL)
267 cfs_mem_cache_free(raw_page_cache, pg->virtual);
271 void raw_page_death_row_clean(void)
273 struct xnu_raw_page *pg;
275 spin_lock(&page_death_row_phylax);
276 while (!list_empty(&page_death_row)) {
277 pg = container_of(page_death_row.next,
278 struct xnu_raw_page, link);
280 spin_unlock(&page_death_row_phylax);
282 spin_lock(&page_death_row_phylax);
284 spin_unlock(&page_death_row_phylax);
288 void free_raw_page(struct xnu_raw_page *pg)
290 if (!atomic_dec_and_test(&pg->count))
293 * kmem_free()->vm_map_remove()->vm_map_delete()->lock_write() may
294 * block. (raw_page_done()->upl_abort() can block too) On the other
295 * hand, cfs_free_page() may be called in non-blockable context. To
296 * work around this, park pages on global list when cannot block.
298 if (get_preemption_level() > 0) {
299 spin_lock(&page_death_row_phylax);
300 list_add(&pg->link, &page_death_row);
301 spin_unlock(&page_death_row_phylax);
304 raw_page_death_row_clean();
308 cfs_page_t *cfs_alloc_page(u_int32_t flags)
310 struct xnu_raw_page *page;
313 * XXX nikita: do NOT call libcfs_debug_msg() (CDEBUG/ENTRY/EXIT)
314 * from here: this will lead to infinite recursion.
317 page = cfs_alloc(sizeof *page, flags);
319 page->virtual = cfs_mem_cache_alloc(raw_page_cache, flags);
320 if (page->virtual != NULL) {
322 page->header.type = XNU_PAGE_RAW;
323 atomic_set(&page->count, 1);
329 return page != NULL ? &page->header : NULL;
332 void cfs_free_page(cfs_page_t *pages)
334 free_raw_page(as_raw(pages));
337 void cfs_get_page(cfs_page_t *p)
339 atomic_inc(&as_raw(p)->count);
342 int cfs_put_page_testzero(cfs_page_t *p)
344 return atomic_dec_and_test(&as_raw(p)->count);
347 int cfs_page_count(cfs_page_t *p)
349 return atomic_read(&as_raw(p)->count);
353 * Generic page operations
356 void *cfs_page_address(cfs_page_t *pg)
359 * XXX nikita: do NOT call libcfs_debug_msg() (CDEBUG/ENTRY/EXIT)
360 * from here: this will lead to infinite recursion.
362 LASSERT(page_type_is_valid(pg));
363 return page_ops[pg->type]->page_address(pg);
366 void *cfs_kmap(cfs_page_t *pg)
368 LASSERT(page_type_is_valid(pg));
369 return page_ops[pg->type]->page_map(pg);
372 void cfs_kunmap(cfs_page_t *pg)
374 LASSERT(page_type_is_valid(pg));
375 return page_ops[pg->type]->page_unmap(pg);
378 void xnu_page_ops_register(int type, struct xnu_page_ops *ops)
380 LASSERT(0 <= type && type < XNU_PAGE_NTYPES);
381 LASSERT(ops != NULL);
382 LASSERT(page_ops[type] == NULL);
384 page_ops[type] = ops;
387 void xnu_page_ops_unregister(int type)
389 LASSERT(0 <= type && type < XNU_PAGE_NTYPES);
390 LASSERT(page_ops[type] != NULL);
392 page_ops[type] = NULL;
396 * Portable memory allocator API
398 #ifdef HAVE_GET_PREEMPTION_LEVEL
399 extern int get_preemption_level(void);
401 #define get_preemption_level() (0)
404 void *cfs_alloc(size_t nr_bytes, u_int32_t flags)
409 if (flags & CFS_ALLOC_ATOMIC) {
412 LASSERT(get_preemption_level() == 0);
416 if (flags & CFS_ALLOC_ZERO)
419 return _MALLOC(nr_bytes, M_TEMP, mflags);
422 void cfs_free(void *addr)
424 return _FREE(addr, M_TEMP);
427 void *cfs_alloc_large(size_t nr_bytes)
429 LASSERT(get_preemption_level() == 0);
430 return _MALLOC(nr_bytes, M_TEMP, M_WAITOK);
433 void cfs_free_large(void *addr)
435 LASSERT(get_preemption_level() == 0);
436 return _FREE(addr, M_TEMP);
440 * Lookup cfs_zone_nob by sysctl.zone, if it cannot be
441 * found (first load of * libcfs since boot), allocate
442 * sysctl libcfs.zone.
444 int cfs_mem_init(void)
446 #if CFS_INDIVIDUAL_ZONE
450 len = sizeof(struct cfs_zone_nob);
451 rc = sysctlbyname("libcfs.zone",
452 (void *)&cfs_zone_nob, &len, NULL, 0);
454 /* zone_nob is not register in libcfs_sysctl */
455 struct cfs_zone_nob *nob;
456 struct sysctl_oid *oid;
458 assert(cfs_sysctl_isvalid());
460 nob = _MALLOC(sizeof(struct cfs_zone_nob),
461 M_TEMP, M_WAITOK | M_ZERO);
462 CFS_INIT_LIST_HEAD(&nob->z_link);
463 nob->z_nob = &nob->z_link;
464 oid = cfs_alloc_sysctl_struct(NULL, OID_AUTO, CTLFLAG_RD | CTLFLAG_KERN,
465 "zone", nob, sizeof(struct cfs_zone_nob));
470 sysctl_register_oid(oid);
472 cfs_zone_nob.z_nob = nob->z_nob;
474 spin_lock_init(&cfs_zone_guard);
476 CFS_INIT_LIST_HEAD(&page_death_row);
477 spin_lock_init(&page_death_row_phylax);
478 raw_page_cache = cfs_mem_cache_create("raw-page", CFS_PAGE_SIZE, 0, 0);
482 void cfs_mem_fini(void)
484 raw_page_death_row_clean();
485 spin_lock_done(&page_death_row_phylax);
486 cfs_mem_cache_destroy(raw_page_cache);
488 #if CFS_INDIVIDUAL_ZONE
489 cfs_zone_nob.z_nob = NULL;
490 spin_lock_done(&cfs_zone_guard);