diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2006-11-27 10:12:05 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-11-30 10:36:56 -0500 |
commit | dcf3dd852f554bb0016aa23892596717cc123a26 (patch) | |
tree | 643785eb26407b7f4690ad804434b93636ae01ab /fs/gfs2/ops_inode.c | |
parent | 300c7d75f3a5e8edd3e390ccd56b808f3fb14e33 (diff) | |
download | lwn-dcf3dd852f554bb0016aa23892596717cc123a26.tar.gz lwn-dcf3dd852f554bb0016aa23892596717cc123a26.zip |
[GFS2] Fix recursive locking in gfs2_getattr
The readdirplus NFS operation can result in gfs2_getattr being
called with the glock already held. In this case we do not want
to try and grab the lock again.
This fixes Red Hat bugzilla #215727
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/ops_inode.c')
-rw-r--r-- | fs/gfs2/ops_inode.c | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index fd9fee2ceeac..fbe38c1ab54e 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -992,6 +992,12 @@ out: * @dentry: The dentry to stat * @stat: The inode's stats * + * This may be called from the VFS directly, or from within GFS2 with the + * inode locked, so we look to see if the glock is already locked and only + * lock the glock if its not already been done. Note that its the NFS + * readdirplus operation which causes this to be called (from filldir) + * with the glock already held. + * * Returns: errno */ @@ -1002,14 +1008,20 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder gh; int error; + int unlock = 0; - error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); - if (!error) { - generic_fillattr(inode, stat); - gfs2_glock_dq_uninit(&gh); + if (gfs2_glock_is_locked_by_me(ip->i_gl) == 0) { + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); + if (error) + return error; + unlock = 1; } - return error; + generic_fillattr(inode, stat); + if (unlock); + gfs2_glock_dq_uninit(&gh); + + return 0; } static int gfs2_setxattr(struct dentry *dentry, const char *name, |