summaryrefslogtreecommitdiff
path: root/fs
AgeCommit message (Collapse)Author
2026-07-28exfat: free new directory cluster if zeroing failsYichong Chen
exfat_alloc_new_dir() allocates a cluster for a new directory before zeroing it. If exfat_zeroed_cluster() fails, the function returns the error but leaves the allocated cluster in use. Free the newly allocated cluster before returning the zeroing error. Signed-off-by: Yichong Chen <chenyichong@uniontech.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-07-28afs: Fix UAF when sending a messageDavid Howells
In afs_make_call(), there's a race with async call reception and destruction. If a call is dispatched that doesn't have call->write_iter set (used to specify the data content for FS.StoreData), then the first rxrpc_kernel_send_data() will not set MSG_MORE in the msghdr. Once rxrpc_send_data() queues the last request packet, the response could come in at any time and cause the call to be completed and put. However, afs_make_call() will look at the call again to see it ->write_iter should be handled - something it's only allowed to do if it has its own ref on the call. Whilst this is the case for synchronous calls, it isn't true for async calls such as FS.FetchData. There's also a potential UAF in afs_make_call() in the event that an asynchronous call is being sent, but the call fails in some way (e.g. it gets aborted from the server). The problem there is that afs_make_call() tries to abort a call if the rxrpc send fails, but the asynchronous notification from rxrpc may have caused the afs_call to be torn down. generic/650 plays games with randomly taking CPUs offline, and can interject a significant delay such that the call is deallocated before afs_make_call() gets to check call->write_iter - and a UAF ensues (caught by KASAN). BUG: KASAN: slab-use-after-free in afs_make_call+0x1c90/0x2210 [kafs] Read of size 8 at addr ffff888035e050e8 by task fsstress/1409 Fix this by making afs_make_op_call() give the op->call its own ref rather than transferring the caller's ref to it and then dropping the ref when afs_make_call() returns. This also means that the afs_make_call() func never loses its ref on the call now. Fixes: eddf51f2bb2c ("afs: Make {Y,}FS.FetchData an asynchronous operation") Fixes: e49c7b2f6de7 ("afs: Build an abstraction around an "operation" concept") Link: https://sashiko.dev/#/patchset/20260702144919.172295-1-dhowells%40redhat.com Reported-by: Marc Dionne <marc.dionne@auristor.com> Signed-off-by: David Howells <dhowells@redhat.com> Link: https://patch.msgid.link/20260723113452.566619-4-dhowells@redhat.com cc: Jeffrey Altman <jaltman@auristor.com> cc: linux-afs@lists.infradead.org cc: stable@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-28afs: Fix afs_fs_fetch_data() to subtract transferred from lenDavid Howells
Fix afs_fs_fetch_data() to subtract subreq->transferred from subreq->len rather than adding it. Fixes: f28fc2010d62 ("afs: Eliminate afs_read") Link: https://sashiko.dev/#/patchset/20260713081022.2186481-1-dhowells%40redhat.com Signed-off-by: David Howells <dhowells@redhat.com> Link: https://patch.msgid.link/20260723113452.566619-3-dhowells@redhat.com cc: Marc Dionne <marc.dionne@auristor.com> cc: Jeffrey Altman <jaltman@auristor.com> cc: linux-afs@lists.infradead.org cc: stable@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-28afs: Fix afs_fs_fetch_data() to set call->asyncDavid Howells
Fix afs_fs_fetch_data() to set call->async on an async operation as does afs_fs_fetch_data64(). Fixes: eddf51f2bb2c ("afs: Make {Y,}FS.FetchData an asynchronous operation") Link: https://sashiko.dev/#/patchset/20260702144919.172295-1-dhowells%40redhat.com Signed-off-by: David Howells <dhowells@redhat.com> Link: https://patch.msgid.link/20260723113452.566619-2-dhowells@redhat.com cc: Marc Dionne <marc.dionne@auristor.com> cc: Jeffrey Altman <jaltman@auristor.com> cc: linux-afs@lists.infradead.org cc: stable@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27hfs: rework MDB locking schemeViacheslav Dubeyko
hfs_mdb_commit() used to hold the primary MDB buffer_head (mdb_bh) locked for the whole commit, including writing the alternate MDB and the volume bitmap. A corrupted image can set drVBMSt so the bitmap block aliases mdb_bh. The bitmap writeback path then calls lock_buffer() on that same buffer_head while it is already locked by hfs_mdb_commit(). Finally, we have a deadlock during flushing the MDB to the file system volume. However, even for valid images, the locking scheme of holding the mdb_bh locked across this much unrelated I/O is fragile anyway. This patch adds a dedicated sbi->mdb_lock and take it around every hfs_mdb_commit() caller (hfs_sync_fs(), flush_mdb(), and the initial hfs_mdb_get() in hfs_fill_super()). Additionally, this patch makes sbi->mdb/sbi->alt_mdb independent in-memory copies (allocated with kmemdup()) instead of pointers into mdb_bh's/alt_mdb_bh's page cache data. Every MDB field read or write in hfs_mdb_commit(), hfs_mdb_close() and hfs_mdb_get() now operates on these copies. Also, hfs_mdb_publish() and hfs_alt_mdb_publish() are the only places left that touch the buffer_heads. The hfs_mdb_put() frees the two copies. Reported-by: Yue Sun <samsun1006219@gmail.com> Link: https://lore.kernel.org/all/CAEkJfYMB47v1yOWHB8q2dc8kf=uj-rLO=+yMyudwPguJ8Kd3jA@mail.gmail.com/ Signed-off-by: Yue Sun <samsun1006219@gmail.com> cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260720184414.195213-2-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-07-27cifs: add fscache_resize_cookie() to cifs_setsize()Frank Sorenson
Several code paths update the VFS inode size by calling netfs_resize_file() and cifs_setsize(), but omit the corresponding fscache_resize_cookie() call, leaving the fscache cookie out of sync with the actual file size: - cifs_file_set_size() in inode.c: server-side truncation via setattr - cifs_do_truncate() in file.c: truncates to zero on O_TRUNC open - smb2_duplicate_extents() in smb2ops.c: file clone extending EOF - smb3_simple_falloc() in smb2ops.c: two branches that extend EOF via write-range and SMB2_set_eof respectively Since every caller of cifs_setsize() must resize the fscache cookie, add the call to cifs_setsize() itself, consistent with how truncate_pagecache() is already consolidated there. Fixes: 70431bfd825d ("cifs: Support fscache indexing rewrite") Fixes: 93a43155127f ("cifs: Fix missing set of remote_i_size") Fixes: 110fee6b9bb5 ("smb: client: fix missing timestamp updates with O_TRUNC") Fixes: 7a06d3b816d7 ("smb/client: emulate small EOF-extending mode 0 fallocate ranges") Cc: stable@vger.kernel.org Cc: David Howells <dhowells@redhat.com> Cc: Paulo Alcantara <pc@manguebit.org> Cc: Huiwen He <hehuiwen@kylinos.cn> Signed-off-by: Frank Sorenson <sorenson@redhat.com> Reviewed-by: Paulo Alcantara <pc@manguebit.org> Signed-off-by: Steve French <stfrench@microsoft.com>
2026-07-28f2fs: fix dentry folio leak in find_in_levelGuanghui Yang
find_in_level() gets a dentry folio with f2fs_find_data_folio() before calling find_in_block(). If find_in_block() returns an error, the function stores the error in res_folio and breaks out of the loop without dropping the dentry folio. This leaks the folio reference on the find_in_block() error path. Drop the dentry folio before returning the error to the caller. Fixes: 7ad08a58bf67 ("f2fs: Handle casefolding with Encryption") Cc: stable@vger.kernel.org Reviewed-by: Chao Yu <chao@kernel.org> Signed-off-by: Guanghui Yang <3497809730@qq.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2026-07-27fs: hfsplus: remove redundant NULL check before kfree()Mohammad Shahid
kfree() safely handles NULL pointers, so the explicit NULL check before calling kfree() is unnecessary. This issue was reported by ifnullfree.cocci. Signed-off-by: Mohammad Shahid <mdshahid03@gmail.com> Link: https://lore.kernel.org/r/20260726064228.248199-1-mdshahid03@gmail.com Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-07-28f2fs: fix folio_nr_pages() race after put in large folio invalidateZhaoyang Huang
Our v6.18 based Android system is continuely suffering livelock and bad page stat as shown in[1] which related to broken xarray slot status. By investigating big folio operations within f2fs, we find below races and fix it by get the nr_pages before drop the refcount and folio_lock. f2fs_get_read_data_folio() calls f2fs_folio_put() before folio_nr_pages() when invalidating a large folio from the page cache. That unlocks the folio and drops the caller reference, leaving a window where a concurrent truncate or folio split can shrink the compound folio or free it before the invalidate range is computed. An undersized range then leaves split sub-folios in mapping->i_pages, which can later interact badly with truncate and reclaim (stale xarray entries and bad page state when folio->mapping no longer matches the mapping being truncated). [1] PID: 2594 TASK: ffffff8169b81580 CPU: 7 COMMAND: "Thread-3" #0 [ffffffc08ef2b8a0] xas_load at ffffffe52d1f42a4 #1 [ffffffc08ef2b900] find_get_entries at ffffffe52c185798 #2 [ffffffc08ef2bb60] truncate_inode_pages_range at ffffffe52c19e83c #3 [ffffffc08ef2bbc0] truncate_inode_pages_final at ffffffe52c19ec2c #4 [ffffffc08ef2bc20] f2fs_evict_inode at ffffffe52c4c8400 #5 [ffffffc08ef2bcc0] evict at ffffffe52c2de9f4 #6 [ffffffc08ef2bd00] iput at ffffffe52c2db1b4 #7 [ffffffc08ef2bd30] dentry_unlink_inode at ffffffe52c2d7204 #8 [ffffffc08ef2bd50] __dentry_kill at ffffffe52c2d3dcc #9 [ffffffc08ef2bd80] dput at ffffffe52c2d3c3c #10 [ffffffc08ef2bda0] __fput at ffffffe52c2b0a7c #11 [ffffffc08ef2bde0] ____fput at ffffffe52c2b1034 #12 [ffffffc08ef2bdf0] task_work_run at ffffffe52beea200 #13 [ffffffc08ef2be20] exit_to_user_mode_loop at ffffffe52bfbc17c #14 [ffffffc08ef2be80] el0_svc at ffffffe52d1f8e54 #15 [ffffffc08ef2beb0] el0t_64_sync_handler at ffffffe52d1f8d10 Cc: stable@kernel.org Fixes: 05e65c14ea59 ("f2fs: support large folio for immutable non-compressed case") Reviewed-by: Chao Yu <chao@kernel.org> Signed-off-by: Zhaoyang Huang <zhaoyang.huang@unisoc.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2026-07-28f2fs: fix to avoid potential section-unaligned pinfileChao Yu
Blocks of pinfile may not aligned to section size due to wrong use on pinfile, result in heavy overhead of GC, let avoid this by adding additional check condition in f2fs_setattr(). - truncate -s 8mb pinfile : random checkpoint may persist filesize w/ inode - fallocate -o 0 -l 8mb pinfile - f2fs_fallocate - f2fs_expand_inode_data - f2fs_allocate_pinning_section - f2fs_map_blocks - f2fs_map_lock - __allocate_data_block - file_need_truncate : w/ FADVISE_TRUNC_BIT, we can expect unaligned mapping can be truncated while open() if f2fs is not umount abnormally - f2fs_map_unlock : following f2fs checkpoint and sudden power-cut - mount - open pinfile - f2fs_file_open - finish_preallocate_blocks - truncate_setsize : filesize is 8mb - f2fs_truncate : can only truncate block outside filesize, rather than truncating unaligned blocks inside filesize Fixes: f5a53edcf01e ("f2fs: support aligned pinned file") Cc: stable@kernel.org Cc: Daeho Jeong <daehojeong@google.com> Signed-off-by: Chao Yu <chao@kernel.org> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2026-07-28f2fs: embed f2fs_gc_kthread in f2fs_sb_infoChao Yu
Instead of allocating f2fs_gc_kthread dynamically, embed it in f2fs_sb_info. This simplifies lifetime management and prepares for fixing race conditions during teardown. - __sbi_store - remount|shutdown - f2fs_stop_gc_thread - access sbi->gc_thread - sbi->gc_thread = NULL - access sbi->gc_thread->f2fs_gc_task Fixes: 52190933c37a ("f2fs: sysfs: introduce critical_task_priority") Fixes: 7950e9ac638e ("f2fs: stop gc/discard thread after fs shutdown") Cc: stable@kernel.org Signed-off-by: Chao Yu <chao@kernel.org> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2026-07-28f2fs: quota: do not use GFP_NOFS in f2fs_quota_read()Chao Yu
Commit 02117b8ae9c0 ("f2fs: Set GF_NOFS in read_cache_page_gfp while doing f2fs_quota_read") adds GFP_NOFS in f2fs_quota_read() to avoid below deadlock: - do_sys_open - vfs_open - dquot_file_open - dquot_initialize - dqget - dquot_acquire : locks &dqopt->dqio_mutex (VFS Quota Mutex) - qtree_read_dquot - f2fs_quota_read - read_mapping_page (GFP_KERNEL / allows GFP_FS) - __alloc_pages_nodemask - try_to_free_pages (Direct Reclaim) - prune_icache_sb - evict - f2fs_evict_inode - dquot_drop - dqput - dquot_commit : tries to lock &dqopt->dqio_mutex again ==> DEADLOCK (waiting for itself) As Jan Kara mentioned, quota system has fixed this issue w/ commit 537e11cdc7a6 ("quota: Prevent memory allocation recursion while holding dq_lock"), so this GFP_NOFS flag should be relic, let's use GFP_KERNEL instead. Cc: Jan Kara <jack@suse.cz> Cc: Matthew Wilcox <willy@infradead.org> Signed-off-by: Chao Yu <chao@kernel.org> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2026-07-28f2fs: drop FGP_NOFS in f2fs_write_begin()Chao Yu
This patch proposes to drop FGP_NOFS from f2fs_filemap_get_folio() in f2fs_write_begin(), I don't see there is potential deadlock issue when __filemap_get_folio() calling into filesystem reclaim interfaces, e.g. .writepages, evict_inode, shrinker. Cc: Matthew Wilcox <willy@infradead.org> Signed-off-by: Chao Yu <chao@kernel.org> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2026-07-27cifs: fix time_last_write stamp placement in setattr/truncate pathsFrank Sorenson
cifs_file_set_size() calls cifs_setsize() on success, which calls i_size_write(), updating i_size to the new value. The subsequent check attrs->ia_size != i_size_read() in both cifs_setattr_unix() and cifs_setattr_nounix() therefore always evaluates false after a successful cifs_file_set_size(), making the smp_store_release() of time_last_write dead code. The truncate path was unprotected against stale readdir size updates. Move the stamp to before the cifs_file_set_size() RPC call, guarded by attrs->ia_size != i_size_read() to exclude no-op same-size ftruncate(2) calls from stamping time_last_write unnecessarily. On the error path the stamp remains rather than being restored: restoring a stale snapshot (prev_tlw) could silently erase a concurrent _cifsFileInfo_put() close stamp if that close arrived between the READ_ONCE and the smp_store_release. readdir is suppressed until the stamp expires, which extends beyond one acregmax if the caller retries failed truncations. stat() is unaffected: the cifs_revalidate_dentry_attr() path calls cifs_fattr_to_inode() with from_readdir=false, which bypasses the time_last_write check in is_size_safe_to_change() entirely and always writes the authoritative QUERY_INFO result to i_size. Remove the now-unreachable stamp from the dead block in both functions. Fixes: e8a8d54c2d50 ("cifs: prevent readdir from changing file size due to stale directory metadata") Signed-off-by: Frank Sorenson <sorenson@redhat.com> Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org> Signed-off-by: Steve French <stfrench@microsoft.com>
2026-07-27cifs: consolidate time_last_write stamp into _cifsFileInfo_put()Frank Sorenson
The time_last_write stamp was scattered across cifs_close(), smb2_deferred_work_close(), and the three drain functions in misc.c. This missed the case where background I/O holds the final reference after userspace close() returns, and required explicit maintenance at each close-path site. Move the smp_store_release() into _cifsFileInfo_put(), immediately before releasing open_file_lock. This single location covers all close paths unconditionally: normal close, background I/O dropping the final reference, deferred close via timer or external drain. The spinlock's store-release/load-acquire pairing with is_inode_writable() already provides the ordering guarantee documented in is_size_safe_to_change(). Remove the now-redundant stamps from cifs_close(), smb2_deferred_work_close(), and all six stamp sites in the misc.c deferred-close drain functions. Fixes: e8a8d54c2d50 ("cifs: prevent readdir from changing file size due to stale directory metadata") Signed-off-by: Frank Sorenson <sorenson@redhat.com> Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org> Signed-off-by: Steve French <stfrench@microsoft.com>
2026-07-27smb: client: simplify cifs_fscache_get_super_cookie()Dmitry Antipov
Avoid redundant 'strlen()' and use the convenient 'strreplace()' to simplify 'cifs_fscache_get_super_cookie()'. Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru> Signed-off-by: Steve French <stfrench@microsoft.com>
2026-07-27smb: client: free partially allocated transform folio queueYichong Chen
netfs_alloc_folioq_buffer() may leave a partially allocated folio queue attached to the caller's buffer pointer when it returns an error. smb3_init_transform_rq() stores the buffer in the request only after allocation succeeds, so the common error path cannot free a partial allocation. Store the buffer pointer before checking the return value so err_free releases it. Signed-off-by: Yichong Chen <chenyichong@uniontech.com> Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn> Signed-off-by: Steve French <stfrench@microsoft.com>
2026-07-27Merge tag 'mm-hotfixes-stable-2026-07-27-14-18' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm Pull misc fixes from Andrew Morton: "13 hotfixes. All are cc:stable. 11 are for MM. All are singletons - please see the changelogs for details" * tag 'mm-hotfixes-stable-2026-07-27-14-18' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: fs/proc/task_mmu: fix PAGEMAP_SCAN written state for PMD holes mm/hugetlb: fix list corruption in allocate_file_region_entries() mm: mglru: fix stale batch updates after memcg reparenting selftest: fix headers in fclog.c ocfs2: fix boundary check in ocfs2_check_dir_entry() to use buffer offset mm/percpu-km: fix bitmap overflow and accounting in pcpu_create_chunk() mm/util: don't read __page_2 for order-1 folios in snapshot_page() mm/hugetlb: fix swap entry corruption when clearing uffd-wp at fork() mm: migrate_device: fix pte_pfn/pte_dirty called on non-present PTE fs/proc/task_mmu: fix PAGEMAP_SCAN written state for unpopulated ptes userfaultfd: wait on source PMD during UFFDIO_MOVE lib: test_hmm: use device devt for coherent device range selection mm/vmstat: fold stranded per-cpu node stats when a node comes online
2026-07-27quota: remove CONFIG_PRINT_QUOTA_WARNING codeJiri Slaby (SUSE)
CONFIG_PRINT_QUOTA_WARNING was marked as BROKEN in 2023 by 36d532d713db ("quota: mark PRINT_QUOTA_WARNING as BROKEN"). The code is apparently unused and uninteresting, so remove it all, incl. the abuse of TTY. Signed-off-by: Jiri Slaby (SUSE) <jirislaby@kernel.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jan Kara <jack@suse.com> Cc: Yangtao Li <frank.li@vivo.com> Link: https://patch.msgid.link/20260722060155.1111519-1-jirislaby@kernel.org Signed-off-by: Jan Kara <jack@suse.cz>
2026-07-27Merge tag 'erofs-for-7.2-rc6-fixes' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs Pull erofs fixes from Gao Xiang: "Fix a regression in page cache sharing which can cause a NULL pointer dereference, and limit LZMA stream memory usage on systems with many CPUs. - Keep a valid f_path for page cache sharing to fix a recent mincore() NULL pointer dereference - Limit LZMA stream pool size when too many processors are available - Sync up with Hongbo Li's latest email address" * tag 'erofs-for-7.2-rc6-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs: erofs: cap LZMA stream pool size erofs: ensure valid f_path for page cache sharing MAINTAINERS: update Hongbo Li's email address
2026-07-27udf: Fix i_lenExtents truncation on 32-bit kernelsZhan Xusheng
In udf_do_extend_file() the total extent length is rounded up to a block boundary with: iinfo->i_lenExtents = (iinfo->i_lenExtents + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1); i_lenExtents is a __u64, but sb->s_blocksize is unsigned long. On 32-bit kernels unsigned long is 32-bit, so ~(sb->s_blocksize - 1) is a 32-bit value (e.g. 0xfffff800 for a 2 KiB block) that is zero-extended in the AND, clearing the upper 32 bits of i_lenExtents. For UDF files whose total extent length exceeds 4 GiB this truncates i_lenExtents when the file is extended, corrupting the tracked extent length. Cast the block size to 64-bit before forming the mask. 64-bit kernels are unaffected. Fixes: 48d6d8ff7dca ("udf: cache struct udf_inode_info") Cc: stable@vger.kernel.org Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com> Link: https://patch.msgid.link/20260722082425.213311-1-zhanxusheng@xiaomi.com Signed-off-by: Jan Kara <jack@suse.cz>
2026-07-27fs: support FD_FAILFS_ROOT in fchroot()Christian Brauner
Allow a process to move its root directory into failfs via fchroot(FD_FAILFS_ROOT). From that point on every absolute path lookup and every absolute symlink fails with EOPNOTSUPP. Combined with fchdir(FD_FAILFS_ROOT) this leaves the process with lookups anchored at explicit directory file descriptors only. It is the fs_struct equivalent of RESOLVE_BENEATH. This allows taks to drop their filesystem state completely. Callers with CAP_SYS_CHROOT in their user namespace may always do this, mirroring chroot(2). Unprivileged callers are subject to three requirements (which may be loosened later): (1) no_new_privs must be set After entering failfs suid binaries on regular mounts remain reachable via inherited directory file descriptors or the working directory. A setuid program executing with an unusable root directory might be tricked by this. I'm not 100% convinced that this is needed but it feels more secure initially and it also forces more no_new_privs on userspace. So win-win imo. (2) The caller must not already be chrooted. The root directory is what confines .. resolution. The failfs root can never be reached by walking up a real mount tree. A task whose root is failfs has no .. barrier left below the top of its mount tree. A .. walk from any real directory fd it still holds climbs to the mount-namespace root. Which is kinda the point if you want to do fd-based lookup only. If failfs prevented you from doing that then it doesn't make a lot of sense. A task that a privileged manager chrooted into a subtree could use chroot()ing into failfs as a way to allow for an inherited fd to resolve it again. So reject already-chrooted callers closing that issue without losing anything for the intended self-sandboxing use case. (3) The caller must not share its fs_struct. Requirement (1) is checked on the calling thread, but the root lives in the fs_struct which may be shared via CLONE_FS. A sibling thread without no_new_privs could then execute a setuid binary with the failfs root and defeat (1). setns() to a mount or user namespace refuses a shared fs_struct for the same kind of reason, so do the same here and require fs->users == 1. no_new_privs is inherited across clone() and can never be cleared, so any CLONE_FS child created afterwards carries it too and the guarantee holds. Privileged callers (CAP_SYS_CHROOT) are not subject to these requirements and may share the fs_struct. They can already chroot and exec a setuid binary today, so failfs hands them nothing new. Backing out is currently hard, but that is a property of the current implementation and not a promise. current_chrooted() treats a failfs root as chrooted so for now the task cannot create user namespaces to regain CAP_SYS_CHROOT and chroot()/fchroot() back out require CAP_SYS_CHROOT. This is not guaranteed though. current_chrooted() may change, or an unprivileged no_new_privs task could be allowed to chroot to a real directory, either of which would loosen this. So don't treat it as a permanent one-way door. The remaining way out today is setns() to a mount namespace file descriptor which requires CAP_SYS_ADMIN over the target namespace plus CAP_SYS_CHROOT and CAP_SYS_ADMIN in the caller's user namespace and resets both root and working directory. A task that closes or never had such file descriptors and restricts *chdir()/*chroot()/setns() via seccomp currently cannot get back out. Link: https://patch.msgid.link/20260724-work-failfs-v2-4-485dabbae185@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27fs: add fchroot()Christian Brauner
Add a file descriptor based counterpart to chroot(2). This has been overdue for a long time. It is the natural companion to fchdir() and avoids re-resolving a path that the caller already holds a file descriptor to. No TOCTOU between resolving the target and changing the root. It composes with modern fd-based APIs meaning it works with O_PATH file descriptors and file descriptors to detached mount trees created via open_tree(OPEN_TREE_CLONE). The permission model is identical to chroot(2). The caller must have CAP_SYS_CHROOT in its user namespace, must pass MAY_EXEC | MAY_CHDIR permission checks on the target directory, and LSMs are consulted via the same security_path_chroot() hook. The system call takes a flags argument for future extensibility which must currently be zero. Link: https://patch.msgid.link/20260724-work-failfs-v2-3-485dabbae185@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27fs: support FD_FAILFS_ROOT in fchdir()Christian Brauner
Add a new file descriptor sentinel FD_FAILFS_ROOT following FD_PIDFS_ROOT and FD_NSFS_ROOT and teach fchdir() to accept it. A process calling fchdir(FD_FAILFS_ROOT) moves its working directory into failfs. Every AT_FDCWD-relative lookup afterwards fails with EOPNOTSUPP including "." and ".." and getcwd() reports the working directory as unreachable from the process root by returning a path prefixed with "(unreachable)". Lookups relative to explicit directory file descriptors are unaffected. The sentinel is the only way in. No privilege or gating is required. Setting the working directory to a directory in which every operation fails grants nothing and loses nothing that closing file descriptors couldn't lose. An unlinked working directory behaves the same way today modulo errno. The working directory also plays no role in confining ".." resolution so no boundary is weakened. Link: https://patch.msgid.link/20260724-work-failfs-v2-2-485dabbae185@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27fs: add failfsChristian Brauner
nullfs provides a permanently empty and immutable directory. Lookups fail with ENOENT. The directory can be opened, read, stat, mounted upon. It behaves like nothing is there. Add its counterpart failfs where the semantics are not "there is nothing here" but "nothing is supported here". Every operation that reaches the filesystem fails with EOPNOTSUPP. Even statfs()/fstatfs() fail so the filesystem cannot be discovered through an fd to it. EOPNOTSUPP rather than a permission errno keeps that coherent. There is no permission model in which anything could ever be allowed and EACCES or EPERM would merely suggest that different credentials might succeed while EIO would suggest corruption. It also makes hitting the failfs boundary mostly quite dinstinguishable. A task anchoring its lookups at real directory file descriptors may be able to tell a failfs refusal from an ordinary permission failure. I wouldn't go so far as guaranteeing that but it should mostly work. No path lookup can open the root, not even with O_PATH. It is never reached by a lookup in a parent directory. The only way to a path-walk terminal at the root is a jump through a /proc/<pid>/{root,cwd} magic link or by mountpoint traversal. The root also refuses ->d_weak_revalidate() which the VFS calls for jumped terminals. That covers the jump-based references too: an O_PATH open is refused, name_to_handle_at() cannot encode it into a file handle, and following a magic link into it fails. A plain readlink() of such a link still works and shows "failfs:/". There is a single instance of failfs mounted during early boot via kern_mount() making it logically distinct from every mount namespace. Since the mount is a member of no mount namespace mounting onto it fails. So nothing can ever be mounted on top of it. It cannot be cloned via OPEN_TREE_CLONE and it does not show up in statmount()/listmount() or /proc/<pid>/mountinfo. The filesystem is not registered so it is not visible in /proc/filesystems and cannot be mounted from userspace. This lets tasks shed their filesystem state completely. A process with its root directory or working directory in failfs must anchor every path lookup at an explicit file descriptor or is doomed to fail any lookup. Absolute paths, absolute symlinks, and AT_FDCWD-relative lookups simply fail. Followup patches will expose it via a new FD_FAILFS_ROOT file descriptor sentinel understood by fchdir() and the new fchroot() system call. Link: https://patch.msgid.link/20260724-work-failfs-v2-1-485dabbae185@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27fat: Fix persisting directory entries on fsync(2) of the root directoryChristian Brauner
Buffers containing the directory entries of a directory's children are tracked in the directory inode's metadata bh list. Before commit 525da4f40a7c ("fat: Fix missed inode writeback during fsync(2)") fsync(2) of a directory wrote that list out unconditionally via mmb_fsync_noflush(). Now the list is written by fat_sync_inode_metadata() which __writeback_single_inode() only invokes when the inode has I_METADATA_WRITEBACK set. The root inode never gets I_METADATA_WRITEBACK - __fat_write_inode() returns early for it since the root directory has no directory entry of its own - and fat_sync_inode_metadata() returns early for it as well. Hence fsync(2) on the root directory returns success without writing out the directory entries of its children. Set I_METADATA_WRITEBACK for the root inode in __fat_write_inode() and make fat_sync_inode_metadata() only skip the nonexistent directory entry for the root inode but still sync the metadata bh list. Fixes: 525da4f40a7c ("fat: Fix missed inode writeback during fsync(2)") Reported-by: Sashiko <sashiko-bot@kernel.org> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27fat: Propagate inode buffer write errors from fat_sync_inode_metadata()Christian Brauner
fat_sync_inode_metadata() ignores the result of writing the buffer containing the inode's directory entry. Before commit 525da4f40a7c ("fat: Fix missed inode writeback during fsync(2)") a write error was propagated to fsync(2) via __fat_write_inode() -> sync_dirty_buffer(), now fsync(2) reports success even though the inode's directory entry could not be written. Check buffer_write_io_error() after sync_dirty_buffer() like the other ->sync_inode_metadata implementations do. Fixes: 525da4f40a7c ("fat: Fix missed inode writeback during fsync(2)") Reported-by: Sashiko <sashiko-bot@kernel.org> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27fat: Fix lost inode update in do_msdos_rename() with DIRSYNCChristian Brauner
Commit e668e0668181 ("fat: Replace fat_sync_inode() with sync_inode_metadata()") hoisted mark_inode_dirty() in front of the IS_DIRSYNC conditional in all converted callers except for the main rename path of do_msdos_rename(). There old_inode is generally still clean when the target directory has DIRSYNC set and, unlike fat_sync_inode(), sync_inode_metadata() does nothing for a clean inode. Thus the directory entry at the new location is never updated with the contents of old_inode: it stays the way msdos_add_entry() created it, with start cluster 0 and size 0 (or, when the rename replaced an existing target, it keeps describing the deleted target). Since old_inode is also never marked dirty, later writeback doesn't update the entry either and the stale directory entry ends up on disk even on a clean unmount, so the renamed file loses its contents. Mark old_inode dirty before calling sync_inode_metadata() like all the other call sites do. Fixes: e668e0668181 ("fat: Replace fat_sync_inode() with sync_inode_metadata()") Reported-by: Sashiko <sashiko-bot@kernel.org> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27isofs: release zisofs block pointer buffer headYichong Chen
zisofs_fill_pages() reads the compressed block pointer table. The error paths release the current buffer_head, the loop also releases the old buffer_head when it advances. However, the success path leaves the last buffer_head referenced. Release it before returning success. Fixes: 59bc055211b8 ("zisofs: Implement reading of compressed files when PAGE_CACHE_SIZE > compress block size") Signed-off-by: Yichong Chen <chenyichong@uniontech.com> Link: https://patch.msgid.link/20260721091152.1450622-1-chenyichong@uniontech.com Signed-off-by: Jan Kara <jack@suse.cz>
2026-07-27vfs: Remove mmb_fsync()Jan Kara
Now that everybody has been converted from mmb_fsync() (and it's variant mmb_fsync_noflush()) to simple_fsync(), we can delete these calls. Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-40-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27fat: Replace fat_sync_inode() with sync_inode_metadata()Jan Kara
Use generic sync_inode_metadata() instead of fat_sync_inode() for persisting inode metadata changes for DIRSYNC inodes. This slightly simplifies code and also addresses a theoretical race where fat_sync_inode() could return before all metadata buffers associated with the inode were properly written out when racing with fsync(2). Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-39-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27fat: Fix missed inode writeback during fsync(2)Jan Kara
FAT could fail to properly write out inode on fsync(2) due to races with WB_SYNC_NONE writeback. Several racing fsyncs could also result in some fsync returning earlier than all metadata buffers were properly persisted. Fix these issues by using new .sync_inode_metadata method which makes sure all inode related metadata is written to disk during any WB_SYNC_ALL writeback. The slight disadvantage of this approach is that when fsync(2) of an inode races with rename(2) of the inode, the window during which inode isn't properly persisted becomes wider. Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-38-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27ext4: Fix data integrity writeout issues in nojournal modeJan Kara
Several racing fsyncs on ext4 in nojournal mode could result in some fsync returning earlier than all metadata buffers were properly persisted. Also ext4_fsync() in nojournal mode was somewhat inefficient because it was always writing out the inode regardless whether it was dirty or not. Fix these issues by using new .sync_inode_metadata method which makes sure all inode related metadata is written to disk during any WB_SYNC_ALL writeback in nojournal mode. This also somewhat simplifies the nojournal mode fsync handling. Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-37-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27minix: Fix data integrity writeout issuesJan Kara
Minix could fail to properly write out inode on fsync(2) due to races with WB_SYNC_NONE writeback. Several racing fsyncs could also result in some fsync returning earlier than all metadata buffers were properly persisted. Furthermore DIRSYNC handling missed writing inode related metadata. Fix all these issues by using new .sync_inode_metadata method which makes sure all inode related metadata is written to disk during any WB_SYNC_ALL writeback. Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-36-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27bfs: Fix data integrity writeout issuesJan Kara
BFS could fail to properly write out inode on fsync(2) due to races with WB_SYNC_NONE writeback. Several racing fsyncs could also result in some fsync returning earlier than all metadata buffers were properly persisted. Fix all these issues by using new .sync_inode_metadata method which makes sure all inode related metadata is written to disk during any WB_SYNC_ALL writeback. Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-35-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27udf: Fold udf_update_inode() into udf_write_inode()Jan Kara
There is no point in udf_update_inode() anymore as it has a single caller. Just fold udf_update_inode() into it. Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-34-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27udf: Use sync_inode_metadata() in udf_evict_inode()Jan Kara
Instead of opencoding inode update in udf_evict_inode() just use sync_inode_metadata(). Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-33-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27udf: Drop udf_sync_inode()Jan Kara
The only place using udf_sync_inode() is now inode_getblk() for flushing IS_SYNC inodes after write and page_mkwrite allocating blocks. For write the flushing is actually taken care of by generic_write_sync() so it isn't needed here. For page_mkwrite it does have effect however none of the other filesystems seem to bother with flushing IS_SYNC inode on page fault and properly synchronizing such writeback with standard inode writeback would be slightly complex due to locking constraints. So just drop IS_SYNC inode handling from inode_getblk(). Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-32-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27udf: Use sync_inode_metadata() to writeout IS_SYNC inodeJan Kara
When setting inode size we directly writeout inode in udf_setsize(). This misses proper writeout of other inode related metadata. Use sync_inode_metadata() instead and move the flushing to udf_setattr() to avoid it for udf_evict_inode() where it would be pointless. Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-31-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27udf: Fix data integrity writeout issuesJan Kara
UDF could fail to properly write out inode on fsync(2) due to races with WB_SYNC_NONE writeback. Several racing fsyncs could also result in some fsync returning earlier than all metadata buffers were properly persisted. Fix all these issues by using new .sync_inode_metadata method which makes sure all inode related metadata is written to disk during any WB_SYNC_ALL writeback. Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-30-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27ext2: Fix data integrity writeout issuesJan Kara
Ext2 could fail to properly write out inode on fsync(2) due to races with WB_SYNC_NONE writeback. Several racing fsyncs could also result in some fsync returning earlier than all metadata buffers were properly persisted. Finally DIRSYNC handling was not properly persisting all inode related metadata. Fix all these issues by using new .sync_inode_metadata method which makes sure all inode related metadata is written to disk during any WB_SYNC_ALL writeback. Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-29-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27ext2: Avoid unnecessary inode buffer writeback for sync(2)Jan Kara
For sync(2) the generic code calls sync_blockdev_nowait() and later sync_blockdev() to persist all metadata buffers. Thus there's no need for ext2_write_inode() to do that which speeds up sync(2) writeback. Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-28-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27ext2: Drop __ext2_write_inode()Jan Kara
Fold special helper __ext2_write_inode() into ext2_write_inode() and just learn the single caller of __ext2_write_inode() to pass proper wbc instead. No functional changes. Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-27-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27ext2: Fix lost inode updates for IS_SYNC inodesJan Kara
ext2_setsize() and ext2_xattr_set2() had a construct like: if (IS_SYNC(inode)) { sync_inode_metadata(inode, 1); } else { mark_inode_dirty(inode); } which leads to lost inode updates for IS_SYNC inodes because sync_inode_metadata() does anything only if the inode is already dirty and hence inode updates may be simply lost. Fix the problem by unconditionally marking the inode dirty and *then* call sync_inode_metadata(). CC: stable@vger.kernel.org Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-26-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27fs: Provide way for filesystem to wait for metadata writebackJan Kara
Currently, inode and in general metadata writeback is handled in a lazy manner. When inode is dirty, __writeback_single_inode() calls .write_inode method which for lots of filesystems just copies inode metadata into the underlying block buffer. Writeback of other metadata associated with the inode (as well as buffers underlying inodes) is usually handled completely separately and implicitely during writeback of block device inode. This is good for efficiency of WB_SYNC_NONE writeback or sync(2). However it becomes problematic for situations where we want to make sure inode and its metadata is really persistent on disk. fsync(2) is the most pronounced example of this and thus we have grown a special file operation and various helper functions to assist with this task. However fsync(2) is not the only case, For example directories with DIRSYNC flag need similar functionality and current use of sync_inode_metadata() for this task in filesystems generally misses writeout of necessary metadata. Furthermore even fsync(2) handling as implemented by simple_fsync() or similar helpers is racy and can fail to properly persist the inode. The problem is that WB_SYNC_NONE writeback can copy inode metadata into underlying buffer and clean inode dirty bits. Following fsync(2) will see inode is clean and will fail to make sure underlying buffer is written out. When multiple fsync(2) calls race, there's also another type of race involving mmb_fsync(). There the problem is buffers already submitted to the disk are no longer tracked in the mmb list and so racing mmb_sync() can return before all of the IO completes. Provide a new inode state bit I_METADATA_WRITEBACK tracking whether writeback of inode related metadata may be needed for successful data integrity sync and if this bit is set __writeback_single_inode() for data integrity writeback will call new superblock operation .sync_inode_metadata whose task is to make sure all metadata associated with the inode (including the inode itself) is properly persisted. This will allow filesystems to address the data integrity issues described above and at the same time somewhat simplify our fsync implementations. Issues with racing fsync(2) calls will be addressed by synchronization on I_SYNC inode state which is set while calling .sync_inode_metadata, issues with missed inode buffer writeback are fixed by filesystems looking up corresponding buffer head and writing it out if needed. Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-25-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27ext4: Allocate mapping_metadata_bhs struct on demandJan Kara
Currently every ext4 inode gets mapping_metadata_bhs struct although it is only needed when running without a journal and only for inodes where any metadata was dirtied. Allocate mapping_metadata_bhs struct on demand when dirtying the first metadata buffer for the inode. Acked-by: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-24-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27fs: Fix missed inode writeback when racing with __writeback_single_inodeJan Kara
When mmb_fsync_noflush() or simple_fsync_noflush() race with another writeback of the same inode, they can see inode dirty bits are already clear and skip inode writeback although the racing __writeback_single_inode() didn't yet get to writing anything. This can result in fsync(2) returning without properly persisting the inode. We already have I_SYNC bit for this synchronization and writeback_single_inode() properly uses it so just fix mmb_fsync_noflush() and simple_fsync_noflush() to take it into account as well. Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-23-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27fs: Fix possible UAF in mark_buffer_write_io_error()Jan Kara
When filesystem is freeing inode it calls mmb_invalidate() which removes bhs from inode's metadata bh tracking and clears b_mmb for them. However if the inode is getting deleted, we don't bother with calling mmb_sync() before and thus these buffers can be under IO and we can be racing with IO completion handler calling mark_buffer_write_io_error(). This race can lead to mark_buffer_write_io_error() either hitting NULL pointer reference or trying to operate on already freed inode. Protect the mapping handling with RCU to make sure mmb and inode aren't freed before we are done with them. Reported-by: Sashiko <sashiko-bot@kernel.org> Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-22-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27affs: Drop support for metadata bh trackingJan Kara
AFFS did all the hard work of tracking metadata bhs dirtied for an inode but it actually never used this information as affs_file_fsync() just calls sync_blockdev() to writeback all filesystem metadata bhs. After a discussion with AFFS maintainer nobody cares about AFFS performance so let's keep this affs_file_fsync() behavior and just drop all the pointless tracking from AFFS. CC: David Sterba <dsterba@suse.com> Acked-by: David Sterba <dsterba@suse.com> Signed-off-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260727104923.3828017-21-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27exfat: write moved entry before removing sourceYichong Chen
exfat_move_file() removes the old directory entry before the new entry has been written. If writing the new entry fails, rename returns an error after the source entry has already been marked deleted. Write the new entry first, then remove the old entry and update the cached inode location. This keeps the source entry intact if creating the destination entry fails. Signed-off-by: Yichong Chen <chenyichong@uniontech.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>