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-7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat

Pull exfat updates from Namjae Jeon:

- Improve error code handling and four cleanups

- Reduce unnecessary valid_size extension during mmap write to avoid
over-extending writes

- Optimize consecutive FAT entry reads by caching buffer heads in
__exfat_ent_get to significantly reduce sb_bread() calls

- Add multi-cluster (contiguous cluster) support to exfat_get_cluster()
and exfat_map_cluster() for better sequential read performance,
especially on small cluster sizes

* tag 'exfat-for-7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat:
exfat: add blank line after declarations
exfat: remove unnecessary else after return statement
exfat: support multi-cluster for exfat_get_cluster
exfat: return the start of next cache in exfat_cache_lookup
exfat: tweak cluster cache to support zero offset
exfat: support multi-cluster for exfat_map_cluster
exfat: remove handling of non-file types in exfat_map_cluster
exfat: reuse cache to improve exfat_get_cluster
exfat: reduce the number of parameters for exfat_get_cluster()
exfat: remove the unreachable warning for cache miss cases
exfat: remove the check for infinite cluster chain loop
exfat: improve exfat_find_last_cluster
exfat: improve exfat_count_num_clusters
exfat: support reuse buffer head for exfat_ent_get
exfat: add cache option for __exfat_ent_get
exfat: reduce unnecessary writes during mmap write
exfat: improve error code handling in exfat_find_empty_entry()

