These dir blocks are currently fully populated with numbers.
This seems to be the pattern with all non-7 blocks.
+
+ 02Sep2009
+ Found a problem, possibly related to the dir blocks not being
+ cleaned up.
+ When lafs_incorporate sets ->depth to 1 it doesn't dirty the inode,
+ so that fact is never copied in to the datablock.
+ On further exploration, the I_Dirty bit is set but never used, which
+ isn't good.
+ So: exactly when do we copy inode into datablock, and what do we do
+ when dirty_inode is call (if anything).
+ We could just set I_Dirty when dirty_inode is called, checking that
+ the block is Pinned which it usually will be.
+ Then we copy inode to data just before writing data block.
+ However that defeats transactional properties. We to copy in the
+ same transaction, and that means either straight away, or when
+ the data block's phase changes.
+ So dirty_inode either copies to the block, or sets I_Dirty.
+ When lafs_refile unpins an inode data block, it need to check
+ I_Dirty and possibly re-dirty it.
+
+ To redirty it we must steal the NCredits. Any further dirty attempt
+ will have to allocate more.
+ The stealing is done automatically by dirty_dblock, so we just flip
+ the phase and call dirty_inode ... making sure it doesn't try to
+ prealloc too hard.
+
+ Need to review when inodes get dirtied.
+ - commit_write only sets I_Dirty !
+
+ We call lafs_dirty_inode:
+ dir_create_commit - a child of inode is PinPending
+ lafs_create - ditto
+ lafs_link - before dir_create_commit
+ lafs_unlink, lafs_rmdir - data block is pinned
+ lafs_symlink - before create_commit
+ lafs_mkdir - before create_commit, or block pinned
+ lafs_mknod - before create_commit
+ lafs_rename - (moved to) before create_commit/update_commit
+ or data block is pinned
+ lafs_dir_handle_orphan - (assured that) child is pinned.
+ choose_free_inum - child is pinned
+ lafs_incorporate - block is pinned
+
+ So either the data block is pinned, or the index block is pinned.
+ In either case it is OK to set something to Dirty.
+
+ (the new) lafs_dirty_vfs_inode gets called by mark_dirty_inode{,_sync}
+ this is called from:
+ inode_inc_link_count
+ inode_dec_link_count
+ ..various quota ops...
+ inode_setattr
+ __set_page_dirty (Which we don't use)
+ other buffer stuff
+ other quota stuff we won't use
+ touch_atime
+ file_update_time
+ page_symlink
+
+ only the time updates are interesting. Others we have locking
+ for.
+ file_update_time is called from generic_file_aio_write_nlock etc
+ before ->prepare_write/->commit_write. So they can pick up the
+ change.
+ Similarly before set_page_dirty is called.
+ touch_atime is called from do_follow_link and readlink and
+ file_accessed which is called all over the place.
+
+ So what to do?
+ If block is pinned, then dirty it to ensure writeout.
+ If not, don't. But copy data in any case.
(phase == -1 && test_bit(B_Realloc, &lai->iblock->b.flags)))
) {
/* Don't really want this to be pinned yet. When the
- * InoIdx block gets proceed we will get pinned again.
+ * InoIdx block gets processed we will get pinned again.
*/
list_del_init(&b->lru);
clear_bit(B_Pinned, &b->flags);
kfree(doh->temp);
doh->temp = NULL;
lafs_dirty_dblock(doh->new);
- if (((doh->new->b.fileaddr+1) << dir->i_blkbits) > dir->i_size)
+ if (((doh->new->b.fileaddr+1) << dir->i_blkbits) > dir->i_size) {
i_size_write(dir, ((doh->new->b.fileaddr+1)
<< dir->i_blkbits));
+ lafs_dirty_inode(dir);
+ }
clear_bit(B_PinPending, &doh->new->b.flags);
putdref(doh->new, MKREF(dir_new));
} else
goto abort_unlock;
inode_inc_link_count(inode);
- lafs_dirty_inode(inode);
lafs_inode_checkpin(inode);
clear_bit(B_PinPending, &inodb->b.flags);
putdref(inodb, MKREF(inode_update));
DIROP_UNLINK, NULL);
dir_delete_commit(&doh, fs, dir, de->d_name.name, de->d_name.len);
lafs_checkpoint_unlock(fs);
- lafs_dirty_inode(inode);
lafs_inode_checkpin(inode);
clear_bit(B_PinPending, &inodb->b.flags);
putdref(inodb, MKREF(inode_update));
dir_log_commit(&uh, fs, dir, &de->d_name, inode->i_ino,
DIROP_UNLINK, NULL);
dir_delete_commit(&doh, fs, dir, de->d_name.name, de->d_name.len);
- lafs_dirty_inode(inode);
clear_bit(B_PinPending, &inodb->b.flags);
putdref(inodb, MKREF(inode_update));
- lafs_dirty_inode(dir);
lafs_inode_checkpin(inode);
lafs_inode_checkpin(dir);
lafs_checkpoint_unlock(fs);
lafs_dirty_dblock(b);
clear_bit(B_PinPending, &b->b.flags);
putdref(b, MKREF(symlink));
- ino->i_size = l;
+ i_size_write(ino, l);
lafs_dirty_inode(ino);
lafs_inode_checkpin(ino);
lai->md.file.parent = dir->i_ino;
inode_inc_link_count(dir);
ino->i_nlink = 2; /* From parent, and from '.' */
- lafs_dirty_inode(dir);
lafs_dirty_inode(ino);
lafs_inode_checkpin(dir);
lafs_inode_checkpin(ino);
0,
new_inode ? DIROP_REN_OLD_TARGET : DIROP_REN_NEW_TARGET,
&renhandle);
- if (new_inode) {
+ if (S_ISDIR(old_inode->i_mode)) {
+ inode_dec_link_count(old_dir);
+ if (!new_inode)
+ inode_inc_link_count(new_dir);
+ }
+ if (new_inode)
dir_update_commit(fs, old_inode->i_ino,
mode_to_dt(old_inode->i_mode),
&new_doh);
- } else
+ else
dir_create_commit(&new_doh, fs, new_dir,
new_dentry->d_name.name,
new_dentry->d_name.len,
old_inode->i_ino,
mode_to_dt(old_inode->i_mode));
- if (S_ISDIR(old_inode->i_mode)) {
- inode_dec_link_count(old_dir);
- if (!new_inode)
- inode_inc_link_count(new_dir);
- lafs_dirty_inode(old_dir);
- lafs_dirty_inode(new_dir);
- }
LAFSI(old_inode)->md.file.parent = new_dir->i_ino;
if (new_inode) {
if (S_ISDIR(new_inode->i_mode))
inode_dec_link_count(new_inode);
inode_dec_link_count(new_inode);
- lafs_dirty_inode(new_inode);
lafs_inode_checkpin(new_inode);
}
lafs_dirty_inode(old_inode);
loff_t bnum;
unmap_dblock(b, buf);
+ err = lafs_pin_dblock(b, ReleaseSpace);
+ if (err)
+ goto abort;
+
bnum = 1;
err = lafs_find_next(dir, &bnum);
if (err < 0)
lafs_dirty_inode(dir);
}
lafs_erase_dblock(b);
+ clear_bit(B_PinPending, &b->b.flags);
} else {
unmap_dblock(b, buf);
}
!test_bit(B_PinPending, &b->flags) &&
!test_bit(B_Dirty, &b->flags) &&
!test_bit(B_Realloc, &b->flags) &&
- iblk(b)->uninc_table.pending_cnt == 0 &&
- iblk(b)->uninc == NULL &&
- iblk(b)->uninc_next == NULL &&
atomic_read(&b->refcnt) == 1 && /* This is us */
- atomic_read(&iblk(b)->pincnt[0]) == 0 &&
- atomic_read(&iblk(b)->pincnt[1]) == 0 &&
+ (!test_bit(B_Index, &b->flags) ||
+ (iblk(b)->uninc_table.pending_cnt == 0 &&
+ iblk(b)->uninc == NULL &&
+ iblk(b)->uninc_next == NULL &&
+ atomic_read(&iblk(b)->pincnt[0]) == 0 &&
+ atomic_read(&iblk(b)->pincnt[1]) == 0)) &&
(!test_bit(B_InoIdx, &b->flags) ||
!(test_bit(B_PinPending, &LAFSI(b->inode)->dblock->b.flags)
|| test_bit(B_Dirty, &LAFSI(b->inode)->dblock->b.flags)
|| test_bit(B_Realloc, &LAFSI(b->inode)->dblock->b.flags)))
) {
- if (test_and_clear_bit(B_Pinned, &b->flags)) {
+ if (!test_bit(B_Index, &b->flags) &&
+ LAFSI(b->inode)->type == TypeInodeFile &&
+ test_and_clear_bit(I_Dirty, &LAFSI(dblk(b)->my_inode)->iflags)) {
+ /* Need to keep pinned in new phase and make new
+ * changes.
+ */
+ atomic_inc(&b->parent->pincnt[1-oldphase]);
+ atomic_dec(&b->parent->pincnt[oldphase]);
+ if (oldphase)
+ clear_bit(B_Phase1, &b->flags);
+ else
+ set_bit(B_Phase1, &b->flags);
+ lafs_dirty_inode(b->inode);
+ } else if (test_and_clear_bit(B_Pinned, &b->flags)) {
if (!test_bit(B_Root, &b->flags)) {
atomic_dec(&b->parent->pincnt[oldphase]);
lafs_refile(&b->parent->b, 0);
void lafs_dirty_inode(struct inode *ino)
{
- /* This inode must be pinned to a phase.
- * If it is 'this' phase, copy data into block.
- * If not, just set I_Dirty.
+ /* this is called in one of three cases:
+ * 1/ by lafs internally when dblock or iblock is pinned and
+ * ready to be dirties
+ * 2/ by writeout before requesting a write - to update mtime
+ * 3/ by read to update atime
+ *
+ * In 1/ we are free to dirty the block.
+ * In 2/ we can just update the block as it will get dirtied soon
+ * In 3/ we just punt for now and worry about it later
*/
- struct datablock *db;
struct block *b;
- struct fs *fs = fs_from_inode(ino);
+ struct datablock *db;
+ int nodirty = 0;
int ino_phase;
-
+ struct fs *fs = fs_from_inode(ino);
spin_lock(&ino->i_data.private_lock);
if (LAFSI(ino)->iblock)
b = &getiref_locked(LAFSI(ino)->iblock,
db = LAFSI(ino)->dblock;
spin_unlock(&ino->i_data.private_lock);
- lafs_checkpoint_lock(fs);
- if (b == NULL || !test_bit(B_Pinned, &b->flags)) {
- /* must be a timestamp update. No need to
- * journal those - they'll eventually get
- * processed ... or lost (for atime if we are too busy).;
- */
- //WARN_ON(1);
- set_bit(I_Dirty, &LAFSI(ino)->iflags);
- lafs_checkpoint_unlock(fs);
- if (b)
- putref(b, MKREF(dirty_inode));
- return;
- }
+ BUG_ON(b==NULL);
- if (lafs_prealloc(b, ReleaseSpace)) {
- /* Very tight on space... this is probably an atime
- * update when we just happen to be pinned. Any other
- * update should prealloc before proceeding
- */
- set_bit(I_Dirty, &LAFSI(ino)->iflags);
- lafs_checkpoint_unlock(fs);
- putref(b, MKREF(dirty_inode));
- return;
- }
- if (b != &db->b &&
- test_bit(B_Pinned, &db->b.flags))
+ if (test_bit(B_Pinned, &db->b.flags))
ino_phase = !!test_bit(B_Phase1, &db->b.flags);
- else
+ else if (test_bit(B_Pinned, &b->flags))
ino_phase = !!test_bit(B_Phase1, &b->flags);
+ else {
+ ino_phase = fs->phase;
+ nodirty = 1;
+ }
- if (ino_phase == fs->phase)
+ if (ino_phase == fs->phase) {
lafs_inode_fillblock(ino);
- else
+ if (!nodirty)
+ lafs_dirty_dblock(db);
+ } else
set_bit(I_Dirty, &LAFSI(ino)->iflags);
- lafs_checkpoint_unlock(fs);
putref(b, MKREF(dirty_inode));
}
}
}
unmap_dblock(db, lai);
- lafs_dirty_dblock(db);
}
/*-----------------------------------------------------------------------
memset(buf, 0xff, filesys->i_sb->s_blocksize);
unmap_dblock(b, buf);
set_bit(B_Valid, &b->b.flags);
- lafs_inode_fillblock(im);
LAFSI(im)->md.inodemap.size = bnum+1;
+ lafs_dirty_inode(im);
lafs_dirty_dblock(b);
clear_bit(B_PinPending, &b->b.flags);
lafs_checkpoint_unlock(fs);
void lafs_clear_inode(struct inode *ino);
void lafs_delete_inode(struct inode *ino);
void lafs_dirty_inode(struct inode *ino);
+void lafs_dirty_vfs_inode(struct inode *ino);
int lafs_write_inode(struct inode *ino, int wait);
struct inode *lafs_new_inode(struct fs *fs, struct inode *dir, int type,
int inum, int mode, struct datablock **inodbp);
ibuf = map_iblock(new);
memcpy(ib->data, ibuf + offset, blksize - offset);
memset(ib->data + blksize - offset, 0, offset);
+ new->depth = ib->depth + 1;
+ LAFSI(new->b.inode)->depth++;
+ ((struct la_inode*)(ibuf))->depth = LAFSI(new->b.inode)->depth;
+
unmap_iblock(new, ibuf);
set_bit(B_Valid, &new->b.flags);
list_add(&ib->b.siblings, &new->children);
INIT_LIST_HEAD(&new->b.siblings);
- new->depth = ib->depth + 1;
- LAFSI(new->b.inode)->depth++;
LAFS_BUG(new->depth != LAFSI(new->b.inode)->depth, &ib->b);
lafs_clear_index(new);
memset(buf, 0, blocksize - offset);
*(u16 *)(buf) = cpu_to_le16(IBLK_EXTENT);
LAFSI(ib->b.inode)->depth = 1;
+ ((struct la_inode*)(buf-offset))->depth = 1;
ib->depth = 1;
}
} else
credits--;
}
if (test_bit(B_Index, &b->flags) ||
+ LAFSI(b->inode)->type == TypeInodeFile ||
LAFSI(b->inode)->type == TypeOrphanList ||
LAFSI(b->inode)->type == TypeQuota ||
LAFSI(b->inode)->type == TypeSegmentMap) {
if (err)
break;
+ /* FIXME do I need to dirty the inode to flush
+ * this change into the datablock?
+ */
if (li->type >= TypeBase &&
inode->i_size <= (bnum << inode->i_blkbits))
inode->i_size = ((bnum) << inode->i_blkbits) + type;