{
        trace_xfs_invalidatepage(page->mapping->host, page, offset,
                                 length);
+
+       /*
+        * If we are invalidating the entire page, clear the dirty state from it
+        * so that we can check for attempts to release dirty cached pages in
+        * xfs_vm_releasepage().
+        */
+       if (offset == 0 && length >= PAGE_SIZE)
+               cancel_dirty_page(page);
        block_invalidatepage(page, offset, length);
 }
 
         * mm accommodates an old ext3 case where clean pages might not have had
         * the dirty bit cleared. Thus, it can send actual dirty pages to
         * ->releasepage() via shrink_active_list(). Conversely,
-        * block_invalidatepage() can send pages that are still marked dirty
-        * but otherwise have invalidated buffers.
+        * block_invalidatepage() can send pages that are still marked dirty but
+        * otherwise have invalidated buffers.
         *
         * We want to release the latter to avoid unnecessary buildup of the
-        * LRU, skip the former and warn if we've left any lingering
-        * delalloc/unwritten buffers on clean pages. Skip pages with delalloc
-        * or unwritten buffers and warn if the page is not dirty. Otherwise
-        * try to release the buffers.
+        * LRU, so xfs_vm_invalidatepage() clears the page dirty flag on pages
+        * that are entirely invalidated and need to be released.  Hence the
+        * only time we should get dirty pages here is through
+        * shrink_active_list() and so we can simply skip those now.
+        *
+        * warn if we've left any lingering delalloc/unwritten buffers on clean
+        * or invalidated pages we are about to release.
         */
+       if (PageDirty(page))
+               return 0;
+
        xfs_count_page_state(page, &delalloc, &unwritten);
 
-       if (delalloc) {
-               WARN_ON_ONCE(!PageDirty(page));
+       if (WARN_ON_ONCE(delalloc))
                return 0;
-       }
-       if (unwritten) {
-               WARN_ON_ONCE(!PageDirty(page));
+       if (WARN_ON_ONCE(unwritten))
                return 0;
-       }
 
        return try_to_free_buffers(page);
 }