Changeset View
Standalone View
sys/kern/uipc_shm.c
Show First 20 Lines • Show All 140 Lines • ▼ Show 20 Lines | |||||
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_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_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,691 Lines • ▼ Show 20 Lines | |||||
shm_get_seals(struct file *fp, int *seals) | 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 void | |||||
shm_deallocate(struct shmfd *shmfd, off_t off, off_t len, int flags, | |||||
void *rl_cookie, struct thread *td) | |||||
{ | |||||
vm_pindex_t startpg, pg, endpg; | |||||
int startofs, endofs, size; | |||||
vm_page_t m; | |||||
startofs = off & PAGE_MASK; | |||||
endofs = (off + len) & PAGE_MASK; | |||||
kib: Can offset + PAGE_MASK overflow ? | |||||
startpg = OFF_TO_IDX(off); | |||||
endpg = OFF_TO_IDX(off + len); | |||||
pg = (off > OFF_MAX - PAGE_MASK) ? endpg : | |||||
OFF_TO_IDX(off + PAGE_MASK); | |||||
Done Inline ActionsTODO: kill this, and kill int error; khng: TODO: kill this, and kill `int error;` | |||||
VM_OBJECT_WLOCK(shmfd->shm_object); | |||||
if (pg < endpg) | |||||
Done Inline ActionsI believe this should be an earlier error from overflow, and not the truncation at this stage. kib: I believe this should be an earlier error from overflow, and not the truncation at this stage. | |||||
vm_object_page_remove(shmfd->shm_object, pg, endpg, 0); | |||||
if (startofs != 0) { | |||||
Done Inline ActionsI do not understand this condition. Why it is not (offset & PAGE_MASK) != 0? kib: I do not understand this condition. Why it is not (offset & PAGE_MASK) != 0?
And I think it… | |||||
m = vm_page_grab(shmfd->shm_object, startpg, | |||||
VM_ALLOC_NOCREAT); | |||||
if (m != NULL) { | |||||
Done Inline ActionsThis was copied from shm_dotruncate_locked(), right? It misses the vm_pager_has_page() case. Basically, the page that you need to partially zero might be not resident but swap contains the user data. So we need to read the page from swap. Perhaps you should refactor code to instantiate the page from shm_dotruncate_locked() and reuse it. Perhaps the code should take some control which region of the page should be cleared, to be passed to pmap_zero_page_area(). kib: This was copied from shm_dotruncate_locked(), right? It misses the vm_pager_has_page() case. | |||||
size = startpg != endpg ? | |||||
PAGE_SIZE - startofs : endofs - startofs; | |||||
pmap_zero_page_area(m, startofs, size); | |||||
vm_page_set_dirty(m); | |||||
vm_page_xunbusy(m); | |||||
} | |||||
} | |||||
if (endofs != 0 && startpg != endpg) { | |||||
m = vm_page_grab(shmfd->shm_object, endpg, VM_ALLOC_NOCREAT); | |||||
if (m != NULL) { | |||||
pmap_zero_page_area(m, 0, endofs); | |||||
vm_page_set_dirty(m); | |||||
vm_page_xunbusy(m); | |||||
} | |||||
} | |||||
VM_OBJECT_WUNLOCK(shmfd->shm_object); | |||||
} | |||||
Done Inline ActionsTODO: Just directly return (0). khng: TODO: Just directly return (0). | |||||
static int | |||||
shm_fspacectl(struct file *fp, int cmd, off_t *offset, off_t *length, int flags, | |||||
struct ucred *active_cred, struct thread *td) | |||||
{ | |||||
void *rl_cookie; | |||||
struct shmfd *shmfd; | |||||
off_t off, len; | |||||
int error; | |||||
/* This assumes that the caller already checked for overflow. */ | |||||
error = 0; | |||||
shmfd = fp->f_data; | |||||
off = *offset; | |||||
len = *length; | |||||
if (cmd != SPACECTL_DEALLOC || off < 0 || len <= 0 || | |||||
len > OFF_MAX - off || flags != 0) | |||||
return (EINVAL); | |||||
rl_cookie = rangelock_wlock(&shmfd->shm_rl, off, off + len, | |||||
&shmfd->shm_mtx); | |||||
switch (cmd) { | |||||
case SPACECTL_DEALLOC: | |||||
Done Inline ActionsI see that this comment was copied/pasted without looking at the content. kib: I see that this comment was copied/pasted without looking at the content. | |||||
shm_deallocate(shmfd, off, len, flags, rl_cookie, | |||||
td); | |||||
error = 0; | |||||
*offset = 0; | |||||
*length = 0; | |||||
break; | |||||
default: | |||||
panic("%s: unknown cmd %d", __func__, cmd); | |||||
} | |||||
rangelock_unlock(&shmfd->shm_rl, rl_cookie, &shmfd->shm_mtx); | |||||
return (error); | |||||
} | |||||
static int | static int | ||||
shm_fallocate(struct file *fp, off_t offset, off_t len, struct thread *td) | shm_fallocate(struct file *fp, off_t offset, off_t len, 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; | ||||
Done Inline ActionsTODO: Move them to D28833. khng: TODO: Move them to D28833. | |||||
/* 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; | ||||
/* | /* | ||||
* 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 | ||||
▲ Show 20 Lines • Show All 87 Lines • Show Last 20 Lines |
Can offset + PAGE_MASK overflow ?