svn commit: r236683 - in stable/9: share/man/man9 sys/kern sys/sys
John Baldwin
jhb at FreeBSD.org
Wed Jun 6 16:00:32 UTC 2012
Author: jhb
Date: Wed Jun 6 16:00:31 2012
New Revision: 236683
URL: http://svn.freebsd.org/changeset/base/236683
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/9/share/man/man9/shm_map.9
- copied, changed from r228509, head/share/man/man9/shm_map.9
Modified:
stable/9/share/man/man9/Makefile
stable/9/sys/kern/uipc_shm.c
stable/9/sys/sys/mman.h
Directory Properties:
stable/9/share/man/man9/ (props changed)
stable/9/sys/ (props changed)
stable/9/sys/amd64/include/xen/ (props changed)
stable/9/sys/boot/ (props changed)
stable/9/sys/boot/i386/efi/ (props changed)
stable/9/sys/boot/ia64/efi/ (props changed)
stable/9/sys/boot/ia64/ski/ (props changed)
stable/9/sys/boot/powerpc/boot1.chrp/ (props changed)
stable/9/sys/boot/powerpc/ofw/ (props changed)
stable/9/sys/cddl/contrib/opensolaris/ (props changed)
stable/9/sys/conf/ (props changed)
stable/9/sys/contrib/dev/acpica/ (props changed)
stable/9/sys/contrib/octeon-sdk/ (props changed)
stable/9/sys/contrib/pf/ (props changed)
stable/9/sys/contrib/x86emu/ (props changed)
stable/9/sys/dev/ (props changed)
stable/9/sys/dev/e1000/ (props changed)
stable/9/sys/dev/ixgbe/ (props changed)
stable/9/sys/fs/ (props changed)
stable/9/sys/fs/ntfs/ (props changed)
stable/9/sys/modules/ (props changed)
Modified: stable/9/share/man/man9/Makefile
==============================================================================
--- stable/9/share/man/man9/Makefile Wed Jun 6 15:29:27 2012 (r236682)
+++ stable/9/share/man/man9/Makefile Wed Jun 6 16:00:31 2012 (r236683)
@@ -237,6 +237,7 @@ MAN= accept_filter.9 \
sema.9 \
sf_buf.9 \
sglist.9 \
+ shm_map.9 \
signal.9 \
sleep.9 \
sleepqueue.9 \
@@ -1156,6 +1157,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/9/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/9/share/man/man9/shm_map.9 Wed Jun 6 16:00:31 2012 (r236683)
@@ -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/9/sys/kern/uipc_shm.c
==============================================================================
--- stable/9/sys/kern/uipc_shm.c Wed Jun 6 15:29:27 2012 (r236682)
+++ stable/9/sys/kern/uipc_shm.c Wed Jun 6 16:00:31 2012 (r236683)
@@ -74,7 +74,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_pageout.h>
@@ -260,6 +262,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);
+ }
/*
* Zero the truncated part of the last page.
@@ -732,3 +742,105 @@ out:
mtx_unlock(&shm_timestamp_lock);
return (error);
}
+
+/*
+ * 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/9/sys/sys/mman.h
==============================================================================
--- stable/9/sys/sys/mman.h Wed Jun 6 15:29:27 2012 (r236682)
+++ stable/9/sys/sys/mman.h Wed Jun 6 16:00:31 2012 (r236683)
@@ -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 */
More information about the svn-src-stable-9
mailing list