return 2;
}
-static u32 update_index(struct indexblock *ib, u32 addr, u64 newphys)
-{
- /* addr exists in the given internal index block.
- * 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;
- int len = 1 << ib->b.inode->i_blkbits;
- u32 rv = 0;
- u64 phys;
- u32 a;
- int found = 0;
- int type;
-
- p = buf;
- if (test_bit(B_InoIdx, &ib->b.flags)) {
- int offset = LAFSI(ib->b.inode)->metadata_size;
- len -= offset;
- p += offset;
- }
- type = decode16(p);
- len -= 2;
- LAFS_BUG(type != IBLK_INDEX, &ib->b);
- while (len > 10) {
- phys = decode48(p);
- a = decode32(p);
- len -= 10;
- if (found) {
- p -= 20;
- encode48(p, phys);
- LAFS_BUG(a && !phys, &ib->b);
- if (rv == 0 && a) {
- rv = a;
- p += 4;
- } else
- encode32(p, a);
- encode48(p, 0ULL);
- encode32(p, 0UL);
- } else if (a == addr) {
- found = 1;
- 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);
- lafs_dirty_iblock(ib);
- 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_unhash_iblock(ib);
- lafs_hash_iblock(ib);
- lafs_iounlock_block(&ib->b);
- putiref(ib, MKREF(readdr));
- }
- depth--;
- }
-}
-
static void filter_empties(struct block **uninc)
{
/* If any block has phys==0 and there is another block
void lafs_incorporate(struct fs *fs, struct indexblock *ib)
{
int offset; /* start of block where indexing is */
- struct indexblock *new = NULL, *orig_ib, *locked_ib, *nxt, *prv;
- struct block *uninc = NULL, **bp;
+ struct indexblock *new = NULL;
+ 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 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 this index block is now empty and has no
+ * children which are not EmptyIndex, we flag it
+ * as EmptyIndex so index lookups know to avoid it.
*/
- orig_ib = ib;
- locked_ib = ib;
- recurse:
if (test_bit(B_InoIdx, &ib->b.flags)) {
/* Empty InoIdx blocks are allowed. However depth must
* be 1. This is where we suddenly collapse a now-empty
}
if (ib->depth > 1 && ! lafs_index_empty(ib))
goto out2;
+ if (ib->depth > 1) {
+ int non_empty = 0;
+ struct block *b;
+ spin_lock(&ib->b.inode->i_data.private_lock);
+ list_for_each_entry(b, &ib->children, siblings)
+ if (!test_bit(B_EmptyIndex, &b->flags)) {
+ non_empty = 1;
+ break;
+ }
+ spin_unlock(&ib->b.inode->i_data.private_lock);
+ if (non_empty)
+ goto out2;
+ }
if (ib->depth == 1 &&
(lafs_leaf_next(ib, 0) != 0xFFFFFFFF ||
!list_empty(&ib->children)))
goto out2;
- /* 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))
- // FIXME this call is improperly locked
- 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);
- locked_ib = ib->b.parent;
- /* 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);
-
- /* ib is empty and so we are going to remove it from the parent.
- * So we need to clear any 'dirty' status and remove from the
- * uninc list
- */
- if (test_bit(B_Uninc, &ib->b.flags)) {
- int doput = 0;
- spin_lock(&ib->b.inode->i_data.private_lock);
- for (bp = &ib->b.parent->uninc ; *bp ; ) {
- if (*bp == &ib->b) {
- *bp = ib->b.chain;
- clear_bit(B_Uninc, &ib->b.flags);
- doput = 1;
- break;
- } else
- bp = &(*bp)->chain;
- }
- spin_unlock(&ib->b.inode->i_data.private_lock);
- if (doput)
- putiref(ib, MKREF(uninc));
- }
- if (test_and_clear_bit(B_Dirty, &ib->b.flags))
- lafs_space_return(fs, 1);
- if (test_and_clear_bit(B_Realloc, &ib->b.flags))
- lafs_space_return(fs, 1);
- /* refile should remove from leaf list */
- lafs_refile(&ib->b, 0);
- /* 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,
- * 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.
- */
- nxt = NULL;
- if (ib->b.siblings.next != &ib->b.parent->children)
- nxt = list_entry(ib->b.siblings.next, struct indexblock, b.siblings);
- prv = NULL;
- if (ib->b.siblings.prev != &ib->b.parent->children)
- prv = list_entry(ib->b.siblings.prev, struct indexblock, b.siblings);
- /* we don't need to move to the inode->free_index list as that will
- * happen when refile drops the ->parent link.
- * If we completely remove from the list, refile will get confused in
- * consistency checks. So just move to the end of the list
- * to avoid confusing PrimaryRef chains.
- */
- list_move_tail(&ib->b.siblings, &ib->b.parent->children);
- lafs_unhash_iblock(ib);
- if (test_and_clear_bit(B_PrimaryRef, &ib->b.flags)) {
- /* This was not incorporated yet, revert the uninc status */
- if (nxt && test_bit(B_PrimaryRef, &nxt->b.flags)) {
- /* I was in a PrimaryRef chain */
- putiref(ib, MKREF(primary));
- } else {
- LAFS_BUG(!prv, &ib->b);
- putiref(prv, MKREF(primary));
- }
- } else if (nxt && test_bit(B_PrimaryRef, &nxt->b.flags)) {
- /* Next block is not incorporated yet, so simply re-address
- * it to replace this block.
- */
- clear_bit(B_PrimaryRef, &nxt->b.flags);
- putiref(ib, MKREF(primary));
- 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);
- }
- } 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
- */
- readdress_index(ib->b.inode, next, ib->depth, ib->b.fileaddr);
- } else if (ib->b.parent->b.fileaddr == ib->b.fileaddr) {
- /* The parent has just become empty and needs to be
- * removed from it's parent.
- */
- ib = ib->b.parent;
- goto recurse;
- }
- /* Currently hold iolock on ib->b.parent, and refcnt on orig_ib
- * which is a descendent.
- * Need to return with iolock on orig_ib.
- */
+ /* Block is really really empty */
+ set_bit(B_EmptyIndex, &ib->b.flags);
out2:
- if (locked_ib != orig_ib) {
- lafs_iolock_block(&orig_ib->b);
- lafs_iounlock_block(&locked_ib->b);
- }
+ return;
}
/***************************************************************