Merge tag 'x86-boot-2021-06-28' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / fs / gfs2 / glock.c
index ea7fc5c..d9cb261 100644 (file)
@@ -582,6 +582,16 @@ out_locked:
        spin_unlock(&gl->gl_lockref.lock);
 }
 
+static bool is_system_glock(struct gfs2_glock *gl)
+{
+       struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
+       struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
+
+       if (gl == m_ip->i_gl)
+               return true;
+       return false;
+}
+
 /**
  * do_xmote - Calls the DLM to change the state of a lock
  * @gl: The lock state
@@ -671,17 +681,25 @@ skip_inval:
         * to see sd_log_error and withdraw, and in the meantime, requeue the
         * work for later.
         *
+        * We make a special exception for some system glocks, such as the
+        * system statfs inode glock, which needs to be granted before the
+        * gfs2_quotad daemon can exit, and that exit needs to finish before
+        * we can unmount the withdrawn file system.
+        *
         * However, if we're just unlocking the lock (say, for unmount, when
         * gfs2_gl_hash_clear calls clear_glock) and recovery is complete
         * then it's okay to tell dlm to unlock it.
         */
        if (unlikely(sdp->sd_log_error && !gfs2_withdrawn(sdp)))
                gfs2_withdraw_delayed(sdp);
-       if (glock_blocked_by_withdraw(gl)) {
-               if (target != LM_ST_UNLOCKED ||
-                   test_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags)) {
+       if (glock_blocked_by_withdraw(gl) &&
+           (target != LM_ST_UNLOCKED ||
+            test_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags))) {
+               if (!is_system_glock(gl)) {
                        gfs2_glock_queue_work(gl, GL_GLOCK_DFT_HOLD);
                        goto out;
+               } else {
+                       clear_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags);
                }
        }
 
@@ -1466,9 +1484,11 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
            glock_blocked_by_withdraw(gl) &&
            gh->gh_gl != sdp->sd_jinode_gl) {
                sdp->sd_glock_dqs_held++;
+               spin_unlock(&gl->gl_lockref.lock);
                might_sleep();
                wait_on_bit(&sdp->sd_flags, SDF_WITHDRAW_RECOVERY,
                            TASK_UNINTERRUPTIBLE);
+               spin_lock(&gl->gl_lockref.lock);
        }
        if (gh->gh_flags & GL_NOCACHE)
                handle_callback(gl, LM_ST_UNLOCKED, 0, false);
@@ -1775,6 +1795,7 @@ __acquires(&lru_lock)
        while(!list_empty(list)) {
                gl = list_first_entry(list, struct gfs2_glock, gl_lru);
                list_del_init(&gl->gl_lru);
+               clear_bit(GLF_LRU, &gl->gl_flags);
                if (!spin_trylock(&gl->gl_lockref.lock)) {
 add_back_to_lru:
                        list_add(&gl->gl_lru, &lru_list);
@@ -1820,7 +1841,6 @@ static long gfs2_scan_glock_lru(int nr)
                if (!test_bit(GLF_LOCK, &gl->gl_flags)) {
                        list_move(&gl->gl_lru, &dispose);
                        atomic_dec(&lru_count);
-                       clear_bit(GLF_LRU, &gl->gl_flags);
                        freed++;
                        continue;
                }