uipc_shm.c (247602) | uipc_shm.c (248084) |
---|---|
1/*- 2 * Copyright (c) 2006, 2011 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 28 unchanged lines hidden (view full) --- 37 * 38 * (2) Add support for this file type to fstat(1). 39 * 40 * (3) Resource limits? Does this need its own resource limits or are the 41 * existing limits in mmap(2) sufficient? 42 */ 43 44#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2006, 2011 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 28 unchanged lines hidden (view full) --- 37 * 38 * (2) Add support for this file type to fstat(1). 39 * 40 * (3) Resource limits? Does this need its own resource limits or are the 41 * existing limits in mmap(2) sufficient? 42 */ 43 44#include <sys/cdefs.h> |
45__FBSDID("$FreeBSD: head/sys/kern/uipc_shm.c 247602 2013-03-02 00:53:12Z pjd $"); | 45__FBSDID("$FreeBSD: head/sys/kern/uipc_shm.c 248084 2013-03-09 02:32:23Z attilio $"); |
46 47#include "opt_capsicum.h" 48 49#include <sys/param.h> 50#include <sys/capability.h> 51#include <sys/fcntl.h> 52#include <sys/file.h> 53#include <sys/filedesc.h> 54#include <sys/fnv_hash.h> 55#include <sys/kernel.h> 56#include <sys/lock.h> 57#include <sys/malloc.h> 58#include <sys/mman.h> 59#include <sys/mutex.h> 60#include <sys/priv.h> 61#include <sys/proc.h> 62#include <sys/refcount.h> 63#include <sys/resourcevar.h> | 46 47#include "opt_capsicum.h" 48 49#include <sys/param.h> 50#include <sys/capability.h> 51#include <sys/fcntl.h> 52#include <sys/file.h> 53#include <sys/filedesc.h> 54#include <sys/fnv_hash.h> 55#include <sys/kernel.h> 56#include <sys/lock.h> 57#include <sys/malloc.h> 58#include <sys/mman.h> 59#include <sys/mutex.h> 60#include <sys/priv.h> 61#include <sys/proc.h> 62#include <sys/refcount.h> 63#include <sys/resourcevar.h> |
64#include <sys/rwlock.h> |
|
64#include <sys/stat.h> 65#include <sys/sysctl.h> 66#include <sys/sysproto.h> 67#include <sys/systm.h> 68#include <sys/sx.h> 69#include <sys/time.h> 70#include <sys/vnode.h> 71 --- 176 unchanged lines hidden (view full) --- 248{ 249 vm_object_t object; 250 vm_page_t m, ma[1]; 251 vm_pindex_t idx, nobjsize; 252 vm_ooffset_t delta; 253 int base, rv; 254 255 object = shmfd->shm_object; | 65#include <sys/stat.h> 66#include <sys/sysctl.h> 67#include <sys/sysproto.h> 68#include <sys/systm.h> 69#include <sys/sx.h> 70#include <sys/time.h> 71#include <sys/vnode.h> 72 --- 176 unchanged lines hidden (view full) --- 249{ 250 vm_object_t object; 251 vm_page_t m, ma[1]; 252 vm_pindex_t idx, nobjsize; 253 vm_ooffset_t delta; 254 int base, rv; 255 256 object = shmfd->shm_object; |
256 VM_OBJECT_LOCK(object); | 257 VM_OBJECT_WLOCK(object); |
257 if (length == shmfd->shm_size) { | 258 if (length == shmfd->shm_size) { |
258 VM_OBJECT_UNLOCK(object); | 259 VM_OBJECT_WUNLOCK(object); |
259 return (0); 260 } 261 nobjsize = OFF_TO_IDX(length + PAGE_MASK); 262 263 /* Are we shrinking? If so, trim the end. */ 264 if (length < shmfd->shm_size) { 265 /* 266 * Disallow any requests to shrink the size if this 267 * object is mapped into the kernel. 268 */ 269 if (shmfd->shm_kmappings > 0) { | 260 return (0); 261 } 262 nobjsize = OFF_TO_IDX(length + PAGE_MASK); 263 264 /* Are we shrinking? If so, trim the end. */ 265 if (length < shmfd->shm_size) { 266 /* 267 * Disallow any requests to shrink the size if this 268 * object is mapped into the kernel. 269 */ 270 if (shmfd->shm_kmappings > 0) { |
270 VM_OBJECT_UNLOCK(object); | 271 VM_OBJECT_WUNLOCK(object); |
271 return (EBUSY); 272 } 273 274 /* 275 * Zero the truncated part of the last page. 276 */ 277 base = length & PAGE_MASK; 278 if (base != 0) { --- 4 unchanged lines hidden (view full) --- 283 if ((m->oflags & VPO_BUSY) != 0 || 284 m->busy != 0) { 285 vm_page_sleep(m, "shmtrc"); 286 goto retry; 287 } 288 } else if (vm_pager_has_page(object, idx, NULL, NULL)) { 289 m = vm_page_alloc(object, idx, VM_ALLOC_NORMAL); 290 if (m == NULL) { | 272 return (EBUSY); 273 } 274 275 /* 276 * Zero the truncated part of the last page. 277 */ 278 base = length & PAGE_MASK; 279 if (base != 0) { --- 4 unchanged lines hidden (view full) --- 284 if ((m->oflags & VPO_BUSY) != 0 || 285 m->busy != 0) { 286 vm_page_sleep(m, "shmtrc"); 287 goto retry; 288 } 289 } else if (vm_pager_has_page(object, idx, NULL, NULL)) { 290 m = vm_page_alloc(object, idx, VM_ALLOC_NORMAL); 291 if (m == NULL) { |
291 VM_OBJECT_UNLOCK(object); | 292 VM_OBJECT_WUNLOCK(object); |
292 VM_WAIT; | 293 VM_WAIT; |
293 VM_OBJECT_LOCK(object); | 294 VM_OBJECT_WLOCK(object); |
294 goto retry; 295 } else if (m->valid != VM_PAGE_BITS_ALL) { 296 ma[0] = m; 297 rv = vm_pager_get_pages(object, ma, 1, 298 0); 299 m = vm_page_lookup(object, idx); 300 } else 301 /* A cached page was reactivated. */ 302 rv = VM_PAGER_OK; 303 vm_page_lock(m); 304 if (rv == VM_PAGER_OK) { 305 vm_page_deactivate(m); 306 vm_page_unlock(m); 307 vm_page_wakeup(m); 308 } else { 309 vm_page_free(m); 310 vm_page_unlock(m); | 295 goto retry; 296 } else if (m->valid != VM_PAGE_BITS_ALL) { 297 ma[0] = m; 298 rv = vm_pager_get_pages(object, ma, 1, 299 0); 300 m = vm_page_lookup(object, idx); 301 } else 302 /* A cached page was reactivated. */ 303 rv = VM_PAGER_OK; 304 vm_page_lock(m); 305 if (rv == VM_PAGER_OK) { 306 vm_page_deactivate(m); 307 vm_page_unlock(m); 308 vm_page_wakeup(m); 309 } else { 310 vm_page_free(m); 311 vm_page_unlock(m); |
311 VM_OBJECT_UNLOCK(object); | 312 VM_OBJECT_WUNLOCK(object); |
312 return (EIO); 313 } 314 } 315 if (m != NULL) { 316 pmap_zero_page_area(m, base, PAGE_SIZE - base); 317 KASSERT(m->valid == VM_PAGE_BITS_ALL, 318 ("shm_dotruncate: page %p is invalid", m)); 319 vm_page_dirty(m); --- 13 unchanged lines hidden (view full) --- 333 334 /* Free the swap accounted for shm */ 335 swap_release_by_cred(delta, object->cred); 336 object->charge -= delta; 337 } else { 338 /* Attempt to reserve the swap */ 339 delta = ptoa(nobjsize - object->size); 340 if (!swap_reserve_by_cred(delta, object->cred)) { | 313 return (EIO); 314 } 315 } 316 if (m != NULL) { 317 pmap_zero_page_area(m, base, PAGE_SIZE - base); 318 KASSERT(m->valid == VM_PAGE_BITS_ALL, 319 ("shm_dotruncate: page %p is invalid", m)); 320 vm_page_dirty(m); --- 13 unchanged lines hidden (view full) --- 334 335 /* Free the swap accounted for shm */ 336 swap_release_by_cred(delta, object->cred); 337 object->charge -= delta; 338 } else { 339 /* Attempt to reserve the swap */ 340 delta = ptoa(nobjsize - object->size); 341 if (!swap_reserve_by_cred(delta, object->cred)) { |
341 VM_OBJECT_UNLOCK(object); | 342 VM_OBJECT_WUNLOCK(object); |
342 return (ENOMEM); 343 } 344 object->charge += delta; 345 } 346 shmfd->shm_size = length; 347 mtx_lock(&shm_timestamp_lock); 348 vfs_timestamp(&shmfd->shm_ctime); 349 shmfd->shm_mtime = shmfd->shm_ctime; 350 mtx_unlock(&shm_timestamp_lock); 351 object->size = nobjsize; | 343 return (ENOMEM); 344 } 345 object->charge += delta; 346 } 347 shmfd->shm_size = length; 348 mtx_lock(&shm_timestamp_lock); 349 vfs_timestamp(&shmfd->shm_ctime); 350 shmfd->shm_mtime = shmfd->shm_ctime; 351 mtx_unlock(&shm_timestamp_lock); 352 object->size = nobjsize; |
352 VM_OBJECT_UNLOCK(object); | 353 VM_OBJECT_WUNLOCK(object); |
353 return (0); 354} 355 356/* 357 * shmfd object management including creation and reference counting 358 * routines. 359 */ 360static struct shmfd * --- 4 unchanged lines hidden (view full) --- 365 shmfd = malloc(sizeof(*shmfd), M_SHMFD, M_WAITOK | M_ZERO); 366 shmfd->shm_size = 0; 367 shmfd->shm_uid = ucred->cr_uid; 368 shmfd->shm_gid = ucred->cr_gid; 369 shmfd->shm_mode = mode; 370 shmfd->shm_object = vm_pager_allocate(OBJT_DEFAULT, NULL, 371 shmfd->shm_size, VM_PROT_DEFAULT, 0, ucred); 372 KASSERT(shmfd->shm_object != NULL, ("shm_create: vm_pager_allocate")); | 354 return (0); 355} 356 357/* 358 * shmfd object management including creation and reference counting 359 * routines. 360 */ 361static struct shmfd * --- 4 unchanged lines hidden (view full) --- 366 shmfd = malloc(sizeof(*shmfd), M_SHMFD, M_WAITOK | M_ZERO); 367 shmfd->shm_size = 0; 368 shmfd->shm_uid = ucred->cr_uid; 369 shmfd->shm_gid = ucred->cr_gid; 370 shmfd->shm_mode = mode; 371 shmfd->shm_object = vm_pager_allocate(OBJT_DEFAULT, NULL, 372 shmfd->shm_size, VM_PROT_DEFAULT, 0, ucred); 373 KASSERT(shmfd->shm_object != NULL, ("shm_create: vm_pager_allocate")); |
373 VM_OBJECT_LOCK(shmfd->shm_object); | 374 VM_OBJECT_WLOCK(shmfd->shm_object); |
374 vm_object_clear_flag(shmfd->shm_object, OBJ_ONEMAPPING); 375 vm_object_set_flag(shmfd->shm_object, OBJ_NOSPLIT); | 375 vm_object_clear_flag(shmfd->shm_object, OBJ_ONEMAPPING); 376 vm_object_set_flag(shmfd->shm_object, OBJ_NOSPLIT); |
376 VM_OBJECT_UNLOCK(shmfd->shm_object); | 377 VM_OBJECT_WUNLOCK(shmfd->shm_object); |
377 vfs_timestamp(&shmfd->shm_birthtime); 378 shmfd->shm_atime = shmfd->shm_mtime = shmfd->shm_ctime = 379 shmfd->shm_birthtime; 380 refcount_init(&shmfd->shm_refs, 1); 381#ifdef MAC 382 mac_posixshm_init(shmfd); 383 mac_posixshm_create(ucred, shmfd); 384#endif --- 371 unchanged lines hidden (view full) --- 756 vm_offset_t kva, ofs; 757 vm_object_t obj; 758 int rv; 759 760 if (fp->f_type != DTYPE_SHM) 761 return (EINVAL); 762 shmfd = fp->f_data; 763 obj = shmfd->shm_object; | 378 vfs_timestamp(&shmfd->shm_birthtime); 379 shmfd->shm_atime = shmfd->shm_mtime = shmfd->shm_ctime = 380 shmfd->shm_birthtime; 381 refcount_init(&shmfd->shm_refs, 1); 382#ifdef MAC 383 mac_posixshm_init(shmfd); 384 mac_posixshm_create(ucred, shmfd); 385#endif --- 371 unchanged lines hidden (view full) --- 757 vm_offset_t kva, ofs; 758 vm_object_t obj; 759 int rv; 760 761 if (fp->f_type != DTYPE_SHM) 762 return (EINVAL); 763 shmfd = fp->f_data; 764 obj = shmfd->shm_object; |
764 VM_OBJECT_LOCK(obj); | 765 VM_OBJECT_WLOCK(obj); |
765 /* 766 * XXXRW: This validation is probably insufficient, and subject to 767 * sign errors. It should be fixed. 768 */ 769 if (offset >= shmfd->shm_size || 770 offset + size > round_page(shmfd->shm_size)) { | 766 /* 767 * XXXRW: This validation is probably insufficient, and subject to 768 * sign errors. It should be fixed. 769 */ 770 if (offset >= shmfd->shm_size || 771 offset + size > round_page(shmfd->shm_size)) { |
771 VM_OBJECT_UNLOCK(obj); | 772 VM_OBJECT_WUNLOCK(obj); |
772 return (EINVAL); 773 } 774 775 shmfd->shm_kmappings++; 776 vm_object_reference_locked(obj); | 773 return (EINVAL); 774 } 775 776 shmfd->shm_kmappings++; 777 vm_object_reference_locked(obj); |
777 VM_OBJECT_UNLOCK(obj); | 778 VM_OBJECT_WUNLOCK(obj); |
778 779 /* Map the object into the kernel_map and wire it. */ 780 kva = vm_map_min(kernel_map); 781 ofs = offset & PAGE_MASK; 782 offset = trunc_page(offset); 783 size = round_page(size + ofs); 784 rv = vm_map_find(kernel_map, obj, offset, &kva, size, 785 VMFS_ALIGNED_SPACE, VM_PROT_READ | VM_PROT_WRITE, --- 5 unchanged lines hidden (view full) --- 791 *memp = (void *)(kva + ofs); 792 return (0); 793 } 794 vm_map_remove(kernel_map, kva, kva + size); 795 } else 796 vm_object_deallocate(obj); 797 798 /* On failure, drop our mapping reference. */ | 779 780 /* Map the object into the kernel_map and wire it. */ 781 kva = vm_map_min(kernel_map); 782 ofs = offset & PAGE_MASK; 783 offset = trunc_page(offset); 784 size = round_page(size + ofs); 785 rv = vm_map_find(kernel_map, obj, offset, &kva, size, 786 VMFS_ALIGNED_SPACE, VM_PROT_READ | VM_PROT_WRITE, --- 5 unchanged lines hidden (view full) --- 792 *memp = (void *)(kva + ofs); 793 return (0); 794 } 795 vm_map_remove(kernel_map, kva, kva + size); 796 } else 797 vm_object_deallocate(obj); 798 799 /* On failure, drop our mapping reference. */ |
799 VM_OBJECT_LOCK(obj); | 800 VM_OBJECT_WLOCK(obj); |
800 shmfd->shm_kmappings--; | 801 shmfd->shm_kmappings--; |
801 VM_OBJECT_UNLOCK(obj); | 802 VM_OBJECT_WUNLOCK(obj); |
802 803 return (vm_mmap_to_errno(rv)); 804} 805 806/* 807 * We require the caller to unmap the entire entry. This allows us to 808 * safely decrement shm_kmappings when a mapping is removed. 809 */ --- 25 unchanged lines hidden (view full) --- 835 if (entry->start != kva || entry->end != kva + size) { 836 vm_map_lookup_done(map, entry); 837 return (EINVAL); 838 } 839 vm_map_lookup_done(map, entry); 840 if (obj != shmfd->shm_object) 841 return (EINVAL); 842 vm_map_remove(map, kva, kva + size); | 803 804 return (vm_mmap_to_errno(rv)); 805} 806 807/* 808 * We require the caller to unmap the entire entry. This allows us to 809 * safely decrement shm_kmappings when a mapping is removed. 810 */ --- 25 unchanged lines hidden (view full) --- 836 if (entry->start != kva || entry->end != kva + size) { 837 vm_map_lookup_done(map, entry); 838 return (EINVAL); 839 } 840 vm_map_lookup_done(map, entry); 841 if (obj != shmfd->shm_object) 842 return (EINVAL); 843 vm_map_remove(map, kva, kva + size); |
843 VM_OBJECT_LOCK(obj); | 844 VM_OBJECT_WLOCK(obj); |
844 KASSERT(shmfd->shm_kmappings > 0, ("shm_unmap: object not mapped")); 845 shmfd->shm_kmappings--; | 845 KASSERT(shmfd->shm_kmappings > 0, ("shm_unmap: object not mapped")); 846 shmfd->shm_kmappings--; |
846 VM_OBJECT_UNLOCK(obj); | 847 VM_OBJECT_WUNLOCK(obj); |
847 return (0); 848} 849 850void 851shm_path(struct shmfd *shmfd, char *path, size_t size) 852{ 853 854 if (shmfd->shm_path == NULL) 855 return; 856 sx_slock(&shm_dict_lock); 857 if (shmfd->shm_path != NULL) 858 strlcpy(path, shmfd->shm_path, size); 859 sx_sunlock(&shm_dict_lock); 860} | 848 return (0); 849} 850 851void 852shm_path(struct shmfd *shmfd, char *path, size_t size) 853{ 854 855 if (shmfd->shm_path == NULL) 856 return; 857 sx_slock(&shm_dict_lock); 858 if (shmfd->shm_path != NULL) 859 strlcpy(path, shmfd->shm_path, size); 860 sx_sunlock(&shm_dict_lock); 861} |