static int prune(void *data, u32 addr, u64 paddr, int len)
{
+ /* This whole index block is being pruned, just account
+ * for everything and it will be cleared afterwards
+ */
struct indexblock *ib = data;
struct inode *ino = ib->b.inode;
struct fs *fs = fs_from_inode(ino);
return len;
}
+static int prune_some(void *data, u32 addr, u64 paddr, int len)
+{
+ /* Part of this index block is being pruned. Copy
+ * what addresses we can into uninc_table so that
+ * it can be 'incorporated'
+ * We should probably share some code with
+ * lafs_allocated_block??
+ */
+ struct indexblock *ib = data;
+ struct inode *ino = ib->b.inode;
+ struct fs *fs = fs_from_inode(ino);
+ int ph = !! test_bit(B_Phase1, &ib->b.flags);
+ int i;
+ if (paddr == 0 || len == 0)
+ return 0;
+ dprintk("PRUNE2 %d for %d at %lld\n", addr, len, (long long)paddr);
+ for (i = 0 ; i < len ; i++) {
+ /* FIXME do I need to lock anything or is our IOLock enough? */
+ struct addr *a;
+ spin_lock(&fs->lock);
+ a = &ib->uninc_table.pending_addr
+ [ib->uninc_table.pending_cnt - 1];
+ if (ib->uninc_table.pending_cnt >= 1 &&
+ a->fileaddr + a->cnt == addr+i &&
+ a->physaddr + a->cnt == paddr+i)
+ a->cnt++;
+ else if (ib->uninc_table.pending_cnt <
+ ARRAY_SIZE(ib->uninc_table.pending_addr)) {
+ a++;
+ a->fileaddr = addr + i;
+ a->physaddr = paddr + i;
+ a->cnt = 1;
+ ib->uninc_table.pending_cnt ++;
+ } else {
+ spin_unlock(&fs->lock);
+ break;
+ }
+ spin_unlock(&fs->lock);
+ lafs_summary_update(fs, ino, paddr+i, 0, 0, ph);
+ }
+ return i;
+}
+
static int lafs_inode_handle_orphan(struct datablock *b)
{
struct indexblock *ib, *ib2;
struct inode *ino = b->my_inode;
struct fs *fs = fs_from_inode(ino);
- u32 trunc_next;
+ u32 trunc_next, next_trunc;
/* FIXME if the trunc has completed, we don't really
* need the iblock...
* that we can do now, it will do for us. So just
* let it.
*/
-
+ struct indexblock *tmp;
+ struct indexblock *next;
+ u32 lastaddr;
+
+ if (!test_bit(B_Pinned, &ib->b.flags)) {
+ /* must be finished */
+ clear_bit(I_Trunc, &LAFSI(ino)->iflags);
+ wake_up(&fs->trunc_wait);
+ putiref(ib, MKREF(inode_handle_orphan));
+ return 1; /* Try again whenever */
+ }
+ if (fs->checkpointing) {
+ putiref(ib, MKREF(inode_handle_orphan));
+ return 2; /* means "Try again after the checkpoint" */
+ }
/* FIXME I need some sort of lock to safely walk
* down this list */
- while (!list_empty(&ib->children) && !fs->checkpointing) {
- struct indexblock *tmp;
- ib2 = ib;
- /* Find a Pinned descendent of ib which has no
- * Pinned descendents.
- */
- retry:
- list_for_each_entry(tmp, &ib2->children, b.siblings)
- if (test_bit(B_Index, &tmp->b.flags) &&
- test_bit(B_Pinned, &tmp->b.flags)) {
- ib2 = tmp;
- goto retry;
- }
- /* ib2 is an index block with no Pinned children.
- * Incorporating it should unpin it.
- */
- getiref(ib2, MKREF(inode_handle_orphan2));
- lafs_iolock_block(&ib2->b);
- /* call lafs_incorporate at least once to ensure
- * that lafs_erase_iblock gets called
- */
- do
- lafs_incorporate(fs, ib2);
- while (ib2->uninc_table.pending_cnt || ib2->uninc);
- lafs_iounlock_block(&ib2->b, 0);
- putiref(ib2, MKREF(inode_handle_orphan2));
- printk(".");
- if (!list_empty(&ib2->b.siblings)) {
- static int cnt = 10;
- printk("looping on %s\n", strblk(&ib2->b));
- cnt --;
- if (cnt < 0) BUG();
+ ib2 = ib;
+ lastaddr = (i_size_read(ino) +
+ ino->i_sb->s_blocksize - 1)
+ >> ino->i_sb->s_blocksize_bits;
+ /* Find a Pinned descendent of ib which has no
+ * Pinned descendents.
+ * Prefer blocks that are beyond EOF.
+ * If there are none, descend the last block that
+ * is not after EOF and look at its children.
+ */
+ next = ib;
+ while (next) {
+ ib2 = next;
+ next = NULL;
+ list_for_each_entry(tmp, &ib2->children, b.siblings) {
+ if (!test_bit(B_Index, &tmp->b.flags) ||
+ !test_bit(B_Pinned, &tmp->b.flags))
+ continue;
+ if (tmp->b.fileaddr >= lastaddr) {
+ next = tmp;
+ break;
+ }
+ if (next == NULL ||
+ tmp->b.fileaddr > next->b.fileaddr)
+ next = tmp;
}
}
+ if (ib2->b.fileaddr < lastaddr) {
+ /* Must be all done */
+ clear_bit(I_Trunc, &LAFSI(ino)->iflags);
+ wake_up(&fs->trunc_wait);
+ putiref(ib, MKREF(inode_handle_orphan));
+ return 1; /* Try again whenever */
+ }
+
+ /* ib2 is an index block beyond EOF with no
+ * Pinned children.
+ * Incorporating it should unpin it.
+ */
+ getiref(ib2, MKREF(inode_handle_orphan2));
+ lafs_iolock_block(&ib2->b);
+ /* call lafs_incorporate at least once to ensure
+ * that lafs_erase_iblock gets called
+ */
+ do
+ lafs_incorporate(fs, ib2);
+ while (ib2->uninc_table.pending_cnt || ib2->uninc);
+ lafs_iounlock_block(&ib2->b, 0);
+ putiref(ib2, MKREF(inode_handle_orphan2));
+ printk(".");
+ if (!list_empty(&ib2->b.siblings)) {
+ static int cnt = 10;
+ printk("looping on %s\n", strblk(&ib2->b));
+ cnt --;
+ if (cnt < 0) BUG();
+ }
putiref(ib, MKREF(inode_handle_orphan));
- if (fs->checkpointing)
- return 2; /* means "Try again after the checkpoint" */
- /* Truncation has finished */
- clear_bit(I_Trunc, &LAFSI(ino)->iflags);
- wake_up(&fs->trunc_wait);
return 1; /* Try again whenever */
}
putiref(ib, MKREF(inode_handle_orphan));
- ib = lafs_leaf_find(ino, trunc_next, 1, &trunc_next,
+ ib = lafs_leaf_find(ino, trunc_next, 1, &next_trunc,
0, MKREF(inode_handle_orphan3));
if (IS_ERR(ib))
lafs_checkpoint_lock(fs);
if (lafs_reserve_block(&ib->b, ReleaseSpace) == -EAGAIN) {
+ putiref(ib, MKREF(inode_handle_orphan3));
lafs_checkpoint_unlock(fs);
return 2;
}
- LAFSI(ino)->trunc_next = trunc_next;
+ /* It might be that this can happen, in which case
+ * we simply update trunc_next and loop. But I'd like
+ * to be sure before I implement that
+ */
+ BUG_ON(!test_bit(B_Valid, &ib->b.flags));
+
+ if (ib->b.fileaddr < trunc_next) {
+ /* We only want to truncate part of this index block.
+ * So we copy addresses into uninc_table and then
+ * all lafs_incorporate.
+ * This might cause the index tree to grow, so we
+ * cannot trust next_trunc
+ */
+ lafs_iolock_block(&ib->b);
+ if (ib->uninc_table.pending_cnt == 0 &&
+ ib->uninc == NULL)
+ lafs_walk_leaf_index(ib, prune_some, ib);
+ lafs_incorporate(fs, ib);
+ lafs_iounlock_block(&ib->b, 0);
+ return 1;
+ }
+ LAFSI(ino)->trunc_next = next_trunc;
lafs_iolock_block(&ib->b);
+
while (ib->uninc_table.pending_cnt || ib->uninc)
lafs_incorporate(fs, ib);
lafs_iounlock_block(&ib->b, 0);
lafs_orphan_commit(&oi);
set_bit(I_Trunc, &LAFSI(ino)->iflags);
- LAFSI(ino)->trunc_next = 0;
+ LAFSI(ino)->trunc_next = (i_size_read(ino) +
+ ino->i_sb->s_blocksize - 1)
+ >> ino->i_sb->s_blocksize_bits;
putdref(db, MKREF(trunc));
inode_handle_orphan_loop(ino);