GFS2: Fix error path in gfs2_lookup_by_inum()
authorSteven Whitehouse <swhiteho@redhat.com>
Tue, 18 Jan 2011 14:49:08 +0000 (14:49 +0000)
committerSteven Whitehouse <swhiteho@redhat.com>
Tue, 18 Jan 2011 14:49:08 +0000 (14:49 +0000)
In the (impossible, except if there is fs corruption) error path
in gfs2_lookup_by_inum() if the call to gfs2_inode_refresh()
fails, it was leaving the function by calling iput() rather
than iget_failed(). This would cause future lookups of the same
inode to block forever.

This patch fixes the problem by moving the call to gfs2_inode_refresh()
into gfs2_inode_lookup() where iget_failed() is part of the error path
already. Also this cleans up some unreachable code and makes
gfs2_set_iop() static.

Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
fs/gfs2/inode.c
fs/gfs2/inode.h

index 2232b3c..7aa7d4f 100644 (file)
@@ -74,16 +74,14 @@ static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr)
 }
 
 /**
- * GFS2 lookup code fills in vfs inode contents based on info obtained
- * from directory entry inside gfs2_inode_lookup(). This has caused issues
- * with NFS code path since its get_dentry routine doesn't have the relevant
- * directory entry when gfs2_inode_lookup() is invoked. Part of the code
- * segment inside gfs2_inode_lookup code needs to get moved around.
+ * gfs2_set_iop - Sets inode operations
+ * @inode: The inode with correct i_mode filled in
  *
- * Clears I_NEW as well.
- **/
+ * GFS2 lookup code fills in vfs inode contents based on info obtained
+ * from directory entry inside gfs2_inode_lookup().
+ */
 
-void gfs2_set_iop(struct inode *inode)
+static void gfs2_set_iop(struct inode *inode)
 {
        struct gfs2_sbd *sdp = GFS2_SB(inode);
        umode_t mode = inode->i_mode;
@@ -106,8 +104,6 @@ void gfs2_set_iop(struct inode *inode)
                inode->i_op = &gfs2_file_iops;
                init_special_inode(inode, inode->i_mode, inode->i_rdev);
        }
-
-       unlock_new_inode(inode);
 }
 
 /**
@@ -119,10 +115,8 @@ void gfs2_set_iop(struct inode *inode)
  * Returns: A VFS inode, or an error
  */
 
-struct inode *gfs2_inode_lookup(struct super_block *sb,
-                               unsigned int type,
-                               u64 no_addr,
-                               u64 no_formal_ino)
+struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
+                               u64 no_addr, u64 no_formal_ino)
 {
        struct inode *inode;
        struct gfs2_inode *ip;
@@ -152,51 +146,37 @@ struct inode *gfs2_inode_lookup(struct super_block *sb,
                error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
                if (unlikely(error))
                        goto fail_iopen;
-               ip->i_iopen_gh.gh_gl->gl_object = ip;
 
+               ip->i_iopen_gh.gh_gl->gl_object = ip;
                gfs2_glock_put(io_gl);
                io_gl = NULL;
 
-               if ((type == DT_UNKNOWN) && (no_formal_ino == 0))
-                       goto gfs2_nfsbypass;
-
-               inode->i_mode = DT2IF(type);
-
-               /*
-                * We must read the inode in order to work out its type in
-                * this case. Note that this doesn't happen often as we normally
-                * know the type beforehand. This code path only occurs during
-                * unlinked inode recovery (where it is safe to do this glock,
-                * which is not true in the general case).
-                */
                if (type == DT_UNKNOWN) {
-                       struct gfs2_holder gh;
-                       error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
-                       if (unlikely(error))
-                               goto fail_glock;
-                       /* Inode is now uptodate */
-                       gfs2_glock_dq_uninit(&gh);
+                       /* Inode glock must be locked already */
+                       error = gfs2_inode_refresh(GFS2_I(inode));
+                       if (error)
+                               goto fail_refresh;
+               } else {
+                       inode->i_mode = DT2IF(type);
                }
 
                gfs2_set_iop(inode);
+               unlock_new_inode(inode);
        }
 
-gfs2_nfsbypass:
        return inode;
-fail_glock:
-       gfs2_glock_dq(&ip->i_iopen_gh);
+
+fail_refresh:
+       ip->i_iopen_gh.gh_gl->gl_object = NULL;
+       gfs2_glock_dq_uninit(&ip->i_iopen_gh);
 fail_iopen:
        if (io_gl)
                gfs2_glock_put(io_gl);
 fail_put:
-       if (inode->i_state & I_NEW)
-               ip->i_gl->gl_object = NULL;
+       ip->i_gl->gl_object = NULL;
        gfs2_glock_put(ip->i_gl);
 fail:
-       if (inode->i_state & I_NEW)
-               iget_failed(inode);
-       else
-               iput(inode);
+       iget_failed(inode);
        return ERR_PTR(error);
 }
 
@@ -221,14 +201,6 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
        if (IS_ERR(inode))
                goto fail;
 
-       error = gfs2_inode_refresh(GFS2_I(inode));
-       if (error)
-               goto fail_iput;
-
-       /* Pick up the works we bypass in gfs2_inode_lookup */
-       if (inode->i_state & I_NEW) 
-               gfs2_set_iop(inode);
-
        /* Two extra checks for NFS only */
        if (no_formal_ino) {
                error = -ESTALE;
index 732a183..3e00a66 100644 (file)
@@ -96,7 +96,6 @@ err:
        return -EIO;
 }
 
-extern void gfs2_set_iop(struct inode *inode);
 extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, 
                                       u64 no_addr, u64 no_formal_ino);
 extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,