Revert "mm: shmem: don't truncate page if memory failure happens"

This reverts commit b9d02f1bdd98f38e6e5ecacc9786a8f58f3f8b2c.

The error handling of that patch was fundamentally broken, and it needs
to be entirely re-done.

For example, in shmem_write_begin() it would call shmem_getpage(), then
ignore the error return from that, and look at the page pointer contents
instead.

And in shmem_read_mapping_page_gfp(), the patch tested PageHWPoison() on
a page pointer that two lines earlier had potentially been set as an
error pointer.

These issues could be individually fixed, but when it has this many
issues, I'm just reverting it instead of waiting for fixes.

Link: https://lore.kernel.org/linux-mm/20211111084617.6746-1-ajaygargnsit@gmail.com/
Reported-by: Ajay Garg <ajaygargnsit@gmail.com>
Reported-by: Jens Axboe <axboe@kernel.dk>
Cc: Yang Shi <shy828301@gmail.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

+6 -51
+3 -11
mm/memory-failure.c
··· 58 #include <linux/ratelimit.h> 59 #include <linux/page-isolation.h> 60 #include <linux/pagewalk.h> 61 - #include <linux/shmem_fs.h> 62 #include "internal.h" 63 #include "ras/ras_event.h" 64 ··· 867 { 868 int ret; 869 struct address_space *mapping; 870 - bool extra_pins; 871 872 delete_from_lru_cache(p); 873 ··· 896 } 897 898 /* 899 - * The shmem page is kept in page cache instead of truncating 900 - * so is expected to have an extra refcount after error-handling. 901 - */ 902 - extra_pins = shmem_mapping(mapping); 903 - 904 - /* 905 * Truncation is a bit tricky. Enable it per file system for now. 906 * 907 * Open: to take i_rwsem or not for this? Right now we don't. 908 */ 909 ret = truncate_error_page(p, page_to_pfn(p), mapping); 910 - if (has_extra_refcount(ps, p, extra_pins)) 911 - ret = MF_FAILED; 912 - 913 out: 914 unlock_page(p); 915 916 return ret; 917 }
··· 58 #include <linux/ratelimit.h> 59 #include <linux/page-isolation.h> 60 #include <linux/pagewalk.h> 61 #include "internal.h" 62 #include "ras/ras_event.h" 63 ··· 868 { 869 int ret; 870 struct address_space *mapping; 871 872 delete_from_lru_cache(p); 873 ··· 898 } 899 900 /* 901 * Truncation is a bit tricky. Enable it per file system for now. 902 * 903 * Open: to take i_rwsem or not for this? Right now we don't. 904 */ 905 ret = truncate_error_page(p, page_to_pfn(p), mapping); 906 out: 907 unlock_page(p); 908 + 909 + if (has_extra_refcount(ps, p, false)) 910 + ret = MF_FAILED; 911 912 return ret; 913 }
+3 -35
mm/shmem.c
··· 2456 struct inode *inode = mapping->host; 2457 struct shmem_inode_info *info = SHMEM_I(inode); 2458 pgoff_t index = pos >> PAGE_SHIFT; 2459 - int ret = 0; 2460 2461 /* i_rwsem is held by caller */ 2462 if (unlikely(info->seals & (F_SEAL_GROW | ··· 2466 return -EPERM; 2467 } 2468 2469 - ret = shmem_getpage(inode, index, pagep, SGP_WRITE); 2470 - 2471 - if (*pagep && PageHWPoison(*pagep)) { 2472 - unlock_page(*pagep); 2473 - put_page(*pagep); 2474 - ret = -EIO; 2475 - } 2476 - 2477 - return ret; 2478 } 2479 2480 static int ··· 2553 if (sgp == SGP_CACHE) 2554 set_page_dirty(page); 2555 unlock_page(page); 2556 - 2557 - if (PageHWPoison(page)) { 2558 - put_page(page); 2559 - error = -EIO; 2560 - break; 2561 - } 2562 } 2563 2564 /* ··· 3092 page = find_get_page(inode->i_mapping, 0); 3093 if (!page) 3094 return ERR_PTR(-ECHILD); 3095 - if (PageHWPoison(page) || 3096 - !PageUptodate(page)) { 3097 put_page(page); 3098 return ERR_PTR(-ECHILD); 3099 } ··· 3100 error = shmem_getpage(inode, 0, &page, SGP_READ); 3101 if (error) 3102 return ERR_PTR(error); 3103 - if (page && PageHWPoison(page)) { 3104 - unlock_page(page); 3105 - put_page(page); 3106 - return ERR_PTR(-ECHILD); 3107 - } 3108 unlock_page(page); 3109 } 3110 set_delayed_call(done, shmem_put_link, page); ··· 3750 kmem_cache_destroy(shmem_inode_cachep); 3751 } 3752 3753 - /* Keep the page in page cache instead of truncating it */ 3754 - static int shmem_error_remove_page(struct address_space *mapping, 3755 - struct page *page) 3756 - { 3757 - return 0; 3758 - } 3759 - 3760 const struct address_space_operations shmem_aops = { 3761 .writepage = shmem_writepage, 3762 .set_page_dirty = __set_page_dirty_no_writeback, ··· 3760 #ifdef CONFIG_MIGRATION 3761 .migratepage = migrate_page, 3762 #endif 3763 - .error_remove_page = shmem_error_remove_page, 3764 }; 3765 EXPORT_SYMBOL(shmem_aops); 3766 ··· 4171 page = ERR_PTR(error); 4172 else 4173 unlock_page(page); 4174 - 4175 - if (PageHWPoison(page)) 4176 - page = ERR_PTR(-EIO); 4177 - 4178 return page; 4179 #else 4180 /*
··· 2456 struct inode *inode = mapping->host; 2457 struct shmem_inode_info *info = SHMEM_I(inode); 2458 pgoff_t index = pos >> PAGE_SHIFT; 2459 2460 /* i_rwsem is held by caller */ 2461 if (unlikely(info->seals & (F_SEAL_GROW | ··· 2467 return -EPERM; 2468 } 2469 2470 + return shmem_getpage(inode, index, pagep, SGP_WRITE); 2471 } 2472 2473 static int ··· 2562 if (sgp == SGP_CACHE) 2563 set_page_dirty(page); 2564 unlock_page(page); 2565 } 2566 2567 /* ··· 3107 page = find_get_page(inode->i_mapping, 0); 3108 if (!page) 3109 return ERR_PTR(-ECHILD); 3110 + if (!PageUptodate(page)) { 3111 put_page(page); 3112 return ERR_PTR(-ECHILD); 3113 } ··· 3116 error = shmem_getpage(inode, 0, &page, SGP_READ); 3117 if (error) 3118 return ERR_PTR(error); 3119 unlock_page(page); 3120 } 3121 set_delayed_call(done, shmem_put_link, page); ··· 3771 kmem_cache_destroy(shmem_inode_cachep); 3772 } 3773 3774 const struct address_space_operations shmem_aops = { 3775 .writepage = shmem_writepage, 3776 .set_page_dirty = __set_page_dirty_no_writeback, ··· 3788 #ifdef CONFIG_MIGRATION 3789 .migratepage = migrate_page, 3790 #endif 3791 + .error_remove_page = generic_error_remove_page, 3792 }; 3793 EXPORT_SYMBOL(shmem_aops); 3794 ··· 4199 page = ERR_PTR(error); 4200 else 4201 unlock_page(page); 4202 return page; 4203 #else 4204 /*
-5
mm/userfaultfd.c
··· 232 goto out; 233 } 234 235 - if (PageHWPoison(page)) { 236 - ret = -EIO; 237 - goto out_release; 238 - } 239 - 240 ret = mfill_atomic_install_pte(dst_mm, dst_pmd, dst_vma, dst_addr, 241 page, false, wp_copy); 242 if (ret)
··· 232 goto out; 233 } 234 235 ret = mfill_atomic_install_pte(dst_mm, dst_pmd, dst_vma, dst_addr, 236 page, false, wp_copy); 237 if (ret)