xref: /titanic_41/usr/src/lib/libast/common/vmalloc/vmmopen.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #if defined(_UWIN) && defined(_BLD_ast)
23 
_STUB_vmmopen()24 void _STUB_vmmopen(){}
25 
26 #else
27 
28 #include	"vmhdr.h"
29 
30 #if _sys_stat
31 #include	<sys/stat.h>
32 #endif
33 #include	<fcntl.h>
34 
35 #ifdef S_IRUSR
36 #define CREAT_MODE	(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
37 #else
38 #define CREAT_MODE	0644
39 #endif
40 
41 #if _lib_mmap
42 #include	<sys/mman.h>
43 #else
44 #define mmap(a,b,c,d,e,f)	MAP_FAILED
45 #define munmap(a,b)		MAP_FAILED
46 #endif
47 
48 /* Create a region to allocate based on mmap()
49 **
50 ** Written by Kiem-Phong Vo (kpv@research.att.com)
51 */
52 
53 #ifndef MAP_FAILED
54 #define MAP_FAILED	(void*)(-1)
55 #endif
56 
57 #define	MM_MAGIC	(('V'<<24) | ('M'<<16) | ('A'<<8) | ('P'))
58 #define MM_ROUND	(64*1024)
59 #define MM_START	ROUND(sizeof(Mmvm_t),ALIGN)
60 
61 typedef struct _user_s
62 {	struct _user_s*	next;	/* link list		*/
63 	int		key;	/* identifying key	*/
64 	Void_t*		data;	/* data to be returned	*/
65 } User_t;
66 
67 typedef struct _mmvm_s
68 {
69 	Vmulong_t	magic;	/* magic bytes		*/
70 	Void_t*		base;	/* base of the map	*/
71 	size_t		size;	/* current size		*/
72 	size_t		busy;	/* amount in use	*/
73 	size_t		round;	/* amount to round to	*/
74 	User_t*		user;	/* some user data	*/
75 } Mmvm_t;
76 
77 typedef struct _mmvmdisc_s
78 {
79 	Vmdisc_t	disc;	/* Vmalloc discipline	*/
80 	int		fd;	/* file descriptor	*/
81 	Mmvm_t*		mm;	/* mmap data		*/
82 } Mmvmdisc_t;
83 
84 #if __STD_C
mmvminit(char * file,Void_t * addr,size_t round,Mmvm_t * mm)85 static int mmvminit(char* file, Void_t* addr, size_t round, Mmvm_t* mm)
86 #else
87 static int mmvminit(file, addr, round, mm)
88 char*	file;	/* file to map data from	*/
89 Void_t*	addr;	/* desired starting address	*/
90 size_t	round;	/* amount to round requests 	*/
91 Mmvm_t*	mm;	/* to return some mapped info	*/
92 #endif
93 {
94 	int		fd;
95 	off_t		size;
96 	Void_t		*base;
97 	Mmvm_t		*hdr;
98 
99 	base = NIL(Void_t*);
100 	if((fd = open(file, O_RDWR, CREAT_MODE)) >= 0)
101 	{	if((size = lseek(fd, (off_t)0, 2)) < 0)
102 			goto done;
103 		else if(size == 0)
104 			goto new_f;
105 
106 		/* read the header */
107 		if(lseek(fd, (off_t)0, 0) != (off_t)0)
108 			goto done;
109 		if(read(fd, mm, sizeof(Mmvm_t)) != sizeof(Mmvm_t))
110 			goto done;
111 		if(mm->magic != MM_MAGIC || !mm->base ||
112 		   (off_t)mm->size != size || mm->busy > mm->size )
113 			goto done;
114 		base = (Void_t*)mmap(mm->base, mm->size, PROT_READ|PROT_WRITE,
115 				     MAP_FIXED|MAP_SHARED, fd, (off_t)0 );
116 		if(base == (Void_t*)MAP_FAILED)
117 			base = NIL(Void_t*);
118 	}
119 	else
120 	{	if((fd = open(file, O_RDWR|O_CREAT, CREAT_MODE)) < 0)
121 			goto done;
122 
123 	new_f:	/* create an initial set of data */
124 		size = round;
125 		if(lseek(fd, size-1, 0) != (size-1) || write(fd, "", 1) != 1 )
126 			goto done;
127 
128 		base = (Void_t*)mmap(addr, (size_t)size, PROT_READ|PROT_WRITE,
129 				     (addr ? MAP_FIXED : 0)|MAP_SHARED, fd, (off_t)0 );
130 		if(base == (Void_t*)MAP_FAILED)
131 			base = NIL(Void_t*);
132 		if(!base)
133 			goto done;
134 
135 		/* write magic number */
136 		hdr = (Mmvm_t*)base;
137 		hdr->magic = MM_MAGIC;
138 		hdr->base  = base;
139 		hdr->size  = size;
140 		hdr->busy  = MM_START;
141 		hdr->round = round;
142 		hdr->user  = NIL(User_t*);
143 		memcpy(mm, hdr, sizeof(Mmvm_t));
144 	}
145 
146 done:
147 	if(!base)
148 	{	if(fd >= 0)
149 			close(fd);
150 		fd = -1;
151 	}
152 
153 	return fd;
154 }
155 
156 
157 #if __STD_C
mmvmmemory(Vmalloc_t * vm,Void_t * caddr,size_t csize,size_t nsize,Vmdisc_t * disc)158 static Void_t* mmvmmemory(Vmalloc_t* vm, Void_t* caddr,
159 			size_t csize, size_t nsize, Vmdisc_t* disc)
160 #else
161 static Void_t* mmvmmemory(vm, caddr, csize, nsize, disc)
162 Vmalloc_t*	vm;
163 Void_t*		caddr;
164 size_t		csize;
165 size_t		nsize;
166 Vmdisc_t*	disc;
167 #endif
168 {
169 	Mmvmdisc_t	*mmdc = (Mmvmdisc_t*)disc;
170 
171 	if(mmdc->fd < 0 || !mmdc->mm)
172 		return NIL(Void_t*);
173 
174 #define MMADDR(b)	((Void_t*)(((Vmuchar_t*)b) + MM_START) )
175 	if(caddr && caddr != MMADDR(mmdc->mm->base) )
176 		return NIL(Void_t*);
177 	if(nsize < csize)
178 		return NIL(Void_t*);
179 
180 	if(nsize > mmdc->mm->size-MM_START)
181 	{	/* base and size of new map */
182 		caddr = mmdc->mm->base;
183 		csize = MM_START + nsize +
184 			((nsize % disc->round) < (disc->round/2) ? disc->round/2 : 0);
185 		csize = ROUND(csize, disc->round);
186 
187 		/* make room for new space */
188 		if(lseek(mmdc->fd, (off_t)(csize-1), 0) != (off_t)(csize-1) ||
189 		   write(mmdc->fd, "", 1) != 1 )
190 			return NIL(Void_t*);
191 
192 		/* remap the space */
193 		(void)munmap(caddr, mmdc->mm->size);
194 		caddr = (Void_t*)mmap(caddr, csize, PROT_READ|PROT_WRITE,
195 				     MAP_FIXED|MAP_SHARED, mmdc->fd, (off_t)0 );
196 		if(caddr == (Void_t*)MAP_FAILED)
197 			caddr = NIL(Void_t*);
198 		if(caddr)
199 			mmdc->mm->size = csize;
200 		else	/* bad problem */
201 		{	close(mmdc->fd);
202 			mmdc->fd = -1;
203 			mmdc->mm = NIL(Mmvm_t*);
204 			return NIL(Void_t*);
205 		}
206 	}
207 
208 	mmdc->mm->busy = nsize+MM_START;
209 	return (Void_t*)(((Vmuchar_t*)mmdc->mm->base) + MM_START);
210 }
211 
212 
213 #if __STD_C
mmvmexcept(Vmalloc_t * vm,int type,Void_t * data,Vmdisc_t * disc)214 static int mmvmexcept(Vmalloc_t* vm, int type, Void_t* data, Vmdisc_t* disc)
215 #else
216 static int mmvmexcept(vm, type, data, disc)
217 Vmalloc_t*	vm;
218 int		type;
219 Void_t*		data;
220 Vmdisc_t*	disc;
221 #endif
222 {
223 	Mmvmdisc_t	*mmdc = (Mmvmdisc_t*)disc;
224 	Vmuchar_t	*base;
225 
226 	if(type == VM_OPEN)
227 	{	if(mmdc->mm->busy > MM_START)
228 		{	base = ((Vmuchar_t*)mmdc->mm->base) + MM_START;
229 			*((Void_t**)data) = (Void_t*)base;
230 			return 1;
231 		}
232 		else	return 0;
233 	}
234 	else if(type == VM_CLOSE)
235 	{	(void)munmap(mmdc->mm->base, mmdc->mm->size);
236 		(void)close(mmdc->fd);
237 		vmfree(Vmheap, mmdc);
238 		return 1; /* freeing of mapped data is already done */
239 	}
240 	else	return 0;
241 }
242 
243 
244 #if __STD_C
vmmopen(char * file,Void_t * base,size_t round)245 Vmalloc_t* vmmopen(char* file, Void_t* base, size_t round)
246 #else
247 Vmalloc_t* vmmopen(file, base, round)
248 char*		file;	/* file mapping data from	*/
249 Void_t* 	base;	/* desired starting address	*/
250 size_t		round;	/* amount to round requests	*/
251 #endif
252 {
253 	Vmalloc_t	*vm;
254 	Mmvmdisc_t	*mmdc;
255 	Mmvm_t		mm;
256 	int		fd;
257 
258 	if(!file)
259 		return NIL(Vmalloc_t*);
260 
261 	/* set the amount to round up to on each memory request */
262 	GETPAGESIZE(_Vmpagesize);
263 	if(round < MM_ROUND)
264 		round = MM_ROUND;
265 	round = ROUND(round, _Vmpagesize);
266 
267 	if((fd = mmvminit(file, base, round, &mm)) < 0)
268 		return NIL(Vmalloc_t*);
269 
270 	if(!(mmdc = (Mmvmdisc_t*)vmalloc(Vmheap, sizeof(Mmvmdisc_t))) )
271 	{	close(fd);
272 		return NIL(Vmalloc_t*);
273 	}
274 
275 	mmdc->disc.memoryf = mmvmmemory;
276 	mmdc->disc.exceptf = mmvmexcept;
277 	mmdc->disc.round   = mm.round;
278 	mmdc->fd = fd;
279 	mmdc->mm = (Mmvm_t*)mm.base;
280 
281 	if(!(vm = vmopen(&mmdc->disc, Vmbest, VM_TRUST)) )
282 	{	mmvmexcept(NIL(Vmalloc_t*), VM_CLOSE, NIL(Void_t*), &mmdc->disc);
283 		return NIL(Vmalloc_t*);
284 	}
285 
286 	return vm;
287 }
288 
289 
290 #if __STD_C
vmmset(Vmalloc_t * vm,int key,Void_t * data,int set)291 Void_t* vmmset(Vmalloc_t* vm, int key, Void_t* data, int set)
292 #else
293 Void_t* vmmset(vm, data, key, set)
294 Vmalloc_t*	vm;	/* a region based on vmmmopen	*/
295 int		key;	/* key of data to be set	*/
296 Void_t*		data;	/* data to be set		*/
297 int		set;	/* 1 for setting, 0 for getting	*/
298 #endif
299 {
300 	User_t	*u;
301 	Mmvm_t	*mmvm = ((Mmvmdisc_t*)vm->disc)->mm;
302 
303 	for(u = mmvm->user; u; u = u->next)
304 		if(u->key == key)
305 			break;
306 	if(!set)
307 		return u ? u->data : NIL(Void_t*);
308 	else if(u)
309 	{	Void_t* old = u->data;
310 		u->data = data;
311 		return old;
312 	}
313 	else if(!(u = (User_t*)vmalloc(vm, sizeof(User_t))) )
314 		return NIL(Void_t*);
315 	else
316 	{	u->data = data;
317 		u->key  = key;
318 		u->next = mmvm->user;
319 		mmvm->user = u;
320 		return data;
321 	}
322 }
323 
324 #endif
325