diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2006-11-27 09:55:28 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-11-30 10:36:53 -0500 |
commit | 300c7d75f3a5e8edd3e390ccd56b808f3fb14e33 (patch) | |
tree | 1cc627b0e6ef37c3e72691cc75c5be5db14cac72 | |
parent | cb4c03131836a55bf95e1c165409244ac6b4f39f (diff) |
[GFS2] Fix recursive locking in gfs2_permission
Since gfs2_permission may be called either from the VFS (in which case
we need to obtain a shared glock) or from GFS2 (in which case we already
have a glock) we need to test to see whether or not a lock is required.
The original test was buggy due to a potential race. This one should
be safe.
This fixes Red Hat bugzilla #217129
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
-rw-r--r-- | fs/gfs2/ops_inode.c | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index b247f25effbf..fd9fee2ceeac 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c | |||
@@ -835,6 +835,10 @@ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
835 | * @mask: | 835 | * @mask: |
836 | * @nd: passed from Linux VFS, ignored by us | 836 | * @nd: passed from Linux VFS, ignored by us |
837 | * | 837 | * |
838 | * This may be called from the VFS directly, or from within GFS2 with the | ||
839 | * inode locked, so we look to see if the glock is already locked and only | ||
840 | * lock the glock if its not already been done. | ||
841 | * | ||
838 | * Returns: errno | 842 | * Returns: errno |
839 | */ | 843 | */ |
840 | 844 | ||
@@ -843,15 +847,18 @@ static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
843 | struct gfs2_inode *ip = GFS2_I(inode); | 847 | struct gfs2_inode *ip = GFS2_I(inode); |
844 | struct gfs2_holder i_gh; | 848 | struct gfs2_holder i_gh; |
845 | int error; | 849 | int error; |
850 | int unlock = 0; | ||
846 | 851 | ||
847 | if (!test_bit(GIF_INVALID, &ip->i_flags)) | 852 | if (gfs2_glock_is_locked_by_me(ip->i_gl) == 0) { |
848 | return generic_permission(inode, mask, gfs2_check_acl); | 853 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); |
854 | if (error) | ||
855 | return error; | ||
856 | unlock = 1; | ||
857 | } | ||
849 | 858 | ||
850 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); | 859 | error = generic_permission(inode, mask, gfs2_check_acl_locked); |
851 | if (!error) { | 860 | if (unlock) |
852 | error = generic_permission(inode, mask, gfs2_check_acl_locked); | ||
853 | gfs2_glock_dq_uninit(&i_gh); | 861 | gfs2_glock_dq_uninit(&i_gh); |
854 | } | ||
855 | 862 | ||
856 | return error; | 863 | return error; |
857 | } | 864 | } |