Author: kib
Date: Thu Dec 30 10:41:17 2010
New Revision: 216817
URL: http://svn.freebsd.org/changeset/base/216817

Log:
  In indir_trunc(), when processing jnewblk entries that are not written
  to the disk, recurse to handle indirect blocks of next level that are
  hidden by the corresponding entry.
  
  In collaboration with:        pho
  Reviewed by:  jeff, mckusick
  Tested by:    mckusick, pho

Modified:
  head/sys/ufs/ffs/ffs_softdep.c

Modified: head/sys/ufs/ffs/ffs_softdep.c
==============================================================================
--- head/sys/ufs/ffs/ffs_softdep.c      Thu Dec 30 09:46:45 2010        
(r216816)
+++ head/sys/ufs/ffs/ffs_softdep.c      Thu Dec 30 10:41:17 2010        
(r216817)
@@ -6140,17 +6140,20 @@ indir_trunc(freework, dbn, lbn)
                ufs1fmt = 0;
                bap2 = (ufs2_daddr_t *)bp->b_data;
        }
+
+       if (needj)
+               freework->fw_ref += NINDIR(fs) + 1;
+
        /*
         * Reclaim indirect blocks which never made it to disk.
         */
        cnt = 0;
        LIST_FOREACH_SAFE(wk, &wkhd, wk_list, wkn) {
-               struct workhead freewk;
                if (wk->wk_type != D_JNEWBLK)
                        continue;
-               WORKLIST_REMOVE_UNLOCKED(wk);
-               LIST_INIT(&freewk);
-               WORKLIST_INSERT_UNLOCKED(&freewk, wk);
+               ACQUIRE_LOCK(&lk);
+               WORKLIST_REMOVE(wk);
+               FREE_LOCK(&lk);
                jnewblk = WK_JNEWBLK(wk);
                if (jnewblk->jn_lbn > 0)
                        i = (jnewblk->jn_lbn - -lbn) / lbnadd;
@@ -6158,8 +6161,8 @@ indir_trunc(freework, dbn, lbn)
                        i = (-(jnewblk->jn_lbn + level - 1) - -(lbn + level)) /
                            lbnadd;
                KASSERT(i >= 0 && i < NINDIR(fs),
-                   ("indir_trunc: Index out of range %d parent %jd lbn %jd",
-                   i, lbn, jnewblk->jn_lbn));
+                   ("indir_trunc: Index out of range %d parent %jd lbn %jd 
level %d",
+                   i, lbn, jnewblk->jn_lbn, level));
                /* Clear the pointer so it isn't found below. */
                if (ufs1fmt) {
                        nb = bap1[i];
@@ -6171,13 +6174,29 @@ indir_trunc(freework, dbn, lbn)
                KASSERT(nb == jnewblk->jn_blkno,
                    ("indir_trunc: Block mismatch %jd != %jd",
                    nb, jnewblk->jn_blkno));
-               ffs_blkfree(ump, fs, freeblks->fb_devvp, jnewblk->jn_blkno,
-                   fs->fs_bsize, freeblks->fb_previousinum, &freewk);
+               if (level != 0) {
+                       ufs_lbn_t nlbn;
+
+                       nlbn = (lbn + 1) - (i * lbnadd);
+                       nfreework = newfreework(freeblks, freework,
+                           nlbn, nb, fs->fs_frag, 0);
+                       WORKLIST_INSERT_UNLOCKED(&nfreework->fw_jwork, wk);
+                       freedeps++;
+                       indir_trunc(nfreework, fsbtodb(fs, nb), nlbn);
+               } else {
+                       struct workhead freewk;
+
+                       LIST_INIT(&freewk);
+                       ACQUIRE_LOCK(&lk);
+                       WORKLIST_INSERT(&freewk, wk);
+                       FREE_LOCK(&lk);
+                       ffs_blkfree(ump, fs, freeblks->fb_devvp,
+                           jnewblk->jn_blkno, fs->fs_bsize,
+                           freeblks->fb_previousinum, &freewk);
+               }
                cnt++;
        }
        ACQUIRE_LOCK(&lk);
-       if (needj)
-               freework->fw_ref += NINDIR(fs) + 1;
        /* Any remaining journal work can be completed with freeblks. */
        jwork_move(&freeblks->fb_jwork, &wkhd);
        FREE_LOCK(&lk);
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to