]> git.neil.brown.name Git - LaFS.git/commitdiff
Handle extents getting added before an indirect block.
authorNeilBrown <neilb@suse.de>
Sun, 13 Jun 2010 10:11:56 +0000 (20:11 +1000)
committerNeilBrown <neilb@suse.de>
Fri, 18 Jun 2010 11:16:45 +0000 (21:16 +1000)
Now that indirect blocks are 'mobile' and can have a
start address, it is possible that an extent in uninc_table
starts before the indirect addresses.
In this case the logic that assured us there was room for all
the addresses fall down.

So detect that case earlier and force the indirect block
to either start at the start of the uninc bloc, or become
an extent block.  Possibly it will split as part of this.

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

index e781cc3040c6e3c269be5fd371dedb9014e1ab63..c25b54436a5e82729119df7916ee6bf4c0b70614 100644 (file)
--- a/modify.c
+++ b/modify.c
@@ -560,6 +560,7 @@ void lafs_print_uninc(struct uninc *ui)
 struct layoutinfo {
        char *data;
        int size;
+       u32 forcestart;
 
        u64 lastphys;
        u32 lastaddr;
@@ -616,10 +617,13 @@ static int add_indirect(void *data, u32 addr, u64 phys, int len)
 
        if (li->lastphys == 0) {
                /* This is the first address, add the address header */
-               li->lastaddr = addr;
+               if (li->forcestart)
+                       li->lastaddr = li->forcestart;
+               else
+                       li->lastaddr = addr;
                li->lastphys = phys;
                p = li->data;
-               encode32(p, addr);
+               encode32(p, li->lastaddr);
                li->data = p;
                li->size -= 4;
        }
@@ -724,7 +728,7 @@ static int check_leaf(void *data, u32 addr, u64 phys, int len)
        }
        if (len == 0)
                return 0; /* nothing to finalise */
-       if (li->cnt == 0)
+       if (li->cnt == 0 && li->firstaddr == 0)
                li->firstaddr = addr;
 
        li->cnt++;
