summaryrefslogtreecommitdiffstats
path: root/fs/gfs2/ops_dentry.c
diff options
context:
space:
mode:
authorWendy Cheng <wcheng@redhat.com>2007-02-06 09:52:16 +0100
committerSteven Whitehouse <swhiteho@redhat.com>2007-02-06 17:36:01 +0100
commit549ae0ac3d574a682e82b02e79259a65445a675b (patch)
tree53e316e1f2d9aacc01f71eee23a8f2b04230c788 /fs/gfs2/ops_dentry.c
parent[DLM] fix softlockup in dlm_recv (diff)
downloadlinux-549ae0ac3d574a682e82b02e79259a65445a675b.tar.xz
linux-549ae0ac3d574a682e82b02e79259a65445a675b.zip
[GFS2] nfsd readdirplus assertion failure
Glock assertion failure found in '07 NFS connectathon. One of the NFSDs is doing a "readdirplus" procedure call. It passes the logic into gfs2_readdir() where it obtains its directory inode glock. This is then followed by filehandle construction that invokes lookup code. It hits the assertion failure while trying to obtain the inode glock again inside gfs2_drevalidate(). This patch bypasses the recursive glock call if caller already holds the lock. Signed-off-by: S. Wendy Cheng <wcheng@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/ops_dentry.c')
-rw-r--r--fs/gfs2/ops_dentry.c16
1 files changed, 11 insertions, 5 deletions
diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c
index d355899585d8..9187eb174b43 100644
--- a/fs/gfs2/ops_dentry.c
+++ b/fs/gfs2/ops_dentry.c
@@ -46,6 +46,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
struct gfs2_inum_host inum;
unsigned int type;
int error;
+ int had_lock=0;
if (inode && is_bad_inode(inode))
goto invalid;
@@ -53,9 +54,12 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
if (sdp->sd_args.ar_localcaching)
goto valid;
- error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
- if (error)
- goto fail;
+ had_lock = gfs2_glock_is_locked_by_me(dip->i_gl);
+ if (!had_lock) {
+ error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
+ if (error)
+ goto fail;
+ }
error = gfs2_dir_search(parent->d_inode, &dentry->d_name, &inum, &type);
switch (error) {
@@ -82,13 +86,15 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
}
valid_gunlock:
- gfs2_glock_dq_uninit(&d_gh);
+ if (!had_lock)
+ gfs2_glock_dq_uninit(&d_gh);
valid:
dput(parent);
return 1;
invalid_gunlock:
- gfs2_glock_dq_uninit(&d_gh);
+ if (!had_lock)
+ gfs2_glock_dq_uninit(&d_gh);
invalid:
if (inode && S_ISDIR(inode->i_mode)) {
if (have_submounts(dentry))