improve post-ubc file overwrite performance in common cases.

ie. when it's safe, actually overwrite blocks rather than doing
read-modify-write.

also fixes PR/33152 and PR/36303.
This commit is contained in:
yamt 2007-06-05 12:31:30 +00:00
parent ae34899ec3
commit da51d139a4
16 changed files with 214 additions and 107 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_vnops.c,v 1.73 2007/06/01 15:59:37 yamt Exp $ */
/* $NetBSD: puffs_vnops.c,v 1.74 2007/06/05 12:31:30 yamt Exp $ */
/*
* Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved.
@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: puffs_vnops.c,v 1.73 2007/06/01 15:59:37 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: puffs_vnops.c,v 1.74 2007/06/05 12:31:30 yamt Exp $");
#include <sys/param.h>
#include <sys/fstrans.h>
@ -1552,7 +1552,6 @@ puffs_write(void *v)
struct puffs_mount *pmp;
struct uio *uio;
struct vnode *vp;
void *win;
size_t tomove, argsize;
off_t oldoff, newoff, origoff;
vsize_t bytelen;
@ -1566,7 +1565,7 @@ puffs_write(void *v)
pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
if (vp->v_type == VREG && PUFFS_DOCACHE(pmp)) {
ubcflags = 0;
ubcflags = UBC_WRITE | UBC_PARTIALOK;
if (UBC_WANT_UNMAP(vp))
ubcflags = UBC_UNMAP;
@ -1584,26 +1583,28 @@ puffs_write(void *v)
oldoff = uio->uio_offset;
bytelen = uio->uio_resid;
win = ubc_alloc(&vp->v_uobj, oldoff, &bytelen,
UVM_ADV_NORMAL, UBC_WRITE);
error = uiomove(win, bytelen, uio);
newoff = oldoff + bytelen;
if (vp->v_size < newoff) {
uvm_vnp_setwritesize(vp, newoff);
}
error = ubc_uiomove(&vp->v_uobj, uio, bytelen,
ubcflags);
/*
* There is no guarantee that the faults
* generated by uiomove() succeed at all.
* Therefore, in case of an uiomove() error,
* In case of a ubc_uiomove() error,
* opt to not extend the file at all and
* return an error. Otherwise, if we attempt
* to clear the memory we couldn't fault to,
* we might generate a kernel page fault.
*/
newoff = oldoff + bytelen;
if (vp->v_size < newoff && error == 0) {
uflags |= PUFFS_UPDATESIZE;
uvm_vnp_setsize(vp, newoff);
if (vp->v_size < newoff) {
if (error == 0) {
uflags |= PUFFS_UPDATESIZE;
uvm_vnp_setsize(vp, newoff);
} else {
uvm_vnp_setwritesize(vp, vp->v_size);
}
}
ubc_release(win, ubcflags);
if (error)
break;

View File

@ -1,4 +1,4 @@
/* $NetBSD: vfs_subr.c,v 1.287 2007/04/16 05:14:54 chs Exp $ */
/* $NetBSD: vfs_subr.c,v 1.288 2007/06/05 12:31:31 yamt Exp $ */
/*-
* Copyright (c) 1997, 1998, 2004, 2005 The NetBSD Foundation, Inc.
@ -80,7 +80,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.287 2007/04/16 05:14:54 chs Exp $");
__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.288 2007/06/05 12:31:31 yamt Exp $");
#include "opt_inet.h"
#include "opt_ddb.h"
@ -594,7 +594,7 @@ getnewvnode(enum vtagtype tag, struct mount *mp, int (**vops)(void *),
KASSERT(uobj->pgops == &uvm_vnodeops);
KASSERT(uobj->uo_npages == 0);
KASSERT(TAILQ_FIRST(&uobj->memq) == NULL);
vp->v_size = VSIZENOTSET;
vp->v_size = vp->v_writesize = VSIZENOTSET;
if (mp && error != EDEADLK)
vfs_unbusy(mp);
@ -2638,8 +2638,8 @@ vfs_vnode_print(struct vnode *vp, int full, void (*pr)(const char *, ...))
uvm_object_printit(&vp->v_uobj, full, pr);
bitmask_snprintf(vp->v_flag, vnode_flagbits, bf, sizeof(bf));
(*pr)("\nVNODE flags %s\n", bf);
(*pr)("mp %p numoutput %d size 0x%llx\n",
vp->v_mount, vp->v_numoutput, vp->v_size);
(*pr)("mp %p numoutput %d size 0x%llx writesize 0x%llx\n",
vp->v_mount, vp->v_numoutput, vp->v_size, vp->v_writesize);
(*pr)("data %p usecount %d writecount %ld holdcnt %ld numoutput %d\n",
vp->v_data, vp->v_usecount, vp->v_writecount,

View File

@ -1,4 +1,4 @@
/* $NetBSD: genfs_vnops.c,v 1.153 2007/05/17 07:26:22 hannken Exp $ */
/* $NetBSD: genfs_vnops.c,v 1.154 2007/06/05 12:31:31 yamt Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: genfs_vnops.c,v 1.153 2007/05/17 07:26:22 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: genfs_vnops.c,v 1.154 2007/06/05 12:31:31 yamt Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -425,7 +425,7 @@ genfs_getpages(void *v)
int i, error, npages, orignpages, npgs, run, ridx, pidx, pcount;
int fs_bshift, fs_bsize, dev_bshift;
int flags = ap->a_flags;
size_t bytes, iobytes, tailbytes, totalbytes, skipbytes;
size_t bytes, iobytes, tailstart, tailbytes, totalbytes, skipbytes;
vaddr_t kva;
struct buf *bp, *mbp;
struct vnode *vp = ap->a_vp;
@ -465,9 +465,19 @@ startover:
orignpages = *ap->a_count;
GOP_SIZE(vp, origvsize, &diskeof, 0);
if (flags & PGO_PASTEOF) {
#if defined(DIAGNOSTIC)
off_t writeeof;
#endif /* defined(DIAGNOSTIC) */
newsize = MAX(origvsize,
origoffset + (orignpages << PAGE_SHIFT));
GOP_SIZE(vp, newsize, &memeof, GOP_SIZE_MEM);
#if defined(DIAGNOSTIC)
GOP_SIZE(vp, vp->v_writesize, &writeeof, GOP_SIZE_MEM);
if (newsize > round_page(writeeof)) {
panic("%s: past eof", __func__);
}
#endif /* defined(DIAGNOSTIC) */
} else {
GOP_SIZE(vp, origvsize, &memeof, GOP_SIZE_MEM);
}
@ -728,20 +738,22 @@ startover:
/*
* if EOF is in the middle of the range, zero the part past EOF.
* if the page including EOF is not PG_FAKE, skip over it since
* in that case it has valid data that we need to preserve.
* skip over pages which are not PG_FAKE since in that case they have
* valid data that we need to preserve.
*/
if (tailbytes > 0) {
size_t tailstart = bytes;
tailstart = bytes;
while (tailbytes > 0) {
const int len = PAGE_SIZE - (tailstart & PAGE_MASK);
if ((pgs[bytes >> PAGE_SHIFT]->flags & PG_FAKE) == 0) {
tailstart = round_page(tailstart);
tailbytes -= tailstart - bytes;
KASSERT(len <= tailbytes);
if ((pgs[tailstart >> PAGE_SHIFT]->flags & PG_FAKE) != 0) {
memset((void *)(kva + tailstart), 0, len);
UVMHIST_LOG(ubchist, "tailbytes %p 0x%x 0x%x",
kva, tailstart, len, 0);
}
UVMHIST_LOG(ubchist, "tailbytes %p 0x%x 0x%x",
kva, tailstart, tailbytes,0);
memset((void *)(kva + tailstart), 0, tailbytes);
tailstart += len;
tailbytes -= len;
}
/*
@ -1514,7 +1526,8 @@ genfs_do_io(struct vnode *vp, off_t off, vaddr_t kva, size_t len, int flags,
UVMHIST_LOG(ubchist, "vp %p kva %p len 0x%x flags 0x%x",
vp, kva, len, flags);
GOP_SIZE(vp, vp->v_size, &eof, 0);
KASSERT(vp->v_size <= vp->v_writesize);
GOP_SIZE(vp, vp->v_writesize, &eof, 0);
if (vp->v_type != VBLK) {
fs_bshift = vp->v_mount->mnt_fs_bshift;
dev_bshift = vp->v_mount->mnt_dev_bshift;

View File

@ -1,4 +1,4 @@
/* $NetBSD: spec_vnops.c,v 1.98 2007/03/04 06:03:14 christos Exp $ */
/* $NetBSD: spec_vnops.c,v 1.99 2007/06/05 12:31:32 yamt Exp $ */
/*
* Copyright (c) 1989, 1993
@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.98 2007/03/04 06:03:14 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.99 2007/06/05 12:31:32 yamt Exp $");
#include <sys/param.h>
#include <sys/proc.h>
@ -245,7 +245,8 @@ spec_open(v)
if (error)
return error;
if (!(*d_ioctl)(vp->v_rdev, DIOCGPART, (void *)&pi, FREAD, curlwp))
vp->v_size = (voff_t)pi.disklab->d_secsize * pi.part->p_size;
uvm_vnp_setsize(vp,
(voff_t)pi.disklab->d_secsize * pi.part->p_size);
return 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_bio.c,v 1.154 2007/05/09 23:17:45 yamt Exp $ */
/* $NetBSD: nfs_bio.c,v 1.155 2007/06/05 12:31:32 yamt Exp $ */
/*
* Copyright (c) 1989, 1993
@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nfs_bio.c,v 1.154 2007/05/09 23:17:45 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: nfs_bio.c,v 1.155 2007/06/05 12:31:32 yamt Exp $");
#include "opt_nfs.h"
#include "opt_ddb.h"
@ -462,10 +462,9 @@ nfs_write(v)
kauth_cred_t cred = ap->a_cred;
struct vattr vattr;
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
void *win;
voff_t oldoff, origoff;
vsize_t bytelen;
int flags, error = 0;
int error = 0;
int ioflag = ap->a_ioflag;
int extended = 0, wrotedata = 0;
@ -519,7 +518,7 @@ nfs_write(v)
origoff = uio->uio_offset;
do {
bool extending; /* if we are extending whole pages */
bool overwrite; /* if we are overwriting whole pages */
u_quad_t oldsize;
oldoff = uio->uio_offset;
bytelen = uio->uio_resid;
@ -531,17 +530,27 @@ nfs_write(v)
if (np->n_size < uio->uio_offset + bytelen) {
np->n_size = uio->uio_offset + bytelen;
}
extending = ((uio->uio_offset & PAGE_MASK) == 0 &&
(bytelen & PAGE_MASK) == 0 &&
uio->uio_offset >= vp->v_size);
win = ubc_alloc(&vp->v_uobj, uio->uio_offset, &bytelen,
UVM_ADV_NORMAL,
UBC_WRITE | (extending ? UBC_FAULTBUSY : 0));
error = uiomove(win, bytelen, uio);
flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0;
ubc_release(win, flags);
overwrite = false;
if ((uio->uio_offset & PAGE_MASK) == 0) {
if ((vp->v_flag & VMAPPED) == 0 &&
bytelen > PAGE_SIZE) {
bytelen = trunc_page(bytelen);
overwrite = true;
} else if ((bytelen & PAGE_MASK) == 0 &&
uio->uio_offset >= vp->v_size) {
overwrite = true;
}
}
if (vp->v_size < uio->uio_offset + bytelen) {
uvm_vnp_setwritesize(vp, uio->uio_offset + bytelen);
}
error = ubc_uiomove(&vp->v_uobj, uio, bytelen,
UBC_WRITE | UBC_PARTIALOK |
(overwrite ? UBC_FAULTBUSY : 0) |
(UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0));
if (error) {
if (extending) {
uvm_vnp_setwritesize(vp, vp->v_size);
if (overwrite && np->n_size != oldsize) {
/*
* backout size and free pages past eof.
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: vnode.h,v 1.168 2007/04/08 11:20:50 hannken Exp $ */
/* $NetBSD: vnode.h,v 1.169 2007/06/05 12:31:33 yamt Exp $ */
/*
* Copyright (c) 1989, 1993
@ -98,6 +98,7 @@ struct vnode {
#define v_usecount v_uobj.uo_refs
#define v_interlock v_uobj.vmobjlock
voff_t v_size; /* size of file */
voff_t v_writesize; /* new size after write */
int v_flag; /* flags */
int v_numoutput; /* number of pending writes */
long v_writecount; /* reference count of writers */

View File

@ -1,4 +1,4 @@
/* $NetBSD: ext2fs_inode.c,v 1.58 2007/04/07 14:21:52 hannken Exp $ */
/* $NetBSD: ext2fs_inode.c,v 1.59 2007/06/05 12:31:33 yamt Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@ -65,7 +65,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ext2fs_inode.c,v 1.58 2007/04/07 14:21:52 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: ext2fs_inode.c,v 1.59 2007/06/05 12:31:33 yamt Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -290,6 +290,7 @@ ext2fs_truncate(struct vnode *ovp, off_t length, int ioflag,
* value of osize is 0, length will be at least 1.
*/
if (osize < length) {
uvm_vnp_setwritesize(ovp, length);
error = ufs_balloc_range(ovp, length - 1, 1, cred,
ioflag & IO_SYNC ? B_SYNC : 0);
if (error) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: ext2fs_readwrite.c,v 1.46 2007/04/19 11:05:14 yamt Exp $ */
/* $NetBSD: ext2fs_readwrite.c,v 1.47 2007/06/05 12:31:33 yamt Exp $ */
/*-
* Copyright (c) 1993
@ -65,7 +65,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ext2fs_readwrite.c,v 1.46 2007/04/19 11:05:14 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: ext2fs_readwrite.c,v 1.47 2007/06/05 12:31:33 yamt Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -305,6 +305,9 @@ ext2fs_write(void *v)
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)

View File

@ -1,4 +1,4 @@
/* $NetBSD: ext2fs_vfsops.c,v 1.110 2007/03/12 18:18:37 ad Exp $ */
/* $NetBSD: ext2fs_vfsops.c,v 1.111 2007/06/05 12:31:33 yamt Exp $ */
/*
* Copyright (c) 1989, 1991, 1993, 1994
@ -65,7 +65,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsops.c,v 1.110 2007/03/12 18:18:37 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsops.c,v 1.111 2007/06/05 12:31:33 yamt Exp $");
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
@ -1038,7 +1038,7 @@ ext2fs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
ip->i_flag |= IN_MODIFIED;
}
vp->v_size = ext2fs_size(ip);
uvm_vnp_setsize(vp, ext2fs_size(ip));
*vpp = vp;
return (0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ffs_inode.c,v 1.86 2007/03/04 06:03:43 christos Exp $ */
/* $NetBSD: ffs_inode.c,v 1.87 2007/06/05 12:31:34 yamt Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ffs_inode.c,v 1.86 2007/03/04 06:03:43 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: ffs_inode.c,v 1.87 2007/06/05 12:31:34 yamt Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@ -230,18 +230,19 @@ ffs_truncate(struct vnode *ovp, off_t length, int ioflag, kauth_cred_t cred,
off_t eob;
eob = blkroundup(fs, osize);
uvm_vnp_setwritesize(ovp, eob);
error = ufs_balloc_range(ovp, osize, eob - osize,
cred, aflag);
if (error)
return error;
if (ioflag & IO_SYNC) {
ovp->v_size = eob;
simple_lock(&ovp->v_interlock);
VOP_PUTPAGES(ovp,
trunc_page(osize & fs->fs_bmask),
round_page(eob), PGO_CLEANIT | PGO_SYNCIO);
}
}
uvm_vnp_setwritesize(ovp, length);
error = ufs_balloc_range(ovp, length - 1, 1, cred, aflag);
if (error) {
(void) ffs_truncate(ovp, osize, ioflag & IO_SYNC,

View File

@ -1,4 +1,4 @@
/* $NetBSD: ffs_vnops.c,v 1.87 2007/05/17 07:26:23 hannken Exp $ */
/* $NetBSD: ffs_vnops.c,v 1.88 2007/06/05 12:31:34 yamt Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.87 2007/05/17 07:26:23 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.88 2007/06/05 12:31:34 yamt Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -110,7 +110,7 @@ const struct vnodeopv_entry_desc ffs_vnodeop_entries[] = {
{ &vop_pathconf_desc, ufs_pathconf }, /* pathconf */
{ &vop_advlock_desc, ufs_advlock }, /* advlock */
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */
{ &vop_getpages_desc, ffs_getpages }, /* getpages */
{ &vop_getpages_desc, genfs_getpages }, /* getpages */
{ &vop_putpages_desc, genfs_putpages }, /* putpages */
{ &vop_openextattr_desc, ffs_openextattr }, /* openextattr */
{ &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */
@ -514,6 +514,7 @@ ffs_reclaim(void *v)
return (0);
}
#if 0
int
ffs_getpages(void *v)
{
@ -548,6 +549,7 @@ ffs_getpages(void *v)
}
return genfs_getpages(v);
}
#endif
/*
* Return the last logical file offset that should be written for this file

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_inode.c,v 1.109 2007/05/16 19:11:37 perseant Exp $ */
/* $NetBSD: lfs_inode.c,v 1.110 2007/06/05 12:31:34 yamt Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_inode.c,v 1.109 2007/05/16 19:11:37 perseant Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_inode.c,v 1.110 2007/06/05 12:31:34 yamt Exp $");
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
@ -284,12 +284,12 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag,
off_t eob;
eob = blkroundup(fs, osize);
uvm_vnp_setwritesize(ovp, eob);
error = ufs_balloc_range(ovp, osize,
eob - osize, cred, aflags);
if (error)
return error;
if (ioflag & IO_SYNC) {
ovp->v_size = eob;
simple_lock(&ovp->v_interlock);
VOP_PUTPAGES(ovp,
trunc_page(osize & fs->lfs_bmask),
@ -297,6 +297,7 @@ lfs_truncate(struct vnode *ovp, off_t length, int ioflag,
PGO_CLEANIT | PGO_SYNCIO);
}
}
uvm_vnp_setwritesize(ovp, length);
error = ufs_balloc_range(ovp, length - 1, 1, cred,
aflags);
if (error) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: ufs_readwrite.c,v 1.78 2007/05/17 07:26:23 hannken Exp $ */
/* $NetBSD: ufs_readwrite.c,v 1.79 2007/06/05 12:31:35 yamt Exp $ */
/*-
* Copyright (c) 1993
@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(1, "$NetBSD: ufs_readwrite.c,v 1.78 2007/05/17 07:26:23 hannken Exp $");
__KERNEL_RCSID(1, "$NetBSD: ufs_readwrite.c,v 1.79 2007/06/05 12:31:35 yamt Exp $");
#ifdef LFS_READWRITE
#define BLKSIZE(a, b, c) blksize(a, b, c)
@ -214,9 +214,7 @@ WRITE(void *v)
off_t osize, origoff, oldoff, preallocoff, endallocoff, nsize;
int blkoffset, error, flags, ioflag, resid, size, xfersize;
int aflag;
int ubc_alloc_flags, ubc_release_flags;
int extended=0;
void *win;
vsize_t bytelen;
bool async;
bool usepc = false;
@ -314,20 +312,20 @@ WRITE(void *v)
off_t eob;
eob = blkroundup(fs, osize);
uvm_vnp_setwritesize(vp, eob);
error = ufs_balloc_range(vp, osize, eob - osize, cred, aflag);
if (error)
goto out;
if (flags & B_SYNC) {
vp->v_size = eob;
simple_lock(&vp->v_interlock);
VOP_PUTPAGES(vp, trunc_page(osize & fs->fs_bmask),
round_page(eob), PGO_CLEANIT | PGO_SYNCIO);
}
}
ubc_alloc_flags = UBC_WRITE;
while (uio->uio_resid > 0) {
bool extending; /* if we're extending a whole block */
int ubc_flags = UBC_WRITE;
bool overwrite; /* if we're overwrite a whole block */
off_t newoff;
if (ioflag & IO_DIRECT) {
@ -348,15 +346,31 @@ WRITE(void *v)
* since the new blocks will be inaccessible until the write
* is complete.
*/
extending = uio->uio_offset >= preallocoff &&
overwrite = uio->uio_offset >= preallocoff &&
uio->uio_offset < endallocoff;
if (!overwrite && (vp->v_flag & VMAPPED) == 0 &&
blkoff(fs, uio->uio_offset) == 0 &&
(uio->uio_offset & PAGE_MASK) == 0) {
vsize_t len;
if (!extending) {
len = trunc_page(bytelen);
len -= blkoff(fs, len);
if (len > 0) {
overwrite = true;
bytelen = len;
}
}
newoff = oldoff + bytelen;
if (vp->v_size < newoff) {
uvm_vnp_setwritesize(vp, newoff);
}
if (!overwrite) {
error = ufs_balloc_range(vp, uio->uio_offset, bytelen,
cred, aflag);
if (error)
break;
ubc_alloc_flags &= ~UBC_FAULTBUSY;
} else {
genfs_node_wrlock(vp);
error = GOP_ALLOC(vp, uio->uio_offset, bytelen,
@ -364,26 +378,15 @@ WRITE(void *v)
genfs_node_unlock(vp);
if (error)
break;
ubc_alloc_flags |= UBC_FAULTBUSY;
ubc_flags |= UBC_FAULTBUSY;
}
/*
* copy the data.
*/
win = ubc_alloc(&vp->v_uobj, uio->uio_offset, &bytelen,
UVM_ADV_NORMAL, ubc_alloc_flags);
error = uiomove(win, bytelen, uio);
if (error && extending) {
/*
* if we haven't initialized the pages yet,
* do it now. it's safe to use memset here
* because we just mapped the pages above.
*/
memset(win, 0, bytelen);
}
ubc_release_flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0;
ubc_release(win, ubc_release_flags);
ubc_flags |= UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0;
error = ubc_uiomove(&vp->v_uobj, uio, bytelen, ubc_flags);
/*
* update UVM's notion of the size now that we've
@ -393,7 +396,6 @@ WRITE(void *v)
* otherwise ffs_truncate can't flush soft update states.
*/
newoff = oldoff + bytelen;
if (vp->v_size < newoff) {
uvm_vnp_setsize(vp, newoff);
extended = 1;

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_bio.c,v 1.57 2007/05/07 12:39:45 yamt Exp $ */
/* $NetBSD: uvm_bio.c,v 1.58 2007/06/05 12:31:35 yamt Exp $ */
/*
* Copyright (c) 1998 Chuck Silvers.
@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_bio.c,v 1.57 2007/05/07 12:39:45 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: uvm_bio.c,v 1.58 2007/06/05 12:31:35 yamt Exp $");
#include "opt_uvmhist.h"
#include "opt_ubc.h"
@ -632,6 +632,50 @@ ubc_release(void *va, int flags)
simple_unlock(&ubc_object.uobj.vmobjlock);
}
/*
* ubc_uiomove: move data to/from an object.
*/
int
ubc_uiomove(struct uvm_object *uobj, struct uio *uio, vsize_t todo, int flags)
{
voff_t off;
const bool overwrite = (flags & UBC_FAULTBUSY) != 0;
int error;
KASSERT(todo <= uio->uio_resid);
KASSERT(((flags & UBC_WRITE) != 0 && uio->uio_rw == UIO_WRITE) ||
((flags & UBC_READ) != 0 && uio->uio_rw == UIO_READ));
off = uio->uio_offset;
error = 0;
while (todo > 0) {
vsize_t bytelen = todo;
void *win;
win = ubc_alloc(uobj, off, &bytelen, UVM_ADV_NORMAL, flags);
if (error == 0) {
error = uiomove(win, bytelen, uio);
}
if (error != 0 && overwrite) {
/*
* if we haven't initialized the pages yet,
* do it now. it's safe to use memset here
* because we just mapped the pages above.
*/
printf("%s: error=%d\n", __func__, error);
memset(win, 0, bytelen);
}
ubc_release(win, flags);
off += bytelen;
todo -= bytelen;
if (error != 0 && (flags & UBC_PARTIALOK) != 0) {
break;
}
}
return error;
}
#if 0 /* notused */
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_extern.h,v 1.129 2007/03/24 21:15:39 rmind Exp $ */
/* $NetBSD: uvm_extern.h,v 1.130 2007/06/05 12:31:35 yamt Exp $ */
/*
*
@ -189,14 +189,19 @@ typedef voff_t pgoff_t; /* XXX: number of pages within a uvm object */
/*
* flags for ubc_alloc()
*/
#define UBC_READ 0x01
#define UBC_WRITE 0x02
#define UBC_FAULTBUSY 0x04
#define UBC_READ 0x001
#define UBC_WRITE 0x002
#define UBC_FAULTBUSY 0x004
/*
* flags for ubc_release()
*/
#define UBC_UNMAP 0x01
#define UBC_UNMAP 0x010
/*
* flags for ubc_uiomve()
*/
#define UBC_PARTIALOK 0x100
/*
* helpers for calling ubc_release()
@ -556,6 +561,8 @@ void * ubc_alloc(struct uvm_object *, voff_t, vsize_t *, int,
int);
void ubc_release(void *, int);
void ubc_flush(struct uvm_object *, voff_t, voff_t);
int ubc_uiomove(struct uvm_object *, struct uio *, vsize_t,
int);
/* uvm_fault.c */
#define uvm_fault(m, a, p) uvm_fault_internal(m, a, p, 0)
@ -703,6 +710,7 @@ void uvm_deallocate(struct vm_map *, vaddr_t, vsize_t);
/* uvm_vnode.c */
void uvm_vnp_setsize(struct vnode *, voff_t);
void uvm_vnp_setwritesize(struct vnode *, voff_t);
void uvm_vnp_sync(struct mount *);
struct uvm_object *uvn_attach(void *, vm_prot_t);
int uvn_findpages(struct uvm_object *, voff_t,

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_vnode.c,v 1.81 2007/03/04 06:03:49 christos Exp $ */
/* $NetBSD: uvm_vnode.c,v 1.82 2007/06/05 12:31:36 yamt Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@ -50,7 +50,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_vnode.c,v 1.81 2007/03/04 06:03:49 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: uvm_vnode.c,v 1.82 2007/06/05 12:31:36 yamt Exp $");
#include "fs_nfs.h"
#include "opt_uvmhist.h"
@ -212,7 +212,7 @@ uvn_attach(void *arg, vm_prot_t accessprot)
UVMHIST_LOG(maphist,"<- done (VOP_GETATTR FAILED!)", 0,0,0,0);
return(NULL);
}
vp->v_size = used_vnode_size;
vp->v_size = vp->v_writesize = used_vnode_size;
}
@ -469,15 +469,35 @@ uvm_vnp_setsize(struct vnode *vp, voff_t newsize)
* toss some pages...
*/
oldsize = vp->v_size;
if (vp->v_writesize != VSIZENOTSET) {
KASSERT(vp->v_size <= vp->v_writesize);
KASSERT(vp->v_size == vp->v_writesize ||
newsize == vp->v_writesize || newsize <= vp->v_size);
oldsize = vp->v_writesize;
} else {
oldsize = vp->v_size;
}
if (oldsize > pgend && oldsize != VSIZENOTSET) {
(void) uvn_put(uobj, pgend, 0, PGO_FREE | PGO_SYNCIO);
simple_lock(&uobj->vmobjlock);
}
vp->v_size = newsize;
vp->v_size = vp->v_writesize = newsize;
simple_unlock(&uobj->vmobjlock);
}
void
uvm_vnp_setwritesize(struct vnode *vp, voff_t newsize)
{
simple_lock(&vp->v_interlock);
KASSERT(vp->v_size != VSIZENOTSET);
KASSERT(vp->v_writesize != VSIZENOTSET);
KASSERT(vp->v_size <= vp->v_writesize);
KASSERT(vp->v_size <= newsize);
vp->v_writesize = newsize;
simple_unlock(&vp->v_interlock);
}
/*
* uvm_vnp_zerorange: set a range of bytes in a file to zero.
*/