Deleted Added
full compact
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}