+170 -125
+96 -53
fs/exfat/cache.c
··· 80 80 list_move(&cache->cache_list, &ei->cache_lru); 81 81 } 82 82 83 - static unsigned int exfat_cache_lookup(struct inode *inode, 84 - unsigned int fclus, struct exfat_cache_id *cid, 83 + /* 84 + * Find the cache that covers or precedes 'fclus' and return the last 85 + * cluster before the next cache range. 86 + */ 87 + static inline unsigned int 88 + exfat_cache_lookup(struct inode *inode, struct exfat_cache_id *cid, 89 + unsigned int fclus, unsigned int end, 85 90 unsigned int *cached_fclus, unsigned int *cached_dclus) 86 91 { 87 92 struct exfat_inode_info *ei = EXFAT_I(inode); 88 93 static struct exfat_cache nohit = { .fcluster = 0, }; 89 94 struct exfat_cache *hit = &nohit, *p; 90 - unsigned int offset = EXFAT_EOF_CLUSTER; 95 + unsigned int tail = 0; /* End boundary of hit cache */ 91 96 97 + /* 98 + * Search range [fclus, end]. Stop early if: 99 + * 1. Cache covers entire range, or 100 + * 2. Next cache starts at current cache tail 101 + */ 92 102 spin_lock(&ei->cache_lru_lock); 93 103 list_for_each_entry(p, &ei->cache_lru, cache_list) { 94 104 /* Find the cache of "fclus" or nearest cache. */ 95 - if (p->fcluster <= fclus && hit->fcluster < p->fcluster) { 105 + if (p->fcluster <= fclus) { 106 + if (p->fcluster < hit->fcluster) 107 + continue; 108 + 96 109 hit = p; 97 - if (hit->fcluster + hit->nr_contig < fclus) { 98 - offset = hit->nr_contig; 99 - } else { 100 - offset = fclus - hit->fcluster; 110 + tail = hit->fcluster + hit->nr_contig; 111 + 112 + /* Current cache covers [fclus, end] completely */ 113 + if (tail >= end) 101 114 break; 102 - } 115 + } else if (p->fcluster <= end) { 116 + end = p->fcluster - 1; 117 + 118 + /* 119 + * If we have a hit and next cache starts within/at 120 + * its tail, caches are contiguous, stop searching. 121 + */ 122 + if (tail && tail >= end) 123 + break; 103 124 } 104 125 } 105 126 if (hit != &nohit) { 106 - exfat_cache_update_lru(inode, hit); 127 + unsigned int offset; 107 128 129 + exfat_cache_update_lru(inode, hit); 108 130 cid->id = ei->cache_valid_id; 109 131 cid->nr_contig = hit->nr_contig; 110 132 cid->fcluster = hit->fcluster; 111 133 cid->dcluster = hit->dcluster; 134 + 135 + offset = min(cid->nr_contig, fclus - cid->fcluster); 112 136 *cached_fclus = cid->fcluster + offset; 113 137 *cached_dclus = cid->dcluster + offset; 114 138 } 115 139 spin_unlock(&ei->cache_lru_lock); 116 140 117 - return offset; 141 + /* Return next cache start or 'end' if no more caches */ 142 + return end; 118 143 } 119 144 120 145 static struct exfat_cache *exfat_cache_merge(struct inode *inode, ··· 259 234 } 260 235 261 236 int exfat_get_cluster(struct inode *inode, unsigned int cluster, 262 - unsigned int *fclus, unsigned int *dclus, 263 - unsigned int *last_dclus, int allow_eof) 237 + unsigned int *dclus, unsigned int *count, 238 + unsigned int *last_dclus) 264 239 { 265 240 struct super_block *sb = inode->i_sb; 266 - struct exfat_sb_info *sbi = EXFAT_SB(sb); 267 - unsigned int limit = sbi->num_clusters; 268 241 struct exfat_inode_info *ei = EXFAT_I(inode); 242 + struct buffer_head *bh = NULL; 269 243 struct exfat_cache_id cid; 270 - unsigned int content; 244 + unsigned int content, fclus; 245 + unsigned int end = cluster + *count - 1; 271 246 272 247 if (ei->start_clu == EXFAT_FREE_CLUSTER) { 273 248 exfat_fs_error(sb, ··· 276 251 return -EIO; 277 252 } 278 253 279 - *fclus = 0; 254 + fclus = 0; 280 255 *dclus = ei->start_clu; 281 256 *last_dclus = *dclus; 282 257 283 258 /* 284 - * Don`t use exfat_cache if zero offset or non-cluster allocation 259 + * This case should not exist, as exfat_map_cluster function doesn't 260 + * call this routine when start_clu == EXFAT_EOF_CLUSTER. 261 + * This case is retained here for routine completeness. 285 262 */ 286 - if (cluster == 0 || *dclus == EXFAT_EOF_CLUSTER) 263 + if (*dclus == EXFAT_EOF_CLUSTER) { 264 + *count = 0; 287 265 return 0; 288 - 289 - cache_init(&cid, EXFAT_EOF_CLUSTER, EXFAT_EOF_CLUSTER); 290 - 291 - if (exfat_cache_lookup(inode, cluster, &cid, fclus, dclus) == 292 - EXFAT_EOF_CLUSTER) { 293 - /* 294 - * dummy, always not contiguous 295 - * This is reinitialized by cache_init(), later. 296 - */ 297 - WARN_ON(cid.id != EXFAT_CACHE_VALID || 298 - cid.fcluster != EXFAT_EOF_CLUSTER || 299 - cid.dcluster != EXFAT_EOF_CLUSTER || 300 - cid.nr_contig != 0); 301 266 } 302 267 303 - if (*fclus == cluster) 268 + /* If only the first cluster is needed, return now. */ 269 + if (fclus == cluster && *count == 1) 304 270 return 0; 305 271 306 - while (*fclus < cluster) { 307 - /* prevent the infinite loop of cluster chain */ 308 - if (*fclus > limit) { 309 - exfat_fs_error(sb, 310 - "detected the cluster chain loop (i_pos %u)", 311 - (*fclus)); 312 - return -EIO; 313 - } 272 + cache_init(&cid, fclus, *dclus); 273 + /* 274 + * Update the 'end' to exclude the next cache range, as clusters in 275 + * different cache are typically not contiguous. 276 + */ 277 + end = exfat_cache_lookup(inode, &cid, cluster, end, &fclus, dclus); 314 278 315 - if (exfat_ent_get(sb, *dclus, &content)) 279 + /* Return if the cache covers the entire range. */ 280 + if (cid.fcluster + cid.nr_contig >= end) { 281 + *count = end - cluster + 1; 282 + return 0; 283 + } 284 + 285 + /* Find the first cluster we need. */ 286 + while (fclus < cluster) { 287 + if (exfat_ent_get(sb, *dclus, &content, &bh)) 316 288 return -EIO; 317 289 318 290 *last_dclus = *dclus; 319 291 *dclus = content; 320 - (*fclus)++; 292 + fclus++; 321 293 322 - if (content == EXFAT_EOF_CLUSTER) { 323 - if (!allow_eof) { 324 - exfat_fs_error(sb, 325 - "invalid cluster chain (i_pos %u, last_clus 0x%08x is EOF)", 326 - *fclus, (*last_dclus)); 327 - return -EIO; 328 - } 329 - 294 + if (content == EXFAT_EOF_CLUSTER) 330 295 break; 331 - } 332 296 333 297 if (!cache_contiguous(&cid, *dclus)) 334 - cache_init(&cid, *fclus, *dclus); 298 + cache_init(&cid, fclus, *dclus); 335 299 } 336 300 301 + /* 302 + * Now the cid cache contains the first cluster requested, collect 303 + * the remaining clusters of this contiguous extent. 304 + */ 305 + if (*dclus != EXFAT_EOF_CLUSTER) { 306 + unsigned int clu = *dclus; 307 + 308 + while (fclus < end) { 309 + if (exfat_ent_get(sb, clu, &content, &bh)) 310 + return -EIO; 311 + if (++clu != content) 312 + break; 313 + fclus++; 314 + } 315 + cid.nr_contig = fclus - cid.fcluster; 316 + *count = fclus - cluster + 1; 317 + 318 + /* 319 + * Cache this discontiguous cluster, we'll definitely need 320 + * it later 321 + */ 322 + if (fclus < end && content != EXFAT_EOF_CLUSTER) { 323 + exfat_cache_add(inode, &cid); 324 + cache_init(&cid, fclus + 1, content); 325 + } 326 + } else { 327 + *count = 0; 328 + } 329 + brelse(bh); 337 330 exfat_cache_add(inode, &cid); 338 331 return 0; 339 332 }
+3 -4
fs/exfat/exfat_fs.h
··· 432 432 int exfat_clear_volume_dirty(struct super_block *sb); 433 433 434 434 /* fatent.c */ 435 - #define exfat_get_next_cluster(sb, pclu) exfat_ent_get(sb, *(pclu), pclu) 435 + #define exfat_get_next_cluster(sb, pclu) exfat_ent_get(sb, *(pclu), pclu, NULL) 436 436 437 437 int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc, 438 438 struct exfat_chain *p_chain, bool sync_bmap); 439 439 int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain); 440 440 int exfat_ent_get(struct super_block *sb, unsigned int loc, 441 - unsigned int *content); 441 + unsigned int *content, struct buffer_head **last); 442 442 int exfat_ent_set(struct super_block *sb, unsigned int loc, 443 443 unsigned int content); 444 444 int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain, ··· 486 486 void exfat_cache_shutdown(void); 487 487 void exfat_cache_inval_inode(struct inode *inode); 488 488 int exfat_get_cluster(struct inode *inode, unsigned int cluster, 489 - unsigned int *fclus, unsigned int *dclus, 490 - unsigned int *last_dclus, int allow_eof); 489 + unsigned int *dclus, unsigned int *count, unsigned int *last_dclus); 491 490 492 491 /* dir.c */ 493 492 extern const struct inode_operations exfat_dir_inode_operations;
+41 -21
fs/exfat/fatent.c
··· 36 36 } 37 37 38 38 static int __exfat_ent_get(struct super_block *sb, unsigned int loc, 39 - unsigned int *content) 39 + unsigned int *content, struct buffer_head **last) 40 40 { 41 41 unsigned int off; 42 42 sector_t sec; 43 - struct buffer_head *bh; 43 + struct buffer_head *bh = last ? *last : NULL; 44 44 45 45 sec = FAT_ENT_OFFSET_SECTOR(sb, loc); 46 46 off = FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc); 47 47 48 - bh = sb_bread(sb, sec); 49 - if (!bh) 50 - return -EIO; 48 + if (!bh || bh->b_blocknr != sec || !buffer_uptodate(bh)) { 49 + brelse(bh); 50 + bh = sb_bread(sb, sec); 51 + if (last) 52 + *last = bh; 53 + if (unlikely(!bh)) 54 + return -EIO; 55 + } 51 56 52 57 *content = le32_to_cpu(*(__le32 *)(&bh->b_data[off])); 53 58 ··· 60 55 if (*content > EXFAT_BAD_CLUSTER) 61 56 *content = EXFAT_EOF_CLUSTER; 62 57 63 - brelse(bh); 58 + if (!last) 59 + brelse(bh); 64 60 return 0; 65 61 } 66 62 ··· 88 82 return 0; 89 83 } 90 84 85 + /* 86 + * Caller must release the buffer_head if no error return. 87 + */ 91 88 int exfat_ent_get(struct super_block *sb, unsigned int loc, 92 - unsigned int *content) 89 + unsigned int *content, struct buffer_head **last) 93 90 { 94 91 struct exfat_sb_info *sbi = EXFAT_SB(sb); 95 - int err; 96 92 97 93 if (!is_valid_cluster(sbi, loc)) { 98 94 exfat_fs_error_ratelimit(sb, 99 95 "invalid access to FAT (entry 0x%08x)", 100 96 loc); 101 - return -EIO; 97 + goto err; 102 98 } 103 99 104 - err = __exfat_ent_get(sb, loc, content); 105 - if (err) { 100 + if (unlikely(__exfat_ent_get(sb, loc, content, last))) { 106 101 exfat_fs_error_ratelimit(sb, 107 - "failed to access to FAT (entry 0x%08x, err:%d)", 108 - loc, err); 109 - return err; 102 + "failed to access to FAT (entry 0x%08x)", 103 + loc); 104 + goto err; 110 105 } 111 106 112 - if (*content == EXFAT_FREE_CLUSTER) { 107 + if (unlikely(*content == EXFAT_FREE_CLUSTER)) { 113 108 exfat_fs_error_ratelimit(sb, 114 109 "invalid access to FAT free cluster (entry 0x%08x)", 115 110 loc); 116 - return -EIO; 111 + goto err; 117 112 } 118 113 119 - if (*content == EXFAT_BAD_CLUSTER) { 114 + if (unlikely(*content == EXFAT_BAD_CLUSTER)) { 120 115 exfat_fs_error_ratelimit(sb, 121 116 "invalid access to FAT bad cluster (entry 0x%08x)", 122 117 loc); 123 - return -EIO; 118 + goto err; 124 119 } 125 120 126 121 if (*content != EXFAT_EOF_CLUSTER && !is_valid_cluster(sbi, *content)) { 127 122 exfat_fs_error_ratelimit(sb, 128 123 "invalid access to FAT (entry 0x%08x) bogus content (0x%08x)", 129 124 loc, *content); 130 - return -EIO; 125 + goto err; 131 126 } 132 127 133 128 return 0; 129 + err: 130 + if (last) { 131 + brelse(*last); 132 + 133 + /* Avoid double release */ 134 + *last = NULL; 135 + } 136 + return -EIO; 134 137 } 135 138 136 139 int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain, ··· 207 192 if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { 208 193 int err; 209 194 unsigned int last_cluster = p_chain->dir + p_chain->size - 1; 195 + 210 196 do { 211 197 bool sync = false; 212 198 ··· 297 281 int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain, 298 282 unsigned int *ret_clu) 299 283 { 284 + struct buffer_head *bh = NULL; 300 285 unsigned int clu, next; 301 286 unsigned int count = 0; 302 287 ··· 310 293 do { 311 294 count++; 312 295 clu = next; 313 - if (exfat_ent_get(sb, clu, &next)) 296 + if (exfat_ent_get(sb, clu, &next, &bh)) 314 297 return -EIO; 315 298 } while (next != EXFAT_EOF_CLUSTER && count <= p_chain->size); 316 299 300 + brelse(bh); 317 301 if (p_chain->size != count) { 318 302 exfat_fs_error(sb, 319 303 "bogus directory size (clus : ondisk(%d) != counted(%d))", ··· 487 469 unsigned int i, count; 488 470 unsigned int clu; 489 471 struct exfat_sb_info *sbi = EXFAT_SB(sb); 472 + struct buffer_head *bh = NULL; 490 473 491 474 if (!p_chain->dir || p_chain->dir == EXFAT_EOF_CLUSTER) { 492 475 *ret_count = 0; ··· 503 484 count = 0; 504 485 for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters; i++) { 505 486 count++; 506 - if (exfat_ent_get(sb, clu, &clu)) 487 + if (exfat_ent_get(sb, clu, &clu, &bh)) 507 488 return -EIO; 508 489 if (clu == EXFAT_EOF_CLUSTER) 509 490 break; 510 491 } 511 492 493 + brelse(bh); 512 494 *ret_count = count; 513 495 514 496 /*
+7 -9
fs/exfat/file.c
··· 683 683 684 684 if (iocb->ki_pos > pos) { 685 685 ssize_t err = generic_write_sync(iocb, iocb->ki_pos - pos); 686 + 686 687 if (err < 0) 687 688 return err; 688 689 } ··· 709 708 static vm_fault_t exfat_page_mkwrite(struct vm_fault *vmf) 710 709 { 711 710 int err; 712 - struct vm_area_struct *vma = vmf->vma; 713 - struct file *file = vma->vm_file; 714 - struct inode *inode = file_inode(file); 711 + struct inode *inode = file_inode(vmf->vma->vm_file); 715 712 struct exfat_inode_info *ei = EXFAT_I(inode); 716 - loff_t start, end; 713 + loff_t new_valid_size; 717 714 718 715 if (!inode_trylock(inode)) 719 716 return VM_FAULT_RETRY; 720 717 721 - start = ((loff_t)vma->vm_pgoff << PAGE_SHIFT); 722 - end = min_t(loff_t, i_size_read(inode), 723 - start + vma->vm_end - vma->vm_start); 718 + new_valid_size = ((loff_t)vmf->pgoff + 1) << PAGE_SHIFT; 719 + new_valid_size = min(new_valid_size, i_size_read(inode)); 724 720 725 - if (ei->valid_size < end) { 726 - err = exfat_extend_valid_size(inode, end); 721 + if (ei->valid_size < new_valid_size) { 722 + err = exfat_extend_valid_size(inode, new_valid_size); 727 723 if (err < 0) { 728 724 inode_unlock(inode); 729 725 return vmf_fs_error(err);
+21 -36
fs/exfat/inode.c
··· 124 124 * *clu = (~0), if it's unable to allocate a new cluster 125 125 */ 126 126 static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset, 127 - unsigned int *clu, int create) 127 + unsigned int *clu, unsigned int *count, int create) 128 128 { 129 129 int ret; 130 130 unsigned int last_clu; ··· 147 147 148 148 *clu = last_clu = ei->start_clu; 149 149 150 - if (ei->flags == ALLOC_NO_FAT_CHAIN) { 151 - if (clu_offset > 0 && *clu != EXFAT_EOF_CLUSTER) { 152 - last_clu += clu_offset - 1; 153 - 154 - if (clu_offset == num_clusters) 155 - *clu = EXFAT_EOF_CLUSTER; 156 - else 157 - *clu += clu_offset; 150 + if (*clu == EXFAT_EOF_CLUSTER) { 151 + *count = 0; 152 + } else if (ei->flags == ALLOC_NO_FAT_CHAIN) { 153 + last_clu += num_clusters - 1; 154 + if (clu_offset < num_clusters) { 155 + *clu += clu_offset; 156 + *count = min(num_clusters - clu_offset, *count); 157 + } else { 158 + *clu = EXFAT_EOF_CLUSTER; 159 + *count = 0; 158 160 } 159 - } else if (ei->type == TYPE_FILE) { 160 - unsigned int fclus = 0; 161 + } else { 161 162 int err = exfat_get_cluster(inode, clu_offset, 162 - &fclus, clu, &last_clu, 1); 163 + clu, count, &last_clu); 163 164 if (err) 164 165 return -EIO; 165 - 166 - clu_offset -= fclus; 167 - } else { 168 - /* hint information */ 169 - if (clu_offset > 0 && ei->hint_bmap.off != EXFAT_EOF_CLUSTER && 170 - ei->hint_bmap.off > 0 && clu_offset >= ei->hint_bmap.off) { 171 - clu_offset -= ei->hint_bmap.off; 172 - /* hint_bmap.clu should be valid */ 173 - WARN_ON(ei->hint_bmap.clu < 2); 174 - *clu = ei->hint_bmap.clu; 175 - } 176 - 177 - while (clu_offset > 0 && *clu != EXFAT_EOF_CLUSTER) { 178 - last_clu = *clu; 179 - if (exfat_get_next_cluster(sb, clu)) 180 - return -EIO; 181 - clu_offset--; 182 - } 183 166 } 184 167 185 168 if (*clu == EXFAT_EOF_CLUSTER) { ··· 234 251 num_to_be_allocated--; 235 252 } 236 253 } 237 - 254 + *count = 1; 238 255 } 239 256 240 257 /* hint information */ ··· 253 270 unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits; 254 271 int err = 0; 255 272 unsigned long mapped_blocks = 0; 256 - unsigned int cluster, sec_offset; 273 + unsigned int cluster, sec_offset, count; 257 274 sector_t last_block; 258 275 sector_t phys = 0; 259 276 sector_t valid_blks; ··· 266 283 goto done; 267 284 268 285 /* Is this block already allocated? */ 286 + count = EXFAT_B_TO_CLU_ROUND_UP(bh_result->b_size, sbi); 269 287 err = exfat_map_cluster(inode, iblock >> sbi->sect_per_clus_bits, 270 - &cluster, create); 288 + &cluster, &count, create); 271 289 if (err) { 272 290 if (err != -ENOSPC) 273 291 exfat_fs_error_ratelimit(sb, ··· 284 300 sec_offset = iblock & (sbi->sect_per_clus - 1); 285 301 286 302 phys = exfat_cluster_to_sector(sbi, cluster) + sec_offset; 287 - mapped_blocks = sbi->sect_per_clus - sec_offset; 303 + mapped_blocks = ((unsigned long)count << sbi->sect_per_clus_bits) - sec_offset; 288 304 max_blocks = min(mapped_blocks, max_blocks); 289 305 290 306 map_bh(bh_result, sb, phys); ··· 495 511 exfat_write_failed(mapping, size); 496 512 497 513 return ret; 498 - } else 499 - size = pos + ret; 514 + } 515 + 516 + size = pos + ret; 500 517 501 518 if (rw == WRITE) { 502 519 /*
+2 -2
fs/exfat/namei.c
··· 304 304 struct exfat_chain *p_dir, int num_entries, 305 305 struct exfat_entry_set_cache *es) 306 306 { 307 - int dentry; 308 - unsigned int ret, last_clu; 307 + int dentry, ret; 308 + unsigned int last_clu; 309 309 loff_t size = 0; 310 310 struct exfat_chain clu; 311 311 struct super_block *sb = inode->i_sb;