Author: jhb
Date: Wed Jun  6 16:01:45 2012
New Revision: 236684
URL: http://svn.freebsd.org/changeset/base/236684

Log:
  MFC 228509,228620,228533:
  Add a helper API to allow in-kernel code to map portions of shared memory
  objects created by shm_open(2) into the kernel's address space.  This
  provides a convenient way for creating shared memory buffers between
  userland and the kernel without requiring custom character devices.

Added:
  stable/8/share/man/man9/shm_map.9
     - copied, changed from r228509, head/share/man/man9/shm_map.9
Modified:
  stable/8/share/man/man9/Makefile
  stable/8/sys/kern/uipc_shm.c
  stable/8/sys/sys/mman.h
Directory Properties:
  stable/8/share/man/man9/   (props changed)
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/boot/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/e1000/   (props changed)

Modified: stable/8/share/man/man9/Makefile
==============================================================================
--- stable/8/share/man/man9/Makefile    Wed Jun  6 16:00:31 2012        
(r236683)
+++ stable/8/share/man/man9/Makefile    Wed Jun  6 16:01:45 2012        
(r236684)
@@ -237,6 +237,7 @@ MAN=        accept_filter.9 \
        sema.9 \
        sf_buf.9 \
        sglist.9 \
+       shm_map.9 \
        signal.9 \
        sleep.9 \
        sleepqueue.9 \
@@ -1117,6 +1118,7 @@ MLINKS+=sglist.9 sglist_alloc.9 \
        sglist.9 sglist_reset.9 \
        sglist.9 sglist_slice.9 \
        sglist.9 sglist_split.9
+MLINKS+=shm_map.9 shm_unmap.9
 MLINKS+=signal.9 cursig.9 \
        signal.9 execsigs.9 \
        signal.9 issignal.9 \

Copied and modified: stable/8/share/man/man9/shm_map.9 (from r228509, 
head/share/man/man9/shm_map.9)
==============================================================================
--- head/share/man/man9/shm_map.9       Wed Dec 14 22:22:19 2011        
(r228509, copy source)
+++ stable/8/share/man/man9/shm_map.9   Wed Jun  6 16:01:45 2012        
(r236684)
@@ -30,9 +30,8 @@
 .Dt SHM_MAP 9
 .Os
 .Sh NAME
-.Nm shm_map ,
-.Nm shm_unmap
-.Nd map shared memory objects into the kernel's address space
+.Nm shm_map , shm_unmap
+.Nd "map shared memory objects into the kernel's address space"
 .Sh SYNOPSIS
 .In sys/types.h
 .In sys/mman.h
@@ -42,9 +41,9 @@
 .Fn shm_unmap "struct file *fp" "void *mem" "size_t size"
 .Sh DESCRIPTION
 The
-.Nm shm_map
+.Fn shm_map
 and
-.Nm shm_unmap
+.Fn shm_unmap
 functions provide an API for mapping shared memory objects into the kernel.
 Shared memory objects are created by
 .Xr shm_open 2 .
@@ -57,13 +56,13 @@ Shared memory objects can still be grown
 .Pp
 To simplify the accounting needed to enforce the above requirement,
 callers of this API are required to unmap the entire region mapped by
-.Nm shm_map
+.Fn shm_map
 when calling
-.Nm shm_unmap .
+.Fn shm_unmap .
 Unmapping only a portion of the region is not permitted.
 .Pp
 The
-.Nm shm_map
+.Fn shm_map
 function locates the shared memory object associated with the open file
 .Fa fp .
 It maps the region of that object described by
@@ -77,9 +76,9 @@ will be set to the start of the mapping.
 All pages for the range will be wired into memory upon successful return.
 .Pp
 The
-.Nm shm_unmap
+.Fn shm_unmap
 function unmaps a region previously mapped by
-.Nm shm_map .
+.Fn shm_map .
 The
 .Fa mem
 argument should match the value previously returned in
@@ -87,22 +86,22 @@ argument should match the value previous
 and the
 .Fa size
 argument should match the value passed to
-.Nm shm_map .
+.Fn shm_map .
 .Pp
 Note that
