aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOGAWA Hirofumi <hirofumi@mail.parknet.co.jp>2014-02-19 02:52:32 +0900
committerDaniel Phillips <daniel@tux3.org>2014-02-19 02:52:32 +0900
commit6e383b6f8990200855bdba4f767a74f93fcdfe24 (patch)
treea558d04c670000ec46cb79386074a11cc117ad05
parent457f803a331c8ce86158ea0594ace9a37245096b (diff)
downloadlinux-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.c44
-rw-r--r--fs/tux3/namei.c14
-rw-r--r--fs/tux3/super.c2
-rw-r--r--fs/tux3/tux3.h1
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);