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--