Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'exfat-for-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat

Pull exfat updates from Namjae Jeon:

- fix referencing wrong parent directory information during rename

- introduce a sys_tz mount option to use system timezone

- improve performance while zeroing a cluster with dirsync mount option

- fix slab-out-bounds in exat_clear_bitmap() reported from syzbot

* tag 'exfat-for-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat:
exfat: check if cluster num is valid
exfat: reduce block requests when zeroing a cluster
block: add sync_blockdev_range()
exfat: introduce mount option 'sys_tz'
exfat: fix referencing wrong parent directory information after renaming

+55 -61
+7
block/bdev.c
··· 200 200 } 201 201 EXPORT_SYMBOL(sync_blockdev); 202 202 203 + int sync_blockdev_range(struct block_device *bdev, loff_t lstart, loff_t lend) 204 + { 205 + return filemap_write_and_wait_range(bdev->bd_inode->i_mapping, 206 + lstart, lend); 207 + } 208 + EXPORT_SYMBOL(sync_blockdev_range); 209 + 203 210 /* 204 211 * Write out and wait upon all dirty data associated with this 205 212 * device. Filesystem data as well as the underlying block
+6 -2
fs/exfat/balloc.c
··· 148 148 struct super_block *sb = inode->i_sb; 149 149 struct exfat_sb_info *sbi = EXFAT_SB(sb); 150 150 151 - WARN_ON(clu < EXFAT_FIRST_CLUSTER); 151 + if (!is_valid_cluster(sbi, clu)) 152 + return -EINVAL; 153 + 152 154 ent_idx = CLUSTER_TO_BITMAP_ENT(clu); 153 155 i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx); 154 156 b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx); ··· 168 166 struct exfat_sb_info *sbi = EXFAT_SB(sb); 169 167 struct exfat_mount_options *opts = &sbi->options; 170 168 171 - WARN_ON(clu < EXFAT_FIRST_CLUSTER); 169 + if (!is_valid_cluster(sbi, clu)) 170 + return; 171 + 172 172 ent_idx = CLUSTER_TO_BITMAP_ENT(clu); 173 173 i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx); 174 174 b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
+7
fs/exfat/exfat_fs.h
··· 203 203 /* on error: continue, panic, remount-ro */ 204 204 enum exfat_error_mode errors; 205 205 unsigned utf8:1, /* Use of UTF-8 character set */ 206 + sys_tz:1, /* Use local timezone */ 206 207 discard:1, /* Issue discard requests on deletions */ 207 208 keep_last_dots:1; /* Keep trailing periods in paths */ 208 209 int time_offset; /* Offset of timestamps from UTC (in minutes) */ ··· 380 379 { 381 380 return ((sec - sbi->data_start_sector) >> sbi->sect_per_clus_bits) + 382 381 EXFAT_RESERVED_CLUSTERS; 382 + } 383 + 384 + static inline bool is_valid_cluster(struct exfat_sb_info *sbi, 385 + unsigned int clus) 386 + { 387 + return clus >= EXFAT_FIRST_CLUSTER && clus < sbi->num_clusters; 383 388 } 384 389 385 390 /* super.c */
+17 -30
fs/exfat/fatent.c
··· 6 6 #include <linux/slab.h> 7 7 #include <asm/unaligned.h> 8 8 #include <linux/buffer_head.h> 9 + #include <linux/blkdev.h> 9 10 10 11 #include "exfat_raw.h" 11 12 #include "exfat_fs.h" ··· 80 79 exfat_mirror_bh(sb, sec, bh); 81 80 brelse(bh); 82 81 return 0; 83 - } 84 - 85 - static inline bool is_valid_cluster(struct exfat_sb_info *sbi, 86 - unsigned int clus) 87 - { 88 - return clus >= EXFAT_FIRST_CLUSTER && clus < sbi->num_clusters; 89 82 } 90 83 91 84 int exfat_ent_get(struct super_block *sb, unsigned int loc, ··· 269 274 { 270 275 struct super_block *sb = dir->i_sb; 271 276 struct exfat_sb_info *sbi = EXFAT_SB(sb); 272 - struct buffer_head *bhs[MAX_BUF_PER_PAGE]; 273 - int nr_bhs = MAX_BUF_PER_PAGE; 277 + struct buffer_head *bh; 274 278 sector_t blknr, last_blknr; 275 - int err, i, n; 279 + int i; 276 280 277 281 blknr = exfat_cluster_to_sector(sbi, clu); 278 282 last_blknr = blknr + sbi->sect_per_clus; ··· 285 291 } 286 292 287 293 /* Zeroing the unused blocks on this cluster */ 288 - while (blknr < last_blknr) { 289 - for (n = 0; n < nr_bhs && blknr < last_blknr; n++, blknr++) { 290 - bhs[n] = sb_getblk(sb, blknr); 291 - if (!bhs[n]) { 292 - err = -ENOMEM; 293 - goto release_bhs; 294 - } 295 - memset(bhs[n]->b_data, 0, sb->s_blocksize); 296 - } 294 + for (i = blknr; i < last_blknr; i++) { 295 + bh = sb_getblk(sb, i); 296 + if (!bh) 297 + return -ENOMEM; 297 298 298 - err = exfat_update_bhs(bhs, n, IS_DIRSYNC(dir)); 299 - if (err) 300 - goto release_bhs; 301 - 302 - for (i = 0; i < n; i++) 303 - brelse(bhs[i]); 299 + memset(bh->b_data, 0, sb->s_blocksize); 300 + set_buffer_uptodate(bh); 301 + mark_buffer_dirty(bh); 302 + brelse(bh); 304 303 } 305 - return 0; 306 304 307 - release_bhs: 308 - exfat_err(sb, "failed zeroed sect %llu\n", (unsigned long long)blknr); 309 - for (i = 0; i < n; i++) 310 - bforget(bhs[i]); 311 - return err; 305 + if (IS_DIRSYNC(dir)) 306 + return sync_blockdev_range(sb->s_bdev, 307 + EXFAT_BLK_TO_B(blknr, sb), 308 + EXFAT_BLK_TO_B(last_blknr, sb) - 1); 309 + 310 + return 0; 312 311 } 313 312 314 313 int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
+8 -2
fs/exfat/misc.c
··· 74 74 ts->tv_sec += TIMEZONE_SEC(0x80 - tz_off); 75 75 } 76 76 77 + static inline int exfat_tz_offset(struct exfat_sb_info *sbi) 78 + { 79 + if (sbi->options.sys_tz) 80 + return -sys_tz.tz_minuteswest; 81 + return sbi->options.time_offset; 82 + } 83 + 77 84 /* Convert a EXFAT time/date pair to a UNIX date (seconds since 1 1 70). */ 78 85 void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, 79 86 u8 tz, __le16 time, __le16 date, u8 time_cs) ··· 103 96 /* Adjust timezone to UTC0. */ 104 97 exfat_adjust_tz(ts, tz & ~EXFAT_TZ_VALID); 105 98 else 106 - /* Convert from local time to UTC using time_offset. */ 107 - ts->tv_sec -= sbi->options.time_offset * SECS_PER_MIN; 99 + ts->tv_sec -= exfat_tz_offset(sbi) * SECS_PER_MIN; 108 100 } 109 101 110 102 /* Convert linear UNIX date to a EXFAT time/date pair. */
+1 -26
fs/exfat/namei.c
··· 1080 1080 1081 1081 exfat_remove_entries(inode, p_dir, oldentry, 0, 1082 1082 num_old_entries); 1083 + ei->dir = *p_dir; 1083 1084 ei->entry = newentry; 1084 1085 } else { 1085 1086 if (exfat_get_entry_type(epold) == TYPE_FILE) { ··· 1168 1167 return 0; 1169 1168 } 1170 1169 1171 - static void exfat_update_parent_info(struct exfat_inode_info *ei, 1172 - struct inode *parent_inode) 1173 - { 1174 - struct exfat_sb_info *sbi = EXFAT_SB(parent_inode->i_sb); 1175 - struct exfat_inode_info *parent_ei = EXFAT_I(parent_inode); 1176 - loff_t parent_isize = i_size_read(parent_inode); 1177 - 1178 - /* 1179 - * the problem that struct exfat_inode_info caches wrong parent info. 1180 - * 1181 - * because of flag-mismatch of ei->dir, 1182 - * there is abnormal traversing cluster chain. 1183 - */ 1184 - if (unlikely(parent_ei->flags != ei->dir.flags || 1185 - parent_isize != EXFAT_CLU_TO_B(ei->dir.size, sbi) || 1186 - parent_ei->start_clu != ei->dir.dir)) { 1187 - exfat_chain_set(&ei->dir, parent_ei->start_clu, 1188 - EXFAT_B_TO_CLU_ROUND_UP(parent_isize, sbi), 1189 - parent_ei->flags); 1190 - } 1191 - } 1192 - 1193 1170 /* rename or move a old file into a new file */ 1194 1171 static int __exfat_rename(struct inode *old_parent_inode, 1195 1172 struct exfat_inode_info *ei, struct inode *new_parent_inode, ··· 1198 1219 return -ENOENT; 1199 1220 } 1200 1221 1201 - exfat_update_parent_info(ei, old_parent_inode); 1202 - 1203 1222 exfat_chain_dup(&olddir, &ei->dir); 1204 1223 dentry = ei->entry; 1205 1224 ··· 1217 1240 exfat_err(sb, "abnormal access to deleted target dentry"); 1218 1241 goto out; 1219 1242 } 1220 - 1221 - exfat_update_parent_info(new_ei, new_parent_inode); 1222 1243 1223 1244 p_dir = &(new_ei->dir); 1224 1245 new_entry = new_ei->entry;
+8 -1
fs/exfat/super.c
··· 170 170 seq_puts(m, ",discard"); 171 171 if (opts->keep_last_dots) 172 172 seq_puts(m, ",keep_last_dots"); 173 - if (opts->time_offset) 173 + if (opts->sys_tz) 174 + seq_puts(m, ",sys_tz"); 175 + else if (opts->time_offset) 174 176 seq_printf(m, ",time_offset=%d", opts->time_offset); 175 177 return 0; 176 178 } ··· 216 214 Opt_errors, 217 215 Opt_discard, 218 216 Opt_keep_last_dots, 217 + Opt_sys_tz, 219 218 Opt_time_offset, 220 219 221 220 /* Deprecated options */ ··· 244 241 fsparam_enum("errors", Opt_errors, exfat_param_enums), 245 242 fsparam_flag("discard", Opt_discard), 246 243 fsparam_flag("keep_last_dots", Opt_keep_last_dots), 244 + fsparam_flag("sys_tz", Opt_sys_tz), 247 245 fsparam_s32("time_offset", Opt_time_offset), 248 246 __fsparam(NULL, "utf8", Opt_utf8, fs_param_deprecated, 249 247 NULL), ··· 301 297 break; 302 298 case Opt_keep_last_dots: 303 299 opts->keep_last_dots = 1; 300 + break; 301 + case Opt_sys_tz: 302 + opts->sys_tz = 1; 304 303 break; 305 304 case Opt_time_offset: 306 305 /*
+1
include/linux/blkdev.h
··· 1535 1535 #ifdef CONFIG_BLOCK 1536 1536 void invalidate_bdev(struct block_device *bdev); 1537 1537 int sync_blockdev(struct block_device *bdev); 1538 + int sync_blockdev_range(struct block_device *bdev, loff_t lstart, loff_t lend); 1538 1539 int sync_blockdev_nowait(struct block_device *bdev); 1539 1540 void sync_bdevs(bool wait); 1540 1541 void printk_all_partitions(void);