Similarly to sb_start_write(), make sb_start_pagefault() return errors for superblocks which are marked as shutdown to avoid modifications to it which reduces noise in the error logs and generally makes life somewhat easier for filesystems. We teach all sb_start_pagefault() callers to handle the error. Signed-off-by: Jan Kara <jack@xxxxxxx> --- fs/bcachefs/fs-io-pagecache.c | 3 ++- fs/btrfs/file.c | 3 ++- fs/ceph/addr.c | 9 ++++++--- fs/ext2/file.c | 3 ++- fs/ext4/file.c | 3 ++- fs/ext4/inode.c | 3 ++- fs/f2fs/file.c | 4 +++- fs/fuse/dax.c | 3 ++- fs/gfs2/file.c | 3 ++- fs/netfs/buffered_write.c | 3 ++- fs/nfs/file.c | 3 ++- fs/nilfs2/file.c | 3 ++- fs/ocfs2/mmap.c | 3 ++- fs/orangefs/inode.c | 3 ++- fs/udf/file.c | 3 ++- fs/xfs/xfs_file.c | 3 ++- fs/zonefs/file.c | 3 ++- include/linux/fs.h | 5 ++++- mm/filemap.c | 3 ++- 19 files changed, 45 insertions(+), 21 deletions(-) diff --git a/fs/bcachefs/fs-io-pagecache.c b/fs/bcachefs/fs-io-pagecache.c index a9cc5cad9cc9..a4efa1b76035 100644 --- a/fs/bcachefs/fs-io-pagecache.c +++ b/fs/bcachefs/fs-io-pagecache.c @@ -611,7 +611,8 @@ vm_fault_t bch2_page_mkwrite(struct vm_fault *vmf) bch2_folio_reservation_init(c, inode, &res); - sb_start_pagefault(inode->v.i_sb); + if (sb_start_pagefault(inode->v.i_sb) < 0) + return VM_FAULT_SIGBUS; file_update_time(file); /* diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 21381de906f6..481d355c66ee 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1900,7 +1900,8 @@ static vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf) reserved_space = PAGE_SIZE; - sb_start_pagefault(inode->i_sb); + if (sb_start_pagefault(inode->i_sb) < 0) + return VM_FAULT_SIGBUS; page_start = page_offset(page); page_end = page_start + PAGE_SIZE - 1; end = page_end; diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 8c16bc5250ef..60ddddce4ec1 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -1686,7 +1686,9 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf) if (!prealloc_cf) return VM_FAULT_OOM; - sb_start_pagefault(inode->i_sb); + err = sb_start_pagefault(inode->i_sb); + if (err) + goto out_free; ceph_block_sigs(&oldset); if (off + thp_size(page) <= size) @@ -1704,7 +1706,7 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf) got = 0; err = ceph_get_caps(vma->vm_file, CEPH_CAP_FILE_WR, want, off + len, &got); if (err < 0) - goto out_free; + goto out_sigs; doutc(cl, "%llx.%llx %llu~%zd got cap refs on %s\n", ceph_vinop(inode), off, len, ceph_cap_string(got)); @@ -1758,9 +1760,10 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf) doutc(cl, "%llx.%llx %llu~%zd dropping cap refs on %s ret %x\n", ceph_vinop(inode), off, len, ceph_cap_string(got), ret); ceph_put_cap_refs_async(ci, got); -out_free: +out_sigs: ceph_restore_sigs(&oldset); sb_end_pagefault(inode->i_sb); +out_free: ceph_free_cap_flush(prealloc_cf); if (err < 0) ret = vmf_error(err); diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 10b061ac5bc0..b57197007b28 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -98,7 +98,8 @@ static vm_fault_t ext2_dax_fault(struct vm_fault *vmf) (vmf->vma->vm_flags & VM_SHARED); if (write) { - sb_start_pagefault(inode->i_sb); + if (sb_start_pagefault(inode->i_sb) < 0) + return VM_FAULT_SIGBUS; file_update_time(vmf->vma->vm_file); } filemap_invalidate_lock_shared(inode->i_mapping); diff --git a/fs/ext4/file.c b/fs/ext4/file.c index c89e434db6b7..37623d4624c0 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -725,7 +725,8 @@ static vm_fault_t ext4_dax_huge_fault(struct vm_fault *vmf, unsigned int order) pfn_t pfn; if (write) { - sb_start_pagefault(sb); + if (sb_start_pagefault(sb) < 0) + return VM_FAULT_SIGBUS; file_update_time(vmf->vma->vm_file); filemap_invalidate_lock_shared(mapping); retry: diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 941c1c0d5c6e..195fcbb5c083 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -6128,7 +6128,8 @@ vm_fault_t ext4_page_mkwrite(struct vm_fault *vmf) if (unlikely(IS_IMMUTABLE(inode))) return VM_FAULT_SIGBUS; - sb_start_pagefault(inode->i_sb); + if (unlikely(sb_start_pagefault(inode->i_sb) < 0)) + return VM_FAULT_SIGBUS; file_update_time(vma->vm_file); filemap_invalidate_lock_shared(mapping); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 168f08507004..67ee66ff75a7 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -100,7 +100,9 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) if (need_alloc) f2fs_balance_fs(sbi, true); - sb_start_pagefault(inode->i_sb); + err = sb_start_pagefault(inode->i_sb); + if (err) + goto out; f2fs_bug_on(sbi, f2fs_has_inline_data(inode)); diff --git a/fs/fuse/dax.c b/fs/fuse/dax.c index 12ef91d170bb..d42d0aaa1bd9 100644 --- a/fs/fuse/dax.c +++ b/fs/fuse/dax.c @@ -797,7 +797,8 @@ static vm_fault_t __fuse_dax_fault(struct vm_fault *vmf, unsigned int order, bool retry = false; if (write) - sb_start_pagefault(sb); + if (sb_start_pagefault(sb) < 0) + return VM_FAULT_SIGBUS; retry: if (retry && !(fcd->nr_free_ranges > 0)) wait_event(fcd->range_waitq, (fcd->nr_free_ranges > 0)); diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 08982937b5df..774203da5262 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -427,7 +427,8 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf) loff_t size; int err; - sb_start_pagefault(inode->i_sb); + if (sb_start_pagefault(inode->i_sb) < 0) + return VM_FAULT_SIGBUS; gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); err = gfs2_glock_nq(&gh); diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c index 4726c315453c..e46fcd387be6 100644 --- a/fs/netfs/buffered_write.c +++ b/fs/netfs/buffered_write.c @@ -531,7 +531,8 @@ vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr _enter("%lx", folio->index); - sb_start_pagefault(inode->i_sb); + if (sb_start_pagefault(inode->i_sb) < 0) + return VM_FAULT_SIGBUS; if (folio_lock_killable(folio) < 0) goto out; diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 61a8cdb9f1e1..ae0791c67ab8 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -593,7 +593,8 @@ static vm_fault_t nfs_vm_page_mkwrite(struct vm_fault *vmf) filp, filp->f_mapping->host->i_ino, (long long)folio_pos(folio)); - sb_start_pagefault(inode->i_sb); + if (sb_start_pagefault(inode->i_sb) < 0) + return VM_FAULT_SIGBUS; /* make sure the cache has finished storing the page */ if (folio_test_private_2(folio) && /* [DEPRECATED] */ diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c index 0e3fc5ba33c7..6e80377250d1 100644 --- a/fs/nilfs2/file.c +++ b/fs/nilfs2/file.c @@ -54,7 +54,8 @@ static vm_fault_t nilfs_page_mkwrite(struct vm_fault *vmf) if (unlikely(nilfs_near_disk_full(inode->i_sb->s_fs_info))) return VM_FAULT_SIGBUS; /* -ENOSPC */ - sb_start_pagefault(inode->i_sb); + if (sb_start_pagefault(inode->i_sb) < 0) + return VM_FAULT_SIGBUS; folio_lock(folio); if (folio->mapping != inode->i_mapping || folio_pos(folio) >= i_size_read(inode) || diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c index 1834f26522ed..a56465a3a515 100644 --- a/fs/ocfs2/mmap.c +++ b/fs/ocfs2/mmap.c @@ -119,7 +119,8 @@ static vm_fault_t ocfs2_page_mkwrite(struct vm_fault *vmf) int err; vm_fault_t ret; - sb_start_pagefault(inode->i_sb); + if (sb_start_pagefault(inode->i_sb) < 0) + return VM_FAULT_SIGBUS; ocfs2_block_signals(&oldset); /* diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c index fdb9b65db1de..170ef9456ff1 100644 --- a/fs/orangefs/inode.c +++ b/fs/orangefs/inode.c @@ -632,7 +632,8 @@ vm_fault_t orangefs_page_mkwrite(struct vm_fault *vmf) vm_fault_t ret; struct orangefs_write_range *wr; - sb_start_pagefault(inode->i_sb); + if (sb_start_pagefault(inode->i_sb) < 0) + return VM_FAULT_SIGBUS; if (wait_on_bit(bitlock, 1, TASK_KILLABLE)) { ret = VM_FAULT_RETRY; diff --git a/fs/udf/file.c b/fs/udf/file.c index 3a4179de316b..d97ba972f1f3 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -45,7 +45,8 @@ static vm_fault_t udf_page_mkwrite(struct vm_fault *vmf) vm_fault_t ret = VM_FAULT_LOCKED; int err; - sb_start_pagefault(inode->i_sb); + if (sb_start_pagefault(inode->i_sb) < 0) + return VM_FAULT_SIGBUS; file_update_time(vma->vm_file); filemap_invalidate_lock_shared(mapping); folio_lock(folio); diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 4cdc54dc9686..7e2c9bd70bc2 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -1283,7 +1283,8 @@ xfs_write_fault( unsigned int lock_mode = XFS_MMAPLOCK_SHARED; vm_fault_t ret; - sb_start_pagefault(inode->i_sb); + if (sb_start_pagefault(inode->i_sb) < 0) + return VM_FAULT_SIGBUS; file_update_time(vmf->vma->vm_file); /* diff --git a/fs/zonefs/file.c b/fs/zonefs/file.c index 3b103715acc9..0b100d48056a 100644 --- a/fs/zonefs/file.c +++ b/fs/zonefs/file.c @@ -294,7 +294,8 @@ static vm_fault_t zonefs_filemap_page_mkwrite(struct vm_fault *vmf) if (zonefs_inode_is_seq(inode)) return VM_FAULT_NOPAGE; - sb_start_pagefault(inode->i_sb); + if (sb_start_pagefault(inode->i_sb) < 0) + return VM_FAULT_SIGBUS; file_update_time(vmf->vma->vm_file); /* Serialize against truncates */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 44ae86f46b12..a082777eac6a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1858,9 +1858,12 @@ static inline bool __must_check sb_start_write_trylock(struct super_block *sb) * mmap_lock * -> sb_start_pagefault */ -static inline void sb_start_pagefault(struct super_block *sb) +static inline int __must_check sb_start_pagefault(struct super_block *sb) { + if (sb_test_iflag(sb, SB_I_SHUTDOWN)) + return -EROFS; __sb_start_write(sb, SB_FREEZE_PAGEFAULT); + return 0; } /** diff --git a/mm/filemap.c b/mm/filemap.c index d62150418b91..97efc8a62c21 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -3672,7 +3672,8 @@ vm_fault_t filemap_page_mkwrite(struct vm_fault *vmf) struct folio *folio = page_folio(vmf->page); vm_fault_t ret = VM_FAULT_LOCKED; - sb_start_pagefault(mapping->host->i_sb); + if (sb_start_pagefault(mapping->host->i_sb) < 0) + return VM_FAULT_SIGBUS; file_update_time(vmf->vma->vm_file); folio_lock(folio); if (folio->mapping != mapping) { -- 2.35.3