diff options
Diffstat (limited to 'fs/gfs2')
-rw-r--r-- | fs/gfs2/glock.c | 7 | ||||
-rw-r--r-- | fs/gfs2/incore.h | 1 | ||||
-rw-r--r-- | fs/gfs2/inode.c | 7 |
3 files changed, 14 insertions, 1 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 5788ebff716a..7f0257309b3e 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -572,6 +572,12 @@ static void delete_work_func(struct work_struct *work) struct inode *inode; u64 no_addr = gl->gl_name.ln_number; + /* If someone's using this glock to create a new dinode, the block must + have been freed by another node, then re-used, in which case our + iopen callback is too late after the fact. Ignore it. */ + if (test_bit(GLF_INODE_CREATING, &gl->gl_flags)) + goto out; + ip = gl->gl_object; /* Note: Unsafe to dereference ip as we don't hold right refs/locks */ @@ -583,6 +589,7 @@ static void delete_work_func(struct work_struct *work) d_prune_aliases(inode); iput(inode); } +out: gfs2_glock_put(gl); } diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 845fb09cc606..a6a3389a07fc 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -328,6 +328,7 @@ enum { GLF_LRU = 13, GLF_OBJECT = 14, /* Used only for tracing */ GLF_BLOCKING = 15, + GLF_INODE_CREATING = 16, /* Inode creation occurring */ }; struct gfs2_glock { diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 3e94400d587c..95a914524a39 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -592,7 +592,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, struct inode *inode = NULL; struct gfs2_inode *dip = GFS2_I(dir), *ip; struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - struct gfs2_glock *io_gl; + struct gfs2_glock *io_gl = NULL; int error, free_vfs_inode = 1; u32 aflags = 0; unsigned blocks = 1; @@ -729,6 +729,8 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, if (error) goto fail_gunlock2; + BUG_ON(test_and_set_bit(GLF_INODE_CREATING, &io_gl->gl_flags)); + error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); if (error) goto fail_gunlock2; @@ -771,12 +773,15 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, } gfs2_glock_dq_uninit(ghs); gfs2_glock_dq_uninit(ghs + 1); + clear_bit(GLF_INODE_CREATING, &io_gl->gl_flags); return error; fail_gunlock3: gfs2_glock_dq_uninit(&ip->i_iopen_gh); gfs2_glock_put(io_gl); fail_gunlock2: + if (io_gl) + clear_bit(GLF_INODE_CREATING, &io_gl->gl_flags); gfs2_glock_dq_uninit(ghs + 1); fail_free_inode: if (ip->i_gl) |