xfs: clear ail delwri queued bufs on unmount of shutdown fs
[linux-2.6-block.git] / fs / xfs / xfs_trans_ail.c
index 55326f971cb36bb87e35552f461a81a1c206ef3f..d3a4e89bf4a0ddb916ed4f5d395285e2e2188869 100644 (file)
@@ -531,17 +531,33 @@ xfsaild(
                        set_current_state(TASK_INTERRUPTIBLE);
 
                /*
-                * Check kthread_should_stop() after we set the task state
-                * to guarantee that we either see the stop bit and exit or
-                * the task state is reset to runnable such that it's not
-                * scheduled out indefinitely and detects the stop bit at
-                * next iteration.
-                *
+                * Check kthread_should_stop() after we set the task state to
+                * guarantee that we either see the stop bit and exit or the
+                * task state is reset to runnable such that it's not scheduled
+                * out indefinitely and detects the stop bit at next iteration.
                 * A memory barrier is included in above task state set to
                 * serialize again kthread_stop().
                 */
                if (kthread_should_stop()) {
                        __set_current_state(TASK_RUNNING);
+
+                       /*
+                        * The caller forces out the AIL before stopping the
+                        * thread in the common case, which means the delwri
+                        * queue is drained. In the shutdown case, the queue may
+                        * still hold relogged buffers that haven't been
+                        * submitted because they were pinned since added to the
+                        * queue.
+                        *
+                        * Log I/O error processing stales the underlying buffer
+                        * and clears the delwri state, expecting the buf to be
+                        * removed on the next submission attempt. That won't
+                        * happen if we're shutting down, so this is the last
+                        * opportunity to release such buffers from the queue.
+                        */
+                       ASSERT(list_empty(&ailp->ail_buf_list) ||
+                              XFS_FORCED_SHUTDOWN(ailp->ail_mount));
+                       xfs_buf_delwri_cancel(&ailp->ail_buf_list);
                        break;
                }