diff options
author | Bob Peterson <rpeterso@redhat.com> | 2017-07-18 13:15:01 -0400 |
---|---|---|
committer | Bob Peterson <rpeterso@redhat.com> | 2017-07-21 09:20:42 -0400 |
commit | 4d7c18c7df89ef549f2de79b0faf873b49dea57a (patch) | |
tree | d1ae15098ea5fa6eeaaa03ec0e3a8c1d44c20455 /fs/gfs2/inode.c | |
parent | df3d87bde121213560fde0edb71bc46f0f75692c (diff) |
GFS2: Set gl_object in inode lookup only after block type check
Before this patch, the inode glock's gl_object was set after a
reference was acquired, but before the block type was verified.
In cases where the block was unlinked, then freed and reused on
another node, a residule delete callback (delete_work) would try
to look up the inode, eventually failing the block check, but
only after it overwrites gl_object with a pointer to the wrong
inode. This patch moves the assignment of gl_object after the
block check so it won't be improperly overwritten.
Likewise, at the end of the function, gfs2_inode_lookup was
clearing gl_object after it unlocked the glock, which meant
another process might free the glock in the meantime. This
patch guards against that case.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
Diffstat (limited to 'fs/gfs2/inode.c')
-rw-r--r-- | fs/gfs2/inode.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 2578bd824e34..fd6e1da3c5ab 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -145,7 +145,6 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, | |||
145 | if (unlikely(error)) | 145 | if (unlikely(error)) |
146 | goto fail; | 146 | goto fail; |
147 | flush_delayed_work(&ip->i_gl->gl_work); | 147 | flush_delayed_work(&ip->i_gl->gl_work); |
148 | glock_set_object(ip->i_gl, ip); | ||
149 | 148 | ||
150 | error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl); | 149 | error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl); |
151 | if (unlikely(error)) | 150 | if (unlikely(error)) |
@@ -170,6 +169,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, | |||
170 | } | 169 | } |
171 | } | 170 | } |
172 | 171 | ||
172 | glock_set_object(ip->i_gl, ip); | ||
173 | set_bit(GIF_INVALID, &ip->i_flags); | 173 | set_bit(GIF_INVALID, &ip->i_flags); |
174 | error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); | 174 | error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); |
175 | if (unlikely(error)) | 175 | if (unlikely(error)) |
@@ -206,9 +206,9 @@ fail_refresh: | |||
206 | fail_put: | 206 | fail_put: |
207 | if (io_gl) | 207 | if (io_gl) |
208 | gfs2_glock_put(io_gl); | 208 | gfs2_glock_put(io_gl); |
209 | glock_clear_object(ip->i_gl, ip); | ||
209 | if (gfs2_holder_initialized(&i_gh)) | 210 | if (gfs2_holder_initialized(&i_gh)) |
210 | gfs2_glock_dq_uninit(&i_gh); | 211 | gfs2_glock_dq_uninit(&i_gh); |
211 | glock_clear_object(ip->i_gl, ip); | ||
212 | fail: | 212 | fail: |
213 | iget_failed(inode); | 213 | iget_failed(inode); |
214 | return ERR_PTR(error); | 214 | return ERR_PTR(error); |