From: Chi Zhiling This patch introduces a parameter 'count' to support fetching multiple clusters in exfat_map_cluster. The returned 'count' indicates the number of consecutive clusters, or 0 when the input cluster offset is past EOF. And the 'count' is also an input parameter for the caller to specify the required number of clusters. Only NO_FAT_CHAIN files enable multi-cluster fetching in this patch. After this patch, the time proportion of exfat_get_block has decreased, The performance data is as follows: Cluster size: 512 bytes Sequential read of a 30GB NO_FAT_CHAIN file: 2.4GB/s -> 2.5 GB/s proportion of exfat_get_block: 10.8% -> 0.02% Signed-off-by: Chi Zhiling --- fs/exfat/inode.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c index 1062ce470cb1..8c49ab15eafe 100644 --- a/fs/exfat/inode.c +++ b/fs/exfat/inode.c @@ -124,7 +124,7 @@ void exfat_sync_inode(struct inode *inode) * *clu = (~0), if it's unable to allocate a new cluster */ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset, - unsigned int *clu, int create) + unsigned int *clu, unsigned int *count, int create) { int ret; unsigned int last_clu; @@ -147,20 +147,23 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset, *clu = last_clu = ei->start_clu; - if (ei->flags == ALLOC_NO_FAT_CHAIN) { - if (clu_offset > 0 && *clu != EXFAT_EOF_CLUSTER) { - last_clu += clu_offset - 1; - - if (clu_offset == num_clusters) - *clu = EXFAT_EOF_CLUSTER; - else - *clu += clu_offset; + if (*clu == EXFAT_EOF_CLUSTER) { + *count = 0; + } else if (ei->flags == ALLOC_NO_FAT_CHAIN) { + last_clu += num_clusters - 1; + if (clu_offset < num_clusters) { + *clu += clu_offset; + *count = num_clusters - clu_offset; + } else { + *clu = EXFAT_EOF_CLUSTER; + *count = 0; } } else if (ei->type == TYPE_FILE) { int err = exfat_get_cluster(inode, clu_offset, clu, &last_clu); if (err) return -EIO; + *count = (*clu == EXFAT_EOF_CLUSTER) ? 0 : 1; } else { unsigned int fclus = 0; /* hint information */ @@ -178,6 +181,7 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset, return -EIO; fclus++; } + *count = (*clu == EXFAT_EOF_CLUSTER) ? 0 : 1; } if (*clu == EXFAT_EOF_CLUSTER) { @@ -249,7 +253,7 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset, num_to_be_allocated--; } } - + *count = 1; } /* hint information */ @@ -268,7 +272,7 @@ static int exfat_get_block(struct inode *inode, sector_t iblock, unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits; int err = 0; unsigned long mapped_blocks = 0; - unsigned int cluster, sec_offset; + unsigned int cluster, sec_offset, count; sector_t last_block; sector_t phys = 0; sector_t valid_blks; @@ -281,8 +285,9 @@ static int exfat_get_block(struct inode *inode, sector_t iblock, goto done; /* Is this block already allocated? */ + count = EXFAT_B_TO_CLU_ROUND_UP(bh_result->b_size, sbi); err = exfat_map_cluster(inode, iblock >> sbi->sect_per_clus_bits, - &cluster, create); + &cluster, &count, create); if (err) { if (err != -ENOSPC) exfat_fs_error_ratelimit(sb, @@ -293,12 +298,14 @@ static int exfat_get_block(struct inode *inode, sector_t iblock, if (cluster == EXFAT_EOF_CLUSTER) goto done; + if (WARN_ON_ONCE(!count)) + count = 1; /* sector offset in cluster */ sec_offset = iblock & (sbi->sect_per_clus - 1); phys = exfat_cluster_to_sector(sbi, cluster) + sec_offset; - mapped_blocks = sbi->sect_per_clus - sec_offset; + mapped_blocks = count * sbi->sect_per_clus - sec_offset; max_blocks = min(mapped_blocks, max_blocks); map_bh(bh_result, sb, phys); -- 2.43.0