OSDN Git Service

Merge tag 'driver-core-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[uclinux-h8/linux.git] / mm / filemap.c
index d2e6a79..647d72b 100644 (file)
@@ -152,25 +152,25 @@ static void filemap_unaccount_folio(struct address_space *mapping,
 
        VM_BUG_ON_FOLIO(folio_mapped(folio), folio);
        if (!IS_ENABLED(CONFIG_DEBUG_VM) && unlikely(folio_mapped(folio))) {
-               int mapcount;
-
                pr_alert("BUG: Bad page cache in process %s  pfn:%05lx\n",
                         current->comm, folio_pfn(folio));
                dump_page(&folio->page, "still mapped when deleted");
                dump_stack();
                add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);
 
-               mapcount = page_mapcount(&folio->page);
-               if (mapping_exiting(mapping) &&
-                   folio_ref_count(folio) >= mapcount + 2) {
-                       /*
-                        * All vmas have already been torn down, so it's
-                        * a good bet that actually the folio is unmapped,
-                        * and we'd prefer not to leak it: if we're wrong,
-                        * some other bad page check should catch it later.
-                        */
-                       page_mapcount_reset(&folio->page);
-                       folio_ref_sub(folio, mapcount);
+               if (mapping_exiting(mapping) && !folio_test_large(folio)) {
+                       int mapcount = page_mapcount(&folio->page);
+
+                       if (folio_ref_count(folio) >= mapcount + 2) {
+                               /*
+                                * All vmas have already been torn down, so it's
+                                * a good bet that actually the page is unmapped
+                                * and we'd rather not leak it: if we're wrong,
+                                * another bad page check should catch it later.
+                                */
+                               page_mapcount_reset(&folio->page);
+                               folio_ref_sub(folio, mapcount);
+                       }
                }
        }
 
@@ -193,16 +193,20 @@ static void filemap_unaccount_folio(struct address_space *mapping,
        /*
         * At this point folio must be either written or cleaned by
         * truncate.  Dirty folio here signals a bug and loss of
-        * unwritten data.
+        * unwritten data - on ordinary filesystems.
+        *
+        * But it's harmless on in-memory filesystems like tmpfs; and can
+        * occur when a driver which did get_user_pages() sets page dirty
+        * before putting it, while the inode is being finally evicted.
         *
-        * This fixes dirty accounting after removing the folio entirely
+        * Below fixes dirty accounting after removing the folio entirely
         * but leaves the dirty flag set: it has no effect for truncated
         * folio and anyway will be cleared before returning folio to
         * buddy allocator.
         */
-       if (WARN_ON_ONCE(folio_test_dirty(folio)))
-               folio_account_cleaned(folio, mapping,
-                                       inode_to_wb(mapping->host));
+       if (WARN_ON_ONCE(folio_test_dirty(folio) &&
+                        mapping_can_writeback(mapping)))
+               folio_account_cleaned(folio, inode_to_wb(mapping->host));
 }
 
 /*
@@ -1185,24 +1189,17 @@ static void folio_wake_bit(struct folio *folio, int bit_nr)
        }
 
        /*
-        * It is possible for other pages to have collided on the waitqueue
-        * hash, so in that case check for a page match. That prevents a long-
-        * term waiter
+        * It's possible to miss clearing waiters here, when we woke our page
+        * waiters, but the hashed waitqueue has waiters for other pages on it.
+        * That's okay, it's a rare case. The next waker will clear it.
         *
-        * It is still possible to miss a case here, when we woke page waiters
-        * and removed them from the waitqueue, but there are still other
-        * page waiters.
+        * Note that, depending on the page pool (buddy, hugetlb, ZONE_DEVICE,
+        * other), the flag may be cleared in the course of freeing the page;
+        * but that is not required for correctness.
         */
-       if (!waitqueue_active(q) || !key.page_match) {
+       if (!waitqueue_active(q) || !key.page_match)
                folio_clear_waiters(folio);
-               /*
-                * It's possible to miss clearing Waiters here, when we woke
-                * our page waiters, but the hashed waitqueue has waiters for
-                * other pages on it.
-                *
-                * That's okay, it's a rare case. The next waker will clear it.
-                */
-       }
+
        spin_unlock_irqrestore(&q->lock, flags);
 }
 
@@ -3782,7 +3779,7 @@ again:
                 * same page as we're writing to, without it being marked
                 * up-to-date.
                 */
-               if (unlikely(fault_in_iov_iter_readable(i, bytes))) {
+               if (unlikely(fault_in_iov_iter_readable(i, bytes) == bytes)) {
                        status = -EFAULT;
                        break;
                }