Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 6 Jun 2012 16:01:45 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r236684 - in stable/8: share/man/man9 sys/kern sys/sys
Message-ID:  <201206061601.q56G1jeN023951@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 */
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201206061601.q56G1jeN023951>