diff options
author | Bob Peterson <rpeterso@redhat.com> | 2015-12-18 11:54:55 -0600 |
---|---|---|
committer | Bob Peterson <rpeterso@redhat.com> | 2016-01-14 08:47:42 -0500 |
commit | 7508abc4bdac43dc87d2fdd31527063f72da7020 (patch) | |
tree | ef25c3648ace05e47eca1ecc76ddbba541bd4f03 /fs/gfs2/super.c | |
parent | 67990608c8b95d2b8ccc29932376ae73d5818727 (diff) | |
download | op-kernel-dev-7508abc4bdac43dc87d2fdd31527063f72da7020.zip op-kernel-dev-7508abc4bdac43dc87d2fdd31527063f72da7020.tar.gz |
GFS2: Check if iopen is held when deleting inode
This patch fixes an error condition in which an inode is partially
created in gfs2_create_inode() but then some error is discovered,
which causes it to fail and call iput() before the iopen glock is
created or held. In that case, gfs2_delete_inode would try to
unlock an iopen glock that doesn't yet exist. Therefore, we test
its holder (which must exist) for the HIF_HOLDER bit before trying
to dq it.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Acked-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/super.c')
-rw-r--r-- | fs/gfs2/super.c | 26 |
1 files changed, 16 insertions, 10 deletions
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 8f960a5..f8a0cd8 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1551,12 +1551,16 @@ static void gfs2_evict_inode(struct inode *inode) goto out_truncate; } - ip->i_iopen_gh.gh_flags |= GL_NOCACHE; - gfs2_glock_dq_wait(&ip->i_iopen_gh); - gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh); - error = gfs2_glock_nq(&ip->i_iopen_gh); - if (error) - goto out_truncate; + if (ip->i_iopen_gh.gh_gl && + test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) { + ip->i_iopen_gh.gh_flags |= GL_NOCACHE; + gfs2_glock_dq_wait(&ip->i_iopen_gh); + gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, + &ip->i_iopen_gh); + error = gfs2_glock_nq(&ip->i_iopen_gh); + if (error) + goto out_truncate; + } /* Case 1 starts here */ @@ -1606,11 +1610,13 @@ out_unlock: if (gfs2_rs_active(&ip->i_res)) gfs2_rs_deltree(&ip->i_res); - if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) { - ip->i_iopen_gh.gh_flags |= GL_NOCACHE; - gfs2_glock_dq_wait(&ip->i_iopen_gh); + if (ip->i_iopen_gh.gh_gl) { + if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) { + ip->i_iopen_gh.gh_flags |= GL_NOCACHE; + gfs2_glock_dq_wait(&ip->i_iopen_gh); + } + gfs2_holder_uninit(&ip->i_iopen_gh); } - gfs2_holder_uninit(&ip->i_iopen_gh); gfs2_glock_dq_uninit(&gh); if (error && error != GLR_TRYFAILED && error != -EROFS) fs_warn(sdp, "gfs2_evict_inode: %d\n", error); |