When a glock holder has the LM_FLAG_OUTER flag set, we set the current_holds_glock() flag upon taking the lock. With that flag set, we can then recognize when trying to take an "inner" glock and react accordingly. Signed-off-by: Andreas Gruenbacher <agruenba@xxxxxxxxxx> --- fs/gfs2/glock.c | 12 ++++++++++++ fs/gfs2/glock.h | 13 ++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index d9cb261f55b0..f6cae2ee1c83 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1427,6 +1427,11 @@ int gfs2_glock_nq(struct gfs2_holder *gh) if (glock_blocked_by_withdraw(gl) && !(gh->gh_flags & LM_FLAG_NOEXP)) return -EIO; + if (gh->gh_flags & LM_FLAG_OUTER) { + BUG_ON(current_holds_glock()); + set_current_holds_glock(true); + } + if (test_bit(GLF_LRU, &gl->gl_flags)) gfs2_glock_remove_from_lru(gl); @@ -1514,6 +1519,11 @@ void gfs2_glock_dq(struct gfs2_holder *gh) __gfs2_glock_queue_work(gl, delay); } spin_unlock(&gl->gl_lockref.lock); + + if (gh->gh_flags & LM_FLAG_OUTER) { + BUG_ON(!current_holds_glock()); + set_current_holds_glock(false); + } } void gfs2_glock_dq_wait(struct gfs2_holder *gh) @@ -2068,6 +2078,8 @@ static const char *hflags2str(char *buf, u16 flags, unsigned long iflags) *p++ = 'p'; if (flags & LM_FLAG_NODE_SCOPE) *p++ = 'n'; + if (flags & LM_FLAG_OUTER) + *p++ = 'o'; if (flags & GL_ASYNC) *p++ = 'a'; if (flags & GL_EXACT) diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index f0ef6fd24ba4..8b145269fb14 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -94,6 +94,12 @@ static inline bool gfs2_holder_is_compatible(struct gfs2_holder *gh, int state) * This holder agrees to share the lock within this node. In other words, * the glock is held in EX mode according to DLM, but local holders on the * same node can share it. + * + * LM_FLAG_OUTER + * Use set_current_holds_glock() to indicate when the current task is holding + * this "upper" glock, and current_holds_glock() to detect when the current + * task is trying to take another glock. Used to prevent deadlocks involving + * the inode glock during page faults. */ #define LM_FLAG_TRY 0x0001 @@ -102,9 +108,10 @@ static inline bool gfs2_holder_is_compatible(struct gfs2_holder *gh, int state) #define LM_FLAG_ANY 0x0008 #define LM_FLAG_PRIORITY 0x0010 #define LM_FLAG_NODE_SCOPE 0x0020 -#define GL_ASYNC 0x0040 -#define GL_EXACT 0x0080 -#define GL_SKIP 0x0100 +#define LM_FLAG_OUTER 0x0040 +#define GL_ASYNC 0x0080 +#define GL_EXACT 0x0100 +#define GL_SKIP 0x0200 #define GL_NOCACHE 0x0400 /* -- 2.26.3