From dcf67e65d2b58a3b0d31d275cacb4c038ba7ecee Mon Sep 17 00:00:00 2001 From: Stephan Uphoff Date: Thu, 25 May 2006 01:00:35 +0000 Subject: [PATCH] Do not set B_NOCACHE on buffers when releasing them in flushbuflist(). If B_NOCACHE is set the pages of vm backed buffers will be invalidated. However clean buffers can be backed by dirty VM pages so invalidating them can lead to data loss. Add support for flush dirty page in the data invalidation function of some network file systems. This fixes data losses during vnode recycling (and other code paths using invalbuf(*,V_SAVE,*,*)) for data written using an mmaped file. Collaborative effort by: jhb@,mohans@,peter@,ps@,ups@ Reviewed by: tegge@ MFC after: 7 days --- sys/fs/nwfs/nwfs_io.c | 4 ++++ sys/fs/smbfs/smbfs_io.c | 4 ++++ sys/kern/vfs_subr.c | 2 +- sys/nfsclient/nfs_bio.c | 11 +++++++++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/sys/fs/nwfs/nwfs_io.c b/sys/fs/nwfs/nwfs_io.c index 8fdd18a13d5..84ae3cd6b34 100644 --- a/sys/fs/nwfs/nwfs_io.c +++ b/sys/fs/nwfs/nwfs_io.c @@ -611,6 +611,10 @@ nwfs_vinvalbuf(vp, td) return EINTR; } np->n_flag |= NFLUSHINPROG; + + if (vp->v_bufobj.bo_object != NULL) + vm_object_page_clean(vp->v_bufobj.bo_object, 0, 0, OBJPC_SYNC); + error = vinvalbuf(vp, V_SAVE, td, PCATCH, 0); while (error) { if (error == ERESTART || error == EINTR) { diff --git a/sys/fs/smbfs/smbfs_io.c b/sys/fs/smbfs/smbfs_io.c index 478ed5535bb..7e76a876cf2 100644 --- a/sys/fs/smbfs/smbfs_io.c +++ b/sys/fs/smbfs/smbfs_io.c @@ -683,6 +683,10 @@ smbfs_vinvalbuf(struct vnode *vp, struct thread *td) return EINTR; } np->n_flag |= NFLUSHINPROG; + + if (vp->v_bufobj.bo_object != NULL) + vm_object_page_clean(vp->v_bufobj.bo_object, 0, 0, OBJPC_SYNC); + error = vinvalbuf(vp, V_SAVE, td, PCATCH, 0); while (error) { if (error == ERESTART || error == EINTR) { diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 50f889f601b..da6a61b84bd 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1134,7 +1134,7 @@ flushbuflist( struct bufv *bufv, int flags, struct bufobj *bo, int slpflag, return (EAGAIN); /* XXX: why not loop ? */ } bremfree(bp); - bp->b_flags |= (B_INVAL | B_NOCACHE | B_RELBUF); + bp->b_flags |= (B_INVAL | B_RELBUF); bp->b_flags &= ~B_ASYNC; brelse(bp); BO_LOCK(bo); diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c index 19228ac500e..cac21759aa7 100644 --- a/sys/nfsclient/nfs_bio.c +++ b/sys/nfsclient/nfs_bio.c @@ -1312,6 +1312,17 @@ nfs_vinvalbuf(struct vnode *vp, int flags, struct thread *td, int intrflg) /* * Now, flush as required. */ + if ((flags & V_SAVE) && (vp->v_bufobj.bo_object != NULL)) { + vm_object_page_clean(vp->v_bufobj.bo_object, 0, 0, OBJPC_SYNC); + /* + * If the page clean was interrupted, fail the invalidation. + * Not doing so, we run the risk of losing dirty pages in the + * vinvalbuf() call below. + */ + if (intrflg && (error = nfs_sigintr(nmp, NULL, td))) + goto out; + } + error = vinvalbuf(vp, flags, td, slpflag, 0); while (error) { if (intrflg && (error = nfs_sigintr(nmp, NULL, td)))