uipc_shm.c revision 216128
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 2006 Robert N. M. Watson 31556Srgrimes * All rights reserved. 41556Srgrimes * 51556Srgrimes * Redistribution and use in source and binary forms, with or without 61556Srgrimes * modification, are permitted provided that the following conditions 71556Srgrimes * are met: 81556Srgrimes * 1. Redistributions of source code must retain the above copyright 91556Srgrimes * notice, this list of conditions and the following disclaimer. 101556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111556Srgrimes * notice, this list of conditions and the following disclaimer in the 121556Srgrimes * documentation and/or other materials provided with the distribution. 131556Srgrimes * 141556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 151556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 181556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241556Srgrimes * SUCH DAMAGE. 251556Srgrimes */ 261556Srgrimes 271556Srgrimes/* 281556Srgrimes * Support for shared swap-backed anonymous memory objects via 291556Srgrimes * shm_open(2) and shm_unlink(2). While most of the implementation is 301556Srgrimes * here, vm_mmap.c contains mapping logic changes. 311556Srgrimes * 321556Srgrimes * TODO: 331556Srgrimes * 3436150Scharnier * (2) Need to export data to a userland tool via a sysctl. Should ipcs(1) 3536150Scharnier * and ipcrm(1) be expanded or should new tools to manage both POSIX 3636150Scharnier * kernel semaphores and POSIX shared memory be written? 371556Srgrimes * 3899110Sobrien * (3) Add support for this file type to fstat(1). 3999110Sobrien * 401556Srgrimes * (4) Resource limits? Does this need its own resource limits or are the 41100437Stjr * existing limits in mmap(2) sufficient? 4217987Speter * 43102576Skeramida * (5) Partial page truncation. vnode_pager_setsize() will zero any parts 4417987Speter * of a partially mapped page as a result of ftruncate(2)/truncate(2). 45153091Sstefanf * We can do the same (with the same pmap evil), but do we need to 4645266Scracauer * worry about the bits on disk if the page is swapped out or will the 4753891Scracauer * swapper zero the parts of a page that are invalid if the page is 4817987Speter * swapped back in for us? 491556Srgrimes * 501556Srgrimes * (6) Add MAC support in mac_biba(4) and mac_mls(4). 511556Srgrimes * 521556Srgrimes * (7) Add a MAC check_create() hook for creating new named objects. 531556Srgrimes */ 541556Srgrimes 551556Srgrimes#include <sys/cdefs.h> 561556Srgrimes__FBSDID("$FreeBSD: head/sys/kern/uipc_shm.c 216128 2010-12-02 17:37:16Z trasz $"); 571556Srgrimes 581556Srgrimes#include <sys/param.h> 591556Srgrimes#include <sys/fcntl.h> 601556Srgrimes#include <sys/file.h> 611556Srgrimes#include <sys/filedesc.h> 621556Srgrimes#include <sys/fnv_hash.h> 631556Srgrimes#include <sys/kernel.h> 641556Srgrimes#include <sys/lock.h> 651556Srgrimes#include <sys/malloc.h> 661556Srgrimes#include <sys/mman.h> 671556Srgrimes#include <sys/mutex.h> 681556Srgrimes#include <sys/proc.h> 691556Srgrimes#include <sys/refcount.h> 7017987Speter#include <sys/resourcevar.h> 711556Srgrimes#include <sys/stat.h> 7217987Speter#include <sys/sysctl.h> 731556Srgrimes#include <sys/sysproto.h> 7417987Speter#include <sys/systm.h> 751556Srgrimes#include <sys/sx.h> 761556Srgrimes#include <sys/time.h> 771556Srgrimes#include <sys/vnode.h> 781556Srgrimes 791556Srgrimes#include <security/mac/mac_framework.h> 801556Srgrimes 811556Srgrimes#include <vm/vm.h> 821556Srgrimes#include <vm/vm_param.h> 831556Srgrimes#include <vm/pmap.h> 841556Srgrimes#include <vm/vm_map.h> 851556Srgrimes#include <vm/vm_object.h> 86193169Sstefanf#include <vm/vm_page.h> 871556Srgrimes#include <vm/vm_pager.h> 881556Srgrimes#include <vm/swap_pager.h> 891556Srgrimes 901556Srgrimesstruct shm_mapping { 911556Srgrimes char *sm_path; 9217987Speter Fnv32_t sm_fnv; 931556Srgrimes struct shmfd *sm_shmfd; 941556Srgrimes LIST_ENTRY(shm_mapping) sm_link; 95149933Sstefanf}; 96149933Sstefanf 9790111Simpstatic MALLOC_DEFINE(M_SHMFD, "shmfd", "shared memory file descriptor"); 9890111Simpstatic LIST_HEAD(, shm_mapping) *shm_dictionary; 9990111Simpstatic struct sx shm_dict_lock; 10090111Simpstatic struct mtx shm_timestamp_lock; 10190111Simpstatic u_long shm_hash; 10290111Simp 1031556Srgrimes#define SHM_HASH(fnv) (&shm_dictionary[(fnv) & shm_hash]) 1041556Srgrimes 1051556Srgrimesstatic int shm_access(struct shmfd *shmfd, struct ucred *ucred, int flags); 1061556Srgrimesstatic struct shmfd *shm_alloc(struct ucred *ucred, mode_t mode); 1071556Srgrimesstatic void shm_dict_init(void *arg); 1081556Srgrimesstatic void shm_drop(struct shmfd *shmfd); 1091556Srgrimesstatic struct shmfd *shm_hold(struct shmfd *shmfd); 1101556Srgrimesstatic void shm_insert(char *path, Fnv32_t fnv, struct shmfd *shmfd); 1111556Srgrimesstatic struct shmfd *shm_lookup(char *path, Fnv32_t fnv); 1121556Srgrimesstatic int shm_remove(char *path, Fnv32_t fnv, struct ucred *ucred); 1131556Srgrimesstatic int shm_dotruncate(struct shmfd *shmfd, off_t length); 1141556Srgrimes 1151556Srgrimesstatic fo_rdwr_t shm_read; 1161556Srgrimesstatic fo_rdwr_t shm_write; 1171556Srgrimesstatic fo_truncate_t shm_truncate; 1181556Srgrimesstatic fo_ioctl_t shm_ioctl; 1191556Srgrimesstatic fo_poll_t shm_poll; 1201556Srgrimesstatic fo_kqfilter_t shm_kqfilter; 1211556Srgrimesstatic fo_stat_t shm_stat; 1221556Srgrimesstatic fo_close_t shm_close; 1231556Srgrimes 1241556Srgrimes/* File descriptor operations. */ 1251556Srgrimesstatic struct fileops shm_ops = { 12646684Skris .fo_read = shm_read, 1271556Srgrimes .fo_write = shm_write, 1281556Srgrimes .fo_truncate = shm_truncate, 12917987Speter .fo_ioctl = shm_ioctl, 13090111Simp .fo_poll = shm_poll, 1311556Srgrimes .fo_kqfilter = shm_kqfilter, 1321556Srgrimes .fo_stat = shm_stat, 1331556Srgrimes .fo_close = shm_close, 1341556Srgrimes .fo_flags = DFLAG_PASSABLE 1351556Srgrimes}; 1361556Srgrimes 1371556SrgrimesFEATURE(posix_shm, "POSIX shared memory"); 1381556Srgrimes 1391556Srgrimesstatic int 1401556Srgrimesshm_read(struct file *fp, struct uio *uio, struct ucred *active_cred, 1411556Srgrimes int flags, struct thread *td) 1421556Srgrimes{ 1431556Srgrimes 1441556Srgrimes return (EOPNOTSUPP); 1451556Srgrimes} 1461556Srgrimes 1471556Srgrimesstatic int 1481556Srgrimesshm_write(struct file *fp, struct uio *uio, struct ucred *active_cred, 1491556Srgrimes int flags, struct thread *td) 1501556Srgrimes{ 151193169Sstefanf 1521556Srgrimes return (EOPNOTSUPP); 1531556Srgrimes} 1541556Srgrimes 1551556Srgrimesstatic int 1561556Srgrimesshm_truncate(struct file *fp, off_t length, struct ucred *active_cred, 1571556Srgrimes struct thread *td) 1581556Srgrimes{ 1591556Srgrimes struct shmfd *shmfd; 1601556Srgrimes#ifdef MAC 1611556Srgrimes int error; 162193169Sstefanf#endif 16390111Simp 1641556Srgrimes shmfd = fp->f_data; 1651556Srgrimes#ifdef MAC 1661556Srgrimes error = mac_posixshm_check_truncate(active_cred, fp->f_cred, shmfd); 1671556Srgrimes if (error) 1681556Srgrimes return (error); 1691556Srgrimes#endif 170190698Sstefanf return (shm_dotruncate(shmfd, length)); 171193169Sstefanf} 1721556Srgrimes 1731556Srgrimesstatic int 1741556Srgrimesshm_ioctl(struct file *fp, u_long com, void *data, 1751556Srgrimes struct ucred *active_cred, struct thread *td) 1761556Srgrimes{ 1771556Srgrimes 1781556Srgrimes return (EOPNOTSUPP); 1791556Srgrimes} 1801556Srgrimes 1811556Srgrimesstatic int 1821556Srgrimesshm_poll(struct file *fp, int events, struct ucred *active_cred, 1831556Srgrimes struct thread *td) 1841556Srgrimes{ 1851556Srgrimes 18690111Simp return (EOPNOTSUPP); 18717987Speter} 188149927Sstefanf 189149927Sstefanfstatic int 190149927Sstefanfshm_kqfilter(struct file *fp, struct knote *kn) 1911556Srgrimes{ 1921556Srgrimes 1931556Srgrimes return (EOPNOTSUPP); 1941556Srgrimes} 1951556Srgrimes 19617987Speterstatic int 1971556Srgrimesshm_stat(struct file *fp, struct stat *sb, struct ucred *active_cred, 19817987Speter struct thread *td) 199149802Sstefanf{ 2001556Srgrimes struct shmfd *shmfd; 2011556Srgrimes#ifdef MAC 202149932Sstefanf int error; 2031556Srgrimes#endif 2041556Srgrimes 2051556Srgrimes shmfd = fp->f_data; 2061556Srgrimes 2071556Srgrimes#ifdef MAC 2081556Srgrimes error = mac_posixshm_check_stat(active_cred, fp->f_cred, shmfd); 20918754Ssteve if (error) 2101556Srgrimes return (error); 21118754Ssteve#endif 2121556Srgrimes 2131556Srgrimes /* 2141556Srgrimes * Attempt to return sanish values for fstat() on a memory file 2151556Srgrimes * descriptor. 2161556Srgrimes */ 2171556Srgrimes bzero(sb, sizeof(*sb)); 2181556Srgrimes sb->st_mode = S_IFREG | shmfd->shm_mode; /* XXX */ 2191556Srgrimes sb->st_blksize = PAGE_SIZE; 2201556Srgrimes sb->st_size = shmfd->shm_size; 2211556Srgrimes sb->st_blocks = (sb->st_size + sb->st_blksize - 1) / sb->st_blksize; 2221556Srgrimes sb->st_atim = shmfd->shm_atime; 2231556Srgrimes sb->st_ctim = shmfd->shm_ctime; 2241556Srgrimes sb->st_mtim = shmfd->shm_mtime; 2251556Srgrimes sb->st_birthtim = shmfd->shm_birthtime; 2261556Srgrimes sb->st_uid = shmfd->shm_uid; 2271556Srgrimes sb->st_gid = shmfd->shm_gid; 228149927Sstefanf 2291556Srgrimes return (0); 2301556Srgrimes} 2311556Srgrimes 2321556Srgrimesstatic int 2331556Srgrimesshm_close(struct file *fp, struct thread *td) 2341556Srgrimes{ 2351556Srgrimes struct shmfd *shmfd; 2361556Srgrimes 23720425Ssteve shmfd = fp->f_data; 2381556Srgrimes fp->f_data = NULL; 23917987Speter shm_drop(shmfd); 2401556Srgrimes 24120425Ssteve return (0); 24220425Ssteve} 2431556Srgrimes 2441556Srgrimesstatic int 2451556Srgrimesshm_dotruncate(struct shmfd *shmfd, off_t length) 2461556Srgrimes{ 247149933Sstefanf vm_object_t object; 2481556Srgrimes vm_page_t m; 2491556Srgrimes vm_pindex_t nobjsize; 250149933Sstefanf vm_ooffset_t delta; 2511556Srgrimes 2521556Srgrimes object = shmfd->shm_object; 2531556Srgrimes VM_OBJECT_LOCK(object); 2541556Srgrimes if (length == shmfd->shm_size) { 2551556Srgrimes VM_OBJECT_UNLOCK(object); 2561556Srgrimes return (0); 2571556Srgrimes } 2581556Srgrimes nobjsize = OFF_TO_IDX(length + PAGE_MASK); 2591556Srgrimes 2601556Srgrimes /* Are we shrinking? If so, trim the end. */ 2611556Srgrimes if (length < shmfd->shm_size) { 2621556Srgrimes delta = ptoa(object->size - nobjsize); 2631556Srgrimes 2641556Srgrimes /* Toss in memory pages. */ 2651556Srgrimes if (nobjsize < object->size) 266149927Sstefanf vm_object_page_remove(object, nobjsize, object->size, 2671556Srgrimes FALSE); 2681556Srgrimes 2691556Srgrimes /* Toss pages from swap. */ 270149927Sstefanf if (object->type == OBJT_SWAP) 2711556Srgrimes swap_pager_freespace(object, nobjsize, delta); 2721556Srgrimes 2731556Srgrimes /* Free the swap accounted for shm */ 2741556Srgrimes swap_release_by_cred(delta, object->cred); 2751556Srgrimes object->charge -= delta; 2761556Srgrimes 2771556Srgrimes /* 2781556Srgrimes * If the last page is partially mapped, then zero out 2791556Srgrimes * the garbage at the end of the page. See comments 280149927Sstefanf * in vnode_pager_setsize() for more details. 2811556Srgrimes * 2821556Srgrimes * XXXJHB: This handles in memory pages, but what about 2831556Srgrimes * a page swapped out to disk? 2841556Srgrimes */ 2851556Srgrimes if ((length & PAGE_MASK) && 286149933Sstefanf (m = vm_page_lookup(object, OFF_TO_IDX(length))) != NULL && 28717987Speter m->valid != 0) { 2881556Srgrimes int base = (int)length & PAGE_MASK; 2891556Srgrimes int size = PAGE_SIZE - base; 2901556Srgrimes 2911556Srgrimes pmap_zero_page_area(m, base, size); 2921556Srgrimes 2931556Srgrimes /* 2941556Srgrimes * Update the valid bits to reflect the blocks that 2951556Srgrimes * have been zeroed. Some of these valid bits may 2961556Srgrimes * have already been set. 2971556Srgrimes */ 2981556Srgrimes vm_page_set_valid(m, base, size); 2991556Srgrimes 3001556Srgrimes /* 3011556Srgrimes * Round "base" to the next block boundary so that the 3021556Srgrimes * dirty bit for a partially zeroed block is not 3031556Srgrimes * cleared. 3041556Srgrimes */ 3051556Srgrimes base = roundup2(base, DEV_BSIZE); 3061556Srgrimes 3071556Srgrimes vm_page_clear_dirty(m, base, PAGE_SIZE - base); 3081556Srgrimes } else if ((length & PAGE_MASK) && 3091556Srgrimes __predict_false(object->cache != NULL)) { 310149933Sstefanf vm_page_cache_free(object, OFF_TO_IDX(length), 3111556Srgrimes nobjsize); 3121556Srgrimes } 3131556Srgrimes } else { 3141556Srgrimes 3151556Srgrimes /* Attempt to reserve the swap */ 3161556Srgrimes delta = ptoa(nobjsize - object->size); 3171556Srgrimes if (!swap_reserve_by_cred(delta, object->cred)) { 3181556Srgrimes VM_OBJECT_UNLOCK(object); 3191556Srgrimes return (ENOMEM); 3201556Srgrimes } 3211556Srgrimes object->charge += delta; 322149933Sstefanf } 32317987Speter shmfd->shm_size = length; 3241556Srgrimes mtx_lock(&shm_timestamp_lock); 3251556Srgrimes vfs_timestamp(&shmfd->shm_ctime); 3261556Srgrimes shmfd->shm_mtime = shmfd->shm_ctime; 3271556Srgrimes mtx_unlock(&shm_timestamp_lock); 3281556Srgrimes object->size = nobjsize; 3291556Srgrimes VM_OBJECT_UNLOCK(object); 3301556Srgrimes return (0); 3311556Srgrimes} 33217987Speter 3331556Srgrimes/* 3341556Srgrimes * shmfd object management including creation and reference counting 3351556Srgrimes * routines. 3361556Srgrimes */ 3371556Srgrimesstatic struct shmfd * 3381556Srgrimesshm_alloc(struct ucred *ucred, mode_t mode) 3391556Srgrimes{ 3401556Srgrimes struct shmfd *shmfd; 3411556Srgrimes 3421556Srgrimes shmfd = malloc(sizeof(*shmfd), M_SHMFD, M_WAITOK | M_ZERO); 343149933Sstefanf shmfd->shm_size = 0; 3441556Srgrimes shmfd->shm_uid = ucred->cr_uid; 3451556Srgrimes shmfd->shm_gid = ucred->cr_gid; 3461556Srgrimes shmfd->shm_mode = mode; 3471556Srgrimes shmfd->shm_object = vm_pager_allocate(OBJT_DEFAULT, NULL, 3481556Srgrimes shmfd->shm_size, VM_PROT_DEFAULT, 0, ucred); 3491556Srgrimes KASSERT(shmfd->shm_object != NULL, ("shm_create: vm_pager_allocate")); 3501556Srgrimes VM_OBJECT_LOCK(shmfd->shm_object); 3511556Srgrimes vm_object_clear_flag(shmfd->shm_object, OBJ_ONEMAPPING); 3521556Srgrimes vm_object_set_flag(shmfd->shm_object, OBJ_NOSPLIT); 3531556Srgrimes VM_OBJECT_UNLOCK(shmfd->shm_object); 3541556Srgrimes vfs_timestamp(&shmfd->shm_birthtime); 3551556Srgrimes shmfd->shm_atime = shmfd->shm_mtime = shmfd->shm_ctime = 3561556Srgrimes shmfd->shm_birthtime; 3571556Srgrimes refcount_init(&shmfd->shm_refs, 1); 3581556Srgrimes#ifdef MAC 3591556Srgrimes mac_posixshm_init(shmfd); 3601556Srgrimes mac_posixshm_create(ucred, shmfd); 3611556Srgrimes#endif 36290111Simp 36317987Speter return (shmfd); 3641556Srgrimes} 3651556Srgrimes 3661556Srgrimesstatic struct shmfd * 3671556Srgrimesshm_hold(struct shmfd *shmfd) 3681556Srgrimes{ 3691556Srgrimes 3701556Srgrimes refcount_acquire(&shmfd->shm_refs); 37117987Speter return (shmfd); 372172440Sstefanf} 3731556Srgrimes 3741556Srgrimesstatic void 3751556Srgrimesshm_drop(struct shmfd *shmfd) 3761556Srgrimes{ 3771556Srgrimes 3781556Srgrimes if (refcount_release(&shmfd->shm_refs)) { 3791556Srgrimes#ifdef MAC 3801556Srgrimes mac_posixshm_destroy(shmfd); 3811556Srgrimes#endif 3821556Srgrimes vm_object_deallocate(shmfd->shm_object); 3831556Srgrimes free(shmfd, M_SHMFD); 3841556Srgrimes } 3851556Srgrimes} 3861556Srgrimes 3871556Srgrimes/* 3881556Srgrimes * Determine if the credentials have sufficient permissions for a 3891556Srgrimes * specified combination of FREAD and FWRITE. 3901556Srgrimes */ 3911556Srgrimesstatic int 3921556Srgrimesshm_access(struct shmfd *shmfd, struct ucred *ucred, int flags) 3931556Srgrimes{ 3941556Srgrimes accmode_t accmode; 39590111Simp 39617987Speter accmode = 0; 3971556Srgrimes if (flags & FREAD) 3981556Srgrimes accmode |= VREAD; 3991556Srgrimes if (flags & FWRITE) 4001556Srgrimes accmode |= VWRITE; 4011556Srgrimes return (vaccess(VREG, shmfd->shm_mode, shmfd->shm_uid, shmfd->shm_gid, 4021556Srgrimes accmode, ucred, NULL)); 4031556Srgrimes} 4041556Srgrimes 4051556Srgrimes/* 4061556Srgrimes * Dictionary management. We maintain an in-kernel dictionary to map 4071556Srgrimes * paths to shmfd objects. We use the FNV hash on the path to store 4081556Srgrimes * the mappings in a hash table. 4091556Srgrimes */ 41045916Scracauerstatic void 4111556Srgrimesshm_dict_init(void *arg) 4121556Srgrimes{ 4131556Srgrimes 4141556Srgrimes mtx_init(&shm_timestamp_lock, "shm timestamps", NULL, MTX_DEF); 4151556Srgrimes sx_init(&shm_dict_lock, "shm dictionary"); 4161556Srgrimes shm_dictionary = hashinit(1024, M_SHMFD, &shm_hash); 4171556Srgrimes} 4181556SrgrimesSYSINIT(shm_dict_init, SI_SUB_SYSV_SHM, SI_ORDER_ANY, shm_dict_init, NULL); 4191556Srgrimes 4201556Srgrimesstatic struct shmfd * 4211556Srgrimesshm_lookup(char *path, Fnv32_t fnv) 42290111Simp{ 42317987Speter struct shm_mapping *map; 42425222Ssteve 4251556Srgrimes LIST_FOREACH(map, SHM_HASH(fnv), sm_link) { 4261556Srgrimes if (map->sm_fnv != fnv) 42717987Speter continue; 42817987Speter if (strcmp(map->sm_path, path) == 0) 42917987Speter return (map->sm_shmfd); 43017987Speter } 43117987Speter 43217987Speter return (NULL); 43366612Sbrian} 43417987Speter 43596922Stjrstatic void 4361556Srgrimesshm_insert(char *path, Fnv32_t fnv, struct shmfd *shmfd) 4371556Srgrimes{ 43817987Speter struct shm_mapping *map; 43917987Speter 44017987Speter map = malloc(sizeof(struct shm_mapping), M_SHMFD, M_WAITOK); 44117987Speter map->sm_path = path; 442181017Sstefanf map->sm_fnv = fnv; 44317987Speter map->sm_shmfd = shm_hold(shmfd); 44417987Speter LIST_INSERT_HEAD(SHM_HASH(fnv), map, sm_link); 44517987Speter} 4461556Srgrimes 4471556Srgrimesstatic int 4481556Srgrimesshm_remove(char *path, Fnv32_t fnv, struct ucred *ucred) 4491556Srgrimes{ 4501556Srgrimes struct shm_mapping *map; 4511556Srgrimes int error; 4521556Srgrimes 4531556Srgrimes LIST_FOREACH(map, SHM_HASH(fnv), sm_link) { 4541556Srgrimes if (map->sm_fnv != fnv) 4551556Srgrimes continue; 4561556Srgrimes if (strcmp(map->sm_path, path) == 0) { 4571556Srgrimes#ifdef MAC 4581556Srgrimes error = mac_posixshm_check_unlink(ucred, map->sm_shmfd); 4591556Srgrimes if (error) 46090111Simp return (error); 46117987Speter#endif 4621556Srgrimes error = shm_access(map->sm_shmfd, ucred, 4631556Srgrimes FREAD | FWRITE); 4641556Srgrimes if (error) 4651556Srgrimes return (error); 4661556Srgrimes LIST_REMOVE(map, sm_link); 4671556Srgrimes shm_drop(map->sm_shmfd); 468149802Sstefanf free(map->sm_path, M_SHMFD); 4691556Srgrimes free(map, M_SHMFD); 4701556Srgrimes return (0); 4711556Srgrimes } 4721556Srgrimes } 4731556Srgrimes 4741556Srgrimes return (ENOENT); 4751556Srgrimes} 4761556Srgrimes 4771556Srgrimes/* System calls. */ 4781556Srgrimesint 4791556Srgrimesshm_open(struct thread *td, struct shm_open_args *uap) 4801556Srgrimes{ 48153891Scracauer struct filedesc *fdp; 4821556Srgrimes struct shmfd *shmfd; 4831556Srgrimes struct file *fp; 4841556Srgrimes char *path; 4851556Srgrimes Fnv32_t fnv; 4861556Srgrimes mode_t cmode; 487124780Sdes int fd, error; 4881556Srgrimes 4891556Srgrimes if ((uap->flags & O_ACCMODE) != O_RDONLY && 4901556Srgrimes (uap->flags & O_ACCMODE) != O_RDWR) 49153282Scracauer return (EINVAL); 49252900Scracauer 4931556Srgrimes if ((uap->flags & ~(O_ACCMODE | O_CREAT | O_EXCL | O_TRUNC)) != 0) 494124780Sdes return (EINVAL); 4951556Srgrimes 4961556Srgrimes fdp = td->td_proc->p_fd; 4971556Srgrimes cmode = (uap->mode & ~fdp->fd_cmask) & ACCESSPERMS; 4981556Srgrimes 4991556Srgrimes error = falloc(td, &fp, &fd); 5001556Srgrimes if (error) 5011556Srgrimes return (error); 5021556Srgrimes 5031556Srgrimes /* A SHM_ANON path pointer creates an anonymous object. */ 5041556Srgrimes if (uap->path == SHM_ANON) { 5051556Srgrimes /* A read-only anonymous object is pointless. */ 5061556Srgrimes if ((uap->flags & O_ACCMODE) == O_RDONLY) { 5071556Srgrimes fdclose(fdp, fp, fd, td); 50845916Scracauer fdrop(fp, td); 5091556Srgrimes return (EINVAL); 5101556Srgrimes } 5111556Srgrimes shmfd = shm_alloc(td->td_ucred, cmode); 5121556Srgrimes } else { 5131556Srgrimes path = malloc(MAXPATHLEN, M_SHMFD, M_WAITOK); 5141556Srgrimes error = copyinstr(uap->path, path, MAXPATHLEN, NULL); 5151556Srgrimes 5161556Srgrimes /* Require paths to start with a '/' character. */ 5171556Srgrimes if (error == 0 && path[0] != '/') 5181556Srgrimes error = EINVAL; 5191556Srgrimes if (error) { 5201556Srgrimes fdclose(fdp, fp, fd, td); 5211556Srgrimes fdrop(fp, td); 5221556Srgrimes free(path, M_SHMFD); 5231556Srgrimes return (error); 52490111Simp } 52517987Speter 5261556Srgrimes fnv = fnv_32_str(path, FNV1_32_INIT); 5271556Srgrimes sx_xlock(&shm_dict_lock); 5281556Srgrimes shmfd = shm_lookup(path, fnv); 5291556Srgrimes if (shmfd == NULL) { 5301556Srgrimes /* Object does not yet exist, create it if requested. */ 5311556Srgrimes if (uap->flags & O_CREAT) { 5321556Srgrimes shmfd = shm_alloc(td->td_ucred, cmode); 5331556Srgrimes shm_insert(path, fnv, shmfd); 5341556Srgrimes } else { 53517987Speter free(path, M_SHMFD); 53617987Speter error = ENOENT; 5371556Srgrimes } 53817987Speter } else { 5391556Srgrimes /* 54017987Speter * Object already exists, obtain a new 5411556Srgrimes * reference if requested and permitted. 5421556Srgrimes */ 54317987Speter free(path, M_SHMFD); 5441556Srgrimes if ((uap->flags & (O_CREAT | O_EXCL)) == 54553891Scracauer (O_CREAT | O_EXCL)) 5461556Srgrimes error = EEXIST; 5471556Srgrimes else { 5481556Srgrimes#ifdef MAC 5491556Srgrimes error = mac_posixshm_check_open(td->td_ucred, 5501556Srgrimes shmfd); 551124780Sdes if (error == 0) 5521556Srgrimes#endif 5531556Srgrimes error = shm_access(shmfd, td->td_ucred, 5541556Srgrimes FFLAGS(uap->flags & O_ACCMODE)); 5551556Srgrimes } 5561556Srgrimes 5571556Srgrimes /* 5581556Srgrimes * Truncate the file back to zero length if 5591556Srgrimes * O_TRUNC was specified and the object was 5601556Srgrimes * opened with read/write. 5611556Srgrimes */ 562109627Stjr if (error == 0 && 5631556Srgrimes (uap->flags & (O_ACCMODE | O_TRUNC)) == 5641556Srgrimes (O_RDWR | O_TRUNC)) { 5651556Srgrimes#ifdef MAC 5661556Srgrimes error = mac_posixshm_check_truncate( 5671556Srgrimes td->td_ucred, fp->f_cred, shmfd); 5681556Srgrimes if (error == 0) 5691556Srgrimes#endif 5701556Srgrimes shm_dotruncate(shmfd, 0); 5711556Srgrimes } 5721556Srgrimes if (error == 0) 57390111Simp shm_hold(shmfd); 57417987Speter } 5751556Srgrimes sx_xunlock(&shm_dict_lock); 5761556Srgrimes 5771556Srgrimes if (error) { 5781556Srgrimes fdclose(fdp, fp, fd, td); 5791556Srgrimes fdrop(fp, td); 5801556Srgrimes return (error); 5811556Srgrimes } 5821556Srgrimes } 5831556Srgrimes 5841556Srgrimes finit(fp, FFLAGS(uap->flags & O_ACCMODE), DTYPE_SHM, shmfd, &shm_ops); 5851556Srgrimes 5861556Srgrimes FILEDESC_XLOCK(fdp); 5871556Srgrimes if (fdp->fd_ofiles[fd] == fp) 5881556Srgrimes fdp->fd_ofileflags[fd] |= UF_EXCLOSE; 5891556Srgrimes FILEDESC_XUNLOCK(fdp); 5901556Srgrimes td->td_retval[0] = fd; 5911556Srgrimes fdrop(fp, td); 5921556Srgrimes 5931556Srgrimes return (0); 5941556Srgrimes} 59545916Scracauer 59654884Scracauerint 597193222Srseshm_unlink(struct thread *td, struct shm_unlink_args *uap) 59817987Speter{ 59917987Speter char *path; 60017987Speter Fnv32_t fnv; 60117987Speter int error; 60217987Speter 60354884Scracauer path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 60417987Speter error = copyinstr(uap->path, path, MAXPATHLEN, NULL); 6051556Srgrimes if (error) { 6061556Srgrimes free(path, M_TEMP); 607149802Sstefanf return (error); 6081556Srgrimes } 6091556Srgrimes 6101556Srgrimes fnv = fnv_32_str(path, FNV1_32_INIT); 6111556Srgrimes sx_xlock(&shm_dict_lock); 61254884Scracauer error = shm_remove(path, fnv, td->td_ucred); 61317987Speter sx_xunlock(&shm_dict_lock); 61417987Speter free(path, M_TEMP); 6151556Srgrimes 61617987Speter return (error); 6171556Srgrimes} 6181556Srgrimes 6191556Srgrimes/* 6201556Srgrimes * mmap() helper to validate mmap() requests against shm object state 6211556Srgrimes * and give mmap() the vm_object to use for the mapping. 6221556Srgrimes */ 6231556Srgrimesint 6241556Srgrimesshm_mmap(struct shmfd *shmfd, vm_size_t objsize, vm_ooffset_t foff, 6251556Srgrimes vm_object_t *obj) 6261556Srgrimes{ 6271556Srgrimes 6281556Srgrimes /* 6291556Srgrimes * XXXRW: This validation is probably insufficient, and subject to 6301556Srgrimes * sign errors. It should be fixed. 6311556Srgrimes */ 6321556Srgrimes if (foff >= shmfd->shm_size || 6331556Srgrimes foff + objsize > round_page(shmfd->shm_size)) 6341556Srgrimes return (EINVAL); 6351556Srgrimes 6361556Srgrimes mtx_lock(&shm_timestamp_lock); 6371556Srgrimes vfs_timestamp(&shmfd->shm_atime); 6381556Srgrimes mtx_unlock(&shm_timestamp_lock); 6391556Srgrimes vm_object_reference(shmfd->shm_object); 6401556Srgrimes *obj = shmfd->shm_object; 6411556Srgrimes return (0); 6421556Srgrimes} 6431556Srgrimes