return 2;
}
-static u32 remove_from_index(struct indexblock *ib, u32 addr)
+static u32 update_index(struct indexblock *ib, u32 addr, u64 newphys)
{
/* addr exists in the given internal index block.
- * we want to remove it, shuffle down following addresses,
- * and return the next address if one exists, else 0.
+ * We want to replace it's physaddr either with 'newphys'
+ * or with the next entry in which case we remove all
+ * other trace of the next shuffling down subsequent entries.
+ * Return the next address if one exists, else 0.
+ * If we do find there is no next entry, we must be sure to
+ * fully erase *this* entry, not just set phys to 0.
*/
char *buf = map_iblock(ib);
char *p;
first = 0;
}
len -= 10;
- if (phys == 0)
- break;
if (found) {
p -= 20;
encode48(p, phys);
- encode32(p, a);
+ LAFS_BUG(a && !phys, &ib->b);
+ if (rv == 0 && a) {
+ rv = a;
+ p += 4;
+ } else
+ encode32(p, a);
encode48(p, 0ULL);
encode32(p, 0UL);
- if (rv == 0)
- rv = a;
- } else if (a == addr)
+ } else if (a == addr) {
found = 1;
- else
+ if (newphys) {
+ p -= 10;
+ encode48(p, newphys);
+ break;
+ }
+ } else
LAFS_BUG(a > addr, &ib->b);
+ if (phys == 0)
+ break;
}
LAFS_BUG(!found, &ib->b);
unmap_iblock(ib, buf);
return rv;
}
+static void readdress_index(struct inode *ino, u32 addr, int depth,
+ u32 newaddr)
+{
+ /* all index blocks of ino at or below depth need to be
+ * relocated to newaddr, including rehashing them.
+ */
+ while (depth) {
+ struct indexblock *ib = lafs_iblock_get(ino, addr, depth,
+ 0, MKREF(readdr));
+ if (ib) {
+ lafs_iolock_block(&ib->b);
+ ib->b.fileaddr = newaddr;
+ lafs_hash_iblock(ib);
+ lafs_iounlock_block(&ib->b);
+ putiref(ib, MKREF(readdr));
+ }
+ depth--;
+ }
+}
+
/* Incorporate all the addresses in uninc_table into this
* indexblock. Each address carried a credit to allow for
* indexblock splitting etc.
/* Options for how to handle the fact that ib is now empty.
* If this block is not yet incorporated, it can
- * be quietly deleted.
+ * be quietly deleted.
* If it is, but next isn't re-address that one to take the place.
- * If next is incorporated and dirty, re-address it likewise
+ * If next is incorporated and dirty, re-address it likewise,
+ * deleting the phys from the parent
* If next is not dirty, update parent and possibly re-address next
* If no next, and parent not empty, just delete
* If parent becomes empty, recurse upwards.
/* Next block is not incorporated yet, so simply re-address
* it to replace this block.
*/
- nxt->b.fileaddr = ib->b.fileaddr;
- set_bit(B_PhysValid, &nxt->b.flags);
- lafs_hash_iblock(nxt);
+ readdress_index(ib->b.inode, nxt->b.fileaddr, nxt->depth,
+ ib->b.fileaddr);
+ if (test_bit(B_PhysValid, &nxt->b.flags)) {
+ LAFS_BUG(nxt->b.physaddr == 0, &nxt->b);
+ update_index(ib->b.parent, ib->b.fileaddr, nxt->b.physaddr);
+ }
clear_bit(B_PrimaryRef, &nxt->b.flags);
putiref(ib, MKREF(primary));
- } else if ((next = remove_from_index(ib->b.parent, ib->b.fileaddr)) != 0) {
+ } else if ((next = update_index(ib->b.parent, ib->b.fileaddr, 0)) != 0) {
/* Found a 'next' block in the parent and have updated the parent.
* Need to check for block in cache and re-address
*/
- nxt = lafs_iblock_get(ib->b.inode, next, ib->depth, 0, MKREF(inc2));
- if (nxt) {
- nxt->b.fileaddr = ib->b.fileaddr;
- lafs_hash_iblock(nxt);
- putiref(nxt, MKREF(inc2));
- }
+ readdress_index(ib->b.inode, next, ib->depth, ib->b.fileaddr);
} else if (ib->b.parent->b.fileaddr == ib->b.fileaddr &&
!test_bit(B_InoIdx, &ib->b.parent->b.flags)) {
/* The parent has just become empty and needs to be
ib = ib->b.parent;
goto recurse;
}
- /* Current hold iolock on ib->b.parent, and refcnt on orig_ib
+ /* Currently hold iolock on ib->b.parent, and refcnt on orig_ib
* which is a descendent.
* Need to return with iolock on orig_ib.
*/