summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/gfs2/super.c36
1 files changed, 28 insertions, 8 deletions
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index b20494d6730a..e4219a04d16e 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1241,6 +1241,9 @@ static enum evict_behavior evict_should_delete(struct inode *inode,
struct gfs2_sbd *sdp = sb->s_fs_info;
int ret;
+ if (inode->i_nlink)
+ return EVICT_SHOULD_SKIP_DELETE;
+
if (gfs2_holder_initialized(&ip->i_iopen_gh) &&
test_bit(GLF_DEFER_DELETE, &ip->i_iopen_gh.gh_gl->gl_flags))
return EVICT_SHOULD_DEFER_DELETE;
@@ -1279,13 +1282,18 @@ static enum evict_behavior evict_should_delete(struct inode *inode,
/**
* evict_unlinked_inode - delete the pieces of an unlinked evicted inode
* @inode: The inode to evict
+ * @gh: The glock holder structure
*/
-static int evict_unlinked_inode(struct inode *inode)
+static int evict_unlinked_inode(struct inode *inode, struct gfs2_holder *gh)
{
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_glock *gl = ip->i_gl;
int ret;
+ /* The inode glock must be held exclusively and be instantiated. */
+ BUG_ON(!gfs2_holder_initialized(gh) ||
+ test_bit(GLF_INSTANTIATE_NEEDED, &gl->gl_flags));
+
if (S_ISDIR(inode->i_mode) &&
(ip->i_diskflags & GFS2_DIF_EXHASH)) {
ret = gfs2_dir_exhash_dealloc(ip);
@@ -1318,7 +1326,7 @@ static int evict_unlinked_inode(struct inode *inode)
*/
ret = gfs2_dinode_dealloc(ip);
- if (!ret && gl)
+ if (!ret)
gfs2_inode_remember_delete(gl, ip->i_no_formal_ino);
out:
@@ -1357,19 +1365,30 @@ static int gfs2_truncate_inode_pages(struct inode *inode)
/*
* evict_linked_inode - evict an inode whose dinode has not been unlinked
* @inode: The inode to evict
+ * @gh: The glock holder structure
*/
-static int evict_linked_inode(struct inode *inode)
+static int evict_linked_inode(struct inode *inode, struct gfs2_holder *gh)
{
struct super_block *sb = inode->i_sb;
struct gfs2_sbd *sdp = sb->s_fs_info;
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_glock *gl = ip->i_gl;
- struct address_space *metamapping;
+ struct address_space *metamapping = gfs2_glock2aspace(gl);
int ret;
+ if (!(test_bit(GLF_DIRTY, &gl->gl_flags) || inode->i_flags & I_DIRTY))
+ goto clean;
+
+ /* The inode glock must be held exclusively and be instantiated. */
+ if (!gfs2_holder_initialized(gh))
+ ret = gfs2_glock_nq_init(gl, LM_ST_EXCLUSIVE, 0, gh);
+ else
+ ret = gfs2_instantiate(gh);
+ if (ret)
+ return ret;
+
gfs2_log_flush(sdp, gl, GFS2_LOG_HEAD_FLUSH_NORMAL |
GFS2_LFC_EVICT_INODE);
- metamapping = gfs2_glock2aspace(gl);
if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
filemap_fdatawrite(metamapping);
filemap_fdatawait(metamapping);
@@ -1377,6 +1396,7 @@ static int evict_linked_inode(struct inode *inode)
write_inode_now(inode, 1);
gfs2_ail_flush(gl, 0);
+clean:
ret = gfs2_truncate_inode_pages(inode);
if (ret)
return ret;
@@ -1415,7 +1435,7 @@ static void gfs2_evict_inode(struct inode *inode)
int ret;
gfs2_holder_mark_uninitialized(&gh);
- if (inode->i_nlink || sb_rdonly(sb) || !ip->i_no_addr)
+ if (sb_rdonly(sb) || !ip->i_no_addr || !ip->i_gl)
goto out;
/*
@@ -1440,9 +1460,9 @@ static void gfs2_evict_inode(struct inode *inode)
behavior = EVICT_SHOULD_SKIP_DELETE;
}
if (behavior == EVICT_SHOULD_DELETE)
- ret = evict_unlinked_inode(inode);
+ ret = evict_unlinked_inode(inode, &gh);
else
- ret = evict_linked_inode(inode);
+ ret = evict_linked_inode(inode, &gh);
if (gfs2_rs_active(&ip->i_res))
gfs2_rs_deltree(&ip->i_res);