* [syzbot] [exfat?] WARNING in vfat_update_dotdot_de
@ 2026-09-14 16:38 syzbot
2026-09-29 9:00 ` [PATCH] fat: validate dotdot buffers in VFAT and MSDOS rename and rollback Krystian Kaniewski
0 siblings, 1 reply; 4+ messages in thread
From: syzbot @ 2026-09-14 16:38 UTC (permalink / raw)
To: hirofumi, linkinjeon, linux-fsdevel, linux-kernel, sj1557.seo,
syzkaller-bugs
Hello,
syzbot found the following issue on:
HEAD commit: 5225b8eec4c9 mailmap: update entry for Jens Axboe
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=11cd61f9580000
kernel config: https://syzkaller.appspot.com/x/.config?x=5e4e3a0e188a497e
dashboard link: https://syzkaller.appspot.com/bug?extid=b0aebd03565f5774f7f8
compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=11b455f9580000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=13a1b615580000
Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/fdabe739a017/disk-5225b8ee.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/ef60d7040756/vmlinux-5225b8ee.xz
kernel image: https://storage.googleapis.com/syzbot-assets/ccb7b942e430/bzImage-5225b8ee.xz
mounted in repro: https://storage.googleapis.com/syzbot-assets/be5074fab5f0/mount_0.gz
fsck result: failed (log: https://syzkaller.appspot.com/x/fsck.log?x=16cd61f9580000)
IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+b0aebd03565f5774f7f8@syzkaller.appspotmail.com
loop0: rw=8912896, sector=102, nr_sectors = 1 limit=63
syz.0.17: attempt to access beyond end of device
loop0: rw=8912896, sector=103, nr_sectors = 1 limit=63
syz.0.17: attempt to access beyond end of device
loop0: rw=8390657, sector=98, nr_sectors = 1 limit=63
Buffer I/O error on dev loop0, logical block 98, lost sync page write
------------[ cut here ]------------
!buffer_uptodate(bh)
WARNING: fs/buffer.c:991 at mark_buffer_dirty+0x299/0x410 fs/buffer.c:991, CPU#0: syz.0.17/6146
Modules linked in:
CPU: 0 UID: 0 PID: 6146 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 08/05/2026
RIP: 0010:mark_buffer_dirty+0x299/0x410 fs/buffer.c:991
Code: 4c 89 f7 e8 a9 01 d8 ff 49 8b 3e be 40 00 00 00 5b 41 5c 41 5e 41 5f 5d e9 74 52 fb ff e8 ef 00 68 ff eb 8c e8 e8 00 68 ff 90 <0f> 0b 90 e9 a5 fd ff ff e8 da 00 68 ff 90 0f 0b 90 e9 cf fd ff ff
RSP: 0018:ffffc90003b57858 EFLAGS: 00010293
RAX: ffffffff825fc9c8 RBX: ffff888076b98460 RCX: ffff888020348000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000002
RBP: dffffc0000000001 R08: ffff888076b98467 R09: 1ffff1100ed7308c
R10: dffffc0000000000 R11: ffffed100ed7308d R12: ffff88806768a434
R13: 0000000000000000 R14: ffff8880544440b0 R15: ffff88807688ba08
FS: 00007fa0804ca6c0(0000) GS:ffff888124cd2000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007ffdc870d998 CR3: 0000000035986000 CR4: 0000000000350ef0
Call Trace:
<TASK>
mmb_mark_buffer_dirty+0x2c/0x1f0 fs/buffer.c:624
vfat_update_dotdot_de+0x90/0x1c0 fs/fat/namei_vfat.c:917
vfat_rename_exchange fs/fat/namei_vfat.c:1140 [inline]
vfat_rename2+0xe3e/0x1c90 fs/fat/namei_vfat.c:1171
vfs_rename+0xbd9/0xef0 fs/namei.c:6208
filename_renameat2+0x533/0x9a0 fs/namei.c:6326
__do_sys_renameat2 fs/namei.c:6355 [inline]
__se_sys_renameat2+0x5a/0x2c0 fs/namei.c:6350
do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
do_syscall_64+0x166/0x520 arch/x86/entry/syscall_64.c:84
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fa07f59e159
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007fa0804ca028 EFLAGS: 00000246 ORIG_RAX: 000000000000013c
RAX: ffffffffffffffda RBX: 00007fa07f826090 RCX: 00007fa07f59e159
RDX: ffffffffffffff9c RSI: 0000200000000480 RDI: ffffffffffffff9c
RBP: 00007fa07f63503b R08: 0000000000000002 R09: 0000000000000000
R10: 00002000000004c0 R11: 0000000000000246 R12: 0000000000000000
R13: 00007fa07f826128 R14: 00007fa07f826090 R15: 00007ffc6d0e6af8
</TASK>
---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title
If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.
If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)
If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report
If you want to undo deduplication, reply with:
#syz undup
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH] fat: validate dotdot buffers in VFAT and MSDOS rename and rollback
2026-09-14 16:38 [syzbot] [exfat?] WARNING in vfat_update_dotdot_de syzbot
@ 2026-09-29 9:00 ` Krystian Kaniewski
2026-09-30 8:02 ` OGAWA Hirofumi
0 siblings, 1 reply; 4+ messages in thread
From: Krystian Kaniewski @ 2026-09-29 9:00 UTC (permalink / raw)
To: OGAWA Hirofumi; +Cc: linux-kernel, linux-fsdevel, syzbot+b0aebd03565f5774f7f8
During cross-directory rename operations with synchronous directory updates
enabled in VFAT and MSDOS, updating the ".." directory entry writes the
buffer via sync_dirty_buffer(). If this write fails due to an I/O error,
the block layer clears the BH_Uptodate flag. When rename enters its error
rollback path, it attempts to update the ".." directory entry again with
the same buffer head, which calls mmb_mark_buffer_dirty() and triggers a
"!buffer_uptodate(bh)" warning in mark_buffer_dirty().
Fix this by introducing fat_update_dotdot_de() and
fat_sync_update_dotdot_de() in fs/fat/dir.c, used by both VFAT and MSDOS
cross-directory rename and rollback paths. The helpers lock the buffer head
and check buffer_uptodate() before modifying the entry. If the buffer is
not uptodate, unlock it and return -EIO, preventing mmb_mark_buffer_dirty()
from being called on a non-uptodate buffer. fat_sync_update_dotdot_de()
preserves the unconditional buffer sync in the MSDOS rename rollback path.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Assisted-by: Gemini:gemini-3.8-flash syzbot
Reported-by: syzbot+b0aebd03565f5774f7f8@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=b0aebd03565f5774f7f8
Link: https://syzkaller.appspot.com/ai_job?id=f915c371-eb83-48b9-af21-45cf1fd21ba0
Signed-off-by: Krystian Kaniewski <krystianmkaniewski@gmail.com>
---
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 35bdb6294..cee06e635 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -941,6 +941,40 @@ int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
}
EXPORT_SYMBOL_GPL(fat_get_dotdot_entry);
+static int __fat_update_dotdot_de(struct inode *dir, struct inode *inode,
+ struct buffer_head *dotdot_bh,
+ struct msdos_dir_entry *dotdot_de,
+ bool force_sync)
+{
+ lock_buffer(dotdot_bh);
+ if (!buffer_uptodate(dotdot_bh)) {
+ unlock_buffer(dotdot_bh);
+ return -EIO;
+ }
+ fat_set_start(dotdot_de, MSDOS_I(dir)->i_logstart);
+ mmb_mark_buffer_dirty(dotdot_bh, &MSDOS_I(inode)->i_metadata_bhs);
+ unlock_buffer(dotdot_bh);
+ if (force_sync || IS_DIRSYNC(dir))
+ return sync_dirty_buffer(dotdot_bh);
+ return 0;
+}
+
+int fat_update_dotdot_de(struct inode *dir, struct inode *inode,
+ struct buffer_head *dotdot_bh,
+ struct msdos_dir_entry *dotdot_de)
+{
+ return __fat_update_dotdot_de(dir, inode, dotdot_bh, dotdot_de, false);
+}
+EXPORT_SYMBOL_GPL(fat_update_dotdot_de);
+
+int fat_sync_update_dotdot_de(struct inode *dir, struct inode *inode,
+ struct buffer_head *dotdot_bh,
+ struct msdos_dir_entry *dotdot_de)
+{
+ return __fat_update_dotdot_de(dir, inode, dotdot_bh, dotdot_de, true);
+}
+EXPORT_SYMBOL_GPL(fat_sync_update_dotdot_de);
+
/* See if directory is empty */
int fat_dir_empty(struct inode *dir)
{
diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 61338413d..d51d3c11e 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -339,6 +339,12 @@ extern int fat_scan_logstart(struct inode *dir, int i_logstart,
struct fat_slot_info *sinfo);
extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
struct msdos_dir_entry **de);
+extern int fat_update_dotdot_de(struct inode *dir, struct inode *inode,
+ struct buffer_head *dotdot_bh,
+ struct msdos_dir_entry *dotdot_de);
+extern int fat_sync_update_dotdot_de(struct inode *dir, struct inode *inode,
+ struct buffer_head *dotdot_bh,
+ struct msdos_dir_entry *dotdot_de);
extern int fat_alloc_new_dir(struct inode *dir, struct timespec64 *ts);
extern int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
struct fat_slot_info *sinfo);
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
index d46d1a385..31faaeae8 100644
--- a/fs/fat/namei_msdos.c
+++ b/fs/fat/namei_msdos.c
@@ -527,14 +527,10 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
}
if (update_dotdot) {
- fat_set_start(dotdot_de, MSDOS_I(new_dir)->i_logstart);
- mmb_mark_buffer_dirty(dotdot_bh,
- &MSDOS_I(old_inode)->i_metadata_bhs);
- if (IS_DIRSYNC(new_dir)) {
- err = sync_dirty_buffer(dotdot_bh);
- if (err)
- goto error_dotdot;
- }
+ err = fat_update_dotdot_de(new_dir, old_inode, dotdot_bh,
+ dotdot_de);
+ if (err)
+ goto error_dotdot;
drop_nlink(old_dir);
if (!new_inode)
inc_nlink(new_dir);
@@ -565,12 +561,9 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
/* data cluster is shared, serious corruption */
corrupt = 1;
- if (update_dotdot) {
- fat_set_start(dotdot_de, MSDOS_I(old_dir)->i_logstart);
- mmb_mark_buffer_dirty(dotdot_bh,
- &MSDOS_I(old_inode)->i_metadata_bhs);
- corrupt |= sync_dirty_buffer(dotdot_bh);
- }
+ if (update_dotdot)
+ corrupt |= fat_sync_update_dotdot_de(old_dir, old_inode,
+ dotdot_bh, dotdot_de);
error_inode:
fat_detach(old_inode);
fat_attach(old_inode, old_sinfo.i_pos);
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index da3e89c0b..56da78455 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -909,16 +909,6 @@ static int vfat_sync_ipos(struct inode *dir, struct inode *inode)
return 0;
}
-static int vfat_update_dotdot_de(struct inode *dir, struct inode *inode,
- struct buffer_head *dotdot_bh,
- struct msdos_dir_entry *dotdot_de)
-{
- fat_set_start(dotdot_de, MSDOS_I(dir)->i_logstart);
- mmb_mark_buffer_dirty(dotdot_bh, &MSDOS_I(inode)->i_metadata_bhs);
- if (IS_DIRSYNC(dir))
- return sync_dirty_buffer(dotdot_bh);
- return 0;
-}
static void vfat_update_dir_metadata(struct inode *dir, struct timespec64 *ts)
{
@@ -981,8 +971,8 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
goto error_inode;
if (dotdot_de) {
- err = vfat_update_dotdot_de(new_dir, old_inode, dotdot_bh,
- dotdot_de);
+ err = fat_update_dotdot_de(new_dir, old_inode, dotdot_bh,
+ dotdot_de);
if (err)
goto error_dotdot;
drop_nlink(old_dir);
@@ -1014,8 +1004,8 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
corrupt = 1;
if (dotdot_de) {
- corrupt |= vfat_update_dotdot_de(old_dir, old_inode, dotdot_bh,
- dotdot_de);
+ corrupt |= fat_update_dotdot_de(old_dir, old_inode, dotdot_bh,
+ dotdot_de);
}
error_inode:
fat_detach(old_inode);
@@ -1103,14 +1093,14 @@ static int vfat_rename_exchange(struct inode *old_dir, struct dentry *old_dentry
/* update ".." directory entry info */
if (old_dotdot_de) {
- err = vfat_update_dotdot_de(new_dir, old_inode, old_dotdot_bh,
- old_dotdot_de);
+ err = fat_update_dotdot_de(new_dir, old_inode, old_dotdot_bh,
+ old_dotdot_de);
if (err)
goto error_old_dotdot;
}
if (new_dotdot_de) {
- err = vfat_update_dotdot_de(old_dir, new_inode, new_dotdot_bh,
- new_dotdot_de);
+ err = fat_update_dotdot_de(old_dir, new_inode, new_dotdot_bh,
+ new_dotdot_de);
if (err)
goto error_new_dotdot;
}
@@ -1137,14 +1127,14 @@ static int vfat_rename_exchange(struct inode *old_dir, struct dentry *old_dentry
error_new_dotdot:
if (new_dotdot_de) {
- corrupt |= vfat_update_dotdot_de(new_dir, new_inode,
- new_dotdot_bh, new_dotdot_de);
+ corrupt |= fat_update_dotdot_de(new_dir, new_inode,
+ new_dotdot_bh, new_dotdot_de);
}
error_old_dotdot:
if (old_dotdot_de) {
- corrupt |= vfat_update_dotdot_de(old_dir, old_inode,
- old_dotdot_bh, old_dotdot_de);
+ corrupt |= fat_update_dotdot_de(old_dir, old_inode,
+ old_dotdot_bh, old_dotdot_de);
}
error_exchange:
base-commit: 93f51579e7df248780214094418f205253383cc5
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] fat: validate dotdot buffers in VFAT and MSDOS rename and rollback
2026-09-29 9:00 ` [PATCH] fat: validate dotdot buffers in VFAT and MSDOS rename and rollback Krystian Kaniewski
@ 2026-09-30 8:02 ` OGAWA Hirofumi
2026-09-30 12:17 ` Krystian Kaniewski
0 siblings, 1 reply; 4+ messages in thread
From: OGAWA Hirofumi @ 2026-09-30 8:02 UTC (permalink / raw)
To: Krystian Kaniewski
Cc: linux-kernel, linux-fsdevel, syzbot+b0aebd03565f5774f7f8
Krystian Kaniewski <krystianmkaniewski@gmail.com> writes:
> During cross-directory rename operations with synchronous directory updates
> enabled in VFAT and MSDOS, updating the ".." directory entry writes the
> buffer via sync_dirty_buffer(). If this write fails due to an I/O error,
> the block layer clears the BH_Uptodate flag. When rename enters its error
> rollback path, it attempts to update the ".." directory entry again with
> the same buffer head, which calls mmb_mark_buffer_dirty() and triggers a
> "!buffer_uptodate(bh)" warning in mark_buffer_dirty().
>
> Fix this by introducing fat_update_dotdot_de() and
> fat_sync_update_dotdot_de() in fs/fat/dir.c, used by both VFAT and MSDOS
> cross-directory rename and rollback paths. The helpers lock the buffer head
> and check buffer_uptodate() before modifying the entry. If the buffer is
> not uptodate, unlock it and return -EIO, preventing mmb_mark_buffer_dirty()
> from being called on a non-uptodate buffer. fat_sync_update_dotdot_de()
> preserves the unconditional buffer sync in the MSDOS rename rollback path.
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Assisted-by: Gemini:gemini-3.8-flash syzbot
> Reported-by: syzbot+b0aebd03565f5774f7f8@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=b0aebd03565f5774f7f8
> Link: https://syzkaller.appspot.com/ai_job?id=f915c371-eb83-48b9-af21-45cf1fd21ba0
> Signed-off-by: Krystian Kaniewski <krystianmkaniewski@gmail.com>
>
> ---
>
> diff --git a/fs/fat/dir.c b/fs/fat/dir.c
> index 35bdb6294..cee06e635 100644
> --- a/fs/fat/dir.c
> +++ b/fs/fat/dir.c
> @@ -941,6 +941,40 @@ int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
> }
> EXPORT_SYMBOL_GPL(fat_get_dotdot_entry);
>
> +static int __fat_update_dotdot_de(struct inode *dir, struct inode *inode,
> + struct buffer_head *dotdot_bh,
> + struct msdos_dir_entry *dotdot_de,
> + bool force_sync)
> +{
> + lock_buffer(dotdot_bh);
This looks like unnecessarily wait the completion of buffer I/O, isn't
it? I guess, it is ok to give up to revert if surely I/O error, because
the reverted buffer will be the I/O error again.
Thanks.
> + if (!buffer_uptodate(dotdot_bh)) {
> + unlock_buffer(dotdot_bh);
> + return -EIO;
> + }
> + fat_set_start(dotdot_de, MSDOS_I(dir)->i_logstart);
> + mmb_mark_buffer_dirty(dotdot_bh, &MSDOS_I(inode)->i_metadata_bhs);
> + unlock_buffer(dotdot_bh);
> + if (force_sync || IS_DIRSYNC(dir))
> + return sync_dirty_buffer(dotdot_bh);
> + return 0;
> +}
> +
> +int fat_update_dotdot_de(struct inode *dir, struct inode *inode,
> + struct buffer_head *dotdot_bh,
> + struct msdos_dir_entry *dotdot_de)
> +{
> + return __fat_update_dotdot_de(dir, inode, dotdot_bh, dotdot_de, false);
> +}
> +EXPORT_SYMBOL_GPL(fat_update_dotdot_de);
> +
> +int fat_sync_update_dotdot_de(struct inode *dir, struct inode *inode,
> + struct buffer_head *dotdot_bh,
> + struct msdos_dir_entry *dotdot_de)
> +{
> + return __fat_update_dotdot_de(dir, inode, dotdot_bh, dotdot_de, true);
> +}
> +EXPORT_SYMBOL_GPL(fat_sync_update_dotdot_de);
> +
> /* See if directory is empty */
> int fat_dir_empty(struct inode *dir)
> {
> diff --git a/fs/fat/fat.h b/fs/fat/fat.h
> index 61338413d..d51d3c11e 100644
> --- a/fs/fat/fat.h
> +++ b/fs/fat/fat.h
> @@ -339,6 +339,12 @@ extern int fat_scan_logstart(struct inode *dir, int i_logstart,
> struct fat_slot_info *sinfo);
> extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
> struct msdos_dir_entry **de);
> +extern int fat_update_dotdot_de(struct inode *dir, struct inode *inode,
> + struct buffer_head *dotdot_bh,
> + struct msdos_dir_entry *dotdot_de);
> +extern int fat_sync_update_dotdot_de(struct inode *dir, struct inode *inode,
> + struct buffer_head *dotdot_bh,
> + struct msdos_dir_entry *dotdot_de);
> extern int fat_alloc_new_dir(struct inode *dir, struct timespec64 *ts);
> extern int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
> struct fat_slot_info *sinfo);
> diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
> index d46d1a385..31faaeae8 100644
> --- a/fs/fat/namei_msdos.c
> +++ b/fs/fat/namei_msdos.c
> @@ -527,14 +527,10 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
> }
>
> if (update_dotdot) {
> - fat_set_start(dotdot_de, MSDOS_I(new_dir)->i_logstart);
> - mmb_mark_buffer_dirty(dotdot_bh,
> - &MSDOS_I(old_inode)->i_metadata_bhs);
> - if (IS_DIRSYNC(new_dir)) {
> - err = sync_dirty_buffer(dotdot_bh);
> - if (err)
> - goto error_dotdot;
> - }
> + err = fat_update_dotdot_de(new_dir, old_inode, dotdot_bh,
> + dotdot_de);
> + if (err)
> + goto error_dotdot;
> drop_nlink(old_dir);
> if (!new_inode)
> inc_nlink(new_dir);
> @@ -565,12 +561,9 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
> /* data cluster is shared, serious corruption */
> corrupt = 1;
>
> - if (update_dotdot) {
> - fat_set_start(dotdot_de, MSDOS_I(old_dir)->i_logstart);
> - mmb_mark_buffer_dirty(dotdot_bh,
> - &MSDOS_I(old_inode)->i_metadata_bhs);
> - corrupt |= sync_dirty_buffer(dotdot_bh);
> - }
> + if (update_dotdot)
> + corrupt |= fat_sync_update_dotdot_de(old_dir, old_inode,
> + dotdot_bh, dotdot_de);
> error_inode:
> fat_detach(old_inode);
> fat_attach(old_inode, old_sinfo.i_pos);
> diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
> index da3e89c0b..56da78455 100644
> --- a/fs/fat/namei_vfat.c
> +++ b/fs/fat/namei_vfat.c
> @@ -909,16 +909,6 @@ static int vfat_sync_ipos(struct inode *dir, struct inode *inode)
> return 0;
> }
>
> -static int vfat_update_dotdot_de(struct inode *dir, struct inode *inode,
> - struct buffer_head *dotdot_bh,
> - struct msdos_dir_entry *dotdot_de)
> -{
> - fat_set_start(dotdot_de, MSDOS_I(dir)->i_logstart);
> - mmb_mark_buffer_dirty(dotdot_bh, &MSDOS_I(inode)->i_metadata_bhs);
> - if (IS_DIRSYNC(dir))
> - return sync_dirty_buffer(dotdot_bh);
> - return 0;
> -}
>
> static void vfat_update_dir_metadata(struct inode *dir, struct timespec64 *ts)
> {
> @@ -981,8 +971,8 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
> goto error_inode;
>
> if (dotdot_de) {
> - err = vfat_update_dotdot_de(new_dir, old_inode, dotdot_bh,
> - dotdot_de);
> + err = fat_update_dotdot_de(new_dir, old_inode, dotdot_bh,
> + dotdot_de);
> if (err)
> goto error_dotdot;
> drop_nlink(old_dir);
> @@ -1014,8 +1004,8 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
> corrupt = 1;
>
> if (dotdot_de) {
> - corrupt |= vfat_update_dotdot_de(old_dir, old_inode, dotdot_bh,
> - dotdot_de);
> + corrupt |= fat_update_dotdot_de(old_dir, old_inode, dotdot_bh,
> + dotdot_de);
> }
> error_inode:
> fat_detach(old_inode);
> @@ -1103,14 +1093,14 @@ static int vfat_rename_exchange(struct inode *old_dir, struct dentry *old_dentry
>
> /* update ".." directory entry info */
> if (old_dotdot_de) {
> - err = vfat_update_dotdot_de(new_dir, old_inode, old_dotdot_bh,
> - old_dotdot_de);
> + err = fat_update_dotdot_de(new_dir, old_inode, old_dotdot_bh,
> + old_dotdot_de);
> if (err)
> goto error_old_dotdot;
> }
> if (new_dotdot_de) {
> - err = vfat_update_dotdot_de(old_dir, new_inode, new_dotdot_bh,
> - new_dotdot_de);
> + err = fat_update_dotdot_de(old_dir, new_inode, new_dotdot_bh,
> + new_dotdot_de);
> if (err)
> goto error_new_dotdot;
> }
> @@ -1137,14 +1127,14 @@ static int vfat_rename_exchange(struct inode *old_dir, struct dentry *old_dentry
>
> error_new_dotdot:
> if (new_dotdot_de) {
> - corrupt |= vfat_update_dotdot_de(new_dir, new_inode,
> - new_dotdot_bh, new_dotdot_de);
> + corrupt |= fat_update_dotdot_de(new_dir, new_inode,
> + new_dotdot_bh, new_dotdot_de);
> }
>
> error_old_dotdot:
> if (old_dotdot_de) {
> - corrupt |= vfat_update_dotdot_de(old_dir, old_inode,
> - old_dotdot_bh, old_dotdot_de);
> + corrupt |= fat_update_dotdot_de(old_dir, old_inode,
> + old_dotdot_bh, old_dotdot_de);
> }
>
> error_exchange:
>
> base-commit: 93f51579e7df248780214094418f205253383cc5
>
--
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] fat: validate dotdot buffers in VFAT and MSDOS rename and rollback
2026-09-30 8:02 ` OGAWA Hirofumi
@ 2026-09-30 12:17 ` Krystian Kaniewski
0 siblings, 0 replies; 4+ messages in thread
From: Krystian Kaniewski @ 2026-09-30 12:17 UTC (permalink / raw)
To: OGAWA Hirofumi; +Cc: linux-kernel, linux-fsdevel, syzbot+b0aebd03565f5774f7f8
On 9/30/26 10:02, OGAWA Hirofumi wrote:
>> diff --git a/fs/fat/dir.c b/fs/fat/dir.c
>> index 35bdb6294..cee06e635 100644
>> --- a/fs/fat/dir.c
>> +++ b/fs/fat/dir.c
>> @@ -941,6 +941,40 @@ int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
>> }
>> EXPORT_SYMBOL_GPL(fat_get_dotdot_entry);
>>
>> +static int __fat_update_dotdot_de(struct inode *dir, struct inode *inode,
>> + struct buffer_head *dotdot_bh,
>> + struct msdos_dir_entry *dotdot_de,
>> + bool force_sync)
>> +{
>> + lock_buffer(dotdot_bh);
>
> This looks like unnecessarily wait the completion of buffer I/O, isn't
> it? I guess, it is ok to give up to revert if surely I/O error, because
> the reverted buffer will be the I/O error again.
>
> Thanks.
>
Indeed, lock_buffer() may be a bit of an overkill here. I’ll rework the patch to track the buffer whose synchronous write failed and skip rollback operations that would modify the same buffer, while still rolling back entries stored in other buffers.
Thanks for the suggestion.
--
Krystian Kaniewski
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-30 12:17 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-14 16:38 [syzbot] [exfat?] WARNING in vfat_update_dotdot_de syzbot
2026-09-29 9:00 ` [PATCH] fat: validate dotdot buffers in VFAT and MSDOS rename and rollback Krystian Kaniewski
2026-09-30 8:02 ` OGAWA Hirofumi
2026-09-30 12:17 ` Krystian Kaniewski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®