diff options
author | Bob Peterson <rpeterso@redhat.com> | 2017-07-18 12:35:04 -0400 |
---|---|---|
committer | Bob Peterson <rpeterso@redhat.com> | 2017-07-21 09:20:05 -0400 |
commit | df3d87bde121213560fde0edb71bc46f0f75692c (patch) | |
tree | 3efaafb3a13066a1c3d9421721b59cfabf5688fc | |
parent | e477b24b507998bc6568316a2e034025960d2404 (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.h | 34 | ||||
-rw-r--r-- | fs/gfs2/inode.c | 4 | ||||
-rw-r--r-- | fs/gfs2/super.c | 4 |
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 | */ | ||
260 | static inline void glock_set_object(struct gfs2_glock *gl, void *object) | 266 | static 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 | */ | ||
293 | static 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 | ||
202 | fail_refresh: | 202 | fail_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); |
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 | 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); |
212 | fail: | 212 | fail: |
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 | } |