tech-kern archive

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

ffs disk corruption



Hello,
for some time, I've occasionally seen disk corruption on a NFS server
with quotas.
While working on PR 35704, I found something that could explain it, see
http://mail-index.netbsd.org/tech-kern/2010/02/02/msg007156.html

and with this patch the server stopped showing disk corruption issues.
But is has show up again, with always the same behavior: some directory
blocks are overwritten with 0 (data blocks may be overwritten too, but
I've not yet proof of this).
Locking back at the changes in
http://mail-index.netbsd.org/tech-kern/2010/02/02/msg007156.html
I found what I think are 2 problems, fixed with the attached patch:
- There are places where, after a ufs_balloc_range() erorr, ffs_truncate()
  is not called. I guess this can cause the same issue as explained
  in the above mail when ffs_truncate() didn't reset v_writesize.
- in ufs_inode.c:ufs_balloc_range(), we clear PG_RDONLY for all pages
  up to the new size, even if block allocation failed. I think in this case
  we should clear it up to the old size, PG_RELEASEDing all newly
  allocated pages that have no data blocks on disk.

Does anyone see something wrong with this analysis or the attached patch ?
I've not tested this on the NFS server yet, but the test from PR 35704
still passes.

-- 
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
     NetBSD: 26 ans d'experience feront toujours la difference
--
Index: ffs/ffs_inode.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_inode.c,v
retrieving revision 1.99.4.1
diff -u -p -u -r1.99.4.1 ffs_inode.c
--- ffs/ffs_inode.c     22 Feb 2010 04:43:46 -0000      1.99.4.1
+++ ffs/ffs_inode.c     22 Nov 2011 12:35:00 -0000
@@ -273,8 +273,10 @@ ffs_truncate(struct vnode *ovp, off_t le
                        uvm_vnp_setwritesize(ovp, eob);
                        error = ufs_balloc_range(ovp, osize, eob - osize,
                            cred, aflag);
-                       if (error)
+                       if (error) {
+                               (void) ffs_truncate(ovp, osize, ioflag & 
IO_SYNC, cred);
                                return error;
+                       }
                        if (ioflag & IO_SYNC) {
                                mutex_enter(&ovp->v_interlock);
                                VOP_PUTPAGES(ovp,
Index: lfs/lfs_inode.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/lfs_inode.c,v
retrieving revision 1.120.10.1
diff -u -p -u -r1.120.10.1 lfs_inode.c
--- lfs/lfs_inode.c     22 Feb 2010 04:43:46 -0000      1.120.10.1
+++ lfs/lfs_inode.c     22 Nov 2011 12:35:00 -0000
@@ -276,8 +276,11 @@ lfs_truncate(struct vnode *ovp, off_t le
                                uvm_vnp_setwritesize(ovp, eob);
                                error = ufs_balloc_range(ovp, osize,
                                    eob - osize, cred, aflags);
-                               if (error)
+                               if (error) {
+                                       (void) lfs_truncate(ovp, osize,
+                                                   ioflag & IO_SYNC, cred);
                                        return error;
+                               }
                                if (ioflag & IO_SYNC) {
                                        mutex_enter(&ovp->v_interlock);
                                        VOP_PUTPAGES(ovp,
Index: ufs/ufs_inode.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_inode.c,v
retrieving revision 1.76.4.5
diff -u -p -u -r1.76.4.5 ufs_inode.c
--- ufs/ufs_inode.c     16 Jul 2011 00:19:13 -0000      1.76.4.5
+++ ufs/ufs_inode.c     22 Nov 2011 12:35:00 -0000
@@ -306,7 +306,7 @@ ufs_balloc_range(struct vnode *vp, off_t
         * (since they now have backing store) and unbusy them.
         */
 
-       GOP_SIZE(vp, off + len, &eob, 0);
+       GOP_SIZE(vp, error ? off : (off + len), &eob, 0);
        mutex_enter(&uobj->vmobjlock);
        for (i = 0; i < npages; i++) {
                if (off <= pagestart + (i << PAGE_SHIFT) &&


Home | Main Index | Thread Index | Old Index