[Cluster-devel] [GFS2 PATCH] gfs2: clean up iopen glock mess in gfs2_create_inode

Bob Peterson rpeterso at redhat.com
Fri Nov 15 21:02:47 UTC 2019


Hi,

I wrote this patch because Andreas pointed out the problem with
its predecessor patch, "gfs2: if finish_open returns error, clean
up iopen glock mess" wasn't correct because after the instantiate,
subsequent evicts should take care of the iopen glock properly.

This, then, is the revised patch that takes a different approach.
It reorders the iopen processing to make a little more sense and
prevents a possible use-after-free.

This patch has had minimal testing so far, so I don't have much
confidence in it yet. It makes logical sense, but it's a very
sensitive code path. We especially need to test the cases of
doing creates-during-deletes, deletes-during-creates, creates
during remote-node-deletes, and so forth.

Bob
---
Before this patch, gfs2_create_inode had a use-after-free for the
iopen glock in some error paths because it did this:

	gfs2_glock_put(io_gl);
fail_gunlock2:
	if (io_gl)
		clear_bit(GLF_INODE_CREATING, &io_gl->gl_flags);

In some cases, the io_gl was used for create and only had one
reference, so the glock might be freed before the clear_bit().
This patch tries to straighten it out by only jumping to the
error paths where iopen is properly set, and moving the
gfs2_glock_put after the clear_bit.

Signed-off-by: Bob Peterson <rpeterso at redhat.com>
---
 fs/gfs2/inode.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index dcb5d363f9b9..cd7628f06ee6 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -712,7 +712,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 
 	error = gfs2_trans_begin(sdp, blocks, 0);
 	if (error)
-		goto fail_gunlock2;
+		goto fail_free_inode;
 
 	if (blocks > 1) {
 		ip->i_eattr = ip->i_no_addr + 1;
@@ -723,7 +723,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 
 	error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
 	if (error)
-		goto fail_gunlock2;
+		goto fail_free_inode;
 
 	BUG_ON(test_and_set_bit(GLF_INODE_CREATING, &io_gl->gl_flags));
 
@@ -772,15 +772,19 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 	gfs2_glock_dq_uninit(ghs);
 	gfs2_glock_dq_uninit(ghs + 1);
 	clear_bit(GLF_INODE_CREATING, &io_gl->gl_flags);
+	if (error) {
+		glock_clear_object(io_gl, ip);
+		gfs2_glock_dq_uninit(&ip->i_iopen_gh);
+		gfs2_glock_put(io_gl);
+	}
 	return error;
 
 fail_gunlock3:
 	glock_clear_object(io_gl, ip);
 	gfs2_glock_dq_uninit(&ip->i_iopen_gh);
-	gfs2_glock_put(io_gl);
 fail_gunlock2:
-	if (io_gl)
-		clear_bit(GLF_INODE_CREATING, &io_gl->gl_flags);
+	clear_bit(GLF_INODE_CREATING, &io_gl->gl_flags);
+	gfs2_glock_put(io_gl);
 fail_free_inode:
 	if (ip->i_gl) {
 		glock_clear_object(ip->i_gl, ip);




More information about the Cluster-devel mailing list