Edward Adam Davis <eadavis@xxxxxx> writes: > syzbot reports data-race in fat32_ent_get/fat32_ent_put. > > CPU0(Task A) CPU1(Task B) > ==== ==== > vfs_write > new_sync_write > generic_file_write_iter > fat_write_begin > block_write_begin vfs_statfs > fat_get_block statfs_by_dentry > fat_add_cluster fat_statfs > fat_ent_write fat_count_free_clusters > fat32_ent_put fat32_ent_get > > Task A's write operation on CPU0 and Task B's read operation on CPU1 occur > simultaneously, generating an race condition. > > Add READ/WRITE_ONCE to solve the race condition that occurs when accessing > FAT32 entry. I mentioned about READ/WRITE_ONCE though, it was about possibility. Do we really need to add those? Can you clarify more? > diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c > index 1db348f8f887..a9eecd090d91 100644 > --- a/fs/fat/fatent.c > +++ b/fs/fat/fatent.c > @@ -146,8 +146,8 @@ static int fat16_ent_get(struct fat_entry *fatent) > > static int fat32_ent_get(struct fat_entry *fatent) > { > - int next = le32_to_cpu(*fatent->u.ent32_p) & 0x0fffffff; > - WARN_ON((unsigned long)fatent->u.ent32_p & (4 - 1)); > + int next = le32_to_cpu(READ_ONCE(*fatent->u.ent32_p)) & 0x0fffffff; > + WARN_ON((unsigned long)READ_ONCE(fatent->u.ent32_p) & (4 - 1)); Adding READ_ONCE() for pointer is broken. > if (next >= BAD_FAT32) > next = FAT_ENT_EOF; > return next; > @@ -187,8 +187,8 @@ static void fat16_ent_put(struct fat_entry *fatent, int new) > static void fat32_ent_put(struct fat_entry *fatent, int new) > { > WARN_ON(new & 0xf0000000); > - new |= le32_to_cpu(*fatent->u.ent32_p) & ~0x0fffffff; > - *fatent->u.ent32_p = cpu_to_le32(new); > + new |= le32_to_cpu(READ_ONCE(*fatent->u.ent32_p)) & ~0x0fffffff; > + WRITE_ONCE(*fatent->u.ent32_p, cpu_to_le32(new)); > mark_buffer_dirty_inode(fatent->bhs[0], fatent->fat_inode); > } Also READ_ONCE() is really required here? -- OGAWA Hirofumi <hirofumi@xxxxxxxxxxxxxxxxxx>