fix panic (assertion failure) on error case.

if uiomove is failed, we should clean up pages past eof.

the problem reported by kay.
ok'ed by Chuck Silvers.
This commit is contained in:
yamt 2002-10-29 10:15:16 +00:00
parent fc374b9d4f
commit 059aba1c85
1 changed files with 16 additions and 4 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_bio.c,v 1.84 2002/10/23 09:14:48 jdolecek Exp $ */ /* $NetBSD: nfs_bio.c,v 1.85 2002/10/29 10:15:16 yamt Exp $ */
/* /*
* Copyright (c) 1989, 1993 * Copyright (c) 1989, 1993
@ -39,7 +39,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nfs_bio.c,v 1.84 2002/10/23 09:14:48 jdolecek Exp $"); __KERNEL_RCSID(0, "$NetBSD: nfs_bio.c,v 1.85 2002/10/29 10:15:16 yamt Exp $");
#include "opt_nfs.h" #include "opt_nfs.h"
#include "opt_ddb.h" #include "opt_ddb.h"
@ -591,6 +591,8 @@ nfs_write(v)
origoff = uio->uio_offset; origoff = uio->uio_offset;
do { do {
boolean_t extending; /* if we are extending whole pages */
u_quad_t oldsize;
oldoff = uio->uio_offset; oldoff = uio->uio_offset;
bytelen = uio->uio_resid; bytelen = uio->uio_resid;
@ -616,13 +618,15 @@ nfs_write(v)
#endif #endif
nfsstats.biocache_writes++; nfsstats.biocache_writes++;
oldsize = np->n_size;
np->n_flag |= NMODIFIED; np->n_flag |= NMODIFIED;
if (np->n_size < uio->uio_offset + bytelen) { if (np->n_size < uio->uio_offset + bytelen) {
np->n_size = uio->uio_offset + bytelen; np->n_size = uio->uio_offset + bytelen;
} }
if ((uio->uio_offset & PAGE_MASK) == 0 && extending = ((uio->uio_offset & PAGE_MASK) == 0 &&
(bytelen & PAGE_MASK) == 0 && (bytelen & PAGE_MASK) == 0 &&
uio->uio_offset >= vp->v_size) { uio->uio_offset >= vp->v_size);
if (extending) {
win = ubc_alloc(&vp->v_uobj, uio->uio_offset, &bytelen, win = ubc_alloc(&vp->v_uobj, uio->uio_offset, &bytelen,
UBC_WRITE | UBC_FAULTBUSY); UBC_WRITE | UBC_FAULTBUSY);
} else { } else {
@ -632,6 +636,14 @@ nfs_write(v)
error = uiomove(win, bytelen, uio); error = uiomove(win, bytelen, uio);
ubc_release(win, 0); ubc_release(win, 0);
if (error) { if (error) {
if (extending) {
/*
* backout size and free pages past eof.
*/
np->n_size = oldsize;
(void)VOP_PUTPAGES(vp, round_page(vp->v_size),
0, PGO_SYNCIO | PGO_FREE);
}
break; break;
} }
wrotedta = 1; wrotedta = 1;