summaryrefslogtreecommitdiff
path: root/sys/ufs/ffs/ffs_inode.c
diff options
context:
space:
mode:
authorArtur Grabowski <art@cvs.openbsd.org>2001-11-27 05:27:13 +0000
committerArtur Grabowski <art@cvs.openbsd.org>2001-11-27 05:27:13 +0000
commit8a1845e49f56720cbfccd4c7f5f80ba5b980fdf4 (patch)
treed4a522dc41cdc79ba48fe761e94663b795da8cc0 /sys/ufs/ffs/ffs_inode.c
parent0d68e9b5af14f4bfa04d22dbebab5972ac647b26 (diff)
Merge in the unified buffer cache code as found in NetBSD 2001/03/10. The
code is written mostly by Chuck Silvers <chuq@chuq.com>/<chs@netbsd.org>. Tested for the past few weeks by many developers, should be in a pretty stable state, but will require optimizations and additional cleanups.
Diffstat (limited to 'sys/ufs/ffs/ffs_inode.c')
-rw-r--r--sys/ufs/ffs/ffs_inode.c121
1 files changed, 58 insertions, 63 deletions
diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c
index c81c795b2ac..cddf6a368ca 100644
--- a/sys/ufs/ffs/ffs_inode.c
+++ b/sys/ufs/ffs/ffs_inode.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ffs_inode.c,v 1.25 2001/11/21 21:23:56 csapuntz Exp $ */
+/* $OpenBSD: ffs_inode.c,v 1.26 2001/11/27 05:27:12 art Exp $ */
/* $NetBSD: ffs_inode.c,v 1.10 1996/05/11 18:27:19 mycroft Exp $ */
/*
@@ -150,14 +150,14 @@ ffs_truncate(struct inode *oip, off_t length, int flags, struct ucred *cred)
{
struct vnode *ovp;
daddr_t lastblock;
- daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR];
+ daddr_t bn, lastiblock[NIADDR], indir_lbn[NIADDR];
daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
struct fs *fs;
- struct buf *bp;
+ struct proc *p = curproc;
int offset, size, level;
long count, nblocks, vflags, blocksreleased = 0;
register int i;
- int aflags, error, allerror;
+ int error, allerror;
off_t osize;
if (length < 0)
@@ -188,10 +188,55 @@ ffs_truncate(struct inode *oip, off_t length, int flags, struct ucred *cred)
if ((error = getinoquota(oip)) != 0)
return (error);
- uvm_vnp_setsize(ovp, length);
+ fs = oip->i_fs;
+ if (length > fs->fs_maxfilesize)
+ return (EFBIG);
+ osize = oip->i_ffs_size;
oip->i_ci.ci_lasta = oip->i_ci.ci_clen
= oip->i_ci.ci_cstart = oip->i_ci.ci_lastw = 0;
+ /*
+ * Lengthen the size of the file. We must ensure that the
+ * last byte of the file is allocated. Since the smallest
+ * value of osize is 0, length will be at least 1.
+ */
+
+ if (osize < length) {
+ ufs_balloc_range(ovp, length - 1, 1, cred,
+ flags & IO_SYNC ? B_SYNC : 0);
+ oip->i_flag |= IN_CHANGE | IN_UPDATE;
+ return (UFS_UPDATE(oip, 1));
+ }
+
+ /*
+ * When truncating a regular file down to a non-block-aligned size,
+ * we must zero the part of last block which is past the new EOF.
+ * We must synchronously flush the zeroed pages to disk
+ * since the new pages will be invalidated as soon as we
+ * inform the VM system of the new, smaller size.
+ * We must to this before acquiring the GLOCK, since fetching
+ * the pages will acquire the GLOCK internally.
+ * So there is a window where another thread could see a whole
+ * zeroed page past EOF, but that's life.
+ */
+
+ offset = blkoff(fs, length);
+ if (ovp->v_type == VREG && length < osize && offset != 0) {
+ struct uvm_object *uobj;
+ voff_t eoz;
+
+ size = blksize(fs, oip, lblkno(fs, length));
+ eoz = min(lblktosize(fs, lblkno(fs, length)) + size, osize);
+ uvm_vnp_zerorange(ovp, length, eoz - length);
+ uobj = &ovp->v_uvm.u_obj;
+ simple_lock(&uobj->vmobjlock);
+ uobj->pgops->pgo_flush(uobj, length, eoz,
+ PGO_CLEANIT|PGO_DEACTIVATE|PGO_SYNCIO);
+ simple_unlock(&ovp->v_uvm.u_obj.vmobjlock);
+ }
+
+ lockmgr(&ovp->v_glock, LK_EXCLUSIVE, NULL, p);
+
if (DOINGSOFTDEP(ovp)) {
if (length > 0 || softdep_slowdown(ovp)) {
/*
@@ -204,80 +249,29 @@ ffs_truncate(struct inode *oip, off_t length, int flags, struct ucred *cred)
* so that it will have no data structures left.
*/
if ((error = VOP_FSYNC(ovp, cred, MNT_WAIT,
- curproc)) != 0)
+ curproc)) != 0) {
+ lockmgr(&ovp->v_glock, LK_RELEASE, NULL, p);
return (error);
+ }
} else {
+ uvm_vnp_setsize(ovp, length);
(void)ufs_quota_free_blocks(oip, oip->i_ffs_blocks,
NOCRED);
softdep_setup_freeblocks(oip, length);
(void) vinvalbuf(ovp, 0, cred, curproc, 0, 0);
+ lockmgr(&ovp->v_glock, LK_RELEASE, NULL, p);
oip->i_flag |= IN_CHANGE | IN_UPDATE;
return (UFS_UPDATE(oip, 0));
}
}
- fs = oip->i_fs;
- osize = oip->i_ffs_size;
/*
- * Lengthen the size of the file. We must ensure that the
- * last byte of the file is allocated. Since the smallest
- * value of osize is 0, length will be at least 1.
+ * Reduce the size of the file.
*/
- if (osize < length) {
- if (length > fs->fs_maxfilesize)
- return (EFBIG);
- aflags = B_CLRBUF;
- if (flags & IO_SYNC)
- aflags |= B_SYNC;
- error = UFS_BUF_ALLOC(oip, length - 1, 1,
- cred, aflags, &bp);
- if (error)
- return (error);
- oip->i_ffs_size = length;
- uvm_vnp_setsize(ovp, length);
- (void) uvm_vnp_uncache(ovp);
- if (aflags & B_SYNC)
- bwrite(bp);
- else
- bawrite(bp);
- oip->i_flag |= IN_CHANGE | IN_UPDATE;
- return (UFS_UPDATE(oip, MNT_WAIT));
- }
+ oip->i_ffs_size = length;
uvm_vnp_setsize(ovp, length);
/*
- * Shorten the size of the file. If the file is not being
- * truncated to a block boundary, the contents of the
- * partial block following the end of the file must be
- * zero'ed in case it ever becomes accessible again because
- * of subsequent file growth. Directories however are not
- * zero'ed as they should grow back initialized to empty.
- */
- offset = blkoff(fs, length);
- if (offset == 0) {
- oip->i_ffs_size = length;
- } else {
- lbn = lblkno(fs, length);
- aflags = B_CLRBUF;
- if (flags & IO_SYNC)
- aflags |= B_SYNC;
- error = UFS_BUF_ALLOC(oip, length - 1, 1,
- cred, aflags, &bp);
- if (error)
- return (error);
- oip->i_ffs_size = length;
- size = blksize(fs, oip, lbn);
- (void) uvm_vnp_uncache(ovp);
- if (ovp->v_type != VDIR)
- bzero((char *)bp->b_data + offset,
- (u_int)(size - offset));
- allocbuf(bp, size);
- if (aflags & B_SYNC)
- bwrite(bp);
- else
- bawrite(bp);
- }
- /*
* Calculate index into inode's block list of
* last direct and indirect blocks (if any)
* which we want to keep. Lastblock is -1 when
@@ -402,6 +396,7 @@ done:
oip->i_ffs_blocks -= blocksreleased;
if (oip->i_ffs_blocks < 0) /* sanity */
oip->i_ffs_blocks = 0;
+ lockmgr(&ovp->v_glock, LK_RELEASE, NULL, p);
oip->i_flag |= IN_CHANGE;
(void)ufs_quota_free_blocks(oip, blocksreleased, NOCRED);
return (allerror);