1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1991-2001 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 /*
28  * zmalloc	- use mmap(2) to allocate memory from /dev/zero.
29  * zfree	- use munmap(2) to unmap (free) memory.
30  *
31  * These functions should be better than malloc(3) for large memory allocation.
32  */
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/mman.h>
40 #include <sys/stat.h>
41 
42 #include <zmalloc.h>
43 
44 /*
45  * a utility structure to keep track of the (possibly) multiple mmaps
46  * that we have done...
47  */
48 struct buffer_map {
49 	struct buffer_map *bm_next;
50 	char *bm_buffer;
51 	int bm_size;
52 };
53 
54 static  void *bm_empty = (void *) "";		/* special buffer */
55 static	struct buffer_map *bm_list;		/* NULL by default */
56 
57 static struct buffer_map *
insert_bm(char * buf,size_t size)58 insert_bm(char *buf, size_t size)
59 {
60 	struct buffer_map *bm;
61 
62 	bm = (struct buffer_map *)malloc(sizeof (struct buffer_map));
63 	bm->bm_buffer = buf;
64 	bm->bm_size = size;
65 	bm->bm_next = bm_list;
66 
67 	bm_list = bm;
68 
69 	return (bm_list);
70 }
71 
72 static size_t
delete_bm(char * buf)73 delete_bm(char *buf)
74 {
75 	size_t size;
76 	register struct buffer_map *p_curr;
77 	register struct buffer_map *p_prev;
78 
79 	p_prev = NULL;
80 	p_curr = bm_list;
81 	while (p_curr != NULL) {
82 		if (p_curr->bm_buffer == buf) {
83 			if (p_prev == NULL)
84 				bm_list = p_curr->bm_next;
85 			else
86 				p_prev->bm_next = p_curr->bm_next;
87 			size = p_curr->bm_size;
88 			free(p_curr);
89 			return (size);
90 		}
91 
92 		p_prev = p_curr;
93 		p_curr = p_curr->bm_next;
94 	}
95 	return (0);
96 }
97 
98 void *
zmalloc(size_t size)99 zmalloc(size_t size)
100 {
101 	int	fd;
102 	caddr_t	mbuf;
103 
104 	/* XXX - Special case: never allocate 0 bytes, use a special buffer */
105 	if (size == 0)
106 	    return ((void *)NULL); /* return (bm_empty); */
107 
108 	if ((fd = open("/dev/zero", O_RDWR)) < 0) {
109 		perror("/dev/zero");
110 		return ((void *) NULL);
111 	}
112 
113 	mbuf = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
114 	(void) close(fd);
115 
116 	if (mbuf == (caddr_t)-1) {
117 		perror("zmalloc: mmap");
118 		return ((void *) NULL);
119 	}
120 
121 	(void) insert_bm(mbuf, size);
122 
123 	return ((void *) mbuf);
124 }
125 
126 void
zfree(void * mbuf)127 zfree(void* mbuf)
128 {
129 	size_t size;
130 
131 	if (mbuf == bm_empty)
132 	    return;
133 
134 	if (mbuf != NULL) {
135 		if (size = delete_bm((caddr_t)mbuf)) {
136 			if (munmap((char *)mbuf, size) < 0)
137 			    perror("zfree: munmap");
138 		}
139 	}
140 }
141