Source-Changes-HG archive

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

[src/trunk]: src/sys/ufs/lfs lfs_truncate calls vinvalbuf to invalidate all c...



details:   https://anonhg.NetBSD.org/src/rev/271124c36d19
branches:  trunk
changeset: 467820:271124c36d19
user:      perseant <perseant%NetBSD.org@localhost>
date:      Mon Mar 29 21:51:38 1999 +0000

description:
lfs_truncate calls vinvalbuf to invalidate all currently-hald buffers, which
in turn forces a flush of the vnode, whether or not it is involved in a dirop.
(This can happen during a remove or rmdir, when the directory is shrunk.)
Because of the nature of dirops, however, flushing a vnode involved in a dirop
is disallowed (and was marked with a panic).  This patch has lfs_truncate
call a specialized vinvalbuf that only invalidates buffers following the new
end-of-file, and thus does not require a flush.  Also the panic is demoted,
in case I missed any other path to lfs_vflush.

diffstat:

 sys/ufs/lfs/lfs_inode.c   |  68 ++++++++++++++++++++++++++++++++++++++++++++--
 sys/ufs/lfs/lfs_segment.c |   6 ++-
 2 files changed, 69 insertions(+), 5 deletions(-)

diffs (114 lines):

diff -r 49032b0aff4f -r 271124c36d19 sys/ufs/lfs/lfs_inode.c
--- a/sys/ufs/lfs/lfs_inode.c   Mon Mar 29 21:51:25 1999 +0000
+++ b/sys/ufs/lfs/lfs_inode.c   Mon Mar 29 21:51:38 1999 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_inode.c,v 1.20 1999/03/25 21:39:18 perseant Exp $  */
+/*     $NetBSD: lfs_inode.c,v 1.21 1999/03/29 21:51:38 perseant Exp $  */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -94,6 +94,8 @@
 #include <ufs/lfs/lfs.h>
 #include <ufs/lfs/lfs_extern.h>
 
+static int lfs_vinvalbuf __P((struct vnode *, struct ucred *, struct proc *, ufs_daddr_t));
+
 /* Search a block for a specific dinode. */
 struct dinode *
 lfs_ifind(fs, ino, dip)
@@ -439,8 +441,10 @@
        }
 #endif
        fs->lfs_avail += fragstodb(fs, a_released);
-       e1 = vinvalbuf(vp, (length > 0) ? V_SAVE : 0, ap->a_cred, ap->a_p,
-                      0, 0); 
+       if(length>0)
+               e1 = lfs_vinvalbuf(vp, ap->a_cred, ap->a_p, lastblock);
+       else
+               e1 = vinvalbuf(vp, 0, ap->a_cred, ap->a_p, 0, 0); 
        e2 = VOP_UPDATE(vp, NULL, NULL, 0);
        if(e1)
                printf("lfs_truncate: vinvalbuf: %d\n",e1);
@@ -449,3 +453,61 @@
 
        return (e1 ? e1 : e2 ? e2 : 0);
 }
+
+/*
+ * Get rid of blocks a la vinvalbuf; but only blocks that are of a higher
+ * lblkno than the file size allows.
+ */
+int
+lfs_vinvalbuf(vp, cred, p, maxblk)
+       register struct vnode *vp;
+       struct ucred *cred;
+       struct proc *p;
+       ufs_daddr_t maxblk;
+{
+       register struct buf *bp;
+       struct buf *nbp, *blist;
+       int i, s, error;
+
+       for (i=0;i<2;i++) {
+               if(i==0)
+                       blist = vp->v_cleanblkhd.lh_first;
+               else /* i == 1 */
+                       blist = vp->v_dirtyblkhd.lh_first;
+
+               for (bp = blist; bp; bp = nbp) {
+                       nbp = bp->b_vnbufs.le_next;
+                       s = splbio();
+                       if (bp->b_flags & B_BUSY) {
+                               bp->b_flags |= B_WANTED;
+                               error = tsleep((caddr_t)bp,
+                                       (PRIBIO + 1), "lfs_vinval", 0);
+                               splx(s);
+                               if (error)
+                                       return (error);
+                               break;
+                       }
+                       /*
+                        * Don't touch gathered buffers; and certainly don't
+                        * mark cleaner buffers B_INVAL, since that would
+                        * change them to "fake buffers".
+                        *
+                        * But get rid of anything else that's past the new
+                        * last block.
+                        */
+                       bp->b_flags |= B_BUSY;
+                       splx(s);
+                       if((bp->b_lblkno >= 0 && bp->b_lblkno > maxblk)
+                          || (bp->b_lblkno < 0 && bp->b_lblkno < -maxblk-NIADDR))
+                       {
+                               if(!(bp->b_flags & (B_GATHERED|B_CALL)))
+                                       bp->b_flags |= B_INVAL;
+                       }
+                       if(bp->b_flags & B_CALL)
+                               bp->b_flags &= ~B_BUSY;
+                       else
+                               brelse(bp);
+               }
+       }
+       return (0);
+}
diff -r 49032b0aff4f -r 271124c36d19 sys/ufs/lfs/lfs_segment.c
--- a/sys/ufs/lfs/lfs_segment.c Mon Mar 29 21:51:25 1999 +0000
+++ b/sys/ufs/lfs/lfs_segment.c Mon Mar 29 21:51:38 1999 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_segment.c,v 1.20 1999/03/25 22:38:28 perseant Exp $        */
+/*     $NetBSD: lfs_segment.c,v 1.21 1999/03/29 21:51:38 perseant Exp $        */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -237,8 +237,10 @@
        }
 
 #ifdef DIAGNOSTIC
+       /* XXX KS This actually can happen right now, though it shouldn't(?) */
        if(vp->v_flag & VDIROP) {
-               panic("VDIROP being freed...this can\'t happen");
+               printf("lfs_vflush: flushing VDIROP, this shouldn\'t be\n");
+               /* panic("VDIROP being flushed...this can\'t happen"); */
        }
        if(vp->v_usecount<0) {
                printf("usecount=%d\n",vp->v_usecount);



Home | Main Index | Thread Index | Old Index