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;
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);
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? */
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))
* 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);
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,
if (i < icnt) {
b = buf + i*10 + 6;
iaddr = decode32(b);
+ if (i == 0)
+ iaddr = first_addr;
} else
iaddr = 0xffffffff;
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
}
static u32 walk_index(char **bufp, int len, struct block *uninc,
+ u32 first_addr,
int (*handle)(void*, u32, u64),
void *data)
{
phys = decode48(buf);
addr = decode32(buf);
len -= 10;
+ if (buf == *bufp + 10)
+ addr = first_addr;
}
while (uninc &&
*bufp = buf - 10;
return addr;
}
+ if (phys == 0 && uninc == NULL)
+ break;
}
handle(data, 0, ~(u64)0); /* finalise */
return 0;
buf = ibuf + offset + 2;
next = walk_index(&buf, len-2, uninc,
+ ib->b.fileaddr,
add_index,
&layout);
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;
u32 a;
int found = 0;
int type;
+ int first = 1;
p = buf;
if (test_bit(B_InoIdx, &ib->b.flags)) {
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;
/* 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;