tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[PATCH] Re: zero-filed page on VOP_PUTPAGES
Hello again
Here is my latest attempt to fix the race condition on file size between
puffs_vnop_fsync() and puffs_vnop_getattr(). In a nutshell for the one that
missed previous episodes, this is about preventing puffs_vnop_getattr() to
call uvm_vnp_setsize() with a stall value (which causes a truncate) while
a PUFFS_VN_SETATTR operation is in progress.
The PUFFS_VN_SETATTR sent by puffs_vnop_fsync/flushvncache/dosetattr
is kept asynchronous to avoid a deadlock between the ioflush thread
and the file server (see "Re: deadlock on flt_noram5" on
tech-kern%netbsd.org@localhost), but it is not FAF anymore, and has a callback
so that we can keep track of the critical window end.
That code passes my test case for data corruption, and it does not hang
the kernel.
I have two concerns:
1) pn->pn_inresize is decreased in puffs_parkdone_setattr(), but exclusive
access to that field is not guaranteed by vnode locking at that time. Should
I use atomic_inc_uint() and atomic_dec_uint()?
2) puffs_vnop_fsync/flushvncache/dosetattr calls uvm_vnp_setsize() to
set the new size regardless of the PUFFS_VN_SETATTR operation success.
What about if it failed? We could call uvm_vnp_setsize() from
puffs_parkdone_setattr(), but that will open aanother can of worms with
stall size and spurious truncate.
--
Emmanuel Dreyfus
manu%netbsd.org@localhost
? sys/fs/puffs/puffs_vnops.c-debug
? sys/fs/puffs/puffs_vnops.c.ok1
? sys/fs/puffs/puffs_vnops.c.ok2
Index: sys/fs/puffs/puffs_node.c
===================================================================
RCS file: /cvsroot/src/sys/fs/puffs/puffs_node.c,v
retrieving revision 1.13.10.1
diff -u -p -d -r1.13.10.1 puffs_node.c
--- sys/fs/puffs/puffs_node.c 3 Oct 2009 23:11:27 -0000 1.13.10.1
+++ sys/fs/puffs/puffs_node.c 24 Aug 2011 08:00:29 -0000
@@ -162,6 +162,8 @@ puffs_getvnode(struct mount *mp, puffs_c
pnode->pn_vp = vp;
pnode->pn_serversize = vsize;
+ pnode->pn_inresize = 0;
+
genfs_node_init(vp, &puffs_genfsops);
*vpp = vp;
Index: sys/fs/puffs/puffs_subr.c
===================================================================
RCS file: /cvsroot/src/sys/fs/puffs/puffs_subr.c,v
retrieving revision 1.65
diff -u -p -d -r1.65 puffs_subr.c
--- sys/fs/puffs/puffs_subr.c 1 Mar 2008 14:16:51 -0000 1.65
+++ sys/fs/puffs/puffs_subr.c 24 Aug 2011 08:00:29 -0000
@@ -87,6 +87,17 @@ puffs_credcvt(struct puffs_kcred *pkcr,
}
void
+puffs_parkdone_setattr(struct puffs_mount *pmp,
+ struct puffs_req *preq, void *arg)
+{
+ struct puffs_node *pn = arg;
+
+ pn->pn_inresize--;
+
+ return;
+}
+
+void
puffs_parkdone_asyncbioread(struct puffs_mount *pmp,
struct puffs_req *preq, void *arg)
{
Index: sys/fs/puffs/puffs_sys.h
===================================================================
RCS file: /cvsroot/src/sys/fs/puffs/puffs_sys.h,v
retrieving revision 1.70.20.2
diff -u -p -d -r1.70.20.2 puffs_sys.h
--- sys/fs/puffs/puffs_sys.h 18 Jun 2011 16:19:39 -0000 1.70.20.2
+++ sys/fs/puffs/puffs_sys.h 24 Aug 2011 08:00:29 -0000
@@ -205,6 +205,8 @@ struct puffs_node {
voff_t pn_serversize;
struct lockf * pn_lockf;
+ unsigned int pn_inresize;
+
LIST_ENTRY(puffs_node) pn_hashent;
};
@@ -247,6 +249,8 @@ void puffs_makecn(struct puffs_kcn *, st
const struct componentname *, int);
void puffs_credcvt(struct puffs_kcred *, kauth_cred_t);
+void puffs_parkdone_setattr(struct puffs_mount *,
+ struct puffs_req *, void *);
void puffs_parkdone_asyncbioread(struct puffs_mount *,
struct puffs_req *, void *);
void puffs_parkdone_asyncbiowrite(struct puffs_mount *,
Index: sys/fs/puffs/puffs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/puffs/puffs_vnops.c,v
retrieving revision 1.129.4.9
diff -u -p -d -r1.129.4.9 puffs_vnops.c
--- sys/fs/puffs/puffs_vnops.c 17 Jul 2011 15:36:03 -0000 1.129.4.9
+++ sys/fs/puffs/puffs_vnops.c 24 Aug 2011 08:00:30 -0000
@@ -898,7 +898,8 @@ puffs_vnop_getattr(void *v)
} else {
if (rvap->va_size != VNOVAL
&& vp->v_type != VBLK && vp->v_type != VCHR) {
- uvm_vnp_setsize(vp, rvap->va_size);
+ if (pn->pn_inresize == 0)
+ uvm_vnp_setsize(vp, rvap->va_size);
pn->pn_serversize = rvap->va_size;
}
}
@@ -956,8 +957,22 @@ dosetattr(struct vnode *vp, struct vattr
puffs_credcvt(&setattr_msg->pvnr_cred, cred);
puffs_msg_setinfo(park_setattr, PUFFSOP_VN,
PUFFS_VN_SETATTR, VPTOPNC(vp));
+
+ /*
+ * If we are called from puffs_vnop_fsync(), then this
+ * PUFFS_VN_SETATTR operation must be asynchronous, otherwise
+ * the ioflush thread may deadlock with the file server.
+ *
+ * However, the window between PUFFS_VN_SETATTR request is sent
+ * and its completion is critical for uvm_vnp_setsize() calls
+ * from puffs_vnop_getattr(), since it could set a stall size
+ * and trigger a spurious truncate. pn->pn_inresize is here to
+ * ensure it will not happen, and we need a a PUFFS_VN_SETATTR
+ * completion callback to decrease it.
+ */
if (flags & SETATTR_ASYNC)
- puffs_msg_setfaf(park_setattr);
+ puffs_msg_setcall(park_setattr, puffs_parkdone_setattr, pn);
+ pn->pn_inresize++;
puffs_msg_enqueue(pmp, park_setattr);
if ((flags & SETATTR_ASYNC) == 0)
@@ -977,6 +992,10 @@ dosetattr(struct vnode *vp, struct vattr
uvm_vnp_setsize(vp, vap->va_size);
}
+ /* Decreased from puffs_parkdone_setattr() if SETATTR_ASYNC is set */
+ if ((flags & SETATTR_ASYNC) == 0)
+ pn->pn_inresize--;
+
return 0;
}
Home |
Main Index |
Thread Index |
Old Index