Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/lib/libperfuse Fix race conditions between write and getattr...



details:   https://anonhg.NetBSD.org/src/rev/a4d0a7537268
branches:  trunk
changeset: 765656:a4d0a7537268
user:      manu <manu%NetBSD.org@localhost>
date:      Wed Jun 01 15:54:10 2011 +0000

description:
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).

diffstat:

 lib/libperfuse/ops.c |  29 ++++++++++++++++++++---------
 1 files changed, 20 insertions(+), 9 deletions(-)

diffs (78 lines):

diff -r 6ff1e2caf445 -r a4d0a7537268 lib/libperfuse/ops.c
--- a/lib/libperfuse/ops.c      Wed Jun 01 15:52:48 2011 +0000
+++ b/lib/libperfuse/ops.c      Wed Jun 01 15:54:10 2011 +0000
@@ -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 a write is in progress, set the highest
+        * value in the filesystem, otherwise we break 
+        * IO_APPEND.
         */
-       if (vap->va_size != (u_quad_t)PUFFS_VNOVAL)
-               while (pnd->pnd_flags & PND_INWRITE)
-                       requeue_request(pu, opc, PCQ_AFTERWRITE);
+       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;
        }
 



Home | Main Index | Thread Index | Old Index