This patch allows function gfs2_create_inode to keep hold of the
iopen glock longer in cases where the creation of a new dinode fails.
This prevents some nasty timing windows where a dinode is being
created and reused.

Signed-off-by: Bob Peterson <[email protected]>
---
 fs/gfs2/inode.c | 19 ++++++++++++-------
 fs/gfs2/main.c  |  2 ++
 2 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 631d4ef..a878767 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -673,7 +673,7 @@ static int gfs2_create_inode(struct inode *dir, struct 
dentry *dentry,
        struct posix_acl *default_acl, *acl;
        struct gfs2_holder ghs[2];
        struct inode *inode = NULL;
-       struct gfs2_inode *dip = GFS2_I(dir), *ip;
+       struct gfs2_inode *dip = GFS2_I(dir), *ip = NULL;
        struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
        struct gfs2_glock *io_gl;
        int error, free_vfs_inode = 0;
@@ -839,16 +839,16 @@ static int gfs2_create_inode(struct inode *dir, struct 
dentry *dentry,
        }
 
        if (error)
-               goto fail_gunlock3;
+               goto fail_gunlock2;
 
        error = security_inode_init_security(&ip->i_inode, &dip->i_inode, name,
                                             &gfs2_initxattrs, NULL);
        if (error)
-               goto fail_gunlock3;
+               goto fail_gunlock2;
 
        error = link_dinode(dip, name, ip, &da);
        if (error)
-               goto fail_gunlock3;
+               goto fail_gunlock2;
 
        mark_inode_dirty(inode);
        d_instantiate(dentry, inode);
@@ -864,9 +864,6 @@ static int gfs2_create_inode(struct inode *dir, struct 
dentry *dentry,
        gfs2_glock_dq_uninit(ghs + 1);
        return error;
 
-fail_gunlock3:
-       if (ip->i_iopen_gh.gh_gl) /* if holder is linked to the glock */
-               gfs2_glock_put(ip->i_iopen_gh.gh_gl);
 fail_gunlock2:
        gfs2_glock_dq_uninit(ghs + 1);
 fail_free_inode:
@@ -883,6 +880,14 @@ fail_free_acls:
                posix_acl_release(acl);
 fail_free_vfs_inode:
        free_vfs_inode = 1;
+       /* We hold off until the very end to release the iopen glock. That
+        * keeps other processes from acquiring it in EX mode and deleting
+        * it while we're still using it. Since gfs2_delete_inode already
+        * handles the iopen vs. inode glocks in any order, the lock order
+        * does not matter. It must be done before iput, though, otherwise
+        * we might get a segfault trying to dereference it. */
+       if (ip && ip->i_iopen_gh.gh_gl) /* if holder is linked to the glock */
+               gfs2_glock_put(ip->i_iopen_gh.gh_gl);
 fail_gunlock:
        gfs2_dir_no_add(&da);
        gfs2_glock_dq_uninit(ghs);
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index 241a399..a8bd5b6 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -43,6 +43,8 @@ static void gfs2_init_inode_once(void *foo)
        INIT_LIST_HEAD(&ip->i_trunc_list);
        ip->i_res = NULL;
        ip->i_hash_cache = NULL;
+       ip->i_iopen_gh.gh_gl = NULL;
+       INIT_LIST_HEAD(&ip->i_iopen_gh.gh_list);
 }
 
 static void gfs2_init_glock_once(void *foo)
-- 
2.4.3

Reply via email to