Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/uipc_shm.c
Show First 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | |||||
static fo_close_t shm_close; | static fo_close_t shm_close; | ||||
static fo_chmod_t shm_chmod; | static fo_chmod_t shm_chmod; | ||||
static fo_chown_t shm_chown; | static fo_chown_t shm_chown; | ||||
static fo_seek_t shm_seek; | static fo_seek_t shm_seek; | ||||
static fo_fill_kinfo_t shm_fill_kinfo; | static fo_fill_kinfo_t shm_fill_kinfo; | ||||
static fo_mmap_t shm_mmap; | static fo_mmap_t shm_mmap; | ||||
static fo_get_seals_t shm_get_seals; | static fo_get_seals_t shm_get_seals; | ||||
static fo_add_seals_t shm_add_seals; | static fo_add_seals_t shm_add_seals; | ||||
static fo_fallocate_t shm_fallocate; | static fo_fspacectl_t shm_fspacectl; | ||||
/* File descriptor operations. */ | /* File descriptor operations. */ | ||||
struct fileops shm_ops = { | struct fileops shm_ops = { | ||||
.fo_read = shm_read, | .fo_read = shm_read, | ||||
.fo_write = shm_write, | .fo_write = shm_write, | ||||
.fo_truncate = shm_truncate, | .fo_truncate = shm_truncate, | ||||
.fo_ioctl = shm_ioctl, | .fo_ioctl = shm_ioctl, | ||||
.fo_poll = invfo_poll, | .fo_poll = invfo_poll, | ||||
.fo_kqfilter = invfo_kqfilter, | .fo_kqfilter = invfo_kqfilter, | ||||
.fo_stat = shm_stat, | .fo_stat = shm_stat, | ||||
.fo_close = shm_close, | .fo_close = shm_close, | ||||
.fo_chmod = shm_chmod, | .fo_chmod = shm_chmod, | ||||
.fo_chown = shm_chown, | .fo_chown = shm_chown, | ||||
.fo_sendfile = vn_sendfile, | .fo_sendfile = vn_sendfile, | ||||
.fo_seek = shm_seek, | .fo_seek = shm_seek, | ||||
.fo_fill_kinfo = shm_fill_kinfo, | .fo_fill_kinfo = shm_fill_kinfo, | ||||
.fo_mmap = shm_mmap, | .fo_mmap = shm_mmap, | ||||
.fo_get_seals = shm_get_seals, | .fo_get_seals = shm_get_seals, | ||||
.fo_add_seals = shm_add_seals, | .fo_add_seals = shm_add_seals, | ||||
.fo_fallocate = shm_fallocate, | .fo_fspacectl = shm_fspacectl, | ||||
.fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE, | .fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE, | ||||
}; | }; | ||||
FEATURE(posix_shm, "POSIX shared memory"); | FEATURE(posix_shm, "POSIX shared memory"); | ||||
static SYSCTL_NODE(_vm, OID_AUTO, largepages, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, | static SYSCTL_NODE(_vm, OID_AUTO, largepages, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, | ||||
""); | ""); | ||||
▲ Show 20 Lines • Show All 1,693 Lines • ▼ Show 20 Lines | shm_get_seals(struct file *fp, int *seals) | ||||
struct shmfd *shmfd; | struct shmfd *shmfd; | ||||
shmfd = fp->f_data; | shmfd = fp->f_data; | ||||
*seals = shmfd->shm_seals; | *seals = shmfd->shm_seals; | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
shm_fallocate(struct file *fp, off_t offset, off_t len, struct thread *td) | shm_deallocate(struct shmfd *shmfd, off_t offset, off_t len, int flags, | ||||
void *rl_cookie, struct thread *td) | |||||
{ | { | ||||
vm_pindex_t start, start2, end; | |||||
vm_ooffset_t size; | |||||
vm_page_t m; | |||||
int error; | |||||
start = OFF_TO_IDX(offset); | |||||
start2 = OFF_TO_IDX(offset + PAGE_MASK); | |||||
end = OFF_TO_IDX(offset + len); | |||||
size = offset + len; | |||||
error = 0; | |||||
VM_OBJECT_WLOCK(shmfd->shm_object); | |||||
if (start2 < end) | |||||
vm_object_page_remove(shmfd->shm_object, start2, end, 0); | |||||
if (len > OFF_MAX - offset) | |||||
len = OFF_MAX - offset; | |||||
if ((offset & PAGE_MASK) != offset) { | |||||
m = vm_page_grab(shmfd->shm_object, start, VM_ALLOC_NOCREAT); | |||||
if (m != NULL) { | |||||
pmap_zero_page_area(m, offset & PAGE_MASK, | |||||
PAGE_SIZE - (offset & PAGE_MASK)); | |||||
vm_page_set_dirty(m); | |||||
vm_page_xunbusy(m); | |||||
} | |||||
} | |||||
if ((size & PAGE_MASK) != size) { | |||||
m = vm_page_grab(shmfd->shm_object, end, VM_ALLOC_NOCREAT); | |||||
if (m != NULL) { | |||||
pmap_zero_page_area(m, 0, offset + len & PAGE_MASK); | |||||
vm_page_set_dirty(m); | |||||
vm_page_xunbusy(m); | |||||
} | |||||
} | |||||
if (size > shmfd->shm_size && flags & SPACECTL_F_CANEXTEND) | |||||
error = shm_largepage(shmfd) ? shm_dotruncate_largepage(shmfd, | |||||
size, rl_cookie) : shm_dotruncate_locked(shmfd, size, | |||||
rl_cookie); | |||||
VM_OBJECT_WUNLOCK(shmfd->shm_object); | |||||
return (error); | |||||
} | |||||
static int | |||||
shm_fspacectl(struct file *fp, int cmd, off_t offset, off_t len, int flags, | |||||
struct ucred *active_cred, struct thread *td) | |||||
{ | |||||
void *rl_cookie; | void *rl_cookie; | ||||
struct shmfd *shmfd; | struct shmfd *shmfd; | ||||
size_t size; | size_t size; | ||||
int error; | int error; | ||||
/* This assumes that the caller already checked for overflow. */ | /* This assumes that the caller already checked for overflow. */ | ||||
error = 0; | error = 0; | ||||
shmfd = fp->f_data; | shmfd = fp->f_data; | ||||
size = offset + len; | size = offset + len; | ||||
if (cmd != SPACECTL_ALLOC && cmd != SPACECTL_DEALLOC) | |||||
return (EINVAL); | |||||
if (offset < 0 || len < 0 || (flags & ~SPACECTL_F_SUPPORTED) != 0) | |||||
return (EINVAL); | |||||
if (len == 0) | |||||
/* Degenerated case */ | |||||
return (0); | |||||
/* | /* | ||||
* Just grab the rangelock for the range that we may be attempting to | * Just grab the rangelock for the range that we may be attempting to | ||||
* grow, rather than blocking read/write for regions we won't be | * grow, rather than blocking read/write for regions we won't be | ||||
* touching while this (potential) resize is in progress. Other | * touching while this (potential) resize is in progress. Other | ||||
* attempts to resize the shmfd will have to take a write lock from 0 to | * attempts to resize the shmfd will have to take a write lock from 0 to | ||||
* OFF_MAX, so this being potentially beyond the current usable range of | * OFF_MAX, so this being potentially beyond the current usable range of | ||||
* the shmfd is not necessarily a concern. If other mechanisms are | * the shmfd is not necessarily a concern. If other mechanisms are | ||||
* added to grow a shmfd, this may need to be re-evaluated. | * added to grow a shmfd, this may need to be re-evaluated. | ||||
*/ | */ | ||||
rl_cookie = rangelock_wlock(&shmfd->shm_rl, offset, size, | rl_cookie = rangelock_wlock(&shmfd->shm_rl, offset, size, | ||||
&shmfd->shm_mtx); | &shmfd->shm_mtx); | ||||
if (size > shmfd->shm_size) | switch (cmd) { | ||||
case SPACECTL_ALLOC: | |||||
if (size > shmfd->shm_size && flags & SPACECTL_F_CANEXTEND) | |||||
error = shm_dotruncate_cookie(shmfd, size, rl_cookie); | error = shm_dotruncate_cookie(shmfd, size, rl_cookie); | ||||
break; | |||||
case SPACECTL_DEALLOC: | |||||
error = shm_deallocate(shmfd, offset, len, flags, rl_cookie, td); | |||||
break; | |||||
default: | |||||
panic("%s: unknown cmd %d", __func__, cmd); | |||||
} | |||||
rangelock_unlock(&shmfd->shm_rl, rl_cookie, &shmfd->shm_mtx); | rangelock_unlock(&shmfd->shm_rl, rl_cookie, &shmfd->shm_mtx); | ||||
/* Translate to posix_fallocate(2) return value as needed. */ | /* Translate to posix_fallocate(2) return value as needed. */ | ||||
if (error == ENOMEM) | if (error == ENOMEM) | ||||
error = ENOSPC; | error = ENOSPC; | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
▲ Show 20 Lines • Show All 69 Lines • Show Last 20 Lines |