Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+17 -10
+1
fs/gfs2/glock.c
··· 1015 1015 handle_callback(gl, LM_ST_UNLOCKED, 0, false); 1016 1016 1017 1017 list_del_init(&gh->gh_list); 1018 + clear_bit(HIF_HOLDER, &gh->gh_iflags); 1018 1019 if (find_first_holder(gl) == NULL) { 1019 1020 if (glops->go_unlock) { 1020 1021 GLOCK_BUG_ON(gl, test_and_set_bit(GLF_LOCK, &gl->gl_flags));
+16 -10
fs/gfs2/super.c
··· 1551 1551 goto out_truncate; 1552 1552 } 1553 1553 1554 - ip->i_iopen_gh.gh_flags |= GL_NOCACHE; 1555 - gfs2_glock_dq_wait(&ip->i_iopen_gh); 1556 - gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh); 1557 - error = gfs2_glock_nq(&ip->i_iopen_gh); 1558 - if (error) 1559 - goto out_truncate; 1554 + if (ip->i_iopen_gh.gh_gl && 1555 + test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) { 1556 + ip->i_iopen_gh.gh_flags |= GL_NOCACHE; 1557 + gfs2_glock_dq_wait(&ip->i_iopen_gh); 1558 + gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, 1559 + &ip->i_iopen_gh); 1560 + error = gfs2_glock_nq(&ip->i_iopen_gh); 1561 + if (error) 1562 + goto out_truncate; 1563 + } 1560 1564 1561 1565 /* Case 1 starts here */ 1562 1566 ··· 1610 1606 if (gfs2_rs_active(&ip->i_res)) 1611 1607 gfs2_rs_deltree(&ip->i_res); 1612 1608 1613 - if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) { 1614 - ip->i_iopen_gh.gh_flags |= GL_NOCACHE; 1615 - gfs2_glock_dq_wait(&ip->i_iopen_gh); 1609 + if (ip->i_iopen_gh.gh_gl) { 1610 + if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) { 1611 + ip->i_iopen_gh.gh_flags |= GL_NOCACHE; 1612 + gfs2_glock_dq_wait(&ip->i_iopen_gh); 1613 + } 1614 + gfs2_holder_uninit(&ip->i_iopen_gh); 1616 1615 } 1617 - gfs2_holder_uninit(&ip->i_iopen_gh); 1618 1616 gfs2_glock_dq_uninit(&gh); 1619 1617 if (error && error != GLR_TRYFAILED && error != -EROFS) 1620 1618 fs_warn(sdp, "gfs2_evict_inode: %d\n", error);