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>