GFS2: Fix error path in gfs2_lookup_by_inum()
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>
This commit is contained in:
parent
23c3010808
commit
24d9765fc1
|
@ -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
|
* gfs2_set_iop - Sets inode operations
|
||||||
* from directory entry inside gfs2_inode_lookup(). This has caused issues
|
* @inode: The inode with correct i_mode filled in
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
* 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);
|
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
||||||
umode_t mode = inode->i_mode;
|
umode_t mode = inode->i_mode;
|
||||||
|
@ -106,8 +104,6 @@ void gfs2_set_iop(struct inode *inode)
|
||||||
inode->i_op = &gfs2_file_iops;
|
inode->i_op = &gfs2_file_iops;
|
||||||
init_special_inode(inode, inode->i_mode, inode->i_rdev);
|
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
|
* Returns: A VFS inode, or an error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct inode *gfs2_inode_lookup(struct super_block *sb,
|
struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
|
||||||
unsigned int type,
|
u64 no_addr, u64 no_formal_ino)
|
||||||
u64 no_addr,
|
|
||||||
u64 no_formal_ino)
|
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct gfs2_inode *ip;
|
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);
|
error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
|
||||||
if (unlikely(error))
|
if (unlikely(error))
|
||||||
goto fail_iopen;
|
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);
|
gfs2_glock_put(io_gl);
|
||||||
io_gl = NULL;
|
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) {
|
if (type == DT_UNKNOWN) {
|
||||||
struct gfs2_holder gh;
|
/* Inode glock must be locked already */
|
||||||
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
|
error = gfs2_inode_refresh(GFS2_I(inode));
|
||||||
if (unlikely(error))
|
if (error)
|
||||||
goto fail_glock;
|
goto fail_refresh;
|
||||||
/* Inode is now uptodate */
|
} else {
|
||||||
gfs2_glock_dq_uninit(&gh);
|
inode->i_mode = DT2IF(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
gfs2_set_iop(inode);
|
gfs2_set_iop(inode);
|
||||||
|
unlock_new_inode(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
gfs2_nfsbypass:
|
|
||||||
return inode;
|
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:
|
fail_iopen:
|
||||||
if (io_gl)
|
if (io_gl)
|
||||||
gfs2_glock_put(io_gl);
|
gfs2_glock_put(io_gl);
|
||||||
fail_put:
|
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);
|
gfs2_glock_put(ip->i_gl);
|
||||||
fail:
|
fail:
|
||||||
if (inode->i_state & I_NEW)
|
iget_failed(inode);
|
||||||
iget_failed(inode);
|
|
||||||
else
|
|
||||||
iput(inode);
|
|
||||||
return ERR_PTR(error);
|
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))
|
if (IS_ERR(inode))
|
||||||
goto fail;
|
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 */
|
/* Two extra checks for NFS only */
|
||||||
if (no_formal_ino) {
|
if (no_formal_ino) {
|
||||||
error = -ESTALE;
|
error = -ESTALE;
|
||||||
|
|
|
@ -96,7 +96,6 @@ err:
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void gfs2_set_iop(struct inode *inode);
|
|
||||||
extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type,
|
extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type,
|
||||||
u64 no_addr, u64 no_formal_ino);
|
u64 no_addr, u64 no_formal_ino);
|
||||||
extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
|
extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
|
||||||
|
|
Loading…
Reference in New Issue