summaryrefslogtreecommitdiffstats
path: root/sys/kern/uipc_shm.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2013-08-21 17:45:00 +0000
committerkib <kib@FreeBSD.org>2013-08-21 17:45:00 +0000
commitd11c4f9c32bf7f78b6ca5f9fc02e869111dbe680 (patch)
treed04455df948dc71b9ece838e75596e329c610c9d /sys/kern/uipc_shm.c
parent6a459eb27c6a215b645e8673b5275f94003510a4 (diff)
downloadFreeBSD-src-d11c4f9c32bf7f78b6ca5f9fc02e869111dbe680.zip
FreeBSD-src-d11c4f9c32bf7f78b6ca5f9fc02e869111dbe680.tar.gz
Implement read(2)/write(2) and neccessary lseek(2) for posix shmfd.
Add MAC framework entries for posix shm read and write. Do not allow implicit extension of the underlying memory segment past the limit set by ftruncate(2) by either of the syscalls. Read and write returns short i/o, lseek(2) fails with EINVAL when resulting offset does not fit into the limit. Discussed with: alc Tested by: pho Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'sys/kern/uipc_shm.c')
-rw-r--r--sys/kern/uipc_shm.c90
1 files changed, 87 insertions, 3 deletions
diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c
index 55f350a..d034071 100644
--- a/sys/kern/uipc_shm.c
+++ b/sys/kern/uipc_shm.c
@@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sx.h>
#include <sys/time.h>
#include <sys/vnode.h>
+#include <sys/unistd.h>
#include <security/mac/mac_framework.h>
@@ -119,6 +120,7 @@ static fo_stat_t shm_stat;
static fo_close_t shm_close;
static fo_chmod_t shm_chmod;
static fo_chown_t shm_chown;
+static fo_seek_t shm_seek;
/* File descriptor operations. */
static struct fileops shm_ops = {
@@ -133,7 +135,8 @@ static struct fileops shm_ops = {
.fo_chmod = shm_chmod,
.fo_chown = shm_chown,
.fo_sendfile = invfo_sendfile,
- .fo_flags = DFLAG_PASSABLE
+ .fo_seek = shm_seek,
+ .fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE
};
FEATURE(posix_shm, "POSIX shared memory");
@@ -233,19 +236,96 @@ uiomove_object(vm_object_t obj, off_t obj_size, struct uio *uio)
}
static int
+shm_seek(struct file *fp, off_t offset, int whence, struct thread *td)
+{
+ struct shmfd *shmfd;
+ off_t foffset;
+ int error;
+
+ shmfd = fp->f_data;
+ foffset = foffset_lock(fp, 0);
+ error = 0;
+ switch (whence) {
+ case L_INCR:
+ if (foffset < 0 ||
+ (offset > 0 && foffset > OFF_MAX - offset)) {
+ error = EOVERFLOW;
+ break;
+ }
+ offset += foffset;
+ break;
+ case L_XTND:
+ if (offset > 0 && shmfd->shm_size > OFF_MAX - offset) {
+ error = EOVERFLOW;
+ break;
+ }
+ offset += shmfd->shm_size;
+ break;
+ case L_SET:
+ break;
+ default:
+ error = EINVAL;
+ }
+ if (error == 0) {
+ if (offset < 0 || offset > shmfd->shm_size)
+ error = EINVAL;
+ else
+ *(off_t *)(td->td_retval) = offset;
+ }
+ foffset_unlock(fp, offset, error != 0 ? FOF_NOUPDATE : 0);
+ return (error);
+}
+
+static int
shm_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
int flags, struct thread *td)
{
+ struct shmfd *shmfd;
+ void *rl_cookie;
+ int error;
- return (EOPNOTSUPP);
+ shmfd = fp->f_data;
+ foffset_lock_uio(fp, uio, flags);
+ rl_cookie = rangelock_rlock(&shmfd->shm_rl, uio->uio_offset,
+ uio->uio_offset + uio->uio_resid, &shmfd->shm_mtx);
+#ifdef MAC
+ error = mac_posixshm_check_read(active_cred, fp->f_cred, shmfd);
+ if (error)
+ return (error);
+#endif
+ error = uiomove_object(shmfd->shm_object, shmfd->shm_size, uio);
+ rangelock_unlock(&shmfd->shm_rl, rl_cookie, &shmfd->shm_mtx);
+ foffset_unlock_uio(fp, uio, flags);
+ return (error);
}
static int
shm_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
int flags, struct thread *td)
{
+ struct shmfd *shmfd;
+ void *rl_cookie;
+ int error;
- return (EOPNOTSUPP);
+ shmfd = fp->f_data;
+#ifdef MAC
+ error = mac_posixshm_check_write(active_cred, fp->f_cred, shmfd);
+ if (error)
+ return (error);
+#endif
+ foffset_lock_uio(fp, uio, flags);
+ if ((flags & FOF_OFFSET) == 0) {
+ rl_cookie = rangelock_wlock(&shmfd->shm_rl, 0, OFF_MAX,
+ &shmfd->shm_mtx);
+ } else {
+ rl_cookie = rangelock_wlock(&shmfd->shm_rl, uio->uio_offset,
+ uio->uio_offset + uio->uio_resid, &shmfd->shm_mtx);
+ }
+
+ error = uiomove_object(shmfd->shm_object, shmfd->shm_size, uio);
+ rangelock_unlock(&shmfd->shm_rl, rl_cookie, &shmfd->shm_mtx);
+ foffset_unlock_uio(fp, uio, flags);
+ return (error);
}
static int
@@ -471,6 +551,8 @@ shm_alloc(struct ucred *ucred, mode_t mode)
shmfd->shm_atime = shmfd->shm_mtime = shmfd->shm_ctime =
shmfd->shm_birthtime;
refcount_init(&shmfd->shm_refs, 1);
+ mtx_init(&shmfd->shm_mtx, "shmrl", NULL, MTX_DEF);
+ rangelock_init(&shmfd->shm_rl);
#ifdef MAC
mac_posixshm_init(shmfd);
mac_posixshm_create(ucred, shmfd);
@@ -495,6 +577,8 @@ shm_drop(struct shmfd *shmfd)
#ifdef MAC
mac_posixshm_destroy(shmfd);
#endif
+ rangelock_destroy(&shmfd->shm_rl);
+ mtx_destroy(&shmfd->shm_mtx);
vm_object_deallocate(shmfd->shm_object);
free(shmfd, M_SHMFD);
}
OpenPOWER on IntegriCloud