vm_mmap.c

来自「早期freebsd实现」· C语言 代码 · 共 833 行 · 第 1/2 页

C
833
字号
/* * Copyright (c) 1988 University of Utah. * Copyright (c) 1991, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer * Science Department. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: Utah $Hdr: vm_mmap.c 1.6 91/10/21$ * *	@(#)vm_mmap.c	8.4 (Berkeley) 1/12/94 *//* * Mapped file (mmap) interface to VM */#include <sys/param.h>#include <sys/systm.h>#include <sys/filedesc.h>#include <sys/resourcevar.h>#include <sys/proc.h>#include <sys/vnode.h>#include <sys/file.h>#include <sys/mman.h>#include <sys/conf.h>#include <miscfs/specfs/specdev.h>#include <vm/vm.h>#include <vm/vm_pager.h>#include <vm/vm_prot.h>#ifdef DEBUGint mmapdebug = 0;#define MDB_FOLLOW	0x01#define MDB_SYNC	0x02#define MDB_MAPIT	0x04#endifstruct sbrk_args {	int	incr;};/* ARGSUSED */intsbrk(p, uap, retval)	struct proc *p;	struct sbrk_args *uap;	int *retval;{	/* Not yet implemented */	return (EOPNOTSUPP);}struct sstk_args {	int	incr;};/* ARGSUSED */intsstk(p, uap, retval)	struct proc *p;	struct sstk_args *uap;	int *retval;{	/* Not yet implemented */	return (EOPNOTSUPP);}#if defined(COMPAT_43) || defined(COMPAT_SUNOS)struct getpagesize_args {	int	dummy;};/* ARGSUSED */intogetpagesize(p, uap, retval)	struct proc *p;	struct getpagesize_args *uap;	int *retval;{	*retval = PAGE_SIZE;	return (0);}#endif /* COMPAT_43 || COMPAT_SUNOS */struct mmap_args {	caddr_t	addr;	size_t	len;	int	prot;	int	flags;	int	fd;	long	pad;	off_t	pos;};#ifdef COMPAT_43struct ommap_args {	caddr_t	addr;	int	len;	int	prot;	int	flags;	int	fd;	long	pos;};intommap(p, uap, retval)	struct proc *p;	register struct ommap_args *uap;	int *retval;{	struct mmap_args nargs;	static const char cvtbsdprot[8] = {		0,		PROT_EXEC,		PROT_WRITE,		PROT_EXEC|PROT_WRITE,		PROT_READ,		PROT_EXEC|PROT_READ,		PROT_WRITE|PROT_READ,		PROT_EXEC|PROT_WRITE|PROT_READ,	};#define	OMAP_ANON	0x0002#define	OMAP_COPY	0x0020#define	OMAP_SHARED	0x0010#define	OMAP_FIXED	0x0100#define	OMAP_INHERIT	0x0800	nargs.addr = uap->addr;	nargs.len = uap->len;	nargs.prot = cvtbsdprot[uap->prot&0x7];	nargs.flags = 0;	if (uap->flags & OMAP_ANON)		nargs.flags |= MAP_ANON;	if (uap->flags & OMAP_COPY)		nargs.flags |= MAP_COPY;	if (uap->flags & OMAP_SHARED)		nargs.flags |= MAP_SHARED;	else		nargs.flags |= MAP_PRIVATE;	if (uap->flags & OMAP_FIXED)		nargs.flags |= MAP_FIXED;	if (uap->flags & OMAP_INHERIT)		nargs.flags |= MAP_INHERIT;	nargs.fd = uap->fd;	nargs.pos = uap->pos;	return (mmap(p, &nargs, retval));}#endifintmmap(p, uap, retval)	struct proc *p;	register struct mmap_args *uap;	int *retval;{	register struct filedesc *fdp = p->p_fd;	register struct file *fp;	struct vnode *vp;	vm_offset_t addr;	vm_size_t size;	vm_prot_t prot, maxprot;	caddr_t handle;	int flags, error;	prot = uap->prot & VM_PROT_ALL;	flags = uap->flags;#ifdef DEBUG	if (mmapdebug & MDB_FOLLOW)		printf("mmap(%d): addr %x len %x pro %x flg %x fd %d pos %x\n",		       p->p_pid, uap->addr, uap->len, prot,		       flags, uap->fd, (vm_offset_t)uap->pos);#endif	/*	 * Address (if FIXED) must be page aligned.	 * Size is implicitly rounded to a page boundary.	 */	addr = (vm_offset_t) uap->addr;	if (((flags & MAP_FIXED) && (addr & PAGE_MASK)) ||	    (ssize_t)uap->len < 0 || ((flags & MAP_ANON) && uap->fd != -1))		return (EINVAL);	size = (vm_size_t) round_page(uap->len);	/*	 * Check for illegal addresses.  Watch out for address wrap...	 * Note that VM_*_ADDRESS are not constants due to casts (argh).	 */	if (flags & MAP_FIXED) {		if (VM_MAXUSER_ADDRESS > 0 && addr + size >= VM_MAXUSER_ADDRESS)			return (EINVAL);		if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS)			return (EINVAL);		if (addr > addr + size)			return (EINVAL);	}	/*	 * XXX if no hint provided for a non-fixed mapping place it after	 * the end of the largest possible heap.	 *	 * There should really be a pmap call to determine a reasonable	 * location.	 */	if (addr == 0 && (flags & MAP_FIXED) == 0)		addr = round_page(p->p_vmspace->vm_daddr + MAXDSIZ);	if (flags & MAP_ANON) {		/*		 * Mapping blank space is trivial.		 */		handle = NULL;		maxprot = VM_PROT_ALL;	} else {		/*		 * Mapping file, get fp for validation.		 * Obtain vnode and make sure it is of appropriate type.		 */		if (((unsigned)uap->fd) >= fdp->fd_nfiles ||		    (fp = fdp->fd_ofiles[uap->fd]) == NULL)			return (EBADF);		if (fp->f_type != DTYPE_VNODE)			return (EINVAL);		vp = (struct vnode *)fp->f_data;		if (vp->v_type != VREG && vp->v_type != VCHR)			return (EINVAL);		/*		 * XXX hack to handle use of /dev/zero to map anon		 * memory (ala SunOS).		 */		if (vp->v_type == VCHR && iszerodev(vp->v_rdev)) {			handle = NULL;			maxprot = VM_PROT_ALL;			flags |= MAP_ANON;		} else {			/*			 * Ensure that file and memory protections are			 * compatible.  Note that we only worry about			 * writability if mapping is shared; in this case,			 * current and max prot are dictated by the open file.			 * XXX use the vnode instead?  Problem is: what			 * credentials do we use for determination?			 * What if proc does a setuid?			 */			maxprot = VM_PROT_EXECUTE;	/* ??? */			if (fp->f_flag & FREAD)				maxprot |= VM_PROT_READ;			else if (prot & PROT_READ)				return (EACCES);			if (flags & MAP_SHARED) {				if (fp->f_flag & FWRITE)					maxprot |= VM_PROT_WRITE;				else if (prot & PROT_WRITE)					return (EACCES);			} else				maxprot |= VM_PROT_WRITE;			handle = (caddr_t)vp;		}	}	error = vm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot,	    flags, handle, (vm_offset_t)uap->pos);	if (error == 0)		*retval = (int)addr;	return (error);}struct msync_args {	caddr_t	addr;	int	len;};intmsync(p, uap, retval)	struct proc *p;	struct msync_args *uap;	int *retval;{	vm_offset_t addr;	vm_size_t size;	vm_map_t map;	int rv;	boolean_t syncio, invalidate;#ifdef DEBUG	if (mmapdebug & (MDB_FOLLOW|MDB_SYNC))		printf("msync(%d): addr %x len %x\n",		       p->p_pid, uap->addr, uap->len);#endif	if (((int)uap->addr & PAGE_MASK) || uap->addr + uap->len < uap->addr)		return (EINVAL);	map = &p->p_vmspace->vm_map;	addr = (vm_offset_t)uap->addr;	size = (vm_size_t)uap->len;	/*	 * XXX Gak!  If size is zero we are supposed to sync "all modified	 * pages with the region containing addr".  Unfortunately, we	 * don't really keep track of individual mmaps so we approximate	 * by flushing the range of the map entry containing addr.	 * This can be incorrect if the region splits or is coalesced	 * with a neighbor.	 */	if (size == 0) {		vm_map_entry_t entry;		vm_map_lock_read(map);		rv = vm_map_lookup_entry(map, addr, &entry);		vm_map_unlock_read(map);		if (rv)			return (EINVAL);		addr = entry->start;		size = entry->end - entry->start;	}#ifdef DEBUG	if (mmapdebug & MDB_SYNC)		printf("msync: cleaning/flushing address range [%x-%x)\n",		       addr, addr+size);#endif	/*	 * Could pass this in as a third flag argument to implement	 * Sun's MS_ASYNC.	 */	syncio = TRUE;	/*	 * XXX bummer, gotta flush all cached pages to ensure	 * consistency with the file system cache.  Otherwise, we could	 * pass this in to implement Sun's MS_INVALIDATE.	 */	invalidate = TRUE;	/*	 * Clean the pages and interpret the return value.	 */	rv = vm_map_clean(map, addr, addr+size, syncio, invalidate);	switch (rv) {	case KERN_SUCCESS:		break;	case KERN_INVALID_ADDRESS:		return (EINVAL);	/* Sun returns ENOMEM? */	case KERN_FAILURE:		return (EIO);	default:		return (EINVAL);	}	return (0);}struct munmap_args {	caddr_t	addr;	int	len;};intmunmap(p, uap, retval)	register struct proc *p;	register struct munmap_args *uap;	int *retval;{	vm_offset_t addr;	vm_size_t size;	vm_map_t map;#ifdef DEBUG	if (mmapdebug & MDB_FOLLOW)		printf("munmap(%d): addr %x len %x\n",		       p->p_pid, uap->addr, uap->len);#endif	addr = (vm_offset_t) uap->addr;	if ((addr & PAGE_MASK) || uap->len < 0)		return(EINVAL);	size = (vm_size_t) round_page(uap->len);	if (size == 0)		return(0);	/*	 * Check for illegal addresses.  Watch out for address wrap...	 * Note that VM_*_ADDRESS are not constants due to casts (argh).	 */	if (VM_MAXUSER_ADDRESS > 0 && addr + size >= VM_MAXUSER_ADDRESS)		return (EINVAL);	if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS)		return (EINVAL);	if (addr > addr + size)		return (EINVAL);	map = &p->p_vmspace->vm_map;	/*	 * Make sure entire range is allocated.	 */	if (!vm_map_check_protection(map, addr, addr + size, VM_PROT_NONE))		return(EINVAL);	/* returns nothing but KERN_SUCCESS anyway */	(void) vm_map_remove(map, addr, addr+size);	return(0);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?