summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-01-07 20:05:19 +0000
committerjhb <jhb@FreeBSD.org>2008-01-07 20:05:19 +0000
commitf8a246b9791d1450cf4945cc7b38f651a3a456ee (patch)
tree4cf9280569e048ce55d457d60918586c5cf023e5
parent1b130ab3271ae64d5c2979889a661e27bbe422d9 (diff)
downloadFreeBSD-src-f8a246b9791d1450cf4945cc7b38f651a3a456ee.zip
FreeBSD-src-f8a246b9791d1450cf4945cc7b38f651a3a456ee.tar.gz
Make ftruncate a 'struct file' operation rather than a vnode operation.
This makes it possible to support ftruncate() on non-vnode file types in the future. - 'struct fileops' grows a 'fo_truncate' method to handle an ftruncate() on a given file descriptor. - ftruncate() moves to kern/sys_generic.c and now just fetches a file object and invokes fo_truncate(). - The vnode-specific portions of ftruncate() move to vn_truncate() in vfs_vnops.c which implements fo_truncate() for vnode file types. - Non-vnode file types return EINVAL in their fo_truncate() method. Submitted by: rwatson
-rw-r--r--sys/dev/streams/streams.c1
-rw-r--r--sys/fs/devfs/devfs_vnops.c8
-rw-r--r--sys/fs/fifofs/fifo_vnops.c9
-rw-r--r--sys/kern/kern_descrip.c8
-rw-r--r--sys/kern/kern_event.c11
-rw-r--r--sys/kern/sys_generic.c67
-rw-r--r--sys/kern/sys_pipe.c14
-rw-r--r--sys/kern/sys_socket.c9
-rw-r--r--sys/kern/uipc_mqueue.c9
-rw-r--r--sys/kern/vfs_syscalls.c90
-rw-r--r--sys/kern/vfs_vnops.c49
-rw-r--r--sys/opencrypto/cryptodev.c14
-rw-r--r--sys/sys/file.h16
-rw-r--r--sys/sys/syscallsubr.h1
14 files changed, 215 insertions, 91 deletions
diff --git a/sys/dev/streams/streams.c b/sys/dev/streams/streams.c
index 55df9e5..5b97f85 100644
--- a/sys/dev/streams/streams.c
+++ b/sys/dev/streams/streams.c
@@ -90,6 +90,7 @@ static struct cdev *dt_ptm, *dt_arp, *dt_icmp, *dt_ip, *dt_tcp, *dt_udp,
static struct fileops svr4_netops = {
.fo_read = soo_read,
.fo_write = soo_write,
+ .fo_truncate = soo_truncate,
.fo_ioctl = soo_ioctl,
.fo_poll = soo_poll,
.fo_kqfilter = soo_kqfilter,
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
index 269f2c3..7c753f1 100644
--- a/sys/fs/devfs/devfs_vnops.c
+++ b/sys/fs/devfs/devfs_vnops.c
@@ -1278,6 +1278,13 @@ devfs_symlink(struct vop_symlink_args *ap)
return (devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, td));
}
+static int
+devfs_truncate_f(struct file *fp, off_t length, struct ucred *cred, struct thread *td)
+{
+
+ return (vnops.fo_truncate(fp, length, cred, td));
+}
+
/* ARGSUSED */
static int
devfs_write_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td)
@@ -1322,6 +1329,7 @@ dev2udev(struct cdev *x)
static struct fileops devfs_ops_f = {
.fo_read = devfs_read_f,
.fo_write = devfs_write_f,
+ .fo_truncate = devfs_truncate_f,
.fo_ioctl = devfs_ioctl_f,
.fo_poll = devfs_poll_f,
.fo_kqfilter = devfs_kqfilter_f,
diff --git a/sys/fs/fifofs/fifo_vnops.c b/sys/fs/fifofs/fifo_vnops.c
index 78718db..9b0ad1e 100644
--- a/sys/fs/fifofs/fifo_vnops.c
+++ b/sys/fs/fifofs/fifo_vnops.c
@@ -61,10 +61,12 @@ static fo_poll_t fifo_poll_f;
static fo_kqfilter_t fifo_kqfilter_f;
static fo_stat_t fifo_stat_f;
static fo_close_t fifo_close_f;
+static fo_truncate_t fifo_truncate_f;
struct fileops fifo_ops_f = {
.fo_read = fifo_read_f,
.fo_write = fifo_write_f,
+ .fo_truncate = fifo_truncate_f,
.fo_ioctl = fifo_ioctl_f,
.fo_poll = fifo_poll_f,
.fo_kqfilter = fifo_kqfilter_f,
@@ -724,6 +726,13 @@ fifo_stat_f(struct file *fp, struct stat *sb, struct ucred *cred, struct thread
}
static int
+fifo_truncate_f(struct file *fp, off_t length, struct ucred *cred, struct thread *td)
+{
+
+ return (vnops.fo_truncate(fp, length, cred, td));
+}
+
+static int
fifo_write_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td)
{
struct fifoinfo *fip;
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index d68854e..24438dd 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -2760,6 +2760,13 @@ badfo_readwrite(struct file *fp, struct uio *uio, struct ucred *active_cred, int
}
static int
+badfo_truncate(struct file *fp, off_t length, struct ucred *active_cred, struct thread *td)
+{
+
+ return (EINVAL);
+}
+
+static int
badfo_ioctl(struct file *fp, u_long com, void *data, struct ucred *active_cred, struct thread *td)
{
@@ -2797,6 +2804,7 @@ badfo_close(struct file *fp, struct thread *td)
struct fileops badfileops = {
.fo_read = badfo_readwrite,
.fo_write = badfo_readwrite,
+ .fo_truncate = badfo_truncate,
.fo_ioctl = badfo_ioctl,
.fo_poll = badfo_poll,
.fo_kqfilter = badfo_kqfilter,
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index b5d01d0..171a150 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -105,6 +105,7 @@ static void kqueue_fo_release(int filt);
static fo_rdwr_t kqueue_read;
static fo_rdwr_t kqueue_write;
+static fo_truncate_t kqueue_truncate;
static fo_ioctl_t kqueue_ioctl;
static fo_poll_t kqueue_poll;
static fo_kqfilter_t kqueue_kqfilter;
@@ -114,6 +115,7 @@ static fo_close_t kqueue_close;
static struct fileops kqueueops = {
.fo_read = kqueue_read,
.fo_write = kqueue_write,
+ .fo_truncate = kqueue_truncate,
.fo_ioctl = kqueue_ioctl,
.fo_poll = kqueue_poll,
.fo_kqfilter = kqueue_kqfilter,
@@ -1324,6 +1326,15 @@ kqueue_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
/*ARGSUSED*/
static int
+kqueue_truncate(struct file *fp, off_t length, struct ucred *active_cred,
+ struct thread *td)
+{
+
+ return (EINVAL);
+}
+
+/*ARGSUSED*/
+static int
kqueue_ioctl(struct file *fp, u_long cmd, void *data,
struct ucred *active_cred, struct thread *td)
{
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index 9c800f3..90946ea 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <sys/socketvar.h>
#include <sys/uio.h>
#include <sys/kernel.h>
+#include <sys/ktr.h>
#include <sys/limits.h>
#include <sys/malloc.h>
#include <sys/poll.h>
@@ -69,7 +70,7 @@ __FBSDID("$FreeBSD$");
#include <sys/ktrace.h>
#endif
-#include <sys/ktr.h>
+#include <security/audit/audit.h>
static MALLOC_DEFINE(M_IOCTLOPS, "ioctlops", "ioctl data buffer");
static MALLOC_DEFINE(M_SELECT, "select", "select() buffer");
@@ -544,6 +545,70 @@ dofilewrite(td, fd, fp, auio, offset, flags)
return (error);
}
+/*
+ * Truncate a file given a file descriptor.
+ *
+ * Can't use fget_write() here, since must return EINVAL and not EBADF if the
+ * descriptor isn't writable.
+ */
+int
+kern_ftruncate(td, fd, length)
+ struct thread *td;
+ int fd;
+ off_t length;
+{
+ struct file *fp;
+ int error;
+
+ AUDIT_ARG(fd, fd);
+ if (length < 0)
+ return (EINVAL);
+ error = fget(td, fd, &fp);
+ if (error)
+ return (error);
+ AUDIT_ARG(file, td->td_proc, fp);
+ if (!(fp->f_flag & FWRITE)) {
+ fdrop(fp, td);
+ return (EINVAL);
+ }
+ error = fo_truncate(fp, length, td->td_ucred, td);
+ fdrop(fp, td);
+ return (error);
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct ftruncate_args {
+ int fd;
+ int pad;
+ off_t length;
+};
+#endif
+int
+ftruncate(td, uap)
+ struct thread *td;
+ struct ftruncate_args *uap;
+{
+
+ return (kern_ftruncate(td, uap->fd, uap->length));
+}
+
+#if defined(COMPAT_43)
+#ifndef _SYS_SYSPROTO_H_
+struct oftruncate_args {
+ int fd;
+ long length;
+};
+#endif
+int
+oftruncate(td, uap)
+ struct thread *td;
+ struct oftruncate_args *uap;
+{
+
+ return (kern_ftruncate(td, uap->fd, uap->length));
+}
+#endif /* COMPAT_43 */
+
#ifndef _SYS_SYSPROTO_H_
struct ioctl_args {
int fd;
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index 27ecf80..457f30b 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
@@ -140,6 +140,7 @@ __FBSDID("$FreeBSD$");
*/
static fo_rdwr_t pipe_read;
static fo_rdwr_t pipe_write;
+static fo_truncate_t pipe_truncate;
static fo_ioctl_t pipe_ioctl;
static fo_poll_t pipe_poll;
static fo_kqfilter_t pipe_kqfilter;
@@ -149,6 +150,7 @@ static fo_close_t pipe_close;
static struct fileops pipeops = {
.fo_read = pipe_read,
.fo_write = pipe_write,
+ .fo_truncate = pipe_truncate,
.fo_ioctl = pipe_ioctl,
.fo_poll = pipe_poll,
.fo_kqfilter = pipe_kqfilter,
@@ -1230,6 +1232,18 @@ pipe_write(fp, uio, active_cred, flags, td)
return (error);
}
+/* ARGSUSED */
+static int
+pipe_truncate(fp, length, active_cred, td)
+ struct file *fp;
+ off_t length;
+ struct ucred *active_cred;
+ struct thread *td;
+{
+
+ return (EINVAL);
+}
+
/*
* we implement a very minimal set of ioctls for compatibility with sockets.
*/
diff --git a/sys/kern/sys_socket.c b/sys/kern/sys_socket.c
index 7e4547c..8e6b5f2 100644
--- a/sys/kern/sys_socket.c
+++ b/sys/kern/sys_socket.c
@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
struct fileops socketops = {
.fo_read = soo_read,
.fo_write = soo_write,
+ .fo_truncate = soo_truncate,
.fo_ioctl = soo_ioctl,
.fo_poll = soo_poll,
.fo_kqfilter = soo_kqfilter,
@@ -110,6 +111,14 @@ soo_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
}
int
+soo_truncate(struct file *fp, off_t length, struct ucred *active_cred,
+ struct thread *td)
+{
+
+ return (EINVAL);
+}
+
+int
soo_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *active_cred,
struct thread *td)
{
diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c
index 8fe34bc..2d2a477 100644
--- a/sys/kern/uipc_mqueue.c
+++ b/sys/kern/uipc_mqueue.c
@@ -2317,6 +2317,14 @@ mqf_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
}
static int
+mqf_truncate(struct file *fp, off_t length, struct ucred *active_cred,
+ struct thread *td)
+{
+
+ return (EINVAL);
+}
+
+static int
mqf_ioctl(struct file *fp, u_long cmd, void *data,
struct ucred *active_cred, struct thread *td)
{
@@ -2433,6 +2441,7 @@ filt_mqwrite(struct knote *kn, long hint)
static struct fileops mqueueops = {
.fo_read = mqf_read,
.fo_write = mqf_write,
+ .fo_truncate = mqf_truncate,
.fo_ioctl = mqf_ioctl,
.fo_poll = mqf_poll,
.fo_kqfilter = mqf_kqfilter,
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 0e42ea3..483651e 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -3086,68 +3086,6 @@ kern_truncate(struct thread *td, char *path, enum uio_seg pathseg, off_t length)
return (error);
}
-/*
- * Truncate a file given a file descriptor.
- */
-#ifndef _SYS_SYSPROTO_H_
-struct ftruncate_args {
- int fd;
- int pad;
- off_t length;
-};
-#endif
-int
-ftruncate(td, uap)
- struct thread *td;
- register struct ftruncate_args /* {
- int fd;
- int pad;
- off_t length;
- } */ *uap;
-{
- struct mount *mp;
- struct vattr vattr;
- struct vnode *vp;
- struct file *fp;
- int vfslocked;
- int error;
-
- AUDIT_ARG(fd, uap->fd);
- if (uap->length < 0)
- return(EINVAL);
- if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
- return (error);
- if ((fp->f_flag & FWRITE) == 0) {
- fdrop(fp, td);
- return (EINVAL);
- }
- vp = fp->f_vnode;
- vfslocked = VFS_LOCK_GIANT(vp->v_mount);
- if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
- goto drop;
- VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
- vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
- AUDIT_ARG(vnode, vp, ARG_VNODE1);
- if (vp->v_type == VDIR)
- error = EISDIR;
-#ifdef MAC
- else if ((error = mac_vnode_check_write(td->td_ucred, fp->f_cred,
- vp))) {
- }
-#endif
- else if ((error = vn_writechk(vp)) == 0) {
- VATTR_NULL(&vattr);
- vattr.va_size = uap->length;
- error = VOP_SETATTR(vp, &vattr, fp->f_cred, td);
- }
- VOP_UNLOCK(vp, 0, td);
- vn_finished_write(mp);
-drop:
- VFS_UNLOCK_GIANT(vfslocked);
- fdrop(fp, td);
- return (error);
-}
-
#if defined(COMPAT_43)
/*
* Truncate a file given its path name.
@@ -3176,34 +3114,6 @@ otruncate(td, uap)
nuap.length = uap->length;
return (truncate(td, &nuap));
}
-
-/*
- * Truncate a file given a file descriptor.
- */
-#ifndef _SYS_SYSPROTO_H_
-struct oftruncate_args {
- int fd;
- long length;
-};
-#endif
-int
-oftruncate(td, uap)
- struct thread *td;
- register struct oftruncate_args /* {
- int fd;
- long length;
- } */ *uap;
-{
- struct ftruncate_args /* {
- int fd;
- int pad;
- off_t length;
- } */ nuap;
-
- nuap.fd = uap->fd;
- nuap.length = uap->length;
- return (ftruncate(td, &nuap));
-}
#endif /* COMPAT_43 */
/* Versions with the pad argument */
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index 4826b08..10898e5 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$");
static fo_rdwr_t vn_read;
static fo_rdwr_t vn_write;
+static fo_truncate_t vn_truncate;
static fo_ioctl_t vn_ioctl;
static fo_poll_t vn_poll;
static fo_kqfilter_t vn_kqfilter;
@@ -75,6 +76,7 @@ static fo_close_t vn_closefile;
struct fileops vnops = {
.fo_read = vn_read,
.fo_write = vn_write,
+ .fo_truncate = vn_truncate,
.fo_ioctl = vn_ioctl,
.fo_poll = vn_poll,
.fo_kqfilter = vn_kqfilter,
@@ -607,6 +609,53 @@ unlock:
}
/*
+ * File table truncate routine.
+ */
+static int
+vn_truncate(fp, length, active_cred, td)
+ struct file *fp;
+ off_t length;
+ struct ucred *active_cred;
+ struct thread *td;
+{
+ struct vattr vattr;
+ struct mount *mp;
+ struct vnode *vp;
+ int vfslocked;
+ int error;
+
+ vp = fp->f_vnode;
+ vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+ error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
+ if (error) {
+ VFS_UNLOCK_GIANT(vfslocked);
+ return (error);
+ }
+ VOP_LEASE(vp, td, active_cred, LEASE_WRITE);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
+ if (vp->v_type == VDIR) {
+ error = EISDIR;
+ goto out;
+ }
+#ifdef MAC
+ error = mac_vnode_check_write(active_cred, fp->f_cred, vp);
+ if (error)
+ goto out;
+#endif
+ error = vn_writechk(vp);
+ if (error == 0) {
+ VATTR_NULL(&vattr);
+ vattr.va_size = length;
+ error = VOP_SETATTR(vp, &vattr, fp->f_cred, td);
+ }
+out:
+ VOP_UNLOCK(vp, 0, td);
+ vn_finished_write(mp);
+ VFS_UNLOCK_GIANT(vfslocked);
+ return (error);
+}
+
+/*
* File table vnode stat routine.
*/
static int
diff --git a/sys/opencrypto/cryptodev.c b/sys/opencrypto/cryptodev.c
index c9fc6d2..fe7372b 100644
--- a/sys/opencrypto/cryptodev.c
+++ b/sys/opencrypto/cryptodev.c
@@ -86,6 +86,8 @@ struct fcrypt {
static int cryptof_rw(struct file *fp, struct uio *uio,
struct ucred *cred, int flags, struct thread *);
+static int cryptof_truncate(struct file *, off_t, struct ucred *,
+ struct thread *);
static int cryptof_ioctl(struct file *, u_long, void *,
struct ucred *, struct thread *);
static int cryptof_poll(struct file *, int, struct ucred *, struct thread *);
@@ -97,6 +99,7 @@ static int cryptof_close(struct file *, struct thread *);
static struct fileops cryptofops = {
.fo_read = cryptof_rw,
.fo_write = cryptof_rw,
+ .fo_truncate = cryptof_truncate,
.fo_ioctl = cryptof_ioctl,
.fo_poll = cryptof_poll,
.fo_kqfilter = cryptof_kqfilter,
@@ -129,6 +132,17 @@ cryptof_rw(
return (EIO);
}
+static int
+cryptof_truncate(
+ struct file *fp,
+ off_t length,
+ struct ucred *active_cred,
+ struct thread *td)
+{
+
+ return (EINVAL);
+}
+
/*
* Check a crypto identifier to see if it requested
* a software device/driver. This can be done either
diff --git a/sys/sys/file.h b/sys/sys/file.h
index c5f4afb..757c884 100644
--- a/sys/sys/file.h
+++ b/sys/sys/file.h
@@ -69,6 +69,8 @@ typedef int fo_rdwr_t(struct file *fp, struct uio *uio,
struct ucred *active_cred, int flags,
struct thread *td);
#define FOF_OFFSET 1 /* Use the offset in uio argument */
+typedef int fo_truncate_t(struct file *fp, off_t length,
+ struct ucred *active_cred, struct thread *td);
typedef int fo_ioctl_t(struct file *fp, u_long com, void *data,
struct ucred *active_cred, struct thread *td);
typedef int fo_poll_t(struct file *fp, int events,
@@ -82,6 +84,7 @@ typedef int fo_flags_t;
struct fileops {
fo_rdwr_t *fo_read;
fo_rdwr_t *fo_write;
+ fo_truncate_t *fo_truncate;
fo_ioctl_t *fo_ioctl;
fo_poll_t *fo_poll;
fo_kqfilter_t *fo_kqfilter;
@@ -175,6 +178,7 @@ int _fdrop(struct file *fp, struct thread *td);
*/
fo_rdwr_t soo_read;
fo_rdwr_t soo_write;
+fo_truncate_t soo_truncate;
fo_ioctl_t soo_ioctl;
fo_poll_t soo_poll;
fo_kqfilter_t soo_kqfilter;
@@ -195,6 +199,7 @@ void fputsock(struct socket *sp);
static __inline fo_rdwr_t fo_read;
static __inline fo_rdwr_t fo_write;
+static __inline fo_truncate_t fo_truncate;
static __inline fo_ioctl_t fo_ioctl;
static __inline fo_poll_t fo_poll;
static __inline fo_kqfilter_t fo_kqfilter;
@@ -226,6 +231,17 @@ fo_write(fp, uio, active_cred, flags, td)
}
static __inline int
+fo_truncate(fp, length, active_cred, td)
+ struct file *fp;
+ off_t length;
+ struct ucred *active_cred;
+ struct thread *td;
+{
+
+ return ((*fp->f_ops->fo_truncate)(fp, length, active_cred, td));
+}
+
+static __inline int
fo_ioctl(fp, com, data, active_cred, td)
struct file *fp;
u_long com;
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index 1cba85d..b8d6113 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -82,6 +82,7 @@ int kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg);
int kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf);
int kern_fstat(struct thread *td, int fd, struct stat *sbp);
int kern_fstatfs(struct thread *td, int fd, struct statfs *buf);
+int kern_ftruncate(struct thread *td, int fd, off_t length);
int kern_futimes(struct thread *td, int fd, struct timeval *tptr,
enum uio_seg tptrseg);
int kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,
OpenPOWER on IntegriCloud