Subject: ubc and nfs file truncation
To: None <tech-kern@netbsd.org>
From: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
List: tech-kern
Date: 07/18/2004 16:58:05
--NextPart-20040718164642-0459001
Content-Type: Text/Plain; charset=us-ascii
hi,
ubc assumes a file's v_size is never changed while it has
ubc mappings. (see "npages >= 0" assertion in ubc_fault)
while it's true for the most of filesystems because of vnode lock,
it isn't true for nfs because a file can be truncated remotely.
two solutions i can think of:
1. workaround in nfs_loadattrcache.
(similar to the case of NMODIFIED/NTRUNCDELAYED)
2. workaround in nfs_read.
the attached diff is 2.
any comments?
YAMAMOTO Takashi
--NextPart-20040718164642-0459001
Content-Type: Text/Plain; charset=us-ascii
Content-Disposition: attachment; filename="a.diff"
Index: nfs/nfs_bio.c
===================================================================
--- nfs/nfs_bio.c (revision 800)
+++ nfs/nfs_bio.c (revision 801)
@@ -220,25 +220,33 @@ nfs_bioread(vp, uio, ioflag, cred, cflag
nfsstats.biocache_reads++;
error = 0;
- if (uio->uio_offset >= np->n_size) {
- break;
- }
- while (uio->uio_resid > 0) {
+ while (uio->uio_offset < np->n_size && uio->uio_resid > 0) {
void *win;
vsize_t bytelen = MIN(np->n_size - uio->uio_offset,
uio->uio_resid);
- if (bytelen == 0)
- break;
win = ubc_alloc(&vp->v_uobj, uio->uio_offset,
&bytelen, UBC_READ);
error = uiomove(win, bytelen, uio);
ubc_release(win, 0);
if (error) {
- break;
+ if (uio->uio_offset + uio->uio_resid
+ <= np->n_size) {
+ /* report error */
+ break;
+ }
+
+ /*
+ * XXXkludge
+ * the file has been truncated on the server.
+ * there isn't much we can do.
+ */
+ if (uio->uio_offset >= np->n_size) {
+ /* end of file */
+ error = 0;
+ }
}
}
- n = 0;
break;
case VLNK:
Index: uvm/uvm_bio.c
===================================================================
--- uvm/uvm_bio.c (revision 800)
+++ uvm/uvm_bio.c (revision 801)
@@ -266,6 +266,14 @@ ubc_fault(ufi, ign1, ign2, ign3, ign4, f
(round_page(MAX(vp->v_size, umap->offset +
umap->writeoff + umap->writelen)) -
umap->offset)) >> PAGE_SHIFT;
+ KASSERT(npages >= 0);
+ if (npages == 0) {
+ /*
+ * the file is truncated after ubc_alloc.
+ * it's normal for filesystems like nfs.
+ */
+ return EIO; /* XXX */
+ }
again:
memset(pgs, 0, sizeof (pgs));
--NextPart-20040718164642-0459001--