static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
 {
        struct gfs2_sbd *sdp = gl->gl_sbd;
-       const struct gfs2_glock_operations *glops = gl->gl_ops;
+       struct gfs2_holder *gh = gl->gl_req_gh;
 
        gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
        gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
 
        state_change(gl, LM_ST_UNLOCKED);
 
-       if (glops->go_inval)
-               glops->go_inval(gl, DIO_METADATA);
+       if (test_and_clear_bit(GLF_CONV_DEADLK, &gl->gl_flags)) {
+               spin_lock(&gl->gl_spin);
+               gh->gh_error = 0;
+               spin_unlock(&gl->gl_spin);
+               gfs2_glock_xmote_th(gl, gl->gl_req_gh);
+               gfs2_glock_put(gl);
+               return;
+       }
 
        spin_lock(&gl->gl_spin);
        gfs2_demote_wake(gl);
        struct gfs2_sbd *sdp = gl->gl_sbd;
        const struct gfs2_glock_operations *glops = gl->gl_ops;
        struct gfs2_holder *gh = gl->gl_req_gh;
-       int prev_state = gl->gl_state;
        int op_done = 1;
 
        if (!gh && (ret & LM_OUT_ST_MASK) == LM_ST_UNLOCKED) {
 
        state_change(gl, ret & LM_OUT_ST_MASK);
 
-       if (prev_state != LM_ST_UNLOCKED && !(ret & LM_OUT_CACHEABLE)) {
-               if (glops->go_inval)
-                       glops->go_inval(gl, DIO_METADATA);
-       } else if (gl->gl_state == LM_ST_DEFERRED) {
-               /* We might not want to do this here.
-                  Look at moving to the inode glops. */
-               if (glops->go_inval)
-                       glops->go_inval(gl, 0);
-       }
-
        /*  Deal with each possible exit condition  */
 
        if (!gh) {
                }
        } else {
                spin_lock(&gl->gl_spin);
+               if (ret & LM_OUT_CONV_DEADLK) {
+                       gh->gh_error = 0;
+                       set_bit(GLF_CONV_DEADLK, &gl->gl_flags);
+                       spin_unlock(&gl->gl_spin);
+                       gfs2_glock_drop_th(gl);
+                       gfs2_glock_put(gl);
+                       return;
+               }
                list_del_init(&gh->gh_list);
                gh->gh_error = -EIO;
                if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) 
 
        if (glops->go_xmote_th)
                glops->go_xmote_th(gl);
+       if (state == LM_ST_DEFERRED && glops->go_inval)
+               glops->go_inval(gl, DIO_METADATA);
 
        gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
        gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
 
        if (glops->go_xmote_th)
                glops->go_xmote_th(gl);
+       if (glops->go_inval)
+               glops->go_inval(gl, DIO_METADATA);
 
        gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
        gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
 
  * modify the filesystem.  The lock module shouldn't assign a journal to the FS
  * mount.  It shouldn't send recovery callbacks to the FS mount.  If the node
  * dies or withdraws, all locks can be wiped immediately.
+ *
+ * LM_MFLAG_CONV_NODROP
+ * Do not allow the dlm to internally resolve conversion deadlocks by demoting
+ * the lock to unlocked and then reacquiring it in the requested mode. Instead,
+ * it should cancel the request and return LM_OUT_CONV_DEADLK.
  */
 
 #define LM_MFLAG_SPECTATOR     0x00000001
+#define LM_MFLAG_CONV_NODROP   0x00000002
 
 /*
  * lm_lockstruct flags
  *
  * LM_OUT_ASYNC
  * The result of the request will be returned in an LM_CB_ASYNC callback.
+ *
+ * LM_OUT_CONV_DEADLK
+ * The lock request was canceled do to a conversion deadlock.
  */
 
 #define LM_OUT_ST_MASK         0x00000003
 #define LM_OUT_CANCELED                0x00000008
 #define LM_OUT_ASYNC           0x00000080
 #define LM_OUT_ERROR           0x00000100
+#define LM_OUT_CONV_DEADLK     0x00000200
 
 /*
  * lm_callback_t types