From owner-svn-src-stable@FreeBSD.ORG Thu Sep 3 14:23:51 2009 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 7DA3A106566C; Thu, 3 Sep 2009 14:23:51 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 6B03F8FC19; Thu, 3 Sep 2009 14:23:51 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n83ENpso035319; Thu, 3 Sep 2009 14:23:51 GMT (envelope-from jhb@svn.freebsd.org) Received: (from jhb@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n83ENpUW035318; Thu, 3 Sep 2009 14:23:51 GMT (envelope-from jhb@svn.freebsd.org) Message-Id: <200909031423.n83ENpUW035318@svn.freebsd.org> From: John Baldwin Date: Thu, 3 Sep 2009 14:23:51 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r196782 - in stable/7/sys: . contrib/pf kern sys vm X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 03 Sep 2009 14:23:51 -0000 Author: jhb Date: Thu Sep 3 14:23:50 2009 New Revision: 196782 URL: http://svn.freebsd.org/changeset/base/196782 Log: MFC 193275 and 194989: Add an extension to the character device interface that allows character device drivers to use arbitrary VM objects to satisfy individual mmap() requests. - A new d_mmap_single(cdev, &foff, objsize, &object, prot) callback is added to cdevsw. This function is called for each mmap() request. If it returns ENODEV, then the mmap() request will fall back to using the device's device pager object and d_mmap(). Otherwise, the method can return a VM object to satisfy this entire mmap() request via *object. It can also modify the starting offset into this object via *foff. This allows device drivers to use the file offset as a cookie to identify specific VM objects. - vm_mmap_vnode() has been changed to call vm_mmap_cdev() directly when mapping V_CHR vnodes. This avoids duplicating all the cdev mmap handling code and simplifies some of vm_mmap_vnode(). - D_VERSION has been bumped to D_VERSION_02. Older device drivers using D_VERSION_01 are still supported. Modified: stable/7/sys/ (props changed) stable/7/sys/contrib/pf/ (props changed) stable/7/sys/kern/kern_conf.c stable/7/sys/sys/conf.h stable/7/sys/vm/vm_mmap.c Modified: stable/7/sys/kern/kern_conf.c ============================================================================== --- stable/7/sys/kern/kern_conf.c Thu Sep 3 13:56:18 2009 (r196781) +++ stable/7/sys/kern/kern_conf.c Thu Sep 3 14:23:50 2009 (r196782) @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage"); @@ -276,6 +277,7 @@ dead_strategy(struct bio *bp) #define dead_dump (dumper_t *)enxio #define dead_kqfilter (d_kqfilter_t *)enxio +#define dead_mmap_single (d_mmap_single_t *)enodev static struct cdevsw dead_cdevsw = { .d_version = D_VERSION, @@ -290,7 +292,8 @@ static struct cdevsw dead_cdevsw = { .d_strategy = dead_strategy, .d_name = "dead", .d_dump = dead_dump, - .d_kqfilter = dead_kqfilter + .d_kqfilter = dead_kqfilter, + .d_mmap_single = dead_mmap_single }; /* Default methods if driver does not specify method */ @@ -302,6 +305,7 @@ static struct cdevsw dead_cdevsw = { #define no_ioctl (d_ioctl_t *)enodev #define no_mmap (d_mmap_t *)enodev #define no_kqfilter (d_kqfilter_t *)enodev +#define no_mmap_single (d_mmap_single_t *)enodev static void no_strategy(struct bio *bp) @@ -481,6 +485,23 @@ giant_mmap(struct cdev *dev, vm_offset_t return (retval); } +static int +giant_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size, + vm_object_t *object, int nprot) +{ + struct cdevsw *dsw; + int retval; + + dsw = dev_refthread(dev); + if (dsw == NULL) + return (ENXIO); + mtx_lock(&Giant); + retval = dsw->d_gianttrick->d_mmap_single(dev, offset, size, object, + nprot); + mtx_unlock(&Giant); + dev_relthread(dev); + return (retval); +} /* * struct cdev * and u_dev_t primitives @@ -616,7 +637,8 @@ prep_cdevsw(struct cdevsw *devsw) return; } - if (devsw->d_version != D_VERSION_01) { + if (devsw->d_version != D_VERSION_01 && + devsw->d_version != D_VERSION_02) { printf( "WARNING: Device driver \"%s\" has wrong version %s\n", devsw->d_name == NULL ? "???" : devsw->d_name, @@ -632,6 +654,8 @@ prep_cdevsw(struct cdevsw *devsw) devsw->d_dump = dead_dump; devsw->d_kqfilter = dead_kqfilter; } + if (devsw->d_version == D_VERSION_01) + devsw->d_mmap_single = NULL; if (devsw->d_flags & D_TTY) { if (devsw->d_ioctl == NULL) devsw->d_ioctl = ttyioctl; @@ -668,6 +692,7 @@ prep_cdevsw(struct cdevsw *devsw) FIXUP(d_mmap, no_mmap, giant_mmap); FIXUP(d_strategy, no_strategy, giant_strategy); FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter); + FIXUP(d_mmap_single, no_mmap_single, giant_mmap_single); if (devsw->d_dump == NULL) devsw->d_dump = no_dump; Modified: stable/7/sys/sys/conf.h ============================================================================== --- stable/7/sys/sys/conf.h Thu Sep 3 13:56:18 2009 (r196781) +++ stable/7/sys/sys/conf.h Thu Sep 3 14:23:50 2009 (r196782) @@ -106,6 +106,7 @@ struct thread; struct uio; struct knote; struct clonedevs; +struct vm_object; struct vnode; /* @@ -139,10 +140,10 @@ typedef int d_poll_t(struct cdev *dev, i typedef int d_kqfilter_t(struct cdev *dev, struct knote *kn); typedef int d_mmap_t(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot); +typedef int d_mmap_single_t(struct cdev *cdev, vm_ooffset_t *offset, + vm_size_t size, struct vm_object **object, int nprot); typedef void d_purge_t(struct cdev *dev); -typedef int d_spare2_t(struct cdev *dev); - typedef int dumper_t( void *priv, /* Private to the driver. */ void *virtual, /* Virtual (mapped) address. */ @@ -177,7 +178,8 @@ typedef int dumper_t( */ #define D_VERSION_00 0x20011966 #define D_VERSION_01 0x17032005 /* Add d_uid,gid,mode & kind */ -#define D_VERSION D_VERSION_01 +#define D_VERSION_02 0x28042009 /* Add d_mmap_single */ +#define D_VERSION D_VERSION_02 /* * Flags used for internal housekeeping @@ -203,7 +205,7 @@ struct cdevsw { dumper_t *d_dump; d_kqfilter_t *d_kqfilter; d_purge_t *d_purge; - d_spare2_t *d_spare2; + d_mmap_single_t *d_mmap_single; uid_t d_uid; gid_t d_gid; mode_t d_mode; Modified: stable/7/sys/vm/vm_mmap.c ============================================================================== --- stable/7/sys/vm/vm_mmap.c Thu Sep 3 13:56:18 2009 (r196781) +++ stable/7/sys/vm/vm_mmap.c Thu Sep 3 14:23:50 2009 (r196782) @@ -116,9 +116,9 @@ vmmapentry_rsrc_init(dummy) } static int vm_mmap_vnode(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *, - int *, struct vnode *, vm_ooffset_t, vm_object_t *); + int *, struct vnode *, vm_ooffset_t *, vm_object_t *); static int vm_mmap_cdev(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *, - int *, struct cdev *, vm_ooffset_t, vm_object_t *); + int *, struct cdev *, vm_ooffset_t *, vm_object_t *); /* * MPSAFE @@ -1132,14 +1132,13 @@ munlock(td, uap) int vm_mmap_vnode(struct thread *td, vm_size_t objsize, vm_prot_t prot, vm_prot_t *maxprotp, int *flagsp, - struct vnode *vp, vm_ooffset_t foff, vm_object_t *objp) + struct vnode *vp, vm_ooffset_t *foffp, vm_object_t *objp) { struct vattr va; - void *handle; vm_object_t obj; + vm_offset_t foff; struct mount *mp; - struct cdevsw *dsw; - int error, flags, type; + int error, flags; int vfslocked; mp = vp->v_mount; @@ -1148,6 +1147,7 @@ vm_mmap_vnode(struct thread *td, vm_size VFS_UNLOCK_GIANT(vfslocked); return (error); } + foff = *foffp; flags = *flagsp; obj = vp->v_object; if (vp->v_type == VREG) { @@ -1163,41 +1163,12 @@ vm_mmap_vnode(struct thread *td, vm_size vp = (struct vnode*)obj->handle; vget(vp, LK_EXCLUSIVE, td); } - type = OBJT_VNODE; - handle = vp; } else if (vp->v_type == VCHR) { - type = OBJT_DEVICE; - handle = vp->v_rdev; - - dsw = dev_refthread(handle); - if (dsw == NULL) { - error = ENXIO; - goto done; - } - if (dsw->d_flags & D_MMAP_ANON) { - dev_relthread(handle); - *maxprotp = VM_PROT_ALL; - *flagsp |= MAP_ANON; - error = 0; - goto done; - } - dev_relthread(handle); - /* - * cdevs does not provide private mappings of any kind. - */ - if ((*maxprotp & VM_PROT_WRITE) == 0 && - (prot & PROT_WRITE) != 0) { - error = EACCES; - goto done; - } - if (flags & (MAP_PRIVATE|MAP_COPY)) { - error = EINVAL; - goto done; - } - /* - * Force device mappings to be shared. - */ - flags |= MAP_SHARED; + error = vm_mmap_cdev(td, objsize, prot, maxprotp, flagsp, + vp->v_rdev, foffp, objp); + if (error == 0) + goto mark_atime; + goto done; } else { error = EINVAL; goto done; @@ -1224,18 +1195,18 @@ vm_mmap_vnode(struct thread *td, vm_size * we do not need to sync it. * Adjust object size to be the size of actual file. */ - if (vp->v_type == VREG) { - objsize = round_page(va.va_size); - if (va.va_nlink == 0) - flags |= MAP_NOSYNC; - } - obj = vm_pager_allocate(type, handle, objsize, prot, foff); + objsize = round_page(va.va_size); + if (va.va_nlink == 0) + flags |= MAP_NOSYNC; + obj = vm_pager_allocate(OBJT_VNODE, vp, objsize, prot, foff); if (obj == NULL) { - error = (type == OBJT_DEVICE ? EINVAL : ENOMEM); + error = ENOMEM; goto done; } *objp = obj; *flagsp = flags; + +mark_atime: vfs_mark_atime(vp, td); done: @@ -1255,11 +1226,11 @@ done: int vm_mmap_cdev(struct thread *td, vm_size_t objsize, vm_prot_t prot, vm_prot_t *maxprotp, int *flagsp, - struct cdev *cdev, vm_ooffset_t foff, vm_object_t *objp) + struct cdev *cdev, vm_ooffset_t *foff, vm_object_t *objp) { vm_object_t obj; struct cdevsw *dsw; - int flags; + int error, flags; flags = *flagsp; @@ -1272,25 +1243,43 @@ vm_mmap_cdev(struct thread *td, vm_size_ *flagsp |= MAP_ANON; return (0); } - dev_relthread(cdev); /* - * cdevs does not provide private mappings of any kind. + * cdevs do not provide private mappings of any kind. */ if ((*maxprotp & VM_PROT_WRITE) == 0 && - (prot & PROT_WRITE) != 0) + (prot & PROT_WRITE) != 0) { + dev_relthread(cdev); return (EACCES); - if (flags & (MAP_PRIVATE|MAP_COPY)) + } + if (flags & (MAP_PRIVATE|MAP_COPY)) { + dev_relthread(cdev); return (EINVAL); + } /* * Force device mappings to be shared. */ flags |= MAP_SHARED; #ifdef MAC_XXX - error = mac_check_cdev_mmap(td->td_ucred, cdev, prot); - if (error != 0) + error = mac_cdev_check_mmap(td->td_ucred, cdev, prot); + if (error != 0) { + dev_relthread(cdev); return (error); + } #endif - obj = vm_pager_allocate(OBJT_DEVICE, cdev, objsize, prot, foff); + /* + * First, try d_mmap_single(). If that is not implemented + * (returns ENODEV), fall back to using the device pager. + * Note that d_mmap_single() must return a reference to the + * object (it needs to bump the reference count of the object + * it returns somehow). + * + * XXX assumes VM_PROT_* == PROT_* + */ + error = dsw->d_mmap_single(cdev, foff, objsize, objp, (int)prot); + dev_relthread(cdev); + if (error != ENODEV) + return (error); + obj = vm_pager_allocate(OBJT_DEVICE, cdev, objsize, prot, *foff); if (obj == NULL) return (EINVAL); *objp = obj; @@ -1356,11 +1345,11 @@ vm_mmap(vm_map_t map, vm_offset_t *addr, switch (handle_type) { case OBJT_DEVICE: error = vm_mmap_cdev(td, size, prot, &maxprot, &flags, - handle, foff, &object); + handle, &foff, &object); break; case OBJT_VNODE: error = vm_mmap_vnode(td, size, prot, &maxprot, &flags, - handle, foff, &object); + handle, &foff, &object); break; case OBJT_DEFAULT: if (handle == NULL) {