diff options
author | OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> | 2014-02-19 02:52:32 +0900 |
---|---|---|
committer | Daniel Phillips <daniel@tux3.org> | 2014-02-19 02:52:32 +0900 |
commit | 6e383b6f8990200855bdba4f767a74f93fcdfe24 (patch) | |
tree | a558d04c670000ec46cb79386074a11cc117ad05 | |
parent | 457f803a331c8ce86158ea0594ace9a37245096b (diff) | |
download | linux-tux3-6e383b6f8990200855bdba4f767a74f93fcdfe24.tar.gz |
tux3: Fix tux_assign_inum() error path
If inode was failed to initialize, we need special care to drop the
inode.
- If nlink == 0, we use deferred inode deletion
- If inode is not hashed, the inode is not dirtied and doesn't wake up flusher
To drop uninitialized inode, this adds special code to drop carefully.
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
-rw-r--r-- | fs/tux3/inode.c | 44 | ||||
-rw-r--r-- | fs/tux3/namei.c | 14 | ||||
-rw-r--r-- | fs/tux3/super.c | 2 | ||||
-rw-r--r-- | fs/tux3/tux3.h | 1 |
4 files changed, 40 insertions, 21 deletions
diff --git a/fs/tux3/inode.c b/fs/tux3/inode.c index 2afb5fe25af89e..e6d1082c931dba 100644 --- a/fs/tux3/inode.c +++ b/fs/tux3/inode.c @@ -134,6 +134,15 @@ void del_defer_alloc_inum(struct inode *inode) list_del_init(&tux_inode(inode)->alloc_list); } +void cancel_defer_alloc_inum(struct inode *inode) +{ + struct sb *sb = tux_sb(inode->i_sb); + + down_write(&itree_btree(sb)->lock); /* FIXME: spinlock is enough? */ + del_defer_alloc_inum(inode); + up_write(&itree_btree(sb)->lock); +} + /* * Inode btree expansion algorithm * @@ -287,16 +296,31 @@ error: return err; } +static void tux_assign_inum_failed(struct inode *inode) +{ + /* + * If inode was initialized and hashed already, it would be + * better to use deferred deletion path. + */ + assert(!inode_unhashed(inode)); + + cancel_defer_alloc_inum(inode); + + /* We drop the inode early without delete process in flusher */ + make_bad_inode(inode); + + clear_nlink(inode); + unlock_new_inode(inode); + iput(inode); +} + int tux_assign_inum(struct inode *inode, inum_t goal) { int err; err = alloc_inum(inode, goal); - if (err) { - make_bad_inode(inode); - iput(inode); - return err; - } + if (err) + goto error; #if 0 /* * FIXME: temporary hack. We shouldn't insert inode to hash @@ -307,10 +331,12 @@ int tux_assign_inum(struct inode *inode, inum_t goal) /* Can be nfsd race happened, or fs corruption. */ tux3_warn(tux_sb(dir->i_sb), "inode insert error: inum %Lx", inum); - iput(inode); - return -EIO; + err = -EIO; + goto error; } #endif + /* The inode was hashed, we can use deferred deletion from here */ + /* * The unhashed inode ignores mark_inode_dirty(), so it should * be called after insert_inode_hash(). @@ -319,6 +345,10 @@ int tux_assign_inum(struct inode *inode, inum_t goal) tux3_mark_inode_dirty(inode); return 0; + +error: + tux_assign_inum_failed(inode); + return err; } /* Allocate inode with specific inum allocation policy */ diff --git a/fs/tux3/namei.c b/fs/tux3/namei.c index 82bc96349487a8..eecdfae0daa83c 100644 --- a/fs/tux3/namei.c +++ b/fs/tux3/namei.c @@ -62,14 +62,8 @@ static int __tux3_mknod(struct inode *dir, struct dentry *dentry, unlock_new_inode(inode); if (is_dir) inode_inc_link_count(dir); - goto out; } - clear_nlink(inode); - tux3_mark_inode_dirty(inode); - unlock_new_inode(inode); - iput(inode); } -out: change_end(tux_sb(dir->i_sb)); return err; } @@ -143,16 +137,10 @@ static int __tux3_symlink(struct inode *dir, struct dentry *dentry, err = page_symlink(inode, symname, len); if (!err) { err = tux_add_dirent(dir, dentry, inode); - if (!err) { + if (!err) unlock_new_inode(inode); - goto out; - } } - inode_dec_link_count(inode); - unlock_new_inode(inode); - iput(inode); } -out: change_end(sb); return err; diff --git a/fs/tux3/super.c b/fs/tux3/super.c index 0b7cdeac08c6a5..fb662349204752 100644 --- a/fs/tux3/super.c +++ b/fs/tux3/super.c @@ -49,7 +49,7 @@ static void cleanup_dirty_inode(struct inode *inode) trace(">>> clean inum %Lx, i_count %d, i_state %lx", tux_inode(inode)->inum, atomic_read(&inode->i_count), inode->i_state); - del_defer_alloc_inum(inode); + cancel_defer_alloc_inum(inode); tux3_clear_dirty_inode(inode); } } diff --git a/fs/tux3/tux3.h b/fs/tux3/tux3.h index 8deaac5cdcc8e3..139d5712944dc0 100644 --- a/fs/tux3/tux3.h +++ b/fs/tux3/tux3.h @@ -846,6 +846,7 @@ struct inode *tux_new_logmap(struct sb *sb); struct inode *tux_new_inode(struct inode *dir, struct tux_iattr *iattr, dev_t rdev); void del_defer_alloc_inum(struct inode *inode); +void cancel_defer_alloc_inum(struct inode *inode); int tux_assign_inum(struct inode *inode, inum_t goal); struct inode *tux_create_specific_inode(struct inode *dir, inum_t inum, struct tux_iattr *iattr, dev_t rdev); |