Index: kern/uipc_shm.c =================================================================== --- kern/uipc_shm.c (.../mirror/FreeBSD/stable/8/sys) (revision 224114) +++ kern/uipc_shm.c (.../stable/8/sys) (revision 224114) @@ -82,6 +82,7 @@ #include #include #include +#include #include #include #include @@ -255,6 +256,15 @@ VM_OBJECT_UNLOCK(object); return (0); } + + /* + * Disallow any size changes if this object is mapped into the + * kernel. + */; + if (shmfd->shm_kmappings > 0) { + VM_OBJECT_UNLOCK(object); + return (EBUSY); + } nobjsize = OFF_TO_IDX(length + PAGE_MASK); /* Are we shrinking? If so, trim the end. */ @@ -642,3 +652,95 @@ *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, vm_size_t size, vm_ooffset_t foff, 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 (foff >= shmfd->shm_size || + foff + 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 = foff & PAGE_MASK; + foff = trunc_page(foff); + size = round_page(size + ofs); + rv = vm_map_find(kernel_map, obj, foff, &kva, size, TRUE, + 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); + + switch (rv) { + case KERN_INVALID_ADDRESS: + case KERN_NO_SPACE: + return (ENOMEM); + case KERN_PROTECTION_FAILURE: + return (EACCES); + default: + return (EINVAL); + } +} + +/* + * XXX: We have no good way to verify that this mapping actually belongs to + * this file descriptor and its backing vm object. + */ +int +shm_unmap(struct file *fp, void *mem, vm_size_t size) +{ + struct shmfd *shmfd; + vm_offset_t kva, ofs; + vm_object_t obj; + + if (fp->f_type != DTYPE_SHM) + return (EINVAL); + shmfd = fp->f_data; + obj = shmfd->shm_object; + kva = (vm_offset_t)mem; + ofs = kva & PAGE_MASK; + kva = trunc_page(kva); + size = round_page(size + ofs); + vm_map_remove(kernel_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); +} Index: sys/mman.h =================================================================== --- sys/mman.h (.../mirror/FreeBSD/stable/8/sys) (revision 224114) +++ sys/mman.h (.../stable/8/sys) (revision 224114) @@ -177,6 +177,8 @@ #ifdef _KERNEL #include +struct file; + struct shmfd { size_t shm_size; vm_object_t shm_object; @@ -184,6 +186,7 @@ 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 @@ -199,7 +202,10 @@ int shm_mmap(struct shmfd *shmfd, vm_size_t objsize, vm_ooffset_t foff, vm_object_t *obj); +int shm_map(struct file *fp, vm_size_t size, vm_ooffset_t foff, void **memp); +int shm_unmap(struct file *fp, void *mem, vm_size_t size); + #else /* !_KERNEL */ __BEGIN_DECLS