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