]> git.neil.brown.name Git - LaFS.git/commitdiff
roll-forward: don't iput any nlink==0 inode before roll-forward finishes.
authorNeilBrown <neilb@suse.de>
Fri, 15 Oct 2010 04:05:37 +0000 (15:05 +1100)
committerNeilBrown <neilb@suse.de>
Fri, 15 Oct 2010 04:05:37 +0000 (15:05 +1100)
Such inodes might still need to participate in roll-forward, and might
yet get linked into the directory tree.  So don't risk them being
deleted yet.
So any inode with nlink==0 is put on the list to be dealt with at the
end.

Signed-off-by: NeilBrown <neilb@suse.de>
inode.c
roll.c

diff --git a/inode.c b/inode.c
index 759365c59e17c76cc2f9235e98b75a5b79d4accd..05c7350eb24e110a3a682195a65276f4028d24bd 100644 (file)
--- a/inode.c
+++ b/inode.c
@@ -393,7 +393,8 @@ lafs_import_inode(struct inode *ino, struct datablock *b)
                ino->i_size = le64_to_cpu(l->size);
                i->parent = le32_to_cpu(l->parent);
                ino->i_nlink = le32_to_cpu(l->linkcount);
-               if (ino->i_nlink == 0 && list_empty(&b->orphans)) {
+               if (ino->i_nlink == 0 && list_empty(&b->orphans) &&
+                   fs_from_inode(ino)->rolled) {
                        /* This block should already be on the orphan
                         * list, otherwise there is a filesystem
                         * inconsistency.
@@ -401,6 +402,9 @@ lafs_import_inode(struct inode *ino, struct datablock *b)
                         * linkcount is wrong.
                         * It is safest to assume the later - either
                         * way an FS check would be needed to fix it.
+                        * Note: while roll-forward is happening, this
+                        * situation is perfectly possible and is handled
+                        * correctly.
                         */
                        /* FIXME set a superblock flag requesting
                         * directory linkage checking
diff --git a/roll.c b/roll.c
index ca81735888e62a756f01ee62990309dd85ac0845..01d891e25033d9fca061587675524ad516623572 100644 (file)
--- a/roll.c
+++ b/roll.c
@@ -236,7 +236,7 @@ roll_mini(struct fs *fs, int fsnum, int inum, int trunc,
 {
        struct inode *inode;
        struct lafs_inode *li;
-       struct datablock *db;
+       struct datablock *db = NULL;
        int err = 0;
        void *buf;
 
@@ -291,23 +291,17 @@ roll_mini(struct fs *fs, int fsnum, int inum, int trunc,
                        err = PTR_ERR(db);
                        break;
                }
+               /* Should normally iolock the block, but we don't
+                * need that during roll-forward */
+               set_bit(B_PinPending, &db->b.flags);
+               lafs_pin_dblock(db, CleanSpace);
                /* Make sure block is in-sync with inode */
                lafs_inode_fillblock(inode);
                buf = map_dblock(db);
                memcpy(buf+offset, data, len);
                unmap_dblock(db, buf);
                err = lafs_import_inode(inode, db);
-               /* We borrow the orphan list to keep a reference on
-                * this inode until all processing is finished
-                * to make sure inodes that are about to get linked
-                * to get deleted early
-                */
-               if (list_empty(&db->orphans)) {
-                       list_add(&db->orphans, &fs->pending_orphans);
-                       lafs_igrab_fs(inode);
-                       getdref(db, MKREF(roll_orphan));
-               }
-               putdref(db, MKREF(roll));
+               lafs_dirty_dblock(db);
                break;
 
        case TypeDir:
@@ -315,6 +309,22 @@ roll_mini(struct fs *fs, int fsnum, int inum, int trunc,
                BUG();
                break;
        }
+       /* We borrow the orphan list to keep a reference on
+        * this inode until all processing is finished
+        * to make sure inodes that are about to get linked
+        * don't get deleted early
+        */
+       if (inode->i_nlink == 0) {
+               if (!db)
+                       db = lafs_inode_get_dblock(inode, MKREF(roll));
+               if (db &&
+                   list_empty(&db->orphans)) {
+                       list_add(&db->orphans, &fs->pending_orphans);
+                       lafs_igrab_fs(inode);
+                       getdref(db, MKREF(roll_orphan));
+               }
+       }
+       putdref(db, MKREF(roll));
        lafs_iput_fs(inode);
        return err;
 }
@@ -445,6 +455,17 @@ roll_block(struct fs *fs, int fsnum, int inum, int trunc,
        }
        if (blk)
                putdref(blk, MKREF(roll));
+
+       if (inode->i_nlink == 0) {
+               struct datablock *db = lafs_inode_get_dblock(inode, MKREF(roll));
+               if (db &&
+                   list_empty(&db->orphans)) {
+                       list_add(&db->orphans, &fs->pending_orphans);
+                       lafs_igrab_fs(inode);
+                       getdref(db, MKREF(roll_orphan));
+               }
+               putdref(db, MKREF(roll));
+       }
        lafs_iput_fs(inode);
        dprintk("leaving with error %d\n", err);
        return err;