diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/gfs2/glock.h | 14 | ||||
-rw-r--r-- | fs/gfs2/super.c | 21 |
2 files changed, 14 insertions, 21 deletions
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 76cd2fabc668..d561126cfb47 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -322,20 +322,6 @@ static inline void glock_set_object(struct gfs2_glock *gl, void *object) /** * glock_clear_object - clear the gl_object field of a glock * @gl: the glock - * @object: the object - * - * I'd love to similarly add this: - * else if (gfs2_assert_warn(gl->gl_sbd, gl->gl_object == object)) - * gfs2_dump_glock(NULL, gl, true); - * Unfortunately, that's not possible because as soon as gfs2_delete_inode - * frees the block in the rgrp, another process can reassign it for an I_NEW - * inode in gfs2_create_inode because that calls new_inode, not gfs2_iget. - * That means gfs2_delete_inode may subsequently try to call this function - * for a glock that's already pointing to a brand new inode. If we clear the - * new inode's gl_object, we'll introduce metadata corruption. Function - * gfs2_delete_inode calls clear_inode which calls gfs2_clear_inode which also - * tries to clear gl_object, so it's more than just gfs2_delete_inode. - * */ static inline void glock_clear_object(struct gfs2_glock *gl, void *object) { diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 075fad8fb1d1..02f1b5f2d7f2 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1304,14 +1304,21 @@ static int evict_unlinked_inode(struct inode *inode) goto out; } - /* We're about to clear the bitmap for the dinode, but as soon as we - do, gfs2_create_inode can create another inode at the same block - location and try to set gl_object again. We clear gl_object here so - that subsequent inode creates don't see an old gl_object. */ - if (ip->i_gl) { - glock_clear_object(ip->i_gl, ip); + if (ip->i_gl) gfs2_inode_remember_delete(ip->i_gl, ip->i_no_formal_ino); - } + + /* + * As soon as we clear the bitmap for the dinode, gfs2_create_inode() + * can get called to recreate it, or even gfs2_inode_lookup() if the + * inode was recreated on another node in the meantime. + * + * However, inserting the new inode into the inode hash table will not + * succeed until the old inode is removed, and that only happens after + * ->evict_inode() returns. The new inode is attached to its inode and + * iopen glocks after inserting it into the inode hash table, so at + * that point we can be sure that both glocks are unused. + */ + ret = gfs2_dinode_dealloc(ip); out: return ret; |