aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/kern/uipc_shm.c17
1 files changed, 12 insertions, 5 deletions
diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c
index 38065dee7cb0..de8451f951dd 100644
--- a/sys/kern/uipc_shm.c
+++ b/sys/kern/uipc_shm.c
@@ -895,6 +895,7 @@ shm_mmap(struct file *fp, vm_map_t map, vm_offset_t *addr, vm_size_t objsize,
struct shmfd *shmfd;
vm_prot_t maxprot;
int error;
+ bool writecnt;
shmfd = fp->f_data;
maxprot = VM_PROT_NONE;
@@ -905,10 +906,10 @@ shm_mmap(struct file *fp, vm_map_t map, vm_offset_t *addr, vm_size_t objsize,
if ((fp->f_flag & FWRITE) != 0)
maxprot |= VM_PROT_WRITE;
+ writecnt = (flags & MAP_SHARED) != 0 && (prot & VM_PROT_WRITE) != 0;
+
/* Don't permit shared writable mappings on read-only descriptors. */
- if ((flags & MAP_SHARED) != 0 &&
- (maxprot & VM_PROT_WRITE) == 0 &&
- (prot & VM_PROT_WRITE) != 0)
+ if (writecnt && (maxprot & VM_PROT_WRITE) == 0)
return (EACCES);
maxprot &= cap_maxprot;
@@ -931,10 +932,16 @@ shm_mmap(struct file *fp, vm_map_t map, vm_offset_t *addr, vm_size_t objsize,
mtx_unlock(&shm_timestamp_lock);
vm_object_reference(shmfd->shm_object);
+ if (writecnt)
+ vm_pager_update_writecount(shmfd->shm_object, 0, objsize);
error = vm_mmap_object(map, addr, objsize, prot, maxprot, flags,
- shmfd->shm_object, foff, FALSE, td);
- if (error != 0)
+ shmfd->shm_object, foff, writecnt, td);
+ if (error != 0) {
+ if (writecnt)
+ vm_pager_release_writecount(shmfd->shm_object, 0,
+ objsize);
vm_object_deallocate(shmfd->shm_object);
+ }
return (error);
}