return 2;
}
+static u32 remove_from_index(struct indexblock *ib, u32 addr)
+{
+ /* 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.
+ */
+ char *buf = map_iblock(ib);
+ char *p;
+ int len = 1 << ib->b.inode->i_blkbits;
+ u32 rv = 0;
+ u64 phys;
+ u32 a;
+ int found = 0;
+
+ p = buf+2;
+ len -= 2;
+ while (len > 10) {
+ phys = decode48(p);
+ a = decode32(p);
+ len -= 10;
+ if (found) {
+ p -= 20;
+ encode48(p, phys);
+ encode32(p, a);
+ p += 10;
+ if (rv == 0)
+ rv = a;
+ } else if (a == addr)
+ found = 1;
+ else
+ BUG_ON(a > addr);
+ }
+ unmap_iblock(ib, buf);
+ lafs_dirty_iblock(ib);
+ return rv;
+}
+
/* Incorporate all the addresses in uninc_table into this
* indexblock. Each address carried a credit to allow for
* indexblock splitting etc.
void lafs_incorporate(struct fs *fs, struct indexblock *ib)
{
int offset; /* start of block where indexing is */
- struct indexblock *new = NULL;
+ struct indexblock *new = NULL, *orig_ib, *nxt;
struct block *uninc = NULL;
int rv = 0;
+ u32 next;
char *buf;
struct uninc uit;
int blocksize = fs->prime_sb->s_blocksize;
temp_credits = 0;
lafs_space_return(fs, uit.credits);
- /* If this internal index block is now empty, we either
- * invalidate it or merge it with the first dependent block.
- * If it is the first index block in it's parent we need to
- * adjust the start of parent and possibly other ancestors,
- * and incorporate them immediately.
+ /* If this index block is now empty, we either
+ * invalidate it and possibly find something else to take
+ * it's place.
+ * If there is nothing to take it's place, and it is the
+ * first block in the parent, we need to recurse up and
+ * resolve the parent in the same way.
*/
- if (test_bit(B_Valid, &ib->b.flags) &&
- list_empty(&ib->children) &&
- ib->depth > 1 &&
- lafs_index_empty(ib)) {
- struct block *nxt = list_entry(ib->b.siblings.next,
- struct block, siblings);
- if (ib->b.siblings.next != &ib->b.parent->children &&
- test_bit(B_PrimaryRef, &nxt->flags)) {
- /* */
+ if (test_bit(B_InoIdx, &ib->b.flags)) {
+ /* Empty InoIdx blocks aren't a problem, though I should
+ * probably reduce depth to 0 or 1.
+ */
+ ib->depth = 0;
+ LAFSI(ib->b.inode)->depth = 0;
+ /* Don't need to dirty the inode - the fact that we just
+ * did incorporation should ensure it is already dirty
+ */
+ return;
+ }
+ if (!list_empty(&ib->children))
+ /* If there are child, we cannot treat this block as empty. */
+ return;
+ if (ib->depth > 1 && ! lafs_index_empty(ib))
+ return;
+ if (ib->depth == 1 && lafs_leaf_next(ib, 0) != 0xFFFFFFFF)
+ return;
+
+ orig_ib = ib;
+ recurse:
+ /* OK, it is empty now. There are various ways we can handle
+ * this. All involve modification of the parent in some way,
+ * so we need to get a lock on said parent.
+ * This requires dropping the lock on this block, so we
+ * take i_alloc_sem to stop index looks from getting in our way.
+ */
+ if (test_bit(B_PhysValid, &ib->b.flags))
+ lafs_allocated_block(fs, &ib->b, 0);
+ else {
+ ib->b.physaddr = 0;
+ set_bit(B_PhysValid, &ib->b.flags);
+ }
+ down_write(&ib->b.inode->i_alloc_sem);
+ /* Any index lookup in ib will notice it is invalid and block
+ * on i_alloc_sem, so it is safe to unlock ib
+ */
+ lafs_iounlock_block(&ib->b);
+ lafs_iolock_block(&ib->b.parent->b);
+ /* Now anything looking for an address that could be in ib will
+ * block on the parent first, so we don't need i_alloc_sem
+ * any more.
+ */
+ up_write(&ib->b.inode->i_alloc_sem);
+
+ /* Options for how to handle the fact that ib is now empty.
+ * If this block is not yet incorporated, it can
+ * 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 not dirty, update parent and possibly re-address next
+ * If no next, and parent not empty, just delete
+ * If parent becomes empty, recurse upwards.
+ */
+ if (test_and_clear_bit(B_PrimaryRef, &ib->b.flags)) {
+ /* This was not incorporated yet */
+ int cr = incorp_index(&ib->b);
+ list_del_init(&ib->b.siblings);
+ if (test_and_clear_bit(B_Dirty, &ib->b.flags))
+ cr++;
+ lafs_space_return(fs, cr);
+ } else if (ib->b.siblings.next != &ib->b.parent->children &&
+ (nxt = list_entry(ib->b.siblings.next, struct indexblock, b.siblings)) &&
+ test_bit(B_PrimaryRef, &nxt->b.flags)) {
+ /* 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);
+ clear_bit(B_PrimaryRef, &nxt->b.flags);
+ putiref(ib, MKREF(primary));
+ } else if ((next = remove_from_index(ib->b.parent, ib->b.fileaddr)) != 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));
}
+ } 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
+ * removed from it's parent.
+ */
+ ib = ib->b.parent;
+ goto recurse;
}
+ /* Current hold iolock on ib->b.parent, and refcnt on orig_ib
+ * which is a descendent.
+ * Need to return with iolock on orig_ib.
+ */
+ lafs_iolock_block(&orig_ib->b);
+ lafs_iounlock_block(&ib->b.parent->b);
}
/***************************************************************