void *handle;
caddr_t handle;
sys_mmap(p, v, retval)	struct proc *p;	void *v;	register_t *retval;{	struct sys_mmap_args /* {		syscallarg(caddr_t) addr;		syscallarg(size_t) len;		syscallarg(int) prot;		syscallarg(int) flags;		syscallarg(int) fd;		syscallarg(long) pad;		syscallarg(off_t) pos;	} */ *uap = v;	vaddr_t addr;	struct vattr va;	off_t pos;	vsize_t size, pageoff;	vm_prot_t prot, maxprot;	int flags, fd;	vaddr_t vm_min_address = VM_MIN_ADDRESS;	struct filedesc *fdp = p->p_fd;	struct file *fp;	struct vnode *vp;	void *handle;	int error;	/*	 * first, extract syscall args from the uap.	 */	addr = (vaddr_t)SCARG(uap, addr);	size = (vsize_t)SCARG(uap, len);	prot = SCARG(uap, prot) & VM_PROT_ALL;	flags = SCARG(uap, flags);	fd = SCARG(uap, fd);	pos = SCARG(uap, pos);	/*	 * Fixup the old deprecated MAP_COPY into MAP_PRIVATE, and	 * validate the flags.	 */	if (flags & MAP_COPY)		flags = (flags & ~MAP_COPY) | MAP_PRIVATE;	if ((flags & (MAP_SHARED|MAP_PRIVATE)) == (MAP_SHARED|MAP_PRIVATE))		return (EINVAL);	/*	 * align file position and save offset.  adjust size.	 */	pageoff = (pos & PAGE_MASK);	pos  -= pageoff;	size += pageoff;			/* add offset */	size = (vsize_t)round_page(size);	/* round up */	if ((ssize_t) size < 0)		return (EINVAL);			/* don't allow wrap */	/*	 * now check (MAP_FIXED) or get (!MAP_FIXED) the "addr"	 */	if (flags & MAP_FIXED) {		/* ensure address and file offset are aligned properly */		addr -= pageoff;		if (addr & PAGE_MASK)			return (EINVAL);		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);		/* no wrapping! */	} else {		/*		 * not fixed: make sure we skip over the largest possible heap.		 * we will refine our guess later (e.g. to account for VAC, etc)		 */		addr = MAX(addr, round_page((vaddr_t)p->p_vmspace->vm_daddr +					    MAXDSIZ));	}	/*	 * check for file mappings (i.e. not anonymous) and verify file.	 */	if ((flags & MAP_ANON) == 0) {		if ((fp = fd_getfile(fdp, fd)) == NULL)			return(EBADF);		if (fp->f_type != DTYPE_VNODE)			return (ENODEV);		/* only mmap vnodes! */		vp = (struct vnode *)fp->f_data;	/* convert to vnode */		if (vp->v_type != VREG && vp->v_type != VCHR &&		    vp->v_type != VBLK)			return (ENODEV);  /* only REG/CHR/BLK support mmap */		if (vp->v_type == VREG && (pos + size) < pos)			return (EINVAL);		/* no offset wrapping */		/* special case: catch SunOS style /dev/zero */		if (vp->v_type == VCHR && iszerodev(vp->v_rdev)) {			flags |= MAP_ANON;			goto is_anon;		}		/*		 * Old programs may not select a specific sharing type, so		 * default to an appropriate one.		 *		 * XXX: how does MAP_ANON fit in the picture?		 */		if ((flags & (MAP_SHARED|MAP_PRIVATE)) == 0) {#if defined(DEBUG)			printf("WARNING: defaulted mmap() share type to "			   "%s (pid %d comm %s)\n", vp->v_type == VCHR ?			   "MAP_SHARED" : "MAP_PRIVATE", p->p_pid,			    p->p_comm);#endif			if (vp->v_type == VCHR)				flags |= MAP_SHARED;	/* for a device */			else				flags |= MAP_PRIVATE;	/* for a file */		}		/*		 * MAP_PRIVATE device mappings don't make sense (and aren't		 * supported anyway).  However, some programs rely on this,		 * so just change it to MAP_SHARED.		 */		if (vp->v_type == VCHR && (flags & MAP_PRIVATE) != 0) {			flags = (flags & ~MAP_PRIVATE) | MAP_SHARED;		}		/*		 * now check protection		 */		maxprot = VM_PROT_EXECUTE;		/* check read access */		if (fp->f_flag & FREAD)			maxprot |= VM_PROT_READ;		else if (prot & PROT_READ)			return (EACCES);		/* check write access, shared case first */		if (flags & MAP_SHARED) {			/*			 * if the file is writable, only add PROT_WRITE to			 * maxprot if the file is not immutable, append-only.			 * otherwise, if we have asked for PROT_WRITE, return			 * EPERM.			 */			if (fp->f_flag & FWRITE) {				if ((error =				    VOP_GETATTR(vp, &va, p->p_ucred, p)))					return (error);				if ((va.va_flags & (IMMUTABLE|APPEND)) == 0)					maxprot |= VM_PROT_WRITE;				else if (prot & PROT_WRITE)					return (EPERM);			}			else if (prot & PROT_WRITE)				return (EACCES);		} else {			/* MAP_PRIVATE mappings can always write to */			maxprot |= VM_PROT_WRITE;		}		handle = vp;	} else {		/* MAP_ANON case */		/*		 * XXX What do we do about (MAP_SHARED|MAP_PRIVATE) == 0?		 */		if (fd != -1)			return (EINVAL); is_anon:		/* label for SunOS style /dev/zero */		handle = NULL;		maxprot = VM_PROT_ALL;		pos = 0;	}	/*	 * XXX (in)sanity check.  We don't do proper datasize checking	 * XXX for anonymous (or private writable) mmap().  However,	 * XXX know that if we're trying to allocate more than the amount	 * XXX remaining under our current data size limit, _that_ should	 * XXX be disallowed.	 */	if ((flags & MAP_ANON) != 0 ||	    ((flags & MAP_PRIVATE) != 0 && (prot & PROT_WRITE) != 0)) {		if (size >		    (p->p_rlimit[RLIMIT_DATA].rlim_cur -		     ctob(p->p_vmspace->vm_dsize))) {			return (ENOMEM);		}	}	/*	 * now let kernel internal function uvm_mmap do the work.	 */	error = uvm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot,	    flags, handle, pos, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);	if (error == 0)		/* remember to add offset */		*retval = (register_t)(addr + pageoff);	return (error);}