struct layoutinfo {
char *data;
int size;
+ u32 forcestart;
u64 lastphys;
u32 lastaddr;
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;
}
}
if (len == 0)
return 0; /* nothing to finalise */
- if (li->cnt == 0)
+ if (li->cnt == 0 && li->firstaddr == 0)
li->firstaddr = addr;
li->cnt++;
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.
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) {
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);
* 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.
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);
/* 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) &&
/* 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);
}
/* 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);
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);