void lafs_incorporate(struct fs *fs, struct indexblock *ib)
{
int offset; /* start of block where indexing is */
- struct indexblock *new = NULL, *orig_ib, *nxt;
+ struct indexblock *new = NULL, *orig_ib, *locked_ib, *nxt;
struct block *uninc = NULL;
int rv = 0;
u32 next;
* first block in the parent, we need to recurse up and
* resolve the parent in the same way.
*/
+ orig_ib = ib;
+ locked_ib = ib;
+ recurse:
if (!list_empty(&ib->children))
/* If there are children, we cannot treat this block as empty. */
return;
/* Don't need to dirty the inode - the fact that we just
* did incorporation should ensure it is already dirty
*/
- return;
+ goto out2;
}
if (ib->depth > 1 && ! lafs_index_empty(ib))
- return;
+ goto out2;
if (ib->depth == 1 && lafs_leaf_next(ib, 0) != 0xFFFFFFFF)
- return;
+ goto out2;
- 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.
*/
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.
* 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 &&
- !test_bit(B_InoIdx, &ib->b.parent->b.flags)) {
+ } 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.
*/
* 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);
+out2:
+ if (locked_ib != orig_ib) {
+ lafs_iolock_block(&orig_ib->b);
+ lafs_iounlock_block(&locked_ib->b);
+ }
}
/***************************************************************