summaryrefslogtreecommitdiffstats
path: root/sys/kern/sys_generic.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2005-07-07 18:17:55 +0000
committerjhb <jhb@FreeBSD.org>2005-07-07 18:17:55 +0000
commitcf15cbb1b695b3bfb61d396be49bbf6ea3e889c1 (patch)
treec30d76b42af5454db3e0f1a3a40342b16e62fe4e /sys/kern/sys_generic.c
parent909e7ff886fb519c878c02fa47955048637cc7e7 (diff)
downloadFreeBSD-src-cf15cbb1b695b3bfb61d396be49bbf6ea3e889c1.zip
FreeBSD-src-cf15cbb1b695b3bfb61d396be49bbf6ea3e889c1.tar.gz
- Add two new system calls: preadv() and pwritev() which are like readv()
and writev() except that they take an additional offset argument and do not change the current file position. In SAT speak: preadv:readv::pread:read and pwritev:writev::pwrite:write. - Try to reduce code duplication some by merging most of the old kern_foov() and dofilefoo() functions into new dofilefoo() functions that are called by kern_foov() and kern_pfoov(). The non-v functions now all generate a simple uio on the stack from the passed in arguments and then call kern_foov(). For example, read() now just builds a uio and calls kern_readv() and pwrite() just builds a uio and calls kern_pwritev(). PR: kern/80362 Submitted by: Marc Olzheim marcolz at stack dot nl (1) Approved by: re (scottl) MFC after: 1 week
Diffstat (limited to 'sys/kern/sys_generic.c')
-rw-r--r--sys/kern/sys_generic.c365
1 files changed, 198 insertions, 167 deletions
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index a3ae444..3c7199a 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -77,10 +77,10 @@ MALLOC_DEFINE(M_IOV, "iov", "large iov's");
static int pollscan(struct thread *, struct pollfd *, u_int);
static int selscan(struct thread *, fd_mask **, fd_mask **, int);
-static int dofileread(struct thread *, struct file *, int, void *,
- size_t, off_t, int);
-static int dofilewrite(struct thread *, struct file *, int,
- const void *, size_t, off_t, int);
+static int dofileread(struct thread *, int, struct file *, struct uio *,
+ off_t, int);
+static int dofilewrite(struct thread *, int, struct file *, struct uio *,
+ off_t, int);
static void doselwakeup(struct selinfo *, int);
/*
@@ -101,19 +101,24 @@ read(td, uap)
struct thread *td;
struct read_args *uap;
{
- struct file *fp;
+ struct uio auio;
+ struct iovec aiov;
int error;
- if ((error = fget_read(td, uap->fd, &fp)) == 0) {
- error = dofileread(td, fp, uap->fd, uap->buf,
- uap->nbyte, (off_t)-1, 0);
- fdrop(fp, td);
- }
+ if (uap->nbyte > INT_MAX)
+ return (EINVAL);
+ aiov.iov_base = uap->buf;
+ aiov.iov_len = uap->nbyte;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_resid = uap->nbyte;
+ auio.uio_segflg = UIO_USERSPACE;
+ error = kern_readv(td, uap->fd, &auio);
return(error);
}
/*
- * Pread system call
+ * Positioned read system call
*/
#ifndef _SYS_SYSPROTO_H_
struct pread_args {
@@ -132,79 +137,20 @@ pread(td, uap)
struct thread *td;
struct pread_args *uap;
{
- struct file *fp;
- int error;
-
- if ((error = fget_read(td, uap->fd, &fp)) != 0)
- return (error);
- if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE))
- error = ESPIPE;
- else if (uap->offset < 0 && fp->f_vnode->v_type != VCHR)
- error = EINVAL;
- else {
- error = dofileread(td, fp, uap->fd, uap->buf, uap->nbyte,
- uap->offset, FOF_OFFSET);
- }
- fdrop(fp, td);
- return(error);
-}
-
-/*
- * Code common for read and pread
- */
-static int
-dofileread(td, fp, fd, buf, nbyte, offset, flags)
- struct thread *td;
- struct file *fp;
- int fd, flags;
- void *buf;
- size_t nbyte;
- off_t offset;
-{
struct uio auio;
struct iovec aiov;
- ssize_t cnt;
- long error = 0;
-#ifdef KTRACE
- struct uio *ktruio = NULL;
-#endif
+ int error;
- /* Finish zero length reads right here */
- if (nbyte == 0) {
- td->td_retval[0] = 0;
- return(0);
- }
- aiov.iov_base = buf;
- aiov.iov_len = nbyte;
+ if (uap->nbyte > INT_MAX)
+ return (EINVAL);
+ aiov.iov_base = uap->buf;
+ aiov.iov_len = uap->nbyte;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
- auio.uio_offset = offset;
- if (nbyte > INT_MAX)
- return (EINVAL);
- auio.uio_resid = nbyte;
- auio.uio_rw = UIO_READ;
+ auio.uio_resid = uap->nbyte;
auio.uio_segflg = UIO_USERSPACE;
- auio.uio_td = td;
-#ifdef KTRACE
- if (KTRPOINT(td, KTR_GENIO))
- ktruio = cloneuio(&auio);
-#endif
- cnt = nbyte;
-
- if ((error = fo_read(fp, &auio, td->td_ucred, flags, td))) {
- if (auio.uio_resid != cnt && (error == ERESTART ||
- error == EINTR || error == EWOULDBLOCK))
- error = 0;
- }
- cnt -= auio.uio_resid;
-#ifdef KTRACE
- if (ktruio != NULL) {
- ktruio->uio_resid = cnt;
- ktrgenio(fd, UIO_READ, ktruio, error);
- }
-#endif
- td->td_retval[0] = cnt;
- return (error);
+ error = kern_preadv(td, uap->fd, &auio, uap->offset);
+ return(error);
}
/*
@@ -238,29 +184,100 @@ int
kern_readv(struct thread *td, int fd, struct uio *auio)
{
struct file *fp;
- long cnt;
int error;
-#ifdef KTRACE
- struct uio *ktruio = NULL;
+
+ error = fget_read(td, fd, &fp);
+ if (error)
+ return (error);
+ error = dofileread(td, fd, fp, auio, (off_t)-1, 0);
+ fdrop(fp, td);
+ return (error);
+}
+
+/*
+ * Scatter positioned read system call.
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct preadv_args {
+ int fd;
+ struct iovec *iovp;
+ u_int iovcnt;
+ off_t offset;
+};
#endif
+/*
+ * MPSAFE
+ */
+int
+preadv(struct thread *td, struct preadv_args *uap)
+{
+ struct uio *auio;
+ int error;
+
+ error = copyinuio(uap->iovp, uap->iovcnt, &auio);
+ if (error)
+ return (error);
+ error = kern_preadv(td, uap->fd, auio, uap->offset);
+ free(auio, M_IOV);
+ return (error);
+}
+
+int
+kern_preadv(td, fd, auio, offset)
+ struct thread *td;
+ int fd;
+ struct uio *auio;
+ off_t offset;
+{
+ struct file *fp;
+ int error;
error = fget_read(td, fd, &fp);
if (error)
return (error);
+ if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE))
+ error = ESPIPE;
+ else if (offset < 0 && fp->f_vnode->v_type != VCHR)
+ error = EINVAL;
+ else
+ error = dofileread(td, fd, fp, auio, offset, FOF_OFFSET);
+ fdrop(fp, td);
+ return (error);
+}
+
+/*
+ * Common code for readv and preadv that reads data in
+ * from a file using the passed in uio, offset, and flags.
+ */
+static int
+dofileread(td, fd, fp, auio, offset, flags)
+ struct thread *td;
+ int fd;
+ struct file *fp;
+ struct uio *auio;
+ off_t offset;
+ int flags;
+{
+ ssize_t cnt;
+ int error;
+#ifdef KTRACE
+ struct uio *ktruio = NULL;
+#endif
+
/* Finish zero length reads right here */
if (auio->uio_resid == 0) {
td->td_retval[0] = 0;
- fdrop(fp, td);
return(0);
}
auio->uio_rw = UIO_READ;
+ auio->uio_offset = offset;
auio->uio_td = td;
#ifdef KTRACE
if (KTRPOINT(td, KTR_GENIO))
ktruio = cloneuio(auio);
#endif
cnt = auio->uio_resid;
- if ((error = fo_read(fp, auio, td->td_ucred, 0, td))) {
+ if ((error = fo_read(fp, auio, td->td_ucred, flags, td))) {
if (auio->uio_resid != cnt && (error == ERESTART ||
error == EINTR || error == EWOULDBLOCK))
error = 0;
@@ -273,7 +290,6 @@ kern_readv(struct thread *td, int fd, struct uio *auio)
}
#endif
td->td_retval[0] = cnt;
- fdrop(fp, td);
return (error);
}
@@ -295,21 +311,24 @@ write(td, uap)
struct thread *td;
struct write_args *uap;
{
- struct file *fp;
+ struct uio auio;
+ struct iovec aiov;
int error;
- if ((error = fget_write(td, uap->fd, &fp)) == 0) {
- error = dofilewrite(td, fp, uap->fd, uap->buf, uap->nbyte,
- (off_t)-1, 0);
- fdrop(fp, td);
- } else {
- error = EBADF; /* XXX this can't be right */
- }
+ if (uap->nbyte > INT_MAX)
+ return (EINVAL);
+ aiov.iov_base = (void *)(uintptr_t)uap->buf;
+ aiov.iov_len = uap->nbyte;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_resid = uap->nbyte;
+ auio.uio_segflg = UIO_USERSPACE;
+ error = kern_writev(td, uap->fd, &auio);
return(error);
}
/*
- * Pwrite system call
+ * Positioned write system call
*/
#ifndef _SYS_SYSPROTO_H_
struct pwrite_args {
@@ -328,80 +347,20 @@ pwrite(td, uap)
struct thread *td;
struct pwrite_args *uap;
{
- struct file *fp;
- int error;
-
- if ((error = fget_write(td, uap->fd, &fp)) == 0) {
- if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE))
- error = ESPIPE;
- else if (uap->offset < 0 && fp->f_vnode->v_type != VCHR)
- error = EINVAL;
- else {
- error = dofilewrite(td, fp, uap->fd, uap->buf,
- uap->nbyte, uap->offset, FOF_OFFSET);
- }
- fdrop(fp, td);
- } else {
- error = EBADF; /* this can't be right */
- }
- return(error);
-}
-
-static int
-dofilewrite(td, fp, fd, buf, nbyte, offset, flags)
- struct thread *td;
- struct file *fp;
- int fd, flags;
- const void *buf;
- size_t nbyte;
- off_t offset;
-{
struct uio auio;
struct iovec aiov;
- ssize_t cnt;
- long error = 0;
-#ifdef KTRACE
- struct uio *ktruio = NULL;
-#endif
+ int error;
- aiov.iov_base = (void *)(uintptr_t)buf;
- aiov.iov_len = nbyte;
+ if (uap->nbyte > INT_MAX)
+ return (EINVAL);
+ aiov.iov_base = (void *)(uintptr_t)uap->buf;
+ aiov.iov_len = uap->nbyte;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
- auio.uio_offset = offset;
- if (nbyte > INT_MAX)
- return (EINVAL);
- auio.uio_resid = nbyte;
- auio.uio_rw = UIO_WRITE;
+ auio.uio_resid = uap->nbyte;
auio.uio_segflg = UIO_USERSPACE;
- auio.uio_td = td;
-#ifdef KTRACE
- if (KTRPOINT(td, KTR_GENIO))
- ktruio = cloneuio(&auio);
-#endif
- cnt = nbyte;
- if (fp->f_type == DTYPE_VNODE)
- bwillwrite();
- if ((error = fo_write(fp, &auio, td->td_ucred, flags, td))) {
- if (auio.uio_resid != cnt && (error == ERESTART ||
- error == EINTR || error == EWOULDBLOCK))
- error = 0;
- /* Socket layer is responsible for issuing SIGPIPE. */
- if (error == EPIPE && fp->f_type != DTYPE_SOCKET) {
- PROC_LOCK(td->td_proc);
- psignal(td->td_proc, SIGPIPE);
- PROC_UNLOCK(td->td_proc);
- }
- }
- cnt -= auio.uio_resid;
-#ifdef KTRACE
- if (ktruio != NULL) {
- ktruio->uio_resid = cnt;
- ktrgenio(fd, UIO_WRITE, ktruio, error);
- }
-#endif
- td->td_retval[0] = cnt;
- return (error);
+ error = kern_pwritev(td, uap->fd, &auio, uap->offset);
+ return(error);
}
/*
@@ -435,17 +394,89 @@ int
kern_writev(struct thread *td, int fd, struct uio *auio)
{
struct file *fp;
- long cnt;
int error;
-#ifdef KTRACE
- struct uio *ktruio = NULL;
+
+ error = fget_write(td, fd, &fp);
+ if (error)
+ return (EBADF); /* XXX this can't be right */
+ error = dofilewrite(td, fd, fp, auio, (off_t)-1, 0);
+ fdrop(fp, td);
+ return (error);
+}
+
+/*
+ * Gather positioned write system call
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct pwritev_args {
+ int fd;
+ struct iovec *iovp;
+ u_int iovcnt;
+ off_t offset;
+};
#endif
+/*
+ * MPSAFE
+ */
+int
+pwritev(struct thread *td, struct pwritev_args *uap)
+{
+ struct uio *auio;
+ int error;
+
+ error = copyinuio(uap->iovp, uap->iovcnt, &auio);
+ if (error)
+ return (error);
+ error = kern_pwritev(td, uap->fd, auio, uap->offset);
+ free(auio, M_IOV);
+ return (error);
+}
+
+int
+kern_pwritev(td, fd, auio, offset)
+ struct thread *td;
+ struct uio *auio;
+ int fd;
+ off_t offset;
+{
+ struct file *fp;
+ int error;
error = fget_write(td, fd, &fp);
if (error)
- return (EBADF);
+ return (EBADF); /* XXX this can't be right */
+ if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE))
+ error = ESPIPE;
+ else if (offset < 0 && fp->f_vnode->v_type != VCHR)
+ error = EINVAL;
+ else
+ error = dofilewrite(td, fd, fp, auio, offset, FOF_OFFSET);
+ fdrop(fp, td);
+ return (error);
+}
+
+/*
+ * Common code for writev and pwritev that writes data to
+ * a file using the passed in uio, offset, and flags.
+ */
+static int
+dofilewrite(td, fd, fp, auio, offset, flags)
+ struct thread *td;
+ int fd;
+ struct file *fp;
+ struct uio *auio;
+ off_t offset;
+ int flags;
+{
+ ssize_t cnt;
+ int error;
+#ifdef KTRACE
+ struct uio *ktruio = NULL;
+#endif
+
auio->uio_rw = UIO_WRITE;
auio->uio_td = td;
+ auio->uio_offset = offset;
#ifdef KTRACE
if (KTRPOINT(td, KTR_GENIO))
ktruio = cloneuio(auio);
@@ -453,10 +484,11 @@ kern_writev(struct thread *td, int fd, struct uio *auio)
cnt = auio->uio_resid;
if (fp->f_type == DTYPE_VNODE)
bwillwrite();
- if ((error = fo_write(fp, auio, td->td_ucred, 0, td))) {
+ if ((error = fo_write(fp, auio, td->td_ucred, flags, td))) {
if (auio->uio_resid != cnt && (error == ERESTART ||
error == EINTR || error == EWOULDBLOCK))
error = 0;
+ /* Socket layer is responsible for issuing SIGPIPE. */
if (error == EPIPE) {
PROC_LOCK(td->td_proc);
psignal(td->td_proc, SIGPIPE);
@@ -471,7 +503,6 @@ kern_writev(struct thread *td, int fd, struct uio *auio)
}
#endif
td->td_retval[0] = cnt;
- fdrop(fp, td);
return (error);
}
OpenPOWER on IntegriCloud