summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBob Peterson <rpeterso@redhat.com>2017-07-18 12:35:04 -0400
committerBob Peterson <rpeterso@redhat.com>2017-07-21 09:20:05 -0400
commitdf3d87bde121213560fde0edb71bc46f0f75692c (patch)
tree3efaafb3a13066a1c3d9421721b59cfabf5688fc
parente477b24b507998bc6568316a2e034025960d2404 (diff)
GFS2: Introduce helper for clearing gl_object
This patch introduces a new helper function in glock.h that clears gl_object, with an added integrity check. An additional integrity check has been added to glock_set_object, plus comments. This is step 1 in a series to ensure gl_object integrity. Signed-off-by: Bob Peterson <rpeterso@redhat.com> Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
-rw-r--r--fs/gfs2/glock.h34
-rw-r--r--fs/gfs2/inode.c4
-rw-r--r--fs/gfs2/super.c4
3 files changed, 38 insertions, 4 deletions
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index 9ad4a6ac6c84..526d2123f758 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -13,6 +13,7 @@
13#include <linux/sched.h> 13#include <linux/sched.h>
14#include <linux/parser.h> 14#include <linux/parser.h>
15#include "incore.h" 15#include "incore.h"
16#include "util.h"
16 17
17/* Options for hostdata parser */ 18/* Options for hostdata parser */
18 19
@@ -257,11 +258,44 @@ static inline bool gfs2_holder_initialized(struct gfs2_holder *gh)
257 return gh->gh_gl; 258 return gh->gh_gl;
258} 259}
259 260
261/**
262 * glock_set_object - set the gl_object field of a glock
263 * @gl: the glock
264 * @object: the object
265 */
260static inline void glock_set_object(struct gfs2_glock *gl, void *object) 266static inline void glock_set_object(struct gfs2_glock *gl, void *object)
261{ 267{
262 spin_lock(&gl->gl_lockref.lock); 268 spin_lock(&gl->gl_lockref.lock);
269 if (gfs2_assert_warn(gl->gl_name.ln_sbd, gl->gl_object == NULL))
270 gfs2_dump_glock(NULL, gl);
263 gl->gl_object = object; 271 gl->gl_object = object;
264 spin_unlock(&gl->gl_lockref.lock); 272 spin_unlock(&gl->gl_lockref.lock);
265} 273}
266 274
275/**
276 * glock_clear_object - clear the gl_object field of a glock
277 * @gl: the glock
278 * @object: the object
279 *
280 * I'd love to similarly add this:
281 * else if (gfs2_assert_warn(gl->gl_sbd, gl->gl_object == object))
282 * gfs2_dump_glock(NULL, gl);
283 * Unfortunately, that's not possible because as soon as gfs2_delete_inode
284 * frees the block in the rgrp, another process can reassign it for an I_NEW
285 * inode in gfs2_create_inode because that calls new_inode, not gfs2_iget.
286 * That means gfs2_delete_inode may subsequently try to call this function
287 * for a glock that's already pointing to a brand new inode. If we clear the
288 * new inode's gl_object, we'll introduce metadata corruption. Function
289 * gfs2_delete_inode calls clear_inode which calls gfs2_clear_inode which also
290 * tries to clear gl_object, so it's more than just gfs2_delete_inode.
291 *
292 */
293static inline void glock_clear_object(struct gfs2_glock *gl, void *object)
294{
295 spin_lock(&gl->gl_lockref.lock);
296 if (gl->gl_object == object)
297 gl->gl_object = NULL;
298 spin_unlock(&gl->gl_lockref.lock);
299}
300
267#endif /* __GLOCK_DOT_H__ */ 301#endif /* __GLOCK_DOT_H__ */
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index f9302f16a28e..2578bd824e34 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -201,14 +201,14 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
201 201
202fail_refresh: 202fail_refresh:
203 ip->i_iopen_gh.gh_flags |= GL_NOCACHE; 203 ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
204 glock_set_object(ip->i_iopen_gh.gh_gl, NULL); 204 glock_clear_object(ip->i_iopen_gh.gh_gl, ip);
205 gfs2_glock_dq_uninit(&ip->i_iopen_gh); 205 gfs2_glock_dq_uninit(&ip->i_iopen_gh);
206fail_put: 206fail_put:
207 if (io_gl) 207 if (io_gl)
208 gfs2_glock_put(io_gl); 208 gfs2_glock_put(io_gl);
209 if (gfs2_holder_initialized(&i_gh)) 209 if (gfs2_holder_initialized(&i_gh))
210 gfs2_glock_dq_uninit(&i_gh); 210 gfs2_glock_dq_uninit(&i_gh);
211 glock_set_object(ip->i_gl, NULL); 211 glock_clear_object(ip->i_gl, ip);
212fail: 212fail:
213 iget_failed(inode); 213 iget_failed(inode);
214 return ERR_PTR(error); 214 return ERR_PTR(error);
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index fdedec379b78..5fdc54158ff6 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1640,13 +1640,13 @@ out:
1640 gfs2_ordered_del_inode(ip); 1640 gfs2_ordered_del_inode(ip);
1641 clear_inode(inode); 1641 clear_inode(inode);
1642 gfs2_dir_hash_inval(ip); 1642 gfs2_dir_hash_inval(ip);
1643 glock_set_object(ip->i_gl, NULL); 1643 glock_clear_object(ip->i_gl, ip);
1644 wait_on_bit_io(&ip->i_flags, GIF_GLOP_PENDING, TASK_UNINTERRUPTIBLE); 1644 wait_on_bit_io(&ip->i_flags, GIF_GLOP_PENDING, TASK_UNINTERRUPTIBLE);
1645 gfs2_glock_add_to_lru(ip->i_gl); 1645 gfs2_glock_add_to_lru(ip->i_gl);
1646 gfs2_glock_put(ip->i_gl); 1646 gfs2_glock_put(ip->i_gl);
1647 ip->i_gl = NULL; 1647 ip->i_gl = NULL;
1648 if (gfs2_holder_initialized(&ip->i_iopen_gh)) { 1648 if (gfs2_holder_initialized(&ip->i_iopen_gh)) {
1649 glock_set_object(ip->i_iopen_gh.gh_gl, NULL); 1649 glock_clear_object(ip->i_iopen_gh.gh_gl, ip);
1650 ip->i_iopen_gh.gh_flags |= GL_NOCACHE; 1650 ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
1651 gfs2_glock_dq_uninit(&ip->i_iopen_gh); 1651 gfs2_glock_dq_uninit(&ip->i_iopen_gh);
1652 } 1652 }