xref: /onnv-gate/usr/src/lib/libast/common/vmalloc/vmmopen.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #if defined(_UWIN) && defined(_BLD_ast)
234887Schin 
_STUB_vmmopen()244887Schin void _STUB_vmmopen(){}
254887Schin 
264887Schin #else
274887Schin 
284887Schin #include	"vmhdr.h"
294887Schin 
304887Schin #if _sys_stat
314887Schin #include	<sys/stat.h>
324887Schin #endif
334887Schin #include	<fcntl.h>
344887Schin 
354887Schin #ifdef S_IRUSR
364887Schin #define CREAT_MODE	(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
374887Schin #else
384887Schin #define CREAT_MODE	0644
394887Schin #endif
404887Schin 
414887Schin #if _lib_mmap
424887Schin #include	<sys/mman.h>
434887Schin #else
444887Schin #define mmap(a,b,c,d,e,f)	MAP_FAILED
454887Schin #define munmap(a,b)		MAP_FAILED
464887Schin #endif
474887Schin 
484887Schin /* Create a region to allocate based on mmap()
494887Schin **
504887Schin ** Written by Kiem-Phong Vo (kpv@research.att.com)
514887Schin */
524887Schin 
534887Schin #ifndef MAP_FAILED
544887Schin #define MAP_FAILED	(void*)(-1)
554887Schin #endif
564887Schin 
574887Schin #define	MM_MAGIC	(('V'<<24) | ('M'<<16) | ('A'<<8) | ('P'))
584887Schin #define MM_ROUND	(64*1024)
594887Schin #define MM_START	ROUND(sizeof(Mmvm_t),ALIGN)
604887Schin 
614887Schin typedef struct _user_s
624887Schin {	struct _user_s*	next;	/* link list		*/
634887Schin 	int		key;	/* identifying key	*/
644887Schin 	Void_t*		data;	/* data to be returned	*/
654887Schin } User_t;
664887Schin 
674887Schin typedef struct _mmvm_s
684887Schin {
694887Schin 	Vmulong_t	magic;	/* magic bytes		*/
704887Schin 	Void_t*		base;	/* base of the map	*/
714887Schin 	size_t		size;	/* current size		*/
724887Schin 	size_t		busy;	/* amount in use	*/
734887Schin 	size_t		round;	/* amount to round to	*/
744887Schin 	User_t*		user;	/* some user data	*/
754887Schin } Mmvm_t;
764887Schin 
774887Schin typedef struct _mmvmdisc_s
784887Schin {
794887Schin 	Vmdisc_t	disc;	/* Vmalloc discipline	*/
804887Schin 	int		fd;	/* file descriptor	*/
814887Schin 	Mmvm_t*		mm;	/* mmap data		*/
824887Schin } Mmvmdisc_t;
834887Schin 
844887Schin #if __STD_C
mmvminit(char * file,Void_t * addr,size_t round,Mmvm_t * mm)854887Schin static int mmvminit(char* file, Void_t* addr, size_t round, Mmvm_t* mm)
864887Schin #else
874887Schin static int mmvminit(file, addr, round, mm)
884887Schin char*	file;	/* file to map data from	*/
894887Schin Void_t*	addr;	/* desired starting address	*/
904887Schin size_t	round;	/* amount to round requests 	*/
914887Schin Mmvm_t*	mm;	/* to return some mapped info	*/
924887Schin #endif
934887Schin {
944887Schin 	int		fd;
954887Schin 	off_t		size;
964887Schin 	Void_t		*base;
974887Schin 	Mmvm_t		*hdr;
984887Schin 
994887Schin 	base = NIL(Void_t*);
1004887Schin 	if((fd = open(file, O_RDWR, CREAT_MODE)) >= 0)
1014887Schin 	{	if((size = lseek(fd, (off_t)0, 2)) < 0)
1024887Schin 			goto done;
1034887Schin 		else if(size == 0)
1044887Schin 			goto new_f;
1054887Schin 
1064887Schin 		/* read the header */
1074887Schin 		if(lseek(fd, (off_t)0, 0) != (off_t)0)
1084887Schin 			goto done;
1094887Schin 		if(read(fd, mm, sizeof(Mmvm_t)) != sizeof(Mmvm_t))
1104887Schin 			goto done;
1114887Schin 		if(mm->magic != MM_MAGIC || !mm->base ||
1124887Schin 		   (off_t)mm->size != size || mm->busy > mm->size )
1134887Schin 			goto done;
1144887Schin 		base = (Void_t*)mmap(mm->base, mm->size, PROT_READ|PROT_WRITE,
1154887Schin 				     MAP_FIXED|MAP_SHARED, fd, (off_t)0 );
1164887Schin 		if(base == (Void_t*)MAP_FAILED)
1174887Schin 			base = NIL(Void_t*);
1184887Schin 	}
1194887Schin 	else
1204887Schin 	{	if((fd = open(file, O_RDWR|O_CREAT, CREAT_MODE)) < 0)
1214887Schin 			goto done;
1224887Schin 
1234887Schin 	new_f:	/* create an initial set of data */
1244887Schin 		size = round;
1254887Schin 		if(lseek(fd, size-1, 0) != (size-1) || write(fd, "", 1) != 1 )
1264887Schin 			goto done;
1274887Schin 
1284887Schin 		base = (Void_t*)mmap(addr, (size_t)size, PROT_READ|PROT_WRITE,
1294887Schin 				     (addr ? MAP_FIXED : 0)|MAP_SHARED, fd, (off_t)0 );
1304887Schin 		if(base == (Void_t*)MAP_FAILED)
1314887Schin 			base = NIL(Void_t*);
1324887Schin 		if(!base)
1334887Schin 			goto done;
1344887Schin 
1354887Schin 		/* write magic number */
1364887Schin 		hdr = (Mmvm_t*)base;
1374887Schin 		hdr->magic = MM_MAGIC;
1384887Schin 		hdr->base  = base;
1394887Schin 		hdr->size  = size;
1404887Schin 		hdr->busy  = MM_START;
1414887Schin 		hdr->round = round;
1424887Schin 		hdr->user  = NIL(User_t*);
1434887Schin 		memcpy(mm, hdr, sizeof(Mmvm_t));
1444887Schin 	}
1454887Schin 
1464887Schin done:
1474887Schin 	if(!base)
1484887Schin 	{	if(fd >= 0)
1494887Schin 			close(fd);
1504887Schin 		fd = -1;
1514887Schin 	}
1524887Schin 
1534887Schin 	return fd;
1544887Schin }
1554887Schin 
1564887Schin 
1574887Schin #if __STD_C
mmvmmemory(Vmalloc_t * vm,Void_t * caddr,size_t csize,size_t nsize,Vmdisc_t * disc)1584887Schin static Void_t* mmvmmemory(Vmalloc_t* vm, Void_t* caddr,
1594887Schin 			size_t csize, size_t nsize, Vmdisc_t* disc)
1604887Schin #else
1614887Schin static Void_t* mmvmmemory(vm, caddr, csize, nsize, disc)
1624887Schin Vmalloc_t*	vm;
1634887Schin Void_t*		caddr;
1644887Schin size_t		csize;
1654887Schin size_t		nsize;
1664887Schin Vmdisc_t*	disc;
1674887Schin #endif
1684887Schin {
1694887Schin 	Mmvmdisc_t	*mmdc = (Mmvmdisc_t*)disc;
1704887Schin 
1714887Schin 	if(mmdc->fd < 0 || !mmdc->mm)
1724887Schin 		return NIL(Void_t*);
1734887Schin 
1744887Schin #define MMADDR(b)	((Void_t*)(((Vmuchar_t*)b) + MM_START) )
1754887Schin 	if(caddr && caddr != MMADDR(mmdc->mm->base) )
1764887Schin 		return NIL(Void_t*);
1774887Schin 	if(nsize < csize)
1784887Schin 		return NIL(Void_t*);
1794887Schin 
1804887Schin 	if(nsize > mmdc->mm->size-MM_START)
1814887Schin 	{	/* base and size of new map */
1824887Schin 		caddr = mmdc->mm->base;
1834887Schin 		csize = MM_START + nsize +
1844887Schin 			((nsize % disc->round) < (disc->round/2) ? disc->round/2 : 0);
1854887Schin 		csize = ROUND(csize, disc->round);
1864887Schin 
1874887Schin 		/* make room for new space */
1884887Schin 		if(lseek(mmdc->fd, (off_t)(csize-1), 0) != (off_t)(csize-1) ||
1894887Schin 		   write(mmdc->fd, "", 1) != 1 )
1904887Schin 			return NIL(Void_t*);
1914887Schin 
1924887Schin 		/* remap the space */
1934887Schin 		(void)munmap(caddr, mmdc->mm->size);
1944887Schin 		caddr = (Void_t*)mmap(caddr, csize, PROT_READ|PROT_WRITE,
1954887Schin 				     MAP_FIXED|MAP_SHARED, mmdc->fd, (off_t)0 );
1964887Schin 		if(caddr == (Void_t*)MAP_FAILED)
1974887Schin 			caddr = NIL(Void_t*);
1984887Schin 		if(caddr)
1994887Schin 			mmdc->mm->size = csize;
2004887Schin 		else	/* bad problem */
2014887Schin 		{	close(mmdc->fd);
2024887Schin 			mmdc->fd = -1;
2034887Schin 			mmdc->mm = NIL(Mmvm_t*);
2044887Schin 			return NIL(Void_t*);
2054887Schin 		}
2064887Schin 	}
2074887Schin 
2084887Schin 	mmdc->mm->busy = nsize+MM_START;
2094887Schin 	return (Void_t*)(((Vmuchar_t*)mmdc->mm->base) + MM_START);
2104887Schin }
2114887Schin 
2124887Schin 
2134887Schin #if __STD_C
mmvmexcept(Vmalloc_t * vm,int type,Void_t * data,Vmdisc_t * disc)2144887Schin static int mmvmexcept(Vmalloc_t* vm, int type, Void_t* data, Vmdisc_t* disc)
2154887Schin #else
2164887Schin static int mmvmexcept(vm, type, data, disc)
2174887Schin Vmalloc_t*	vm;
2184887Schin int		type;
2194887Schin Void_t*		data;
2204887Schin Vmdisc_t*	disc;
2214887Schin #endif
2224887Schin {
2234887Schin 	Mmvmdisc_t	*mmdc = (Mmvmdisc_t*)disc;
2244887Schin 	Vmuchar_t	*base;
2254887Schin 
2264887Schin 	if(type == VM_OPEN)
2274887Schin 	{	if(mmdc->mm->busy > MM_START)
2284887Schin 		{	base = ((Vmuchar_t*)mmdc->mm->base) + MM_START;
2294887Schin 			*((Void_t**)data) = (Void_t*)base;
2304887Schin 			return 1;
2314887Schin 		}
2324887Schin 		else	return 0;
2334887Schin 	}
2344887Schin 	else if(type == VM_CLOSE)
2354887Schin 	{	(void)munmap(mmdc->mm->base, mmdc->mm->size);
2364887Schin 		(void)close(mmdc->fd);
2374887Schin 		vmfree(Vmheap, mmdc);
2384887Schin 		return 1; /* freeing of mapped data is already done */
2394887Schin 	}
2404887Schin 	else	return 0;
2414887Schin }
2424887Schin 
2434887Schin 
2444887Schin #if __STD_C
vmmopen(char * file,Void_t * base,size_t round)2454887Schin Vmalloc_t* vmmopen(char* file, Void_t* base, size_t round)
2464887Schin #else
2474887Schin Vmalloc_t* vmmopen(file, base, round)
2484887Schin char*		file;	/* file mapping data from	*/
2494887Schin Void_t* 	base;	/* desired starting address	*/
2504887Schin size_t		round;	/* amount to round requests	*/
2514887Schin #endif
2524887Schin {
2534887Schin 	Vmalloc_t	*vm;
2544887Schin 	Mmvmdisc_t	*mmdc;
2554887Schin 	Mmvm_t		mm;
2564887Schin 	int		fd;
2574887Schin 
2584887Schin 	if(!file)
2594887Schin 		return NIL(Vmalloc_t*);
2604887Schin 
2614887Schin 	/* set the amount to round up to on each memory request */
2624887Schin 	GETPAGESIZE(_Vmpagesize);
2634887Schin 	if(round < MM_ROUND)
2644887Schin 		round = MM_ROUND;
2654887Schin 	round = ROUND(round, _Vmpagesize);
2664887Schin 
2674887Schin 	if((fd = mmvminit(file, base, round, &mm)) < 0)
2684887Schin 		return NIL(Vmalloc_t*);
2694887Schin 
2704887Schin 	if(!(mmdc = (Mmvmdisc_t*)vmalloc(Vmheap, sizeof(Mmvmdisc_t))) )
2714887Schin 	{	close(fd);
2724887Schin 		return NIL(Vmalloc_t*);
2734887Schin 	}
2744887Schin 
2754887Schin 	mmdc->disc.memoryf = mmvmmemory;
2764887Schin 	mmdc->disc.exceptf = mmvmexcept;
2774887Schin 	mmdc->disc.round   = mm.round;
2784887Schin 	mmdc->fd = fd;
2794887Schin 	mmdc->mm = (Mmvm_t*)mm.base;
2804887Schin 
2814887Schin 	if(!(vm = vmopen(&mmdc->disc, Vmbest, VM_TRUST)) )
2824887Schin 	{	mmvmexcept(NIL(Vmalloc_t*), VM_CLOSE, NIL(Void_t*), &mmdc->disc);
2834887Schin 		return NIL(Vmalloc_t*);
2844887Schin 	}
2854887Schin 
2864887Schin 	return vm;
2874887Schin }
2884887Schin 
2894887Schin 
2904887Schin #if __STD_C
vmmset(Vmalloc_t * vm,int key,Void_t * data,int set)2914887Schin Void_t* vmmset(Vmalloc_t* vm, int key, Void_t* data, int set)
2924887Schin #else
2934887Schin Void_t* vmmset(vm, data, key, set)
2944887Schin Vmalloc_t*	vm;	/* a region based on vmmmopen	*/
2954887Schin int		key;	/* key of data to be set	*/
2964887Schin Void_t*		data;	/* data to be set		*/
2974887Schin int		set;	/* 1 for setting, 0 for getting	*/
2984887Schin #endif
2994887Schin {
3004887Schin 	User_t	*u;
3014887Schin 	Mmvm_t	*mmvm = ((Mmvmdisc_t*)vm->disc)->mm;
3024887Schin 
3034887Schin 	for(u = mmvm->user; u; u = u->next)
3044887Schin 		if(u->key == key)
3054887Schin 			break;
3064887Schin 	if(!set)
3074887Schin 		return u ? u->data : NIL(Void_t*);
3084887Schin 	else if(u)
3094887Schin 	{	Void_t* old = u->data;
3104887Schin 		u->data = data;
3114887Schin 		return old;
3124887Schin 	}
3134887Schin 	else if(!(u = (User_t*)vmalloc(vm, sizeof(User_t))) )
3144887Schin 		return NIL(Void_t*);
3154887Schin 	else
3164887Schin 	{	u->data = data;
3174887Schin 		u->key  = key;
3184887Schin 		u->next = mmvm->user;
3194887Schin 		mmvm->user = u;
3204887Schin 		return data;
3214887Schin 	}
3224887Schin }
3234887Schin 
3244887Schin #endif
325