-.Nm shm_map
+.Fn shm_map
 will not hold an extra reference on the open file
 .Fa fp
 for the lifetime of the mapping.
 Instead,
 the calling code is required to do this if it wishes to use
-.Nm shm_unmap
+.Fn shm_unmap
 on the region in the future.
 .Sh RETURN VALUES
 The
-.Nm shm_map
+.Fn shm_map
 and
-.Nm shm_unmap
+.Fn shm_unmap
 functions return zero on success or an error on failure.
 .Sh EXAMPLES
 The following function accepts a file descriptor for a shared memory
@@ -110,7 +109,7 @@ object.
 It maps the first sixteen kilobytes of the object into the kernel,
 performs some work on that address,
 and then unmaps the address before returning.
-.Bd -literal
+.Bd -literal -offset indent
 int
 shm_example(int fd)
 {
@@ -118,7 +117,7 @@ shm_example(int fd)
        void *mem;
        int error;
 
-       error = fget(curthread, fd, CAP_MMAP, &fp)
+       error = fget(curthread, fd, CAP_MMAP, &fp);
        if (error)
                return (error);
        error = shm_map(fp, 16384, 0, &mem);
@@ -136,7 +135,7 @@ shm_example(int fd)
 .Ed
 .Sh ERRORS
 The
-.Nm shm_map
+.Fn shm_map
 function returns the following errors on failure:
 .Bl -tag -width Er
 .It Bq Er EINVAL
@@ -158,7 +157,7 @@ The shared memory object could not be ma
 .El
 .Pp
 The
-.Nm shm_unmap
+.Fn shm_unmap
 function returns the following errors on failure:
 .Bl -tag -width Er
 .It Bq Er EINVAL

Modified: stable/8/sys/kern/uipc_shm.c
==============================================================================
--- stable/8/sys/kern/uipc_shm.c        Wed Jun  6 16:00:31 2012        
(r236683)
+++ stable/8/sys/kern/uipc_shm.c        Wed Jun  6 16:01:45 2012        
(r236684)
@@ -81,7 +81,9 @@ __FBSDID("$FreeBSD$");
 #include <vm/vm.h>
 #include <vm/vm_param.h>
 #include <vm/pmap.h>
+#include <vm/vm_extern.h>
 #include <vm/vm_map.h>
+#include <vm/vm_kern.h>
 #include <vm/vm_object.h>
 #include <vm/vm_page.h>
 #include <vm/vm_pager.h>
@@ -259,6 +261,14 @@ shm_dotruncate(struct shmfd *shmfd, off_
 
        /* Are we shrinking?  If so, trim the end. */
        if (length < shmfd->shm_size) {
+               /*
+                * Disallow any requests to shrink the size if this
+                * object is mapped into the kernel.
+                */
+               if (shmfd->shm_kmappings > 0) {
+                       VM_OBJECT_UNLOCK(object);
+                       return (EBUSY);
+               }
                delta = ptoa(object->size - nobjsize);
 
                /* Toss in memory pages. */
@@ -642,3 +652,105 @@ shm_mmap(struct shmfd *shmfd, vm_size_t 
        *obj = shmfd->shm_object;
        return (0);
 }
+
+/*
+ * Helper routines to allow the backing object of a shared memory file
+ * descriptor to be mapped in the kernel.
+ */
+int
+shm_map(struct file *fp, size_t size, off_t offset, void **memp)
+{
+       struct shmfd *shmfd;
+       vm_offset_t kva, ofs;
+       vm_object_t obj;
+       int rv;
+
+       if (fp->f_type != DTYPE_SHM)
+               return (EINVAL);
+       shmfd = fp->f_data;
+       obj = shmfd->shm_object;
+       VM_OBJECT_LOCK(obj);
+       /*
+        * XXXRW: This validation is probably insufficient, and subject to
+        * sign errors.  It should be fixed.
+        */
+       if (offset >= shmfd->shm_size ||
+           offset + size > round_page(shmfd->shm_size)) {
+               VM_OBJECT_UNLOCK(obj);
+               return (EINVAL);
+       }
+
+       shmfd->shm_kmappings++;
+       vm_object_reference_locked(obj);
+       VM_OBJECT_UNLOCK(obj);
+
+       /* Map the object into the kernel_map and wire it. */
+       kva = vm_map_min(kernel_map);
+       ofs = offset & PAGE_MASK;
+       offset = trunc_page(offset);
+       size = round_page(size + ofs);
+       rv = vm_map_find(kernel_map, obj, offset, &kva, size,
+           VMFS_ALIGNED_SPACE, VM_PROT_READ | VM_PROT_WRITE,
+           VM_PROT_READ | VM_PROT_WRITE, 0);
+       if (rv == KERN_SUCCESS) {
+               rv = vm_map_wire(kernel_map, kva, kva + size,
+                   VM_MAP_WIRE_SYSTEM | VM_MAP_WIRE_NOHOLES);
+               if (rv == KERN_SUCCESS) {
+                       *memp = (void *)(kva + ofs);
+                       return (0);
+               }
+               vm_map_remove(kernel_map, kva, kva + size);
+       } else
+               vm_object_deallocate(obj);
+
+       /* On failure, drop our mapping reference. */
+       VM_OBJECT_LOCK(obj);
+       shmfd->shm_kmappings--;
+       VM_OBJECT_UNLOCK(obj);
+
+       return (vm_mmap_to_errno(rv));
+}
+
+/*
+ * We require the caller to unmap the entire entry.  This allows us to
+ * safely decrement shm_kmappings when a mapping is removed.
+ */
+int
+shm_unmap(struct file *fp, void *mem, size_t size)
+{
+       struct shmfd *shmfd;
+       vm_map_entry_t entry;
+       vm_offset_t kva, ofs;
+       vm_object_t obj;
+       vm_pindex_t pindex;
+       vm_prot_t prot;
+       boolean_t wired;
+       vm_map_t map;
+       int rv;
+
+       if (fp->f_type != DTYPE_SHM)
+               return (EINVAL);
+       shmfd = fp->f_data;
+       kva = (vm_offset_t)mem;
+       ofs = kva & PAGE_MASK;
+       kva = trunc_page(kva);
+       size = round_page(size + ofs);
+       map = kernel_map;
+       rv = vm_map_lookup(&map, kva, VM_PROT_READ | VM_PROT_WRITE, &entry,
+           &obj, &pindex, &prot, &wired);
+       if (rv != KERN_SUCCESS)
+               return (EINVAL);
+       if (entry->start != kva || entry->end != kva + size) {
+               vm_map_lookup_done(map, entry);
+               return (EINVAL);
+       }
+       vm_map_lookup_done(map, entry);
+       if (obj != shmfd->shm_object)
+               return (EINVAL);
+       vm_map_remove(map, kva, kva + size);
+       VM_OBJECT_LOCK(obj);
+       KASSERT(shmfd->shm_kmappings > 0, ("shm_unmap: object not mapped"));
+       shmfd->shm_kmappings--;
+       VM_OBJECT_UNLOCK(obj);
+       return (0);
+}

Modified: stable/8/sys/sys/mman.h
==============================================================================
--- stable/8/sys/sys/mman.h     Wed Jun  6 16:00:31 2012        (r236683)
+++ stable/8/sys/sys/mman.h     Wed Jun  6 16:01:45 2012        (r236684)
@@ -181,6 +181,8 @@ typedef     __size_t        size_t;
 #ifdef _KERNEL
 #include <vm/vm.h>
 
+struct file;
+
 struct shmfd {
        size_t          shm_size;
        vm_object_t     shm_object;
@@ -188,6 +190,7 @@ struct shmfd {
        uid_t           shm_uid;
        gid_t           shm_gid;
        mode_t          shm_mode;
+       int             shm_kmappings;
 
        /*
         * Values maintained solely to make this a better-behaved file
@@ -203,6 +206,8 @@ struct shmfd {
 
 int    shm_mmap(struct shmfd *shmfd, vm_size_t objsize, vm_ooffset_t foff,
            vm_object_t *obj);
+int    shm_map(struct file *fp, size_t size, off_t offset, void **memp);
+int    shm_unmap(struct file *fp, void *mem, size_t size);
 
 #else /* !_KERNEL */
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to