Module Name: src
Committed By: riastradh
Date: Fri Mar 27 17:27:56 UTC 2015
Modified Files:
src/sys/ufs/chfs: chfs_vnops.c
src/sys/ufs/ext2fs: ext2fs_extern.h ext2fs_lookup.c ext2fs_readwrite.c
ext2fs_rename.c ext2fs_vfsops.c ext2fs_vnops.c
src/sys/ufs/ffs: ffs_extern.h ffs_vfsops.c
src/sys/ufs/lfs: lfs_extern.h lfs_rename.c lfs_vnops.c ulfs_extern.h
ulfs_lookup.c ulfs_readwrite.c ulfs_vnops.c
src/sys/ufs/ufs: ufs_extern.h ufs_lookup.c ufs_readwrite.c ufs_rename.c
ufs_vnops.c ufsmount.h
Log Message:
Disentangle buffer-cached I/O from page-cached I/O in UFS.
Page-cached I/O is used for regular files, and is initiated by VFS
users such as userland and NFS.
Buffer-cached I/O is used for directories and symlinks, and is issued
only internally by UFS.
New UFS routine ufs_bufio replaces vn_rdwr for internal use.
ufs_bufio is implemented by new UFS operations uo_bufrd/uo_bufwr,
which sit in ufs_readwrite.c alongside the VOP_READ/VOP_WRITE
implementations.
I preserved the code as much as possible and will leave further
simplification for future commits. I kept the ulfs_readwrite.c
copypasta close to ufs_readwrite.c in case we ever want to merge them
back; likewise ext2fs_readwrite.c.
No externally visible semantic change. All atf fs tests still pass.
To generate a diff of this commit:
cvs rdiff -u -r1.24 -r1.25 src/sys/ufs/chfs/chfs_vnops.c
cvs rdiff -u -r1.47 -r1.48 src/sys/ufs/ext2fs/ext2fs_extern.h
cvs rdiff -u -r1.77 -r1.78 src/sys/ufs/ext2fs/ext2fs_lookup.c
cvs rdiff -u -r1.66 -r1.67 src/sys/ufs/ext2fs/ext2fs_readwrite.c
cvs rdiff -u -r1.7 -r1.8 src/sys/ufs/ext2fs/ext2fs_rename.c
cvs rdiff -u -r1.191 -r1.192 src/sys/ufs/ext2fs/ext2fs_vfsops.c
cvs rdiff -u -r1.115 -r1.116 src/sys/ufs/ext2fs/ext2fs_vnops.c
cvs rdiff -u -r1.81 -r1.82 src/sys/ufs/ffs/ffs_extern.h
cvs rdiff -u -r1.325 -r1.326 src/sys/ufs/ffs/ffs_vfsops.c
cvs rdiff -u -r1.101 -r1.102 src/sys/ufs/lfs/lfs_extern.h
cvs rdiff -u -r1.7 -r1.8 src/sys/ufs/lfs/lfs_rename.c \
src/sys/ufs/lfs/ulfs_readwrite.c
cvs rdiff -u -r1.269 -r1.270 src/sys/ufs/lfs/lfs_vnops.c
cvs rdiff -u -r1.13 -r1.14 src/sys/ufs/lfs/ulfs_extern.h
cvs rdiff -u -r1.21 -r1.22 src/sys/ufs/lfs/ulfs_lookup.c \
src/sys/ufs/lfs/ulfs_vnops.c
cvs rdiff -u -r1.78 -r1.79 src/sys/ufs/ufs/ufs_extern.h
cvs rdiff -u -r1.132 -r1.133 src/sys/ufs/ufs/ufs_lookup.c
cvs rdiff -u -r1.107 -r1.108 src/sys/ufs/ufs/ufs_readwrite.c
cvs rdiff -u -r1.11 -r1.12 src/sys/ufs/ufs/ufs_rename.c
cvs rdiff -u -r1.225 -r1.226 src/sys/ufs/ufs/ufs_vnops.c
cvs rdiff -u -r1.42 -r1.43 src/sys/ufs/ufs/ufsmount.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/ufs/chfs/chfs_vnops.c
diff -u src/sys/ufs/chfs/chfs_vnops.c:1.24 src/sys/ufs/chfs/chfs_vnops.c:1.25
--- src/sys/ufs/chfs/chfs_vnops.c:1.24 Sun Jan 11 17:29:57 2015
+++ src/sys/ufs/chfs/chfs_vnops.c Fri Mar 27 17:27:55 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: chfs_vnops.c,v 1.24 2015/01/11 17:29:57 hannken Exp $ */
+/* $NetBSD: chfs_vnops.c,v 1.25 2015/03/27 17:27:55 riastradh Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
@@ -1310,9 +1310,8 @@ chfs_symlink(void *v)
uvm_vnp_setsize(vp, len);
} else {
- err = vn_rdwr(UIO_WRITE, vp, target, len, (off_t)0,
- UIO_SYSSPACE, IO_NODELOCKED, cnp->cn_cred,
- (size_t *)0, NULL);
+ err = ufs_bufio(UIO_WRITE, vp, target, len, (off_t)0,
+ IO_NODELOCKED, cnp->cn_cred, (size_t *)0, NULL);
}
out:
@@ -1454,7 +1453,7 @@ chfs_readlink(void *v)
return (0);
}
- return (VOP_READ(vp, uio, 0, cred));
+ return (UFS_BUFRD(vp, uio, 0, cred));
}
/* --------------------------------------------------------------------- */
Index: src/sys/ufs/ext2fs/ext2fs_extern.h
diff -u src/sys/ufs/ext2fs/ext2fs_extern.h:1.47 src/sys/ufs/ext2fs/ext2fs_extern.h:1.48
--- src/sys/ufs/ext2fs/ext2fs_extern.h:1.47 Sun May 25 14:07:19 2014
+++ src/sys/ufs/ext2fs/ext2fs_extern.h Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ext2fs_extern.h,v 1.47 2014/05/25 14:07:19 hannken Exp $ */
+/* $NetBSD: ext2fs_extern.h,v 1.48 2015/03/27 17:27:56 riastradh Exp $ */
/*-
* Copyright (c) 1991, 1993, 1994
@@ -147,6 +147,8 @@ void ext2fs_set_inode_guid(struct inode
/* ext2fs_readwrite.c */
int ext2fs_read(void *);
int ext2fs_write(void *);
+int ext2fs_bufrd(struct vnode *, struct uio *, int, kauth_cred_t);
+int ext2fs_bufwr(struct vnode *, struct uio *, int, kauth_cred_t);
/* ext2fs_vnops.c */
int ext2fs_create(void *);
Index: src/sys/ufs/ext2fs/ext2fs_lookup.c
diff -u src/sys/ufs/ext2fs/ext2fs_lookup.c:1.77 src/sys/ufs/ext2fs/ext2fs_lookup.c:1.78
--- src/sys/ufs/ext2fs/ext2fs_lookup.c:1.77 Tue Jun 3 19:30:29 2014
+++ src/sys/ufs/ext2fs/ext2fs_lookup.c Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ext2fs_lookup.c,v 1.77 2014/06/03 19:30:29 joerg Exp $ */
+/* $NetBSD: ext2fs_lookup.c,v 1.78 2015/03/27 17:27:56 riastradh Exp $ */
/*
* Modified for NetBSD 1.2E
@@ -48,7 +48,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ext2fs_lookup.c,v 1.77 2014/06/03 19:30:29 joerg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ext2fs_lookup.c,v 1.78 2015/03/27 17:27:56 riastradh Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -180,7 +180,7 @@ ext2fs_readdir(void *v)
}
aiov.iov_base = dirbuf;
- error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
+ error = UFS_BUFRD(ap->a_vp, &auio, 0, ap->a_cred);
if (error == 0) {
readcnt = e2fs_count - auio.uio_resid;
for (dp = (struct ext2fs_direct *)dirbuf;
@@ -952,8 +952,8 @@ ext2fs_dirempty(struct inode *ip, ino_t
#define MINDIRSIZ (sizeof (struct ext2fs_dirtemplate) / 2)
for (off = 0; off < ext2fs_size(ip); off += fs2h16(dp->e2d_reclen)) {
- error = vn_rdwr(UIO_READ, ITOV(ip), (void *)dp, MINDIRSIZ, off,
- UIO_SYSSPACE, IO_NODELOCKED, cred, &count, NULL);
+ error = ufs_bufio(UIO_READ, ITOV(ip), (void *)dp, MINDIRSIZ,
+ off, IO_NODELOCKED, cred, &count, NULL);
/*
* Since we read MINDIRSIZ, residual must
* be 0 unless we're at end of file.
Index: src/sys/ufs/ext2fs/ext2fs_readwrite.c
diff -u src/sys/ufs/ext2fs/ext2fs_readwrite.c:1.66 src/sys/ufs/ext2fs/ext2fs_readwrite.c:1.67
--- src/sys/ufs/ext2fs/ext2fs_readwrite.c:1.66 Sun Nov 9 18:23:28 2014
+++ src/sys/ufs/ext2fs/ext2fs_readwrite.c Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ext2fs_readwrite.c,v 1.66 2014/11/09 18:23:28 maxv Exp $ */
+/* $NetBSD: ext2fs_readwrite.c,v 1.67 2015/03/27 17:27:56 riastradh Exp $ */
/*-
* Copyright (c) 1993
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ext2fs_readwrite.c,v 1.66 2014/11/09 18:23:28 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ext2fs_readwrite.c,v 1.67 2015/03/27 17:27:56 riastradh Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -97,13 +97,9 @@ ext2fs_read(void *v)
struct vnode *vp;
struct inode *ip;
struct uio *uio;
- struct m_ext2fs *fs;
- struct buf *bp;
struct ufsmount *ump;
vsize_t bytelen;
- daddr_t lbn, nextlbn;
- off_t bytesinfile;
- long size, xfersize, blkoffset;
+ int advice;
int error;
vp = ap->a_vp;
@@ -123,7 +119,10 @@ ext2fs_read(void *v)
} else if (vp->v_type != VREG && vp->v_type != VDIR)
panic("%s: type %d", "ext2fs_read", vp->v_type);
#endif
- fs = ip->i_e2fs;
+ /* XXX Eliminate me by refusing directory reads from userland. */
+ if (vp->v_type == VDIR)
+ return ext2fs_bufrd(vp, uio, ap->a_ioflag, ap->a_cred);
+
if ((uint64_t)uio->uio_offset > ump->um_maxfilesize)
return (EFBIG);
if (uio->uio_resid == 0)
@@ -131,22 +130,64 @@ ext2fs_read(void *v)
if (uio->uio_offset >= ext2fs_size(ip))
goto out;
- if (vp->v_type == VREG) {
- const int advice = IO_ADV_DECODE(ap->a_ioflag);
-
- while (uio->uio_resid > 0) {
- bytelen = MIN(ext2fs_size(ip) - uio->uio_offset,
+ KASSERT(vp->v_type == VREG);
+ advice = IO_ADV_DECODE(ap->a_ioflag);
+ while (uio->uio_resid > 0) {
+ bytelen = MIN(ext2fs_size(ip) - uio->uio_offset,
uio->uio_resid);
- if (bytelen == 0)
- break;
+ if (bytelen == 0)
+ break;
- error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
- UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
- if (error)
- break;
- }
- goto out;
+ error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
+ UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
+ if (error)
+ break;
+ }
+
+out:
+ if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
+ ip->i_flag |= IN_ACCESS;
+ if ((ap->a_ioflag & IO_SYNC) == IO_SYNC)
+ error = ext2fs_update(vp, NULL, NULL, UPDATE_WAIT);
}
+ return (error);
+}
+
+/*
+ * UFS op for reading via the buffer cache
+ */
+int
+ext2fs_bufrd(struct vnode *vp, struct uio *uio, int ioflag, kauth_cred_t cred)
+{
+ struct inode *ip;
+ struct ufsmount *ump;
+ struct m_ext2fs *fs;
+ struct buf *bp;
+ off_t bytesinfile;
+ daddr_t lbn, nextlbn;
+ long size, xfersize, blkoffset;
+ int error;
+
+ KASSERT(uio->uio_rw == UIO_READ);
+ KASSERT(VOP_ISLOCKED(vp));
+ KASSERT(vp->v_type == VDIR || vp->v_type == VLNK);
+
+ ip = VTOI(vp);
+ ump = ip->i_ump;
+ fs = ip->i_e2fs;
+ error = 0;
+
+ KASSERT(vp->v_type != VLNK ||
+ ext2fs_size(ip) >= ump->um_maxsymlinklen);
+ KASSERT(vp->v_type != VLNK || ump->um_maxsymlinklen != 0 ||
+ ext2fs_nblock(ip) != 0);
+
+ if (uio->uio_offset > ump->um_maxfilesize)
+ return EFBIG;
+ if (uio->uio_resid == 0)
+ return 0;
+ if (uio->uio_offset >= ext2fs_size(ip))
+ goto out;
for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
bytesinfile = ext2fs_size(ip) - uio->uio_offset;
@@ -196,7 +237,7 @@ ext2fs_read(void *v)
out:
if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
ip->i_flag |= IN_ACCESS;
- if ((ap->a_ioflag & IO_SYNC) == IO_SYNC)
+ if ((ioflag & IO_SYNC) == IO_SYNC)
error = ext2fs_update(vp, NULL, NULL, UPDATE_WAIT);
}
return (error);
@@ -218,11 +259,9 @@ ext2fs_write(void *v)
struct uio *uio;
struct inode *ip;
struct m_ext2fs *fs;
- struct buf *bp;
struct ufsmount *ump;
- daddr_t lbn;
off_t osize;
- int blkoffset, error, flags, ioflag, resid, xfersize;
+ int blkoffset, error, ioflag, resid;
vsize_t bytelen;
off_t oldoff = 0; /* XXX */
bool async;
@@ -271,58 +310,124 @@ ext2fs_write(void *v)
resid = uio->uio_resid;
osize = ext2fs_size(ip);
- if (vp->v_type == VREG) {
- while (uio->uio_resid > 0) {
- oldoff = uio->uio_offset;
- blkoffset = ext2_blkoff(fs, uio->uio_offset);
- bytelen = MIN(fs->e2fs_bsize - blkoffset,
- uio->uio_resid);
+ KASSERT(vp->v_type == VREG);
+ while (uio->uio_resid > 0) {
+ oldoff = uio->uio_offset;
+ blkoffset = ext2_blkoff(fs, uio->uio_offset);
+ bytelen = MIN(fs->e2fs_bsize - blkoffset, uio->uio_resid);
- if (vp->v_size < oldoff + bytelen) {
- uvm_vnp_setwritesize(vp, oldoff + bytelen);
- }
- error = ufs_balloc_range(vp, uio->uio_offset,
- bytelen, ap->a_cred, 0);
- if (error)
- break;
- error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
- UBC_WRITE | UBC_UNMAP_FLAG(vp));
- if (error)
- break;
+ if (vp->v_size < oldoff + bytelen) {
+ uvm_vnp_setwritesize(vp, oldoff + bytelen);
+ }
+ error = ufs_balloc_range(vp, uio->uio_offset, bytelen,
+ ap->a_cred, 0);
+ if (error)
+ break;
+ error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
+ UBC_WRITE | UBC_UNMAP_FLAG(vp));
+ if (error)
+ break;
+
+ /*
+ * update UVM's notion of the size now that we've
+ * copied the data into the vnode's pages.
+ */
- /*
- * update UVM's notion of the size now that we've
- * copied the data into the vnode's pages.
- */
-
- if (vp->v_size < uio->uio_offset) {
- uvm_vnp_setsize(vp, uio->uio_offset);
- extended = 1;
- }
-
- /*
- * flush what we just wrote if necessary.
- * XXXUBC simplistic async flushing.
- */
-
- if (!async && oldoff >> 16 != uio->uio_offset >> 16) {
- mutex_enter(vp->v_interlock);
- error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16,
- (uio->uio_offset >> 16) << 16,
- PGO_CLEANIT | PGO_LAZY);
- }
+ if (vp->v_size < uio->uio_offset) {
+ uvm_vnp_setsize(vp, uio->uio_offset);
+ extended = 1;
}
- if (error == 0 && ioflag & IO_SYNC) {
+
+ /*
+ * flush what we just wrote if necessary.
+ * XXXUBC simplistic async flushing.
+ */
+
+ if (!async && oldoff >> 16 != uio->uio_offset >> 16) {
mutex_enter(vp->v_interlock);
- error = VOP_PUTPAGES(vp, trunc_page(oldoff),
- round_page(ext2_blkroundup(fs, uio->uio_offset)),
- PGO_CLEANIT | PGO_SYNCIO);
+ error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16,
+ (uio->uio_offset >> 16) << 16,
+ PGO_CLEANIT | PGO_LAZY);
}
+ }
+ if (error == 0 && ioflag & IO_SYNC) {
+ mutex_enter(vp->v_interlock);
+ error = VOP_PUTPAGES(vp, trunc_page(oldoff),
+ round_page(ext2_blkroundup(fs, uio->uio_offset)),
+ PGO_CLEANIT | PGO_SYNCIO);
+ }
- goto out;
+ /*
+ * If we successfully wrote any data, and we are not the superuser
+ * we clear the setuid and setgid bits as a precaution against
+ * tampering.
+ */
+ ip->i_flag |= IN_CHANGE | IN_UPDATE;
+ if (vp->v_mount->mnt_flag & MNT_RELATIME)
+ ip->i_flag |= IN_ACCESS;
+ if (resid > uio->uio_resid && ap->a_cred) {
+ if (ip->i_e2fs_mode & ISUID) {
+ if (kauth_authorize_vnode(ap->a_cred,
+ KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0)
+ ip->i_e2fs_mode &= ISUID;
+ }
+
+ if (ip->i_e2fs_mode & ISGID) {
+ if (kauth_authorize_vnode(ap->a_cred,
+ KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0)
+ ip->i_e2fs_mode &= ~ISGID;
+ }
}
+ if (resid > uio->uio_resid)
+ VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
+ if (error) {
+ (void) ext2fs_truncate(vp, osize, ioflag & IO_SYNC, ap->a_cred);
+ uio->uio_offset -= resid - uio->uio_resid;
+ uio->uio_resid = resid;
+ } else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC)
+ error = ext2fs_update(vp, NULL, NULL, UPDATE_WAIT);
+ KASSERT(vp->v_size == ext2fs_size(ip));
+ return (error);
+}
+
+/*
+ * UFS op for writing via the buffer cache
+ */
+int
+ext2fs_bufwr(struct vnode *vp, struct uio *uio, int ioflag, kauth_cred_t cred)
+{
+ struct inode *ip;
+ struct ufsmount *ump;
+ struct m_ext2fs *fs;
+ struct buf *bp;
+ int flags;
+ off_t osize;
+ daddr_t lbn;
+ int resid, blkoffset, xfersize;
+ int extended = 0;
+ int error;
+
+ KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
+ KASSERT(vp->v_type == VDIR || vp->v_type == VLNK);
+ KASSERT(vp->v_type != VDIR || ISSET(ioflag, IO_SYNC));
+ KASSERT(uio->uio_rw == UIO_WRITE);
+
+ ip = VTOI(vp);
+ ump = ip->i_ump;
+ fs = ip->i_e2fs;
+ error = 0;
+
+ if (uio->uio_offset < 0 ||
+ uio->uio_resid > ump->um_maxfilesize ||
+ uio->uio_offset > (ump->um_maxfilesize - uio->uio_resid))
+ return EFBIG;
+ if (uio->uio_resid == 0)
+ return 0;
flags = ioflag & IO_SYNC ? B_SYNC : 0;
+ resid = uio->uio_resid;
+ osize = ext2fs_size(ip);
+
for (error = 0; uio->uio_resid > 0;) {
lbn = ext2_lblkno(fs, uio->uio_offset);
blkoffset = ext2_blkoff(fs, uio->uio_offset);
@@ -331,8 +436,8 @@ ext2fs_write(void *v)
flags |= B_CLRBUF;
else
flags &= ~B_CLRBUF;
- error = ext2fs_balloc(ip,
- lbn, blkoffset + xfersize, ap->a_cred, &bp, flags);
+ error = ext2fs_balloc(ip, lbn, blkoffset + xfersize, cred, &bp,
+ flags);
if (error)
break;
if (ext2fs_size(ip) < uio->uio_offset + xfersize) {
@@ -367,20 +472,18 @@ ext2fs_write(void *v)
* we clear the setuid and setgid bits as a precaution against
* tampering.
*/
-
-out:
ip->i_flag |= IN_CHANGE | IN_UPDATE;
if (vp->v_mount->mnt_flag & MNT_RELATIME)
ip->i_flag |= IN_ACCESS;
- if (resid > uio->uio_resid && ap->a_cred) {
+ if (resid > uio->uio_resid && cred) {
if (ip->i_e2fs_mode & ISUID) {
- if (kauth_authorize_vnode(ap->a_cred,
+ if (kauth_authorize_vnode(cred,
KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0)
ip->i_e2fs_mode &= ISUID;
}
if (ip->i_e2fs_mode & ISGID) {
- if (kauth_authorize_vnode(ap->a_cred,
+ if (kauth_authorize_vnode(cred,
KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0)
ip->i_e2fs_mode &= ~ISGID;
}
@@ -388,7 +491,7 @@ out:
if (resid > uio->uio_resid)
VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
if (error) {
- (void) ext2fs_truncate(vp, osize, ioflag & IO_SYNC, ap->a_cred);
+ (void) ext2fs_truncate(vp, osize, ioflag & IO_SYNC, cred);
uio->uio_offset -= resid - uio->uio_resid;
uio->uio_resid = resid;
} else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC)
Index: src/sys/ufs/ext2fs/ext2fs_rename.c
diff -u src/sys/ufs/ext2fs/ext2fs_rename.c:1.7 src/sys/ufs/ext2fs/ext2fs_rename.c:1.8
--- src/sys/ufs/ext2fs/ext2fs_rename.c:1.7 Sun May 25 13:46:58 2014
+++ src/sys/ufs/ext2fs/ext2fs_rename.c Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ext2fs_rename.c,v 1.7 2014/05/25 13:46:58 hannken Exp $ */
+/* $NetBSD: ext2fs_rename.c,v 1.8 2015/03/27 17:27:56 riastradh Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ext2fs_rename.c,v 1.7 2014/05/25 13:46:58 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ext2fs_rename.c,v 1.8 2015/03/27 17:27:56 riastradh Exp $");
#include <sys/param.h>
#include <sys/buf.h>
@@ -892,8 +892,8 @@ ext2fs_read_dotdot(struct vnode *vp, kau
KASSERT(ino_ret != NULL);
KASSERT(vp->v_type == VDIR);
- error = vn_rdwr(UIO_READ, vp, &dirbuf, sizeof dirbuf, (off_t)0,
- UIO_SYSSPACE, IO_NODELOCKED, cred, NULL, NULL);
+ error = ufs_bufio(UIO_READ, vp, &dirbuf, sizeof dirbuf, (off_t)0,
+ IO_NODELOCKED, cred, NULL, NULL);
if (error)
return error;
@@ -924,8 +924,8 @@ ext2fs_rename_replace_dotdot(struct vnod
VTOI(fdvp)->i_e2fs_nlink--;
VTOI(fdvp)->i_flag |= IN_CHANGE;
- error = vn_rdwr(UIO_READ, vp, &dirbuf, sizeof dirbuf, (off_t)0,
- UIO_SYSSPACE, IO_NODELOCKED, cred, NULL, NULL);
+ error = ufs_bufio(UIO_READ, vp, &dirbuf, sizeof dirbuf, (off_t)0,
+ IO_NODELOCKED, cred, NULL, NULL);
if (error)
return error;
@@ -944,8 +944,8 @@ ext2fs_rename_replace_dotdot(struct vnod
dirbuf.dotdot_ino = h2fs32(VTOI(tdvp)->i_number);
/* XXX WTF? Why not check error? */
- (void)vn_rdwr(UIO_WRITE, vp, &dirbuf, sizeof dirbuf, (off_t)0,
- UIO_SYSSPACE, (IO_NODELOCKED | IO_SYNC), cred, NULL, NULL);
+ (void)ufs_bufio(UIO_WRITE, vp, &dirbuf, sizeof dirbuf, (off_t)0,
+ (IO_NODELOCKED | IO_SYNC), cred, NULL, NULL);
return 0;
}
Index: src/sys/ufs/ext2fs/ext2fs_vfsops.c
diff -u src/sys/ufs/ext2fs/ext2fs_vfsops.c:1.191 src/sys/ufs/ext2fs/ext2fs_vfsops.c:1.192
--- src/sys/ufs/ext2fs/ext2fs_vfsops.c:1.191 Tue Mar 17 09:39:29 2015
+++ src/sys/ufs/ext2fs/ext2fs_vfsops.c Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ext2fs_vfsops.c,v 1.191 2015/03/17 09:39:29 hannken Exp $ */
+/* $NetBSD: ext2fs_vfsops.c,v 1.192 2015/03/27 17:27:56 riastradh Exp $ */
/*
* Copyright (c) 1989, 1991, 1993, 1994
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsops.c,v 1.191 2015/03/17 09:39:29 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsops.c,v 1.192 2015/03/27 17:27:56 riastradh Exp $");
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
@@ -156,6 +156,8 @@ static const struct genfs_ops ext2fs_gen
static const struct ufs_ops ext2fs_ufsops = {
.uo_itimes = ext2fs_itimes,
.uo_update = ext2fs_update,
+ .uo_bufrd = ext2fs_bufrd,
+ .uo_bufwr = ext2fs_bufwr,
};
/* Fill in the inode uid/gid from ext2 halves. */
Index: src/sys/ufs/ext2fs/ext2fs_vnops.c
diff -u src/sys/ufs/ext2fs/ext2fs_vnops.c:1.115 src/sys/ufs/ext2fs/ext2fs_vnops.c:1.116
--- src/sys/ufs/ext2fs/ext2fs_vnops.c:1.115 Sun Nov 9 18:23:28 2014
+++ src/sys/ufs/ext2fs/ext2fs_vnops.c Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ext2fs_vnops.c,v 1.115 2014/11/09 18:23:28 maxv Exp $ */
+/* $NetBSD: ext2fs_vnops.c,v 1.116 2015/03/27 17:27:56 riastradh Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@@ -65,7 +65,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ext2fs_vnops.c,v 1.115 2014/11/09 18:23:28 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ext2fs_vnops.c,v 1.116 2015/03/27 17:27:56 riastradh Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -727,9 +727,9 @@ ext2fs_mkdir(void *v)
dirtemplate.dotdot_type = EXT2_FT_DIR;
}
dirtemplate.dotdot_name[0] = dirtemplate.dotdot_name[1] = '.';
- error = vn_rdwr(UIO_WRITE, tvp, (void *)&dirtemplate,
- sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
- IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (size_t *)0, NULL);
+ error = ufs_bufio(UIO_WRITE, tvp, (void *)&dirtemplate,
+ sizeof (dirtemplate), (off_t)0, IO_NODELOCKED|IO_SYNC,
+ cnp->cn_cred, (size_t *)0, NULL);
if (error) {
dp->i_e2fs_nlink--;
dp->i_flag |= IN_CHANGE;
@@ -895,9 +895,8 @@ ext2fs_symlink(void *v)
ip->i_flag |= IN_ACCESS;
uvm_vnp_setsize(vp, len);
} else
- error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
- UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred,
- (size_t *)0, NULL);
+ error = ufs_bufio(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
+ IO_NODELOCKED, ap->a_cnp->cn_cred, (size_t *)0, NULL);
bad:
VOP_UNLOCK(vp);
if (error)
@@ -927,7 +926,7 @@ ext2fs_readlink(void *v)
uiomove((char *)ip->i_din.e2fs_din->e2di_shortlink, isize, ap->a_uio);
return (0);
}
- return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
+ return (UFS_BUFRD(vp, ap->a_uio, 0, ap->a_cred));
}
/*
Index: src/sys/ufs/ffs/ffs_extern.h
diff -u src/sys/ufs/ffs/ffs_extern.h:1.81 src/sys/ufs/ffs/ffs_extern.h:1.82
--- src/sys/ufs/ffs/ffs_extern.h:1.81 Tue Mar 17 09:39:29 2015
+++ src/sys/ufs/ffs/ffs_extern.h Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ffs_extern.h,v 1.81 2015/03/17 09:39:29 hannken Exp $ */
+/* $NetBSD: ffs_extern.h,v 1.82 2015/03/27 17:27:56 riastradh Exp $ */
/*-
* Copyright (c) 1991, 1993, 1994
@@ -127,6 +127,10 @@ int ffs_cgupdate(struct ufsmount *, int)
/* ffs_vnops.c */
int ffs_read(void *);
int ffs_write(void *);
+int ffs_bufio(enum uio_rw, struct vnode *, void *, size_t, off_t, int,
+ kauth_cred_t, size_t *, struct lwp *);
+int ffs_bufrd(struct vnode *, struct uio *, int, kauth_cred_t);
+int ffs_bufwr(struct vnode *, struct uio *, int, kauth_cred_t);
int ffs_fsync(void *);
int ffs_spec_fsync(void *);
int ffs_reclaim(void *);
Index: src/sys/ufs/ffs/ffs_vfsops.c
diff -u src/sys/ufs/ffs/ffs_vfsops.c:1.325 src/sys/ufs/ffs/ffs_vfsops.c:1.326
--- src/sys/ufs/ffs/ffs_vfsops.c:1.325 Tue Mar 17 09:39:29 2015
+++ src/sys/ufs/ffs/ffs_vfsops.c Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ffs_vfsops.c,v 1.325 2015/03/17 09:39:29 hannken Exp $ */
+/* $NetBSD: ffs_vfsops.c,v 1.326 2015/03/27 17:27:56 riastradh Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.325 2015/03/17 09:39:29 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.326 2015/03/27 17:27:56 riastradh Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@@ -182,6 +182,8 @@ static const struct ufs_ops ffs_ufsops =
.uo_truncate = ffs_truncate,
.uo_balloc = ffs_balloc,
.uo_snapgone = ffs_snapgone,
+ .uo_bufrd = ffs_bufrd,
+ .uo_bufwr = ffs_bufwr,
};
static int
Index: src/sys/ufs/lfs/lfs_extern.h
diff -u src/sys/ufs/lfs/lfs_extern.h:1.101 src/sys/ufs/lfs/lfs_extern.h:1.102
--- src/sys/ufs/lfs/lfs_extern.h:1.101 Tue Mar 18 18:20:44 2014
+++ src/sys/ufs/lfs/lfs_extern.h Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: lfs_extern.h,v 1.101 2014/03/18 18:20:44 riastradh Exp $ */
+/* $NetBSD: lfs_extern.h,v 1.102 2015/03/27 17:27:56 riastradh Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -272,6 +272,9 @@ int lfs_write (void *);
int lfs_getpages (void *);
int lfs_putpages (void *);
+int lfs_bufrd(struct vnode *, struct uio *, int, kauth_cred_t);
+int lfs_bufwr(struct vnode *, struct uio *, int, kauth_cred_t);
+
extern int lfs_mount_type;
extern int (**lfs_vnodeop_p)(void *);
extern int (**lfs_specop_p)(void *);
Index: src/sys/ufs/lfs/lfs_rename.c
diff -u src/sys/ufs/lfs/lfs_rename.c:1.7 src/sys/ufs/lfs/lfs_rename.c:1.8
--- src/sys/ufs/lfs/lfs_rename.c:1.7 Sat May 17 07:08:35 2014
+++ src/sys/ufs/lfs/lfs_rename.c Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: lfs_rename.c,v 1.7 2014/05/17 07:08:35 dholland Exp $ */
+/* $NetBSD: lfs_rename.c,v 1.8 2015/03/27 17:27:56 riastradh Exp $ */
/* from NetBSD: ufs_rename.c,v 1.6 2013/01/22 09:39:18 dholland Exp */
/*-
@@ -89,7 +89,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lfs_rename.c,v 1.7 2014/05/17 07:08:35 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lfs_rename.c,v 1.8 2015/03/27 17:27:56 riastradh Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -629,8 +629,8 @@ ulfs_read_dotdot(struct vnode *vp, kauth
KASSERT(ino_ret != NULL);
KASSERT(vp->v_type == VDIR);
- error = vn_rdwr(UIO_READ, vp, &dirbuf, sizeof dirbuf, (off_t)0,
- UIO_SYSSPACE, IO_NODELOCKED, cred, NULL, NULL);
+ error = ulfs_bufio(UIO_READ, vp, &dirbuf, sizeof dirbuf, (off_t)0,
+ IO_NODELOCKED, cred, NULL, NULL);
if (error)
return error;
Index: src/sys/ufs/lfs/ulfs_readwrite.c
diff -u src/sys/ufs/lfs/ulfs_readwrite.c:1.7 src/sys/ufs/lfs/ulfs_readwrite.c:1.8
--- src/sys/ufs/lfs/ulfs_readwrite.c:1.7 Thu Oct 17 21:01:08 2013
+++ src/sys/ufs/lfs/ulfs_readwrite.c Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ulfs_readwrite.c,v 1.7 2013/10/17 21:01:08 christos Exp $ */
+/* $NetBSD: ulfs_readwrite.c,v 1.8 2015/03/27 17:27:56 riastradh Exp $ */
/* from NetBSD: ufs_readwrite.c,v 1.105 2013/01/22 09:39:18 dholland Exp */
/*-
@@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: ulfs_readwrite.c,v 1.7 2013/10/17 21:01:08 christos Exp $");
+__KERNEL_RCSID(1, "$NetBSD: ulfs_readwrite.c,v 1.8 2015/03/27 17:27:56 riastradh Exp $");
#ifdef LFS_READWRITE
#define FS struct lfs
@@ -42,6 +42,8 @@ __KERNEL_RCSID(1, "$NetBSD: ulfs_readwri
#define READ_S "lfs_read"
#define WRITE lfs_write
#define WRITE_S "lfs_write"
+#define BUFRD lfs_bufrd
+#define BUFWR lfs_bufwr
#define fs_bsize lfs_bsize
#define fs_bmask lfs_bmask
#else
@@ -51,6 +53,8 @@ __KERNEL_RCSID(1, "$NetBSD: ulfs_readwri
#define READ_S "ffs_read"
#define WRITE ffs_write
#define WRITE_S "ffs_write"
+#define BUFRD ffs_bufrd
+#define BUFWR ffs_bufwr
#endif
/*
@@ -69,14 +73,9 @@ READ(void *v)
struct vnode *vp;
struct inode *ip;
struct uio *uio;
- struct buf *bp;
FS *fs;
vsize_t bytelen;
- daddr_t lbn, nextlbn;
- off_t bytesinfile;
- long size, xfersize, blkoffset;
- int error, ioflag;
- bool usepc = false;
+ int error, ioflag, advice;
vp = ap->a_vp;
ip = VTOI(vp);
@@ -89,13 +88,17 @@ READ(void *v)
if (uio->uio_rw != UIO_READ)
panic("%s: mode", READ_S);
- if (vp->v_type == VLNK) {
- if (ip->i_size < fs->um_maxsymlinklen ||
- (fs->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0))
- panic("%s: short symlink", READ_S);
- } else if (vp->v_type != VREG && vp->v_type != VDIR)
+ if (vp->v_type != VREG && vp->v_type != VDIR)
panic("%s: type %d", READ_S, vp->v_type);
#endif
+ /* XXX Eliminate me by refusing directory reads from userland. */
+ if (vp->v_type == VDIR)
+ return BUFRD(vp, uio, ioflag, ap->a_cred);
+#ifdef LFS_READWRITE
+ /* XXX Eliminate me by using ufs_bufio in lfs. */
+ if (vp->v_type == VREG && ip->i_number == LFS_IFILE_INUM)
+ return BUFRD(vp, uio, ioflag, ap->a_cred);
+#endif
if ((u_int64_t)uio->uio_offset > fs->um_maxfilesize)
return (EFBIG);
if (uio->uio_resid == 0)
@@ -111,30 +114,76 @@ READ(void *v)
if (uio->uio_offset >= ip->i_size)
goto out;
-#ifdef LFS_READWRITE
- usepc = (vp->v_type == VREG && ip->i_number != LFS_IFILE_INUM);
-#else /* !LFS_READWRITE */
- usepc = vp->v_type == VREG;
-#endif /* !LFS_READWRITE */
- if (usepc) {
- const int advice = IO_ADV_DECODE(ap->a_ioflag);
+ KASSERT(vp->v_type == VREG);
+ advice = IO_ADV_DECODE(ap->a_ioflag);
+ while (uio->uio_resid > 0) {
+ if (ioflag & IO_DIRECT) {
+ genfs_directio(vp, uio, ioflag);
+ }
+ bytelen = MIN(ip->i_size - uio->uio_offset, uio->uio_resid);
+ if (bytelen == 0)
+ break;
+ error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
+ UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
+ if (error)
+ break;
+ }
- while (uio->uio_resid > 0) {
- if (ioflag & IO_DIRECT) {
- genfs_directio(vp, uio, ioflag);
- }
- bytelen = MIN(ip->i_size - uio->uio_offset,
- uio->uio_resid);
- if (bytelen == 0)
- break;
- error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
- UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
- if (error)
- break;
+ out:
+ if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
+ ip->i_flag |= IN_ACCESS;
+ if ((ap->a_ioflag & IO_SYNC) == IO_SYNC) {
+ error = lfs_update(vp, NULL, NULL, UPDATE_WAIT);
}
- goto out;
}
+ fstrans_done(vp->v_mount);
+ return (error);
+}
+
+/*
+ * UFS op for reading via the buffer cache
+ */
+int
+BUFRD(struct vnode *vp, struct uio *uio, int ioflag, kauth_cred_t cred)
+{
+ struct inode *ip;
+ FS *fs;
+ struct buf *bp;
+ daddr_t lbn, nextlbn;
+ off_t bytesinfile;
+ long size, xfersize, blkoffset;
+ int error;
+
+ KASSERT(VOP_ISLOCKED(vp));
+ KASSERT(vp->v_type == VDIR || vp->v_type == VLNK ||
+ vp->v_type == VREG);
+ KASSERT(uio->uio_rw == UIO_READ);
+
+ ip = VTOI(vp);
+ fs = ip->I_FS;
+ error = 0;
+
+ KASSERT(vp->v_type != VLNK || ip->i_size < fs->um_maxsymlinklen);
+ KASSERT(vp->v_type != VLNK || fs->um_maxsymlinklen != 0 ||
+ DIP(ip, blocks) == 0);
+ KASSERT(vp->v_type != VREG || vp == fs->lfs_ivnode);
+ KASSERT(vp->v_type != VREG || ip->i_number == LFS_IFILE_INUM);
+
+ if (uio->uio_offset > fs->um_maxfilesize)
+ return EFBIG;
+ if (uio->uio_resid == 0)
+ return 0;
+
+#ifndef LFS_READWRITE
+ KASSERT(!ISSET(ip->i_flags, (SF_SNAPSHOT | SF_SNAPINVAL)));
+#endif
+
+ fstrans_start(vp->v_mount, FSTRANS_SHARED);
+
+ if (uio->uio_offset >= ip->i_size)
+ goto out;
+
for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
bytesinfile = ip->i_size - uio->uio_offset;
if (bytesinfile <= 0)
@@ -180,7 +229,7 @@ READ(void *v)
out:
if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
ip->i_flag |= IN_ACCESS;
- if ((ap->a_ioflag & IO_SYNC) == IO_SYNC) {
+ if ((ioflag & IO_SYNC) == IO_SYNC) {
error = lfs_update(vp, NULL, NULL, UPDATE_WAIT);
}
}
@@ -205,19 +254,13 @@ WRITE(void *v)
struct uio *uio;
struct inode *ip;
FS *fs;
- struct buf *bp;
kauth_cred_t cred;
- daddr_t lbn;
off_t osize, origoff, oldoff, preallocoff, endallocoff, nsize;
- int blkoffset, error, flags, ioflag, resid, size, xfersize;
+ int blkoffset, error, flags, ioflag, resid;
int aflag;
int extended=0;
vsize_t bytelen;
bool async;
- bool usepc = false;
-#ifdef LFS_READWRITE
- bool need_unreserve = false;
-#endif
cred = ap->a_cred;
ioflag = ap->a_ioflag;
@@ -237,12 +280,6 @@ WRITE(void *v)
uio->uio_offset = ip->i_size;
if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size)
return (EPERM);
- /* FALLTHROUGH */
- case VLNK:
- break;
- case VDIR:
- if ((ioflag & IO_SYNC) == 0)
- panic("%s: nonsync dir write", WRITE_S);
break;
default:
panic("%s: type", WRITE_S);
@@ -270,15 +307,13 @@ WRITE(void *v)
osize = ip->i_size;
error = 0;
- usepc = vp->v_type == VREG;
+ KASSERT(vp->v_type == VREG);
#ifdef LFS_READWRITE
async = true;
lfs_availwait(fs, lfs_btofsb(fs, uio->uio_resid));
lfs_check(vp, LFS_UNUSED_LBN, 0);
#endif /* !LFS_READWRITE */
- if (!usepc)
- goto bcache;
preallocoff = round_page(lfs_blkroundup(fs, MAX(osize, uio->uio_offset)));
aflag = ioflag & IO_SYNC ? B_SYNC : 0;
@@ -412,9 +447,105 @@ WRITE(void *v)
round_page(lfs_blkroundup(fs, uio->uio_offset)),
PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED);
}
- goto out;
- bcache:
+ /*
+ * If we successfully wrote any data, and we are not the superuser
+ * we clear the setuid and setgid bits as a precaution against
+ * tampering.
+ */
+out:
+ ip->i_flag |= IN_CHANGE | IN_UPDATE;
+ if (vp->v_mount->mnt_flag & MNT_RELATIME)
+ ip->i_flag |= IN_ACCESS;
+ if (resid > uio->uio_resid && ap->a_cred) {
+ if (ip->i_mode & ISUID) {
+ if (kauth_authorize_vnode(ap->a_cred,
+ KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0) {
+ ip->i_mode &= ~ISUID;
+ DIP_ASSIGN(ip, mode, ip->i_mode);
+ }
+ }
+
+ if (ip->i_mode & ISGID) {
+ if (kauth_authorize_vnode(ap->a_cred,
+ KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0) {
+ ip->i_mode &= ~ISGID;
+ DIP_ASSIGN(ip, mode, ip->i_mode);
+ }
+ }
+ }
+ if (resid > uio->uio_resid)
+ VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
+ if (error) {
+ (void) lfs_truncate(vp, osize, ioflag & IO_SYNC, ap->a_cred);
+ uio->uio_offset -= resid - uio->uio_resid;
+ uio->uio_resid = resid;
+ } else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC) {
+ error = lfs_update(vp, NULL, NULL, UPDATE_WAIT);
+ } else {
+ /* nothing */
+ }
+ KASSERT(vp->v_size == ip->i_size);
+ fstrans_done(vp->v_mount);
+
+ return (error);
+}
+
+/*
+ * UFS op for writing via the buffer cache
+ */
+int
+BUFWR(struct vnode *vp, struct uio *uio, int ioflag, kauth_cred_t cred)
+{
+ struct inode *ip;
+ FS *fs;
+ int flags;
+ struct buf *bp;
+ off_t osize, origoff;
+ int resid, xfersize, size, blkoffset;
+ daddr_t lbn;
+ int extended=0;
+ int error;
+#ifdef LFS_READWRITE
+ bool need_unreserve = false;
+#endif
+
+ KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
+ KASSERT(vp->v_type == VDIR || vp->v_type == VLNK);
+ KASSERT(vp->v_type != VDIR || ISSET(ioflag, IO_SYNC));
+ KASSERT(uio->uio_rw == UIO_WRITE);
+
+ ip = VTOI(vp);
+ fs = ip->I_FS;
+
+ KASSERT(vp->v_size == ip->i_size);
+
+ if (uio->uio_offset < 0 ||
+ uio->uio_resid > fs->um_maxfilesize ||
+ uio->uio_offset > (fs->um_maxfilesize - uio->uio_resid))
+ return EFBIG;
+#ifdef LFS_READWRITE
+ KASSERT(vp != fs->lfs_ivnode);
+#endif
+ if (uio->uio_resid == 0)
+ return 0;
+
+ fstrans_start(vp->v_mount, FSTRANS_SHARED);
+
+ flags = ioflag & IO_SYNC ? B_SYNC : 0;
+ origoff = uio->uio_offset;
+ resid = uio->uio_resid;
+ osize = ip->i_size;
+ error = 0;
+
+ KASSERT(vp->v_type != VREG);
+
+#ifdef LFS_READWRITE
+ lfs_availwait(fs, lfs_btofsb(fs, uio->uio_resid));
+ lfs_check(vp, LFS_UNUSED_LBN, 0);
+#endif /* !LFS_READWRITE */
+
+ /* XXX Should never have cached pages here. */
mutex_enter(vp->v_interlock);
VOP_PUTPAGES(vp, trunc_page(origoff), round_page(origoff + resid),
PGO_CLEANIT | PGO_FREE | PGO_SYNCIO | PGO_JOURNALLOCKED);
@@ -434,8 +565,8 @@ WRITE(void *v)
break;
need_unreserve = true;
#endif
- error = lfs_balloc(vp, uio->uio_offset, xfersize,
- ap->a_cred, flags, &bp);
+ error = lfs_balloc(vp, uio->uio_offset, xfersize, cred, flags,
+ &bp);
if (error)
break;
@@ -488,13 +619,12 @@ WRITE(void *v)
* we clear the setuid and setgid bits as a precaution against
* tampering.
*/
-out:
ip->i_flag |= IN_CHANGE | IN_UPDATE;
if (vp->v_mount->mnt_flag & MNT_RELATIME)
ip->i_flag |= IN_ACCESS;
- if (resid > uio->uio_resid && ap->a_cred) {
+ if (resid > uio->uio_resid && cred) {
if (ip->i_mode & ISUID) {
- if (kauth_authorize_vnode(ap->a_cred,
+ if (kauth_authorize_vnode(cred,
KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0) {
ip->i_mode &= ~ISUID;
DIP_ASSIGN(ip, mode, ip->i_mode);
@@ -502,7 +632,7 @@ out:
}
if (ip->i_mode & ISGID) {
- if (kauth_authorize_vnode(ap->a_cred,
+ if (kauth_authorize_vnode(cred,
KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0) {
ip->i_mode &= ~ISGID;
DIP_ASSIGN(ip, mode, ip->i_mode);
@@ -512,7 +642,7 @@ out:
if (resid > uio->uio_resid)
VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
if (error) {
- (void) lfs_truncate(vp, osize, ioflag & IO_SYNC, ap->a_cred);
+ (void) lfs_truncate(vp, osize, ioflag & IO_SYNC, cred);
uio->uio_offset -= resid - uio->uio_resid;
uio->uio_resid = resid;
} else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC) {
Index: src/sys/ufs/lfs/lfs_vnops.c
diff -u src/sys/ufs/lfs/lfs_vnops.c:1.269 src/sys/ufs/lfs/lfs_vnops.c:1.270
--- src/sys/ufs/lfs/lfs_vnops.c:1.269 Fri Jul 25 08:20:53 2014
+++ src/sys/ufs/lfs/lfs_vnops.c Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: lfs_vnops.c,v 1.269 2014/07/25 08:20:53 dholland Exp $ */
+/* $NetBSD: lfs_vnops.c,v 1.270 2015/03/27 17:27:56 riastradh Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -125,7 +125,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,v 1.269 2014/07/25 08:20:53 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,v 1.270 2015/03/27 17:27:56 riastradh Exp $");
#ifdef _KERNEL_OPT
#include "opt_compat_netbsd.h"
@@ -691,9 +691,9 @@ lfs_symlink(void *v)
if ((*vpp)->v_mount->mnt_flag & MNT_RELATIME)
ip->i_flag |= IN_ACCESS;
} else {
- error = vn_rdwr(UIO_WRITE, *vpp, ap->a_target, len, (off_t)0,
- UIO_SYSSPACE, IO_NODELOCKED | IO_JOURNALLOCKED,
- ap->a_cnp->cn_cred, NULL, NULL);
+ error = ulfs_bufio(UIO_WRITE, *vpp, ap->a_target, len, (off_t)0,
+ IO_NODELOCKED | IO_JOURNALLOCKED, ap->a_cnp->cn_cred, NULL,
+ NULL);
}
VOP_UNLOCK(*vpp);
Index: src/sys/ufs/lfs/ulfs_extern.h
diff -u src/sys/ufs/lfs/ulfs_extern.h:1.13 src/sys/ufs/lfs/ulfs_extern.h:1.14
--- src/sys/ufs/lfs/ulfs_extern.h:1.13 Sun May 25 13:49:13 2014
+++ src/sys/ufs/lfs/ulfs_extern.h Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ulfs_extern.h,v 1.13 2014/05/25 13:49:13 hannken Exp $ */
+/* $NetBSD: ulfs_extern.h,v 1.14 2015/03/27 17:27:56 riastradh Exp $ */
/* from NetBSD: ufs_extern.h,v 1.72 2012/05/09 00:21:18 riastradh Exp */
/*-
@@ -170,6 +170,8 @@ int ulfs_makeinode(int, struct vnode *,
struct vnode **, struct componentname *);
int ulfs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t);
void ulfs_gop_markupdate(struct vnode *, int);
+int ulfs_bufio(enum uio_rw, struct vnode *, void *, size_t, off_t, int,
+ kauth_cred_t, size_t *, struct lwp *);
/*
* Snapshot function prototypes.
Index: src/sys/ufs/lfs/ulfs_lookup.c
diff -u src/sys/ufs/lfs/ulfs_lookup.c:1.21 src/sys/ufs/lfs/ulfs_lookup.c:1.22
--- src/sys/ufs/lfs/ulfs_lookup.c:1.21 Tue Jun 3 19:30:30 2014
+++ src/sys/ufs/lfs/ulfs_lookup.c Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ulfs_lookup.c,v 1.21 2014/06/03 19:30:30 joerg Exp $ */
+/* $NetBSD: ulfs_lookup.c,v 1.22 2015/03/27 17:27:56 riastradh Exp $ */
/* from NetBSD: ufs_lookup.c,v 1.122 2013/01/22 09:39:18 dholland Exp */
/*
@@ -38,7 +38,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ulfs_lookup.c,v 1.21 2014/06/03 19:30:30 joerg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ulfs_lookup.c,v 1.22 2015/03/27 17:27:56 riastradh Exp $");
#ifdef _KERNEL_OPT
#include "opt_lfs.h"
@@ -1216,8 +1216,8 @@ ulfs_dirempty(struct inode *ip, ino_t pa
for (off = 0; off < ip->i_size;
off += ulfs_rw16(dp->d_reclen, needswap)) {
- error = vn_rdwr(UIO_READ, ITOV(ip), (void *)dp, MINDIRSIZ, off,
- UIO_SYSSPACE, IO_NODELOCKED, cred, &count, NULL);
+ error = ulfs_bufio(UIO_READ, ITOV(ip), (void *)dp, MINDIRSIZ,
+ off, IO_NODELOCKED, cred, &count, NULL);
/*
* Since we read MINDIRSIZ, residual must
* be 0 unless we're at end of file.
Index: src/sys/ufs/lfs/ulfs_vnops.c
diff -u src/sys/ufs/lfs/ulfs_vnops.c:1.21 src/sys/ufs/lfs/ulfs_vnops.c:1.22
--- src/sys/ufs/lfs/ulfs_vnops.c:1.21 Sat May 17 07:09:09 2014
+++ src/sys/ufs/lfs/ulfs_vnops.c Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ulfs_vnops.c,v 1.21 2014/05/17 07:09:09 dholland Exp $ */
+/* $NetBSD: ulfs_vnops.c,v 1.22 2015/03/27 17:27:56 riastradh Exp $ */
/* from NetBSD: ufs_vnops.c,v 1.213 2013/06/08 05:47:02 kardel Exp */
/*-
@@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ulfs_vnops.c,v 1.21 2014/05/17 07:09:09 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ulfs_vnops.c,v 1.22 2015/03/27 17:27:56 riastradh Exp $");
#if defined(_KERNEL_OPT)
#include "opt_lfs.h"
@@ -934,7 +934,7 @@ ulfs_readlink(void *v)
uiomove((char *)SHORTLINK(ip), isize, ap->a_uio);
return (0);
}
- return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
+ return (lfs_bufrd(vp, ap->a_uio, 0, ap->a_cred));
}
/*
@@ -1320,3 +1320,49 @@ ulfs_gop_markupdate(struct vnode *vp, in
ip->i_flag |= mask;
}
}
+
+int
+ulfs_bufio(enum uio_rw rw, struct vnode *vp, void *buf, size_t len, off_t off,
+ int ioflg, kauth_cred_t cred, size_t *aresid, struct lwp *l)
+{
+ struct iovec iov;
+ struct uio uio;
+ int error;
+
+ /* XXX Remove me -- all callers should be locked. */
+ if (!ISSET(ioflg, IO_NODELOCKED)) {
+ if (rw == UIO_READ)
+ vn_lock(vp, LK_SHARED | LK_RETRY);
+ else /* UIO_WRITE */
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ }
+
+ iov.iov_base = buf;
+ iov.iov_len = len;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_resid = len;
+ uio.uio_offset = off;
+ uio.uio_rw = rw;
+ UIO_SETUP_SYSSPACE(&uio);
+
+ switch (rw) {
+ case UIO_READ:
+ error = lfs_bufrd(vp, &uio, ioflg, cred);
+ break;
+ case UIO_WRITE:
+ error = lfs_bufwr(vp, &uio, ioflg, cred);
+ break;
+ default:
+ panic("invalid uio rw: %d", (int)rw);
+ }
+
+ if (aresid)
+ *aresid = uio.uio_resid;
+ else if (uio.uio_resid && error == 0)
+ error = EIO;
+
+ if (!ISSET(ioflg, IO_NODELOCKED))
+ VOP_UNLOCK(vp);
+ return error;
+}
Index: src/sys/ufs/ufs/ufs_extern.h
diff -u src/sys/ufs/ufs/ufs_extern.h:1.78 src/sys/ufs/ufs/ufs_extern.h:1.79
--- src/sys/ufs/ufs/ufs_extern.h:1.78 Tue Mar 17 09:39:29 2015
+++ src/sys/ufs/ufs/ufs_extern.h Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ufs_extern.h,v 1.78 2015/03/17 09:39:29 hannken Exp $ */
+/* $NetBSD: ufs_extern.h,v 1.79 2015/03/27 17:27:56 riastradh Exp $ */
/*-
* Copyright (c) 1991, 1993, 1994
@@ -186,6 +186,8 @@ void ufs_vinit(struct mount *, int (**)(
int (**)(void *), struct vnode **);
int ufs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t);
void ufs_gop_markupdate(struct vnode *, int);
+int ufs_bufio(enum uio_rw, struct vnode *, void *, size_t, off_t, int,
+ kauth_cred_t, size_t *, struct lwp *);
__END_DECLS
Index: src/sys/ufs/ufs/ufs_lookup.c
diff -u src/sys/ufs/ufs/ufs_lookup.c:1.132 src/sys/ufs/ufs/ufs_lookup.c:1.133
--- src/sys/ufs/ufs/ufs_lookup.c:1.132 Tue Jun 3 19:30:30 2014
+++ src/sys/ufs/ufs/ufs_lookup.c Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ufs_lookup.c,v 1.132 2014/06/03 19:30:30 joerg Exp $ */
+/* $NetBSD: ufs_lookup.c,v 1.133 2015/03/27 17:27:56 riastradh Exp $ */
/*
* Copyright (c) 1989, 1993
@@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_lookup.c,v 1.132 2014/06/03 19:30:30 joerg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_lookup.c,v 1.133 2015/03/27 17:27:56 riastradh Exp $");
#ifdef _KERNEL_OPT
#include "opt_ffs.h"
@@ -1182,8 +1182,8 @@ ufs_dirempty(struct inode *ip, ino_t par
for (off = 0; off < ip->i_size;
off += ufs_rw16(dp->d_reclen, needswap)) {
- error = vn_rdwr(UIO_READ, ITOV(ip), (void *)dp, MINDIRSIZ, off,
- UIO_SYSSPACE, IO_NODELOCKED, cred, &count, NULL);
+ error = ufs_bufio(UIO_READ, ITOV(ip), (void *)dp, MINDIRSIZ,
+ off, IO_NODELOCKED, cred, &count, NULL);
/*
* Since we read MINDIRSIZ, residual must
* be 0 unless we're at end of file.
Index: src/sys/ufs/ufs/ufs_readwrite.c
diff -u src/sys/ufs/ufs/ufs_readwrite.c:1.107 src/sys/ufs/ufs/ufs_readwrite.c:1.108
--- src/sys/ufs/ufs/ufs_readwrite.c:1.107 Sun Jun 23 07:28:37 2013
+++ src/sys/ufs/ufs/ufs_readwrite.c Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ufs_readwrite.c,v 1.107 2013/06/23 07:28:37 dholland Exp $ */
+/* $NetBSD: ufs_readwrite.c,v 1.108 2015/03/27 17:27:56 riastradh Exp $ */
/*-
* Copyright (c) 1993
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: ufs_readwrite.c,v 1.107 2013/06/23 07:28:37 dholland Exp $");
+__KERNEL_RCSID(1, "$NetBSD: ufs_readwrite.c,v 1.108 2015/03/27 17:27:56 riastradh Exp $");
#ifdef LFS_READWRITE
#define FS struct lfs
@@ -41,6 +41,8 @@ __KERNEL_RCSID(1, "$NetBSD: ufs_readwrit
#define READ_S "lfs_read"
#define WRITE lfs_write
#define WRITE_S "lfs_write"
+#define BUFRD lfs_bufrd
+#define BUFWR lfs_bufwr
#define fs_bsize lfs_bsize
#define fs_bmask lfs_bmask
#define UFS_WAPBL_BEGIN(mp) 0
@@ -58,6 +60,8 @@ __KERNEL_RCSID(1, "$NetBSD: ufs_readwrit
#define READ_S "ffs_read"
#define WRITE ffs_write
#define WRITE_S "ffs_write"
+#define BUFRD ffs_bufrd
+#define BUFWR ffs_bufwr
#define ufs_blkoff ffs_blkoff
#define ufs_blksize ffs_blksize
#define ufs_lblkno ffs_lblkno
@@ -82,14 +86,8 @@ READ(void *v)
struct inode *ip;
struct uio *uio;
struct ufsmount *ump;
- struct buf *bp;
- FS *fs;
vsize_t bytelen;
- daddr_t lbn, nextlbn;
- off_t bytesinfile;
- long size, xfersize, blkoffset;
- int error, ioflag;
- bool usepc = false;
+ int error, ioflag, advice;
vp = ap->a_vp;
ip = VTOI(vp);
@@ -102,14 +100,17 @@ READ(void *v)
if (uio->uio_rw != UIO_READ)
panic("%s: mode", READ_S);
- if (vp->v_type == VLNK) {
- if (ip->i_size < ump->um_maxsymlinklen ||
- (ump->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0))
- panic("%s: short symlink", READ_S);
- } else if (vp->v_type != VREG && vp->v_type != VDIR)
+ if (vp->v_type != VREG && vp->v_type != VDIR)
panic("%s: type %d", READ_S, vp->v_type);
#endif
- fs = ip->I_FS;
+ /* XXX Eliminate me by refusing directory reads from userland. */
+ if (vp->v_type == VDIR)
+ return BUFRD(vp, uio, ioflag, ap->a_cred);
+#ifdef LFS_READWRITE
+ /* XXX Eliminate me by using ufs_bufio in lfs. */
+ if (vp->v_type == VREG && ip->i_number == LFS_IFILE_INUM)
+ return BUFRD(vp, uio, ioflag, ap->a_cred);
+#endif
if ((u_int64_t)uio->uio_offset > ump->um_maxfilesize)
return (EFBIG);
if (uio->uio_resid == 0)
@@ -125,30 +126,81 @@ READ(void *v)
if (uio->uio_offset >= ip->i_size)
goto out;
-#ifdef LFS_READWRITE
- usepc = (vp->v_type == VREG && ip->i_number != LFS_IFILE_INUM);
-#else /* !LFS_READWRITE */
- usepc = vp->v_type == VREG;
-#endif /* !LFS_READWRITE */
- if (usepc) {
- const int advice = IO_ADV_DECODE(ap->a_ioflag);
+ KASSERT(vp->v_type == VREG);
+ advice = IO_ADV_DECODE(ap->a_ioflag);
+ while (uio->uio_resid > 0) {
+ if (ioflag & IO_DIRECT) {
+ genfs_directio(vp, uio, ioflag);
+ }
+ bytelen = MIN(ip->i_size - uio->uio_offset, uio->uio_resid);
+ if (bytelen == 0)
+ break;
+ error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
+ UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
+ if (error)
+ break;
+ }
- while (uio->uio_resid > 0) {
- if (ioflag & IO_DIRECT) {
- genfs_directio(vp, uio, ioflag);
+ out:
+ if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
+ ip->i_flag |= IN_ACCESS;
+ if ((ap->a_ioflag & IO_SYNC) == IO_SYNC) {
+ error = UFS_WAPBL_BEGIN(vp->v_mount);
+ if (error) {
+ fstrans_done(vp->v_mount);
+ return error;
}
- bytelen = MIN(ip->i_size - uio->uio_offset,
- uio->uio_resid);
- if (bytelen == 0)
- break;
- error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
- UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
- if (error)
- break;
+ error = UFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
+ UFS_WAPBL_END(vp->v_mount);
}
- goto out;
}
+ fstrans_done(vp->v_mount);
+ return (error);
+}
+
+/*
+ * UFS op for reading via the buffer cache
+ */
+int
+BUFRD(struct vnode *vp, struct uio *uio, int ioflag, kauth_cred_t cred)
+{
+ struct inode *ip;
+ struct ufsmount *ump;
+ FS *fs;
+ struct buf *bp;
+ daddr_t lbn, nextlbn;
+ off_t bytesinfile;
+ long size, xfersize, blkoffset;
+ int error;
+
+ KASSERT(VOP_ISLOCKED(vp));
+ KASSERT(vp->v_type == VDIR || vp->v_type == VLNK);
+ KASSERT(uio->uio_rw == UIO_READ);
+
+ ip = VTOI(vp);
+ ump = ip->i_ump;
+ fs = ip->I_FS;
+ error = 0;
+
+ KASSERT(vp->v_type != VLNK || ip->i_size >= ump->um_maxsymlinklen);
+ KASSERT(vp->v_type != VLNK || ump->um_maxsymlinklen != 0 ||
+ DIP(ip, blocks) == 0);
+
+ if (uio->uio_offset > ump->um_maxfilesize)
+ return EFBIG;
+ if (uio->uio_resid == 0)
+ return 0;
+
+#ifndef LFS_READWRITE
+ KASSERT(!ISSET(ip->i_flags, (SF_SNAPSHOT | SF_SNAPINVAL)));
+#endif
+
+ fstrans_start(vp->v_mount, FSTRANS_SHARED);
+
+ if (uio->uio_offset >= ip->i_size)
+ goto out;
+
for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
bytesinfile = ip->i_size - uio->uio_offset;
if (bytesinfile <= 0)
@@ -194,7 +246,7 @@ READ(void *v)
out:
if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
ip->i_flag |= IN_ACCESS;
- if ((ap->a_ioflag & IO_SYNC) == IO_SYNC) {
+ if ((ioflag & IO_SYNC) == IO_SYNC) {
error = UFS_WAPBL_BEGIN(vp->v_mount);
if (error) {
fstrans_done(vp->v_mount);
@@ -225,19 +277,13 @@ WRITE(void *v)
struct uio *uio;
struct inode *ip;
FS *fs;
- struct buf *bp;
kauth_cred_t cred;
- daddr_t lbn;
off_t osize, origoff, oldoff, preallocoff, endallocoff, nsize;
- int blkoffset, error, flags, ioflag, resid, size, xfersize;
+ int blkoffset, error, flags, ioflag, resid;
int aflag;
int extended=0;
vsize_t bytelen;
bool async;
- bool usepc = false;
-#ifdef LFS_READWRITE
- bool need_unreserve = false;
-#endif
struct ufsmount *ump;
cred = ap->a_cred;
@@ -259,12 +305,6 @@ WRITE(void *v)
uio->uio_offset = ip->i_size;
if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size)
return (EPERM);
- /* FALLTHROUGH */
- case VLNK:
- break;
- case VDIR:
- if ((ioflag & IO_SYNC) == 0)
- panic("%s: nonsync dir write", WRITE_S);
break;
default:
panic("%s: type", WRITE_S);
@@ -292,7 +332,7 @@ WRITE(void *v)
osize = ip->i_size;
error = 0;
- usepc = vp->v_type == VREG;
+ KASSERT(vp->v_type == VREG);
if ((ioflag & IO_JOURNALLOCKED) == 0) {
error = UFS_WAPBL_BEGIN(vp->v_mount);
@@ -307,8 +347,6 @@ WRITE(void *v)
lfs_availwait(fs, btofsb(fs, uio->uio_resid));
lfs_check(vp, LFS_UNUSED_LBN, 0);
#endif /* !LFS_READWRITE */
- if (!usepc)
- goto bcache;
preallocoff = round_page(ufs_blkroundup(fs, MAX(osize, uio->uio_offset)));
aflag = ioflag & IO_SYNC ? B_SYNC : 0;
@@ -440,9 +478,110 @@ WRITE(void *v)
round_page(ufs_blkroundup(fs, uio->uio_offset)),
PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED);
}
- goto out;
- bcache:
+ /*
+ * If we successfully wrote any data, and we are not the superuser
+ * we clear the setuid and setgid bits as a precaution against
+ * tampering.
+ */
+out:
+ ip->i_flag |= IN_CHANGE | IN_UPDATE;
+ if (vp->v_mount->mnt_flag & MNT_RELATIME)
+ ip->i_flag |= IN_ACCESS;
+ if (resid > uio->uio_resid && ap->a_cred) {
+ if (ip->i_mode & ISUID) {
+ if (kauth_authorize_vnode(ap->a_cred,
+ KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0) {
+ ip->i_mode &= ~ISUID;
+ DIP_ASSIGN(ip, mode, ip->i_mode);
+ }
+ }
+
+ if (ip->i_mode & ISGID) {
+ if (kauth_authorize_vnode(ap->a_cred,
+ KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0) {
+ ip->i_mode &= ~ISGID;
+ DIP_ASSIGN(ip, mode, ip->i_mode);
+ }
+ }
+ }
+ if (resid > uio->uio_resid)
+ VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
+ if (error) {
+ (void) UFS_TRUNCATE(vp, osize, ioflag & IO_SYNC, ap->a_cred);
+ uio->uio_offset -= resid - uio->uio_resid;
+ uio->uio_resid = resid;
+ } else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC)
+ error = UFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
+ else
+ UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
+ KASSERT(vp->v_size == ip->i_size);
+ if ((ioflag & IO_JOURNALLOCKED) == 0)
+ UFS_WAPBL_END(vp->v_mount);
+ fstrans_done(vp->v_mount);
+
+ return (error);
+}
+
+/*
+ * UFS op for writing via the buffer cache
+ */
+int
+BUFWR(struct vnode *vp, struct uio *uio, int ioflag, kauth_cred_t cred)
+{
+ struct inode *ip;
+ struct ufsmount *ump;
+ FS *fs;
+ int flags;
+ struct buf *bp;
+ off_t osize, origoff;
+ int resid, xfersize, size, blkoffset;
+ daddr_t lbn;
+ int extended=0;
+ int error;
+#ifdef LFS_READWRITE
+ bool need_unreserve = false;
+#endif
+
+ KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
+ KASSERT(vp->v_type == VDIR || vp->v_type == VLNK);
+ KASSERT(vp->v_type != VDIR || ISSET(ioflag, IO_SYNC));
+ KASSERT(uio->uio_rw == UIO_WRITE);
+
+ ip = VTOI(vp);
+ ump = ip->i_ump;
+ fs = ip->I_FS;
+
+ KASSERT(vp->v_size == ip->i_size);
+
+ if (uio->uio_offset < 0 ||
+ uio->uio_resid > ump->um_maxfilesize ||
+ uio->uio_offset > (ump->um_maxfilesize - uio->uio_resid))
+ return EFBIG;
+#ifdef LFS_READWRITE
+ KASSERT(vp != fs->lfs_ivnode);
+#endif
+ if (uio->uio_resid == 0)
+ return 0;
+
+ fstrans_start(vp->v_mount, FSTRANS_SHARED);
+
+ flags = ioflag & IO_SYNC ? B_SYNC : 0;
+ origoff = uio->uio_offset;
+ resid = uio->uio_resid;
+ osize = ip->i_size;
+ error = 0;
+
+ KASSERT(vp->v_type != VREG);
+ KASSERT(ISSET(ioflag, IO_JOURNALLOCKED));
+ UFS_WAPBL_JLOCK_ASSERT(vp->v_mount);
+
+#ifdef LFS_READWRITE
+ lfs_availwait(fs, btofsb(fs, uio->uio_resid));
+ lfs_check(vp, LFS_UNUSED_LBN, 0);
+#endif /* !LFS_READWRITE */
+
+ /* XXX Should never have pages cached here. */
mutex_enter(vp->v_interlock);
VOP_PUTPAGES(vp, trunc_page(origoff), round_page(origoff + resid),
PGO_CLEANIT | PGO_FREE | PGO_SYNCIO | PGO_JOURNALLOCKED);
@@ -462,8 +601,8 @@ WRITE(void *v)
break;
need_unreserve = true;
#endif
- error = UFS_BALLOC(vp, uio->uio_offset, xfersize,
- ap->a_cred, flags, &bp);
+ error = UFS_BALLOC(vp, uio->uio_offset, xfersize, cred, flags,
+ &bp);
if (error)
break;
@@ -516,13 +655,12 @@ WRITE(void *v)
* we clear the setuid and setgid bits as a precaution against
* tampering.
*/
-out:
ip->i_flag |= IN_CHANGE | IN_UPDATE;
if (vp->v_mount->mnt_flag & MNT_RELATIME)
ip->i_flag |= IN_ACCESS;
- if (resid > uio->uio_resid && ap->a_cred) {
+ if (resid > uio->uio_resid && cred) {
if (ip->i_mode & ISUID) {
- if (kauth_authorize_vnode(ap->a_cred,
+ if (kauth_authorize_vnode(cred,
KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0) {
ip->i_mode &= ~ISUID;
DIP_ASSIGN(ip, mode, ip->i_mode);
@@ -530,7 +668,7 @@ out:
}
if (ip->i_mode & ISGID) {
- if (kauth_authorize_vnode(ap->a_cred,
+ if (kauth_authorize_vnode(cred,
KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0) {
ip->i_mode &= ~ISGID;
DIP_ASSIGN(ip, mode, ip->i_mode);
@@ -540,7 +678,7 @@ out:
if (resid > uio->uio_resid)
VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
if (error) {
- (void) UFS_TRUNCATE(vp, osize, ioflag & IO_SYNC, ap->a_cred);
+ (void) UFS_TRUNCATE(vp, osize, ioflag & IO_SYNC, cred);
uio->uio_offset -= resid - uio->uio_resid;
uio->uio_resid = resid;
} else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC)
Index: src/sys/ufs/ufs/ufs_rename.c
diff -u src/sys/ufs/ufs/ufs_rename.c:1.11 src/sys/ufs/ufs/ufs_rename.c:1.12
--- src/sys/ufs/ufs/ufs_rename.c:1.11 Sun May 25 13:45:39 2014
+++ src/sys/ufs/ufs/ufs_rename.c Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ufs_rename.c,v 1.11 2014/05/25 13:45:39 hannken Exp $ */
+/* $NetBSD: ufs_rename.c,v 1.12 2015/03/27 17:27:56 riastradh Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_rename.c,v 1.11 2014/05/25 13:45:39 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_rename.c,v 1.12 2015/03/27 17:27:56 riastradh Exp $");
#include <sys/param.h>
#include <sys/buf.h>
@@ -874,8 +874,8 @@ ufs_read_dotdot(struct vnode *vp, kauth_
KASSERT(ino_ret != NULL);
KASSERT(vp->v_type == VDIR);
- error = vn_rdwr(UIO_READ, vp, &dirbuf, sizeof dirbuf, (off_t)0,
- UIO_SYSSPACE, IO_NODELOCKED, cred, NULL, NULL);
+ error = ufs_bufio(UIO_READ, vp, &dirbuf, sizeof dirbuf, (off_t)0,
+ IO_NODELOCKED, cred, NULL, NULL);
if (error)
return error;
Index: src/sys/ufs/ufs/ufs_vnops.c
diff -u src/sys/ufs/ufs/ufs_vnops.c:1.225 src/sys/ufs/ufs/ufs_vnops.c:1.226
--- src/sys/ufs/ufs/ufs_vnops.c:1.225 Tue Mar 17 09:39:29 2015
+++ src/sys/ufs/ufs/ufs_vnops.c Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ufs_vnops.c,v 1.225 2015/03/17 09:39:29 hannken Exp $ */
+/* $NetBSD: ufs_vnops.c,v 1.226 2015/03/27 17:27:56 riastradh Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_vnops.c,v 1.225 2015/03/17 09:39:29 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_vnops.c,v 1.226 2015/03/27 17:27:56 riastradh Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@@ -1210,9 +1210,9 @@ ufs_symlink(void *v)
ip->i_flag |= IN_ACCESS;
UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
} else
- error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
- UIO_SYSSPACE, IO_NODELOCKED | IO_JOURNALLOCKED,
- ap->a_cnp->cn_cred, NULL, NULL);
+ error = ufs_bufio(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
+ IO_NODELOCKED | IO_JOURNALLOCKED, ap->a_cnp->cn_cred, NULL,
+ NULL);
UFS_WAPBL_END1(ap->a_dvp->v_mount, ap->a_dvp);
VOP_UNLOCK(vp);
if (error)
@@ -1279,7 +1279,7 @@ ufs_readdir(void *v)
cdbuf = kmem_alloc(cdbufsz, KM_SLEEP);
aiov.iov_base = cdbuf;
aiov.iov_len = rcount;
- error = VOP_READ(vp, &auio, 0, ap->a_cred);
+ error = UFS_BUFRD(vp, &auio, 0, ap->a_cred);
if (error != 0) {
kmem_free(cdbuf, cdbufsz);
return error;
@@ -1399,7 +1399,7 @@ ufs_readlink(void *v)
uiomove((char *)SHORTLINK(ip), isize, ap->a_uio);
return (0);
}
- return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
+ return (UFS_BUFRD(vp, ap->a_uio, 0, ap->a_cred));
}
/*
@@ -1887,3 +1887,49 @@ ufs_gop_markupdate(struct vnode *vp, int
ip->i_flag |= mask;
}
}
+
+int
+ufs_bufio(enum uio_rw rw, struct vnode *vp, void *buf, size_t len, off_t off,
+ int ioflg, kauth_cred_t cred, size_t *aresid, struct lwp *l)
+{
+ struct iovec iov;
+ struct uio uio;
+ int error;
+
+ /* XXX Remove me -- all callers should be locked. */
+ if (!ISSET(ioflg, IO_NODELOCKED)) {
+ if (rw == UIO_READ)
+ vn_lock(vp, LK_SHARED | LK_RETRY);
+ else /* UIO_WRITE */
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ }
+
+ iov.iov_base = buf;
+ iov.iov_len = len;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_resid = len;
+ uio.uio_offset = off;
+ uio.uio_rw = rw;
+ UIO_SETUP_SYSSPACE(&uio);
+
+ switch (rw) {
+ case UIO_READ:
+ error = UFS_BUFRD(vp, &uio, ioflg, cred);
+ break;
+ case UIO_WRITE:
+ error = UFS_BUFWR(vp, &uio, ioflg, cred);
+ break;
+ default:
+ panic("invalid uio rw: %d", (int)rw);
+ }
+
+ if (aresid)
+ *aresid = uio.uio_resid;
+ else if (uio.uio_resid && error == 0)
+ error = EIO;
+
+ if (!ISSET(ioflg, IO_NODELOCKED))
+ VOP_UNLOCK(vp);
+ return error;
+}
Index: src/sys/ufs/ufs/ufsmount.h
diff -u src/sys/ufs/ufs/ufsmount.h:1.42 src/sys/ufs/ufs/ufsmount.h:1.43
--- src/sys/ufs/ufs/ufsmount.h:1.42 Tue Mar 17 09:39:29 2015
+++ src/sys/ufs/ufs/ufsmount.h Fri Mar 27 17:27:56 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ufsmount.h,v 1.42 2015/03/17 09:39:29 hannken Exp $ */
+/* $NetBSD: ufsmount.h,v 1.43 2015/03/27 17:27:56 riastradh Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@@ -137,6 +137,8 @@ struct ufs_ops {
int (*uo_balloc)(struct vnode *, off_t, int, kauth_cred_t, int,
struct buf **);
void (*uo_snapgone)(struct vnode *);
+ int (*uo_bufrd)(struct vnode *, struct uio *, int, kauth_cred_t);
+ int (*uo_bufwr)(struct vnode *, struct uio *, int, kauth_cred_t);
};
#define UFS_OPS(vp) (VFSTOUFS((vp)->v_mount)->um_ops)
@@ -151,6 +153,10 @@ struct ufs_ops {
(*UFS_OPS(vp)->uo_balloc)((vp), (off), (size), (cr), (flags), (bpp))
#define UFS_SNAPGONE(vp) \
(*UFS_OPS(vp)->uo_snapgone)((vp))
+#define UFS_BUFRD(vp, uio, ioflag, cred) \
+ (*UFS_OPS(vp)->uo_bufrd)((vp), (uio), (ioflag), (cred))
+#define UFS_BUFWR(vp, uio, ioflag, cred) \
+ (*UFS_OPS(vp)->uo_bufwr)((vp), (uio), (ioflag), (cred))
/* UFS-specific flags */
#define UFS_NEEDSWAP 0x01 /* filesystem metadata need byte-swapping */