]> git.neil.brown.name Git - LaFS.git/commitdiff
Fix handling of empty index blocks during incorporation.
authorNeilBrown <neilb@suse.de>
Wed, 9 Jun 2010 03:23:14 +0000 (13:23 +1000)
committerNeilBrown <neilb@suse.de>
Thu, 10 Jun 2010 06:47:33 +0000 (16:47 +1000)
If an index block becomes empty we incorporate the address space into
the next index block, and so need to update the address of the leading
children and fix the indexes in the parent properly.

Signed-off-by: NeilBrown <neilb@suse.de>
modify.c

index ee39427c19ec44a315886a85d716ec1e10283267..2d3ef24ccdefb4a0359741f6a37e5fccccf25454 100644 (file)
--- a/modify.c
+++ b/modify.c
@@ -1581,11 +1581,15 @@ static int do_incorporate_internal(struct fs *fs, struct indexblock *ib,
        return 2;
 }
 
-static u32 remove_from_index(struct indexblock *ib, u32 addr)
+static u32 update_index(struct indexblock *ib, u32 addr, u64 newphys)
 {
        /* addr exists in the given internal index block.
-        * we want to remove it, shuffle down following addresses,
-        * and return the next address if one exists, else 0.
+        * We want to replace it's physaddr either with 'newphys'
+        * or with the next entry in which case we remove all 
+        * other trace of the next shuffling down subsequent entries.
+        * Return the next address if one exists, else 0.
+        * If we do find there is no next entry, we must be sure to
+        * fully erase *this* entry, not just set phys to 0.
         */
        char *buf = map_iblock(ib);
        char *p;
@@ -1615,20 +1619,28 @@ static u32 remove_from_index(struct indexblock *ib, u32 addr)
                        first = 0;
                }
                len -= 10;
-               if (phys == 0)
-                       break;
                if (found) {
                        p -= 20;
                        encode48(p, phys);
-                       encode32(p, a);
+                       LAFS_BUG(a && !phys, &ib->b);
+                       if (rv == 0 && a) {
+                               rv = a;
+                               p += 4;
+                       } else
+                               encode32(p, a);
                        encode48(p, 0ULL);
                        encode32(p, 0UL);
-                       if (rv == 0)
-                               rv = a;
-               } else if (a == addr)
+               } else if (a == addr) {
                        found = 1;
-               else
+                       if (newphys) {
+                               p -= 10;
+                               encode48(p, newphys);
+                               break;
+                       }
+               } else
                        LAFS_BUG(a > addr, &ib->b);
+               if (phys == 0)
+                       break;
        }
        LAFS_BUG(!found, &ib->b);
        unmap_iblock(ib, buf);
@@ -1636,6 +1648,26 @@ static u32 remove_from_index(struct indexblock *ib, u32 addr)
        return rv;
 }
 
+static void readdress_index(struct inode *ino, u32 addr, int depth,
+                           u32 newaddr)
+{
+       /* all index blocks of ino at or below depth need to be
+        * relocated to newaddr, including rehashing them.
+        */
+       while (depth) {
+               struct indexblock *ib = lafs_iblock_get(ino, addr, depth,
+                                                       0, MKREF(readdr));
+               if (ib) {
+                       lafs_iolock_block(&ib->b);
+                       ib->b.fileaddr = newaddr;
+                       lafs_hash_iblock(ib);
+                       lafs_iounlock_block(&ib->b);
+                       putiref(ib, MKREF(readdr));
+               }
+               depth--;
+       }
+}
+
 /* Incorporate all the addresses in uninc_table into this
  * indexblock.  Each address carried a credit to allow for
  * indexblock splitting etc.
@@ -1937,9 +1969,10 @@ void lafs_incorporate(struct fs *fs, struct indexblock *ib)
 
        /* Options for how to handle the fact that ib is now empty.
         * If this block is not yet incorporated, it can
-        * be quietly deleted.
+        *    be quietly deleted.
         * If it is, but next isn't re-address that one to take the place.
-        * If next is incorporated and dirty, re-address it likewise
+        * If next is incorporated and dirty, re-address it likewise,
+        *    deleting the phys from the parent
         * If next is not dirty, update parent and possibly re-address next
         * If no next, and parent not empty, just delete
         * If parent becomes empty, recurse upwards.
@@ -1957,21 +1990,19 @@ void lafs_incorporate(struct fs *fs, struct indexblock *ib)
                /* Next block is not incorporated yet, so simply re-address
                 * it to replace this block.
                 */
-               nxt->b.fileaddr = ib->b.fileaddr;
-               set_bit(B_PhysValid, &nxt->b.flags);
-               lafs_hash_iblock(nxt);
+               readdress_index(ib->b.inode, nxt->b.fileaddr, nxt->depth,
+                               ib->b.fileaddr);
+               if (test_bit(B_PhysValid, &nxt->b.flags)) {
+                       LAFS_BUG(nxt->b.physaddr == 0, &nxt->b);
+                       update_index(ib->b.parent, ib->b.fileaddr, nxt->b.physaddr);
+               }
                clear_bit(B_PrimaryRef, &nxt->b.flags);
                putiref(ib, MKREF(primary));
-       } else if ((next = remove_from_index(ib->b.parent, ib->b.fileaddr)) != 0) {
+       } else if ((next = update_index(ib->b.parent, ib->b.fileaddr, 0)) != 0) {
                /* Found a 'next' block in the parent and have updated the parent.
                 * Need to check for block in cache and re-address
                 */
-               nxt = lafs_iblock_get(ib->b.inode, next, ib->depth, 0, MKREF(inc2));
-               if (nxt) {
-                       nxt->b.fileaddr = ib->b.fileaddr;
-                       lafs_hash_iblock(nxt);
-                       putiref(nxt, MKREF(inc2));
-               }
+               readdress_index(ib->b.inode, next, ib->depth, ib->b.fileaddr);
        } else if (ib->b.parent->b.fileaddr == ib->b.fileaddr &&
                   !test_bit(B_InoIdx, &ib->b.parent->b.flags)) {
                /* The parent has just become empty and needs to be 
@@ -1980,7 +2011,7 @@ void lafs_incorporate(struct fs *fs, struct indexblock *ib)
                ib = ib->b.parent;
                goto recurse;
        }
-       /* Current hold iolock on ib->b.parent, and refcnt on orig_ib
+       /* Currently hold iolock on ib->b.parent, and refcnt on orig_ib
         * which is a descendent.
         * Need to return with iolock on orig_ib.
         */