]> git.neil.brown.name Git - LaFS.git/commitdiff
Improve inode orphan handling.
authorNeilBrown <neilb@suse.de>
Wed, 2 Sep 2009 00:10:03 +0000 (10:10 +1000)
committerNeilBrown <neilb@suse.de>
Wed, 2 Sep 2009 00:10:03 +0000 (10:10 +1000)
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.

dir.c
inode.c
lafs.h
orphan.c

diff --git a/dir.c b/dir.c
index e336ef8c6aec4fba72806a2c008799d3b8786021..390d3ff2466cd929defe0002f7efa140a7371429 100644 (file)
--- 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 4bf4fda44f5f12360f46da752720ef5b945c4a42..6af58c9b93f503e345c58944843fd8cf155532fd 100644 (file)
--- 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 ed7a8fce2d2ef4c56f4d75031c5df2122e8eea77..84b45d7c93647f8ca7f7fc8bb52811cb997baa09 100644 (file)
--- 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 */
index 96405c29f5710f2097bcf31e762be8d2f941261d..6594d372f39ef5203497de4f1974002b50fa240a 100644 (file)
--- 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