/*- * Copyright (c) 2011 Advanced Computing Technologies LLC * Written by: John H. Baldwin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Simple driver to demonstrate the d_mmap_single() method as well as * the cdevpriv(9) API. It provides a simple shared memory file * descriptor similar to shm_open() with SHM_ANON. */ #include #include #include #include #include #include #include #include #include #include #include static d_open_t memfd_open; static d_mmap_single_t memfd_mmap_single; static void memfd_dtor(void *); static struct cdevsw memfd_cdevsw = { .d_version = D_VERSION, .d_open = memfd_open, .d_mmap_single = memfd_mmap_single, .d_name = "memfd", }; static int memfd_open(struct cdev *cdev, int oflags, int devtype, struct thread *td) { vm_object_t mem; int error; /* Read-only and write-only opens make no sense. */ if ((oflags & (FREAD | FWRITE)) != (FREAD | FWRITE)) return (EINVAL); /* Create a default VM object for each open file descriptor. */ mem = vm_pager_allocate(OBJT_DEFAULT, NULL, 0, VM_PROT_DEFAULT, 0, curthread->td_ucred); VM_OBJECT_LOCK(mem); vm_object_clear_flag(mem, OBJ_ONEMAPPING); vm_object_set_flag(mem, OBJ_NOSPLIT); VM_OBJECT_UNLOCK(mem); error = devfs_set_cdevpriv(mem, memfd_dtor); if (error != 0) vm_object_deallocate(mem); return (error); } static int memfd_mmap_single(struct cdev *cdev, vm_ooffset_t *offset, vm_size_t size, vm_object_t *object, int nprot) { vm_object_t mem; vm_pindex_t objsize; vm_ooffset_t delta; int error; error = devfs_get_cdevpriv((void **)&mem); if (error != 0) return (error); /* Grow object if necessary. */ objsize = OFF_TO_IDX(*offset + size + PAGE_MASK); VM_OBJECT_LOCK(mem); if (objsize > mem->size) { /* Attempt to reserve swap space. */ delta = ptoa(objsize - mem->size); if (!swap_reserve_by_cred(delta, mem->cred)) { VM_OBJECT_UNLOCK(mem); return (ENOMEM); } mem->charge += delta; mem->size = objsize; } vm_object_reference_locked(mem); *object = mem; VM_OBJECT_UNLOCK(mem); return (0); } static void memfd_dtor(void *arg) { vm_object_t mem; mem = arg; vm_object_deallocate(mem); } static int memfd_modevent(module_t mod, int type, void *arg) { static struct cdev *memfd; switch (type) { case MOD_LOAD: memfd = make_dev(&memfd_cdevsw, 0, UID_ROOT, GID_WHEEL, 0666, "memfd"); if (memfd == NULL) { printf("memfd: Failed to create /dev/memfd\n"); return (ENXIO); } break; case MOD_UNLOAD: if (memfd != NULL) destroy_dev(memfd); break; case MOD_SHUTDOWN: break; default: return (EOPNOTSUPP); } return (0); } DEV_MODULE(memfd, memfd_modevent, NULL);