@@ -1168,7 +1172,8 @@ static void share_children(struct indexblock *ib, struct indexblock *new)
 
 static int do_incorporate_leaf(struct fs *fs, struct indexblock *ib,
                               struct uninc *ui,
-                              struct indexblock *new)
+                              struct indexblock *new,
+                              u32 low_addr)
 {
        /* Incorporate all the changes in ib->uninc_table into ib,
         * with any new address appearing in new.
@@ -1211,6 +1216,9 @@ static int do_incorporate_leaf(struct fs *fs, struct indexblock *ib,
        len = fs->prime_sb->s_blocksize - offset;
 
        check_leaf(&leafinfo, ib->b.fileaddr, 0, len);
+       if (low_addr != 0xFFFFFFFF)
+               leafinfo.firstaddr = low_addr;
+
        current_layout = le16_to_cpu(*(u16 *)(ibuf+offset));
        buf = ibuf + offset + 2;
        switch (current_layout) {
@@ -1244,6 +1252,7 @@ static int do_incorporate_leaf(struct fs *fs, struct indexblock *ib,
        nbuf = map_iblock_2(new);
        layout.data = nbuf;
        layout.size = len;
+       layout.forcestart = low_addr;
        memset(nbuf, 0, fs->prime_sb->s_blocksize);
        set_bit(B_Valid, &new->b.flags);
 
@@ -1294,6 +1303,14 @@ static int do_incorporate_leaf(struct fs *fs, struct indexblock *ib,
         *  The start of ib hasn't changed, so all the addresses that
         *  were there are now in new.  So ib is empty and can fit everything
         *  in ui, as ui is <<< ib
+        *
+        *  Note: this logic doesn't apply if anything from ui was
+        *  *before* the start of the indirect block, as that could
+        *  change the start of the ib (now that ibs are mobile).
+        *  Hence the check involving low_addr which forces an Indirect
+        *  block to be rearranged before including anything in ui
+        *  which is earlier.
+        *
         * INDIRECT -> EXTENT
         *  More fitted as EXTENTS, so we must have included all remaining
         *  addressed from ib, so only some ui addresses remain.
@@ -1699,6 +1716,7 @@ void lafs_incorporate(struct fs *fs, struct indexblock *ib)
        char *buf;
        struct uninc uit;
        int blocksize = fs->prime_sb->s_blocksize;
+       u32 low_addr = 0xFFFFFFFF;
 
        LAFS_BUG(!test_bit(B_IOLock, &ib->b.flags), &ib->b);
 
@@ -1711,15 +1729,52 @@ void lafs_incorporate(struct fs *fs, struct indexblock *ib)
                /* take a copy of the uninc_table so we can work while
                 * more changes can be made
                 */
+               char *b;
+               u16 type;
+               u32 start;
                LAFS_BUG(ib->uninc, &ib->b);
+
+               if (test_bit(B_InoIdx, &ib->b.flags)) {
+                       offset = LAFSI(ib->b.inode)->metadata_size;
+                       if (LAFSI(ib->b.inode)->depth == 0) {
+                               /* data has already been copied
+                                * out.. I hope - FIXME */
+                               LAFSI(ib->b.inode)->depth = 1;
+                               ib->depth = 1;
+                               lafs_clear_index(ib);
+                       }
+               } else
+                       offset = 0;
+
+               buf = map_iblock(ib) + offset;
+               b = buf;
+               type = decode16(b);
+               start = decode32(b);
+
                spin_lock(&fs->lock);
-               memcpy(&uit, &ib->uninc_table, sizeof(uit));
-               ib->uninc_table.pending_cnt = 0;
-               ib->uninc_table.credits = 0;
+
+               if (type == IBLK_INDIRECT &&
+                   ib->uninc_table.pending_cnt > 0 &&
+                   start > ib->uninc_table.pending_addr[0].fileaddr) {
+                       /* new extent before and indirect block.  We cannot
+                        * handle this reliably as it could require
+                        * more than two new index blocks.  So for the
+                        * indirect block to be reshuffled to a lower
+                        * address, possibly causing a split
+                        */
+                       low_addr = ib->uninc_table.pending_addr[0].fileaddr;
+                       uit.pending_cnt = 0;
+               } else {
+                       memcpy(&uit, &ib->uninc_table, sizeof(uit));
+                       ib->uninc_table.pending_cnt = 0;
+                       ib->uninc_table.credits = 0;
+               }
                spin_unlock(&fs->lock);
 
-               if (uit.pending_cnt == 0)
+               if (uit.pending_cnt == 0 && low_addr == 0xFFFFFFFF) {
+                       unmap_iblock(ib, buf-offset);
                        goto out;
+               }
                sort_uninc(&uit);
 
                if(!test_bit(B_Dirty, &ib->b.flags) &&
@@ -1731,21 +1786,8 @@ void lafs_incorporate(struct fs *fs, struct indexblock *ib)
                /* OK, we genuinely have work to do. */
                /* find size and type of current block */
 
-               if (test_bit(B_InoIdx, &ib->b.flags)) {
-                       offset = LAFSI(ib->b.inode)->metadata_size;
-                       if (LAFSI(ib->b.inode)->depth == 0) {
-                               /* data has already been copied
-                                * out.. I hope - FIXME */
-                               LAFSI(ib->b.inode)->depth = 1;
-                               ib->depth = 1;
-                               lafs_clear_index(ib);
-                       }
-               } else
-                       offset = 0;
-
-               buf = map_iblock(ib) + offset;
                /* Maybe a direct update of an indirect block */
-               if (*(u16 *)(buf) == cpu_to_le16(IBLK_INDIRECT) &&
+               if (type == IBLK_INDIRECT && low_addr == 0xFFFFFFFF &&
                    incorporate_indirect(&uit, buf+2,
                                         blocksize-(offset+2))) {
                        unmap_iblock(ib, buf-offset);
@@ -1753,7 +1795,7 @@ void lafs_incorporate(struct fs *fs, struct indexblock *ib)
                }
 
                /* Maybe a fairly direct update of an extent block */
-               if (*(u16 *)(buf) == cpu_to_le16(IBLK_EXTENT) &&
+               if (type == IBLK_EXTENT &&
                    incorporate_extent(&uit, buf+2,
                                       blocksize-(offset+2))) {
                        unmap_iblock(ib, buf-offset);
@@ -1836,7 +1878,7 @@ void lafs_incorporate(struct fs *fs, struct indexblock *ib)
                printk("small depth %s\n", strblk(&ib->b));
        LAFS_BUG(ib->depth < 1, &ib->b);
        if (ib->depth == 1)
-               rv = do_incorporate_leaf(fs, ib, &uit, new);
+               rv = do_incorporate_leaf(fs, ib, &uit, new, low_addr);
        else
                rv = do_incorporate_internal(fs, ib, uninc, &uit.credits, new);