Patch "ubifs: ubifs_releasepage: Remove ubifs_assert(0) to valid this process" has been added to the 6.1-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    ubifs: ubifs_releasepage: Remove ubifs_assert(0) to valid this process

to the 6.1-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     ubifs-ubifs_releasepage-remove-ubifs_assert-0-to-val.patch
and it can be found in the queue-6.1 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit d4645535b33ff0f4e0c94729069a3d9d7065bfab
Author: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
Date:   Wed Jun 1 11:00:00 2022 +0800

    ubifs: ubifs_releasepage: Remove ubifs_assert(0) to valid this process
    
    [ Upstream commit 66f4742e93523ab2f062d9d9828b3e590bc61536 ]
    
    There are two states for ubifs writing pages:
    1. Dirty, Private
    2. Not Dirty, Not Private
    
    The normal process cannot go to ubifs_releasepage() which means there
    exists pages being private but not dirty. Reproducer[1] shows that it
    could occur (which maybe related to [2]) with following process:
    
         PA                     PB                    PC
    lock(page)[PA]
    ubifs_write_end
      attach_page_private         // set Private
      __set_page_dirty_nobuffers  // set Dirty
    unlock(page)
    
    write_cache_pages[PA]
      lock(page)
      clear_page_dirty_for_io(page) // clear Dirty
      ubifs_writepage
    
                            do_truncation[PB]
                              truncate_setsize
                                i_size_write(inode, newsize) // newsize = 0
    
        i_size = i_size_read(inode) // i_size = 0
        end_index = i_size >> PAGE_SHIFT
        if (page->index > end_index)
          goto out // jump
    out:
    unlock(page)   // Private, Not Dirty
    
                                                    generic_fadvise[PC]
                                                      lock(page)
                                                      invalidate_inode_page
                                                        try_to_release_page
                                                          ubifs_releasepage
                                                            ubifs_assert(c, 0)
                                                            // bad assertion!
                                                      unlock(page)
                              truncate_pagecache[PB]
    
    Then we may get following assertion failed:
      UBIFS error (ubi0:0 pid 1683): ubifs_assert_failed [ubifs]:
      UBIFS assert failed: 0, in fs/ubifs/file.c:1513
      UBIFS warning (ubi0:0 pid 1683): ubifs_ro_mode [ubifs]:
      switched to read-only mode, error -22
      CPU: 2 PID: 1683 Comm: aa Not tainted 5.16.0-rc5-00184-g0bca5994cacc-dirty #308
      Call Trace:
        dump_stack+0x13/0x1b
        ubifs_ro_mode+0x54/0x60 [ubifs]
        ubifs_assert_failed+0x4b/0x80 [ubifs]
        ubifs_releasepage+0x67/0x1d0 [ubifs]
        try_to_release_page+0x57/0xe0
        invalidate_inode_page+0xfb/0x130
        __invalidate_mapping_pages+0xb9/0x280
        invalidate_mapping_pagevec+0x12/0x20
        generic_fadvise+0x303/0x3c0
        ksys_fadvise64_64+0x4c/0xb0
    
    [1] https://bugzilla.kernel.org/show_bug.cgi?id=215373
    [2] https://linux-mtd.infradead.narkive.com/NQoBeT1u/patch-rfc-ubifs-fix-assert-failed-in-ubifs-set-page-dirty
    
    Fixes: 1e51764a3c2ac0 ("UBIFS: add new flash file system")
    Signed-off-by: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
    Signed-off-by: Richard Weinberger <richard@xxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 1f429260a85fc..10c1779af9c51 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1472,14 +1472,23 @@ static bool ubifs_release_folio(struct folio *folio, gfp_t unused_gfp_flags)
 	struct inode *inode = folio->mapping->host;
 	struct ubifs_info *c = inode->i_sb->s_fs_info;
 
-	/*
-	 * An attempt to release a dirty page without budgeting for it - should
-	 * not happen.
-	 */
 	if (folio_test_writeback(folio))
 		return false;
+
+	/*
+	 * Page is private but not dirty, weird? There is one condition
+	 * making it happened. ubifs_writepage skipped the page because
+	 * page index beyonds isize (for example. truncated by other
+	 * process named A), then the page is invalidated by fadvise64
+	 * syscall before being truncated by process A.
+	 */
 	ubifs_assert(c, folio_test_private(folio));
-	ubifs_assert(c, 0);
+	if (folio_test_checked(folio))
+		release_new_page_budget(c);
+	else
+		release_existing_page_budget(c);
+
+	atomic_long_dec(&c->dirty_pg_cnt);
 	folio_detach_private(folio);
 	folio_clear_checked(folio);
 	return true;



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux