From: NeilBrown Date: Wed, 9 Jun 2010 02:14:07 +0000 (+1000) Subject: Fix problem with mobility of internal index blocks. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=a21596e51b872635c7cb0683a21fff981f5d3716;p=LaFS.git Fix problem with mobility of internal index blocks. 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 --- diff --git a/index.c b/index.c index e6d6d73..77e21bd 100644 --- 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); diff --git a/modify.c b/modify.c index 6da632e..ee39427 100644 --- 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;