]> git.neil.brown.name Git - LaFS.git/commitdiff
Fix problem with mobility of internal index blocks.
authorNeilBrown <neilb@suse.de>
Wed, 9 Jun 2010 02:14:07 +0000 (12:14 +1000)
committerNeilBrown <neilb@suse.de>
Thu, 10 Jun 2010 06:05:09 +0000 (16:05 +1000)
As index blocks can change address if they are or become the first
block in the parent, we must not put too much weight on the first
address stored in an internal index block - it must always be treated
as the same as the address of that internal index block.

So pass around the current block's address where needed, and use it in
preference to the first address recorded in the block.

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

diff --git a/index.c b/index.c
index e6d6d733cd0e1b32f07e92ece5aa11e38f26d9fd..77e21bd9b766d64abf3d99760097357f603d6f49 100644 (file)
--- a/index.c
+++ b/index.c
@@ -1220,6 +1220,11 @@ u32 lafs_leaf_next(struct indexblock *ib, u32 start)
 static u64
 index_lookup(void *bf, int len, u32 target, u32 *addrp, u32 *nextp)
 {
+       /* We treat the first address in the buffer as *addrp, no
+        * matter what is really there.  *addrp is the address of
+        * *this* index block.  So if we find a hit on the first
+        * entry, we leave *addrp unchanged.
+        */
        unsigned char *buf = bf;
        int lo, hi;
        u32 addr;
@@ -1242,7 +1247,10 @@ index_lookup(void *bf, int len, u32 target, u32 *addrp, u32 *nextp)
                cp = buf;
                cp += mid*10;
                p = decode48(cp);
-               addr = decode32(cp);
+               if (mid == 0)
+                       addr = *addrp;
+               else
+                       addr = decode32(cp);
                dprintk("...addr=%lu target=%lu lo=%d mid=%d hi=%d\n",
                        (unsigned long)addr, (unsigned  long)target,
                        lo, mid, hi);
@@ -1256,7 +1264,8 @@ index_lookup(void *bf, int len, u32 target, u32 *addrp, u32 *nextp)
        cp += lo*10;
        p = decode48(cp);
        addr = decode32(cp);
-       *addrp = addr;
+       if (lo > 0)
+               *addrp = addr;
 
        if (cp+10 <= (unsigned char *) buf + len && nextp) {
                /* FIXME what about non-dense blocks? */
@@ -1273,7 +1282,7 @@ int lafs_index_empty(struct indexblock *ib)
        char *buf = map_iblock(ib);
        int blocksize = ib->b.inode->i_sb->s_blocksize;
        struct lafs_inode *li = LAFSI(ib->b.inode);
-       u32 addr;
+       u32 addr = ib->b.fileaddr;
        u64 phys;
 
        if (test_bit(B_InoIdx, &ib->b.flags))
@@ -1337,6 +1346,7 @@ lafs_leaf_find(struct inode *inode, u32 addr, int adopt, u32 *next,
                 * So we don't use lafs_leaf_find during truncation.
                 */
                buf = map_iblock(ib);
+               iaddr = ib->b.fileaddr;
                iphys = index_lookup(buf + offset, blocksize - offset,
                                     addr, &iaddr, next);
                unmap_iblock(ib, buf);
index 6da632ec95f64db864743db97e3094d4402eed18..ee39427c19ec44a315886a85d716ec1e10283267 100644 (file)
--- a/modify.c
+++ b/modify.c
@@ -236,7 +236,8 @@ static int incorporate_extent(struct uninc *ui, char *buf, int size)
        return credits;
 }
 
-static int incorporate_index(struct block *uninc, char *buf, int size)
+static int incorporate_index(struct block *uninc, char *buf, int size,
+                            u32 first_addr)
 {
        /* see if we can merge the addresses of uninc blocks
         * with those in buf, by counting the total number,
@@ -278,6 +279,8 @@ static int incorporate_index(struct block *uninc, char *buf, int size)
                if (i < icnt) {
                        b = buf + i*10 + 6;
                        iaddr = decode32(b);
+                       if (i == 0)
+                               iaddr = first_addr;
                } else
                        iaddr = 0xffffffff;
 
@@ -358,7 +361,9 @@ static int incorporate_index(struct block *uninc, char *buf, int size)
                        uaddr = uninc->fileaddr;
                else
                        uaddr = 0;
-               if (i) {
+               if (i == 1)
+                       iaddr = first_addr;
+               else if (i > 1) {
                        b = buf + (i-1)*10 + 6;
                        iaddr = decode32(b);
                } else
@@ -760,6 +765,7 @@ static int check_leaf(void *data, u32 addr, u64 phys, int len)
 }
 
 static u32 walk_index(char **bufp, int len, struct block *uninc,
+                     u32 first_addr,
                      int (*handle)(void*, u32, u64),
                      void *data)
 {
@@ -783,6 +789,8 @@ static u32 walk_index(char **bufp, int len, struct block *uninc,
                        phys = decode48(buf);
                        addr = decode32(buf);
                        len -= 10;
+                       if (buf == *bufp + 10)
+                               addr = first_addr;
                }
 
                while (uninc &&
@@ -805,6 +813,8 @@ static u32 walk_index(char **bufp, int len, struct block *uninc,
                        *bufp = buf - 10;
                        return addr;
                }
+               if (phys == 0 && uninc == NULL)
+                       break;
        }
        handle(data, 0, ~(u64)0); /* finalise */
        return 0;
@@ -1462,6 +1472,7 @@ static int do_incorporate_internal(struct fs *fs, struct indexblock *ib,
        buf = ibuf + offset + 2;
 
        next = walk_index(&buf, len-2, uninc,
+                         ib->b.fileaddr,
                          add_index,
                          &layout);
 
@@ -1561,7 +1572,7 @@ static int do_incorporate_internal(struct fs *fs, struct indexblock *ib,
                new->uninc = b->chain;
                b->chain = NULL;
                nbuf = map_iblock(new);
-               cr = incorporate_index(b, nbuf, len);
+               cr = incorporate_index(b, nbuf, len, next);
                unmap_iblock(new, nbuf);
                LAFS_BUG(cr < 0, &ib->b);
                *credits += cr;
@@ -1584,6 +1595,7 @@ static u32 remove_from_index(struct indexblock *ib, u32 addr)
        u32 a;
        int found = 0;
        int type;
+       int first = 1;
 
        p = buf;
        if (test_bit(B_InoIdx, &ib->b.flags)) {
@@ -1597,6 +1609,11 @@ static u32 remove_from_index(struct indexblock *ib, u32 addr)
        while (len > 10) {
                phys = decode48(p);
                a = decode32(p);
+               if (first) {
+                       /* Ignore first address in index blocks */
+                       a = ib->b.fileaddr;
+                       first = 0;
+               }
                len -= 10;
                if (phys == 0)
                        break;
@@ -1752,7 +1769,8 @@ void lafs_incorporate(struct fs *fs, struct indexblock *ib)
                /* internal index block.  Might be able to merge in-place */
                if (*(u16 *)(buf) == cpu_to_le16(IBLK_INDEX) &&
                    (cred = incorporate_index(uninc, buf+2,
-                                             blocksize-(offset+2))) >= 0) {
+                                             blocksize-(offset+2),
+                                             ib->b.fileaddr)) >= 0) {
                        unmap_iblock(ib, buf-offset);
                        uit.credits = cred;
                        goto out;