Module Name:    src
Committed By:   manu
Date:           Wed Jun  1 15:54:10 UTC 2011

Modified Files:
        src/lib/libperfuse: ops.c

Log Message:
Fix race conditions between write and getattr/setattr, which lead to
inconsitencies between kernel and filesystem idea of file size during
writes with IO_APPEND.

At mine, this resulted in a configure script producing config.status
with ": clr\n" lines stripped (not 100% reproductible, but always this
specific string. That is of little interest except for my own future
reference).

When a write is in progress, getattr/setattr get/set the maximum size
among kernel idea (grown by write) and filesystem idea (not yet grown).


To generate a diff of this commit:
cvs rdiff -u -r1.29 -r1.30 src/lib/libperfuse/ops.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libperfuse/ops.c
diff -u src/lib/libperfuse/ops.c:1.29 src/lib/libperfuse/ops.c:1.30
--- src/lib/libperfuse/ops.c:1.29	Wed Jun  1 07:57:24 2011
+++ src/lib/libperfuse/ops.c	Wed Jun  1 15:54:10 2011
@@ -1,4 +1,4 @@
-/*  $NetBSD: ops.c,v 1.29 2011/06/01 07:57:24 manu Exp $ */
+/*  $NetBSD: ops.c,v 1.30 2011/06/01 15:54:10 manu Exp $ */
 
 /*-
  *  Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved.
@@ -1439,12 +1439,14 @@
 	struct perfuse_state *ps;
 	struct fuse_getattr_in *fgi;
 	struct fuse_attr_out *fao;
+	u_quad_t va_size;
 	int error;
 	
 	if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
 		return ENOENT;
 
 	ps = puffs_getspecific(pu);
+	va_size = vap->va_size;
 
 	/*
 	 * FUSE_GETATTR_FH must be set in fgi->flags 
@@ -1476,6 +1478,13 @@
 	 */
 	fuse_attr_to_vap(ps, vap, &fao->attr);
 
+	/*
+	 * If a write is in progress, do not trust filesystem opinion 
+	 * of file size, use the one from kernel.
+	 */
+	if ((PERFUSE_NODE_DATA(opc)->pnd_flags & PND_INWRITE) &&
+	    (va_size != (u_quad_t)PUFFS_VNOVAL))
+		vap->va_size = MAX(va_size, vap->va_size);;
 out:
 	ps->ps_destroy_msg(pm);
 
@@ -1496,6 +1505,7 @@
 	struct fuse_setattr_in *fsi;
 	struct fuse_attr_out *fao;
 	struct vattr *old_va;
+	u_quad_t va_size;
 	int error;
 
 	ps = puffs_getspecific(pu);
@@ -1552,13 +1562,14 @@
 		return EACCES;
 	
 	/*
-	 * It seems troublesome to resize a file while
-	 * a write is just beeing done. Wait for
-	 * it to finish.
-	 */
-	if (vap->va_size != (u_quad_t)PUFFS_VNOVAL)
-		while (pnd->pnd_flags & PND_INWRITE)
-			requeue_request(pu, opc, PCQ_AFTERWRITE);
+	 * If a write is in progress, set the highest
+	 * value in the filesystem, otherwise we break 
+	 * IO_APPEND.
+	 */
+	va_size = vap->va_size;
+	if ((pnd->pnd_flags & PND_INWRITE) &&
+	    (va_size != (u_quad_t)PUFFS_VNOVAL))
+		va_size = MAX(va_size, old_va->va_size);
 
 	pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr);
 	fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in);
@@ -1573,8 +1584,8 @@
 		fsi->valid |= FUSE_FATTR_FH;
 	}
 
-	if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) {
-		fsi->size = vap->va_size;
+	if (va_size != (u_quad_t)PUFFS_VNOVAL) {
+		fsi->size = va_size;
 		fsi->valid |= FUSE_FATTR_SIZE;
 	}
 

Reply via email to