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);