From: NeilBrown Date: Wed, 2 Sep 2009 00:10:03 +0000 (+1000) Subject: Improve inode orphan handling. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=12e95187dc819f0ca4e1efc5f3b58bbcce343b57;p=LaFS.git Improve inode orphan handling. And inode can be an orphan for an extended period of time and should not be on the pending_orphans list all that time. So we need to remove it if nothing needs doing for now, and add it back on when it requires attention. --- diff --git a/dir.c b/dir.c index e336ef8..390d3ff 100644 --- a/dir.c +++ b/dir.c @@ -602,6 +602,7 @@ lafs_create(struct inode *dir, struct dentry *de, int mode, goto abort_unlock; ino->i_nlink = 1; + lafs_add_orphan(fs, db); LAFSI(ino)->md.file.parent = dir->i_ino; lafs_dirty_inode(ino); lafs_inode_checkpin(ino); @@ -610,7 +611,6 @@ lafs_create(struct inode *dir, struct dentry *de, int mode, ino->i_ino, DT_REG); lafs_checkpoint_unlock(fs); d_instantiate(de, ino); /* FIXME do I need to iput?? */ - lafs_orphan_release(fs, db); clear_bit(B_PinPending, &db->b.flags); putdref(db, MKREF(inode_new)); return 0; @@ -876,6 +876,7 @@ lafs_symlink(struct inode *dir, struct dentry *de, ino->i_nlink = 1; LAFSI(ino)->md.file.parent = dir->i_ino; + lafs_add_orphan(fs, inodb); buf = map_dblock(b); memcpy(buf, symlink, l); @@ -894,7 +895,6 @@ lafs_symlink(struct inode *dir, struct dentry *de, ino->i_ino, DT_LNK); lafs_checkpoint_unlock(fs); d_instantiate(de, ino); - lafs_orphan_release(fs, inodb); putdref(inodb, MKREF(inode_new)); return 0; abort_unlock: @@ -953,7 +953,7 @@ lafs_mkdir(struct inode *dir, struct dentry *de, int mode) lafs_dirty_inode(ino); lafs_inode_checkpin(dir); lafs_inode_checkpin(ino); - lafs_orphan_release(fs, inodb); + lafs_add_orphan(fs, inodb); dir_create_commit(&doh, fs, dir, de->d_name.name, de->d_name.len, ino->i_ino, DT_DIR); d_instantiate(de, ino); @@ -1025,6 +1025,7 @@ lafs_mknod(struct inode *dir, struct dentry *de, int mode, LAFSI(ino)->md.file.parent = dir->i_ino; ino->i_nlink = 1; + lafs_add_orphan(fs, inodb); lafs_dirty_inode(ino); lafs_inode_checkpin(ino); @@ -1033,7 +1034,6 @@ lafs_mknod(struct inode *dir, struct dentry *de, int mode, ino->i_ino, type); lafs_checkpoint_unlock(fs); d_instantiate(de, ino); - lafs_orphan_release(fs, inodb); clear_bit(B_PinPending, &inodb->b.flags); putdref(inodb, MKREF(inode_new)); return 0; diff --git a/inode.c b/inode.c index 4bf4fda..6af58c9 100644 --- a/inode.c +++ b/inode.c @@ -473,6 +473,9 @@ void lafs_delete_inode(struct inode *ino) dprintk("DELETE INODE %d\n", (int)ino->i_ino); spin_lock(&ino->i_data.private_lock); b = LAFSI(ino)->dblock; + /* FIXME we use b unconditionally, so either we don't + * need the test, or we need to make the block if it + * doesn't exist.. */ if (b) getdref_locked(b, MKREF(delete_inode)); spin_unlock(&ino->i_data.private_lock); @@ -484,6 +487,7 @@ void lafs_delete_inode(struct inode *ino) set_bit(I_Deleting, &LAFSI(ino)->iflags); set_bit(B_Claimed, &b->b.flags); + lafs_add_orphan(fs, b); inode_map_free(fs, LAFSI(ino)->filesys, ino->i_ino); // FIXME what to do on error (-ENOMEM ) @@ -566,12 +570,14 @@ void lafs_inode_handle_orphan(struct datablock *b) restart: if (!test_bit(I_Trunc, &LAFSI(ino)->iflags)) { - if (ino->i_nlink == 0) { - LAFS_BUG(LAFSI(ino)->type != 0, &b->b); + if (test_bit(I_Deleting, &LAFSI(ino)->iflags)) { + LAFS_BUG(ino->i_nlink, &b->b); lafs_erase_dblock(b); clear_bit(I_Deleting, &LAFSI(ino)->iflags); - } - lafs_orphan_release(fs, b); + } else if (ino->i_nlink) + lafs_orphan_release(fs, b); + else + lafs_orphan_forget(fs, b); return; } diff --git a/lafs.h b/lafs.h index ed7a8fc..84b45d7 100644 --- a/lafs.h +++ b/lafs.h @@ -585,6 +585,8 @@ int lafs_make_orphan_nb(struct fs *fs, struct datablock *db); void lafs_orphan_release(struct fs *fs, struct datablock *b); long lafs_run_orphans(struct fs *fs); int lafs_drop_orphan(struct fs *fs, struct datablock *db); +void lafs_add_orphan(struct fs *fs, struct datablock *db); +void lafs_orphan_forget(struct fs *fs, struct datablock *db); struct datablock *lafs_find_orphan(struct inode *ino); /* Segment.c */ diff --git a/orphan.c b/orphan.c index 96405c2..6594d37 100644 --- a/orphan.c +++ b/orphan.c @@ -532,6 +532,37 @@ int lafs_drop_orphan(struct fs *fs, struct datablock *db) } } +void lafs_add_orphan(struct fs *fs, struct datablock *db) +{ + /* This block is an orphan block but might not be + * on the list any more. + * It now needs orphan processing (probably nlink + * has changed, or I_Deleting), so put it back + * on the list. + */ + LAFS_BUG(!test_bit(B_Orphan, &db->b.flags), &db->b); + spin_lock(&fs->lock); + if (list_empty(&db->orphans)) { + list_add_tail(&db->orphans, &fs->pending_orphans); + getdref(db, MKREF(orphan_list)); + } + spin_unlock(&fs->lock); +} + +void lafs_orphan_forget(struct fs *fs, struct datablock *db) +{ + /* This is still and orphan, but we don't want to handle + * it just now. When we we, lafs_add_orphan will be called */ + LAFS_BUG(!test_bit(B_Orphan, &db->b.flags), &db->b); + spin_lock(&fs->lock); + if (!list_empty(&db->orphans)) { + list_del_init(&db->orphans); + spin_unlock(&fs->lock); + putdref(db, MKREF(orphan_list)); + } else + spin_unlock(&fs->lock); +} + struct datablock *lafs_find_orphan(struct inode *ino) { /* I could walk the child tree of the inode, or