From bd83396c88258526ce5a99fb7f41a233ef68e45f Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 15 Oct 2010 15:05:37 +1100 Subject: [PATCH] roll-forward: don't iput any nlink==0 inode before roll-forward finishes. 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 --- inode.c | 6 +++++- roll.c | 45 +++++++++++++++++++++++++++++++++------------ 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/inode.c b/inode.c index 759365c..05c7350 100644 --- 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 ca81735..01d891e 100644 --- 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; -- 2.43.0