18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/fat/cache.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Written 1992,1993 by Werner Almesberger 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Mar 1999. AV. Changed cache, so that it uses the starting cluster instead 88c2ecf20Sopenharmony_ci * of inode number. 98c2ecf20Sopenharmony_ci * May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include "fat.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* this must be > 0. */ 168c2ecf20Sopenharmony_ci#define FAT_MAX_CACHE 8 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistruct fat_cache { 198c2ecf20Sopenharmony_ci struct list_head cache_list; 208c2ecf20Sopenharmony_ci int nr_contig; /* number of contiguous clusters */ 218c2ecf20Sopenharmony_ci int fcluster; /* cluster number in the file. */ 228c2ecf20Sopenharmony_ci int dcluster; /* cluster number on disk. */ 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct fat_cache_id { 268c2ecf20Sopenharmony_ci unsigned int id; 278c2ecf20Sopenharmony_ci int nr_contig; 288c2ecf20Sopenharmony_ci int fcluster; 298c2ecf20Sopenharmony_ci int dcluster; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic inline int fat_max_cache(struct inode *inode) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci return FAT_MAX_CACHE; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic struct kmem_cache *fat_cache_cachep; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic void init_once(void *foo) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct fat_cache *cache = (struct fat_cache *)foo; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cache->cache_list); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ciint __init fat_cache_init(void) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci fat_cache_cachep = kmem_cache_create("fat_cache", 498c2ecf20Sopenharmony_ci sizeof(struct fat_cache), 508c2ecf20Sopenharmony_ci 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, 518c2ecf20Sopenharmony_ci init_once); 528c2ecf20Sopenharmony_ci if (fat_cache_cachep == NULL) 538c2ecf20Sopenharmony_ci return -ENOMEM; 548c2ecf20Sopenharmony_ci return 0; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_civoid fat_cache_destroy(void) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci kmem_cache_destroy(fat_cache_cachep); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic inline struct fat_cache *fat_cache_alloc(struct inode *inode) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci return kmem_cache_alloc(fat_cache_cachep, GFP_NOFS); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic inline void fat_cache_free(struct fat_cache *cache) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci BUG_ON(!list_empty(&cache->cache_list)); 708c2ecf20Sopenharmony_ci kmem_cache_free(fat_cache_cachep, cache); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic inline void fat_cache_update_lru(struct inode *inode, 748c2ecf20Sopenharmony_ci struct fat_cache *cache) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci if (MSDOS_I(inode)->cache_lru.next != &cache->cache_list) 778c2ecf20Sopenharmony_ci list_move(&cache->cache_list, &MSDOS_I(inode)->cache_lru); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic int fat_cache_lookup(struct inode *inode, int fclus, 818c2ecf20Sopenharmony_ci struct fat_cache_id *cid, 828c2ecf20Sopenharmony_ci int *cached_fclus, int *cached_dclus) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci static struct fat_cache nohit = { .fcluster = 0, }; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci struct fat_cache *hit = &nohit, *p; 878c2ecf20Sopenharmony_ci int offset = -1; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci spin_lock(&MSDOS_I(inode)->cache_lru_lock); 908c2ecf20Sopenharmony_ci list_for_each_entry(p, &MSDOS_I(inode)->cache_lru, cache_list) { 918c2ecf20Sopenharmony_ci /* Find the cache of "fclus" or nearest cache. */ 928c2ecf20Sopenharmony_ci if (p->fcluster <= fclus && hit->fcluster < p->fcluster) { 938c2ecf20Sopenharmony_ci hit = p; 948c2ecf20Sopenharmony_ci if ((hit->fcluster + hit->nr_contig) < fclus) { 958c2ecf20Sopenharmony_ci offset = hit->nr_contig; 968c2ecf20Sopenharmony_ci } else { 978c2ecf20Sopenharmony_ci offset = fclus - hit->fcluster; 988c2ecf20Sopenharmony_ci break; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci if (hit != &nohit) { 1038c2ecf20Sopenharmony_ci fat_cache_update_lru(inode, hit); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci cid->id = MSDOS_I(inode)->cache_valid_id; 1068c2ecf20Sopenharmony_ci cid->nr_contig = hit->nr_contig; 1078c2ecf20Sopenharmony_ci cid->fcluster = hit->fcluster; 1088c2ecf20Sopenharmony_ci cid->dcluster = hit->dcluster; 1098c2ecf20Sopenharmony_ci *cached_fclus = cid->fcluster + offset; 1108c2ecf20Sopenharmony_ci *cached_dclus = cid->dcluster + offset; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci spin_unlock(&MSDOS_I(inode)->cache_lru_lock); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return offset; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic struct fat_cache *fat_cache_merge(struct inode *inode, 1188c2ecf20Sopenharmony_ci struct fat_cache_id *new) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci struct fat_cache *p; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci list_for_each_entry(p, &MSDOS_I(inode)->cache_lru, cache_list) { 1238c2ecf20Sopenharmony_ci /* Find the same part as "new" in cluster-chain. */ 1248c2ecf20Sopenharmony_ci if (p->fcluster == new->fcluster) { 1258c2ecf20Sopenharmony_ci BUG_ON(p->dcluster != new->dcluster); 1268c2ecf20Sopenharmony_ci if (new->nr_contig > p->nr_contig) 1278c2ecf20Sopenharmony_ci p->nr_contig = new->nr_contig; 1288c2ecf20Sopenharmony_ci return p; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci return NULL; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic void fat_cache_add(struct inode *inode, struct fat_cache_id *new) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct fat_cache *cache, *tmp; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (new->fcluster == -1) /* dummy cache */ 1398c2ecf20Sopenharmony_ci return; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci spin_lock(&MSDOS_I(inode)->cache_lru_lock); 1428c2ecf20Sopenharmony_ci if (new->id != FAT_CACHE_VALID && 1438c2ecf20Sopenharmony_ci new->id != MSDOS_I(inode)->cache_valid_id) 1448c2ecf20Sopenharmony_ci goto out; /* this cache was invalidated */ 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci cache = fat_cache_merge(inode, new); 1478c2ecf20Sopenharmony_ci if (cache == NULL) { 1488c2ecf20Sopenharmony_ci if (MSDOS_I(inode)->nr_caches < fat_max_cache(inode)) { 1498c2ecf20Sopenharmony_ci MSDOS_I(inode)->nr_caches++; 1508c2ecf20Sopenharmony_ci spin_unlock(&MSDOS_I(inode)->cache_lru_lock); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci tmp = fat_cache_alloc(inode); 1538c2ecf20Sopenharmony_ci if (!tmp) { 1548c2ecf20Sopenharmony_ci spin_lock(&MSDOS_I(inode)->cache_lru_lock); 1558c2ecf20Sopenharmony_ci MSDOS_I(inode)->nr_caches--; 1568c2ecf20Sopenharmony_ci spin_unlock(&MSDOS_I(inode)->cache_lru_lock); 1578c2ecf20Sopenharmony_ci return; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci spin_lock(&MSDOS_I(inode)->cache_lru_lock); 1618c2ecf20Sopenharmony_ci cache = fat_cache_merge(inode, new); 1628c2ecf20Sopenharmony_ci if (cache != NULL) { 1638c2ecf20Sopenharmony_ci MSDOS_I(inode)->nr_caches--; 1648c2ecf20Sopenharmony_ci fat_cache_free(tmp); 1658c2ecf20Sopenharmony_ci goto out_update_lru; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci cache = tmp; 1688c2ecf20Sopenharmony_ci } else { 1698c2ecf20Sopenharmony_ci struct list_head *p = MSDOS_I(inode)->cache_lru.prev; 1708c2ecf20Sopenharmony_ci cache = list_entry(p, struct fat_cache, cache_list); 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci cache->fcluster = new->fcluster; 1738c2ecf20Sopenharmony_ci cache->dcluster = new->dcluster; 1748c2ecf20Sopenharmony_ci cache->nr_contig = new->nr_contig; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ciout_update_lru: 1778c2ecf20Sopenharmony_ci fat_cache_update_lru(inode, cache); 1788c2ecf20Sopenharmony_ciout: 1798c2ecf20Sopenharmony_ci spin_unlock(&MSDOS_I(inode)->cache_lru_lock); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* 1838c2ecf20Sopenharmony_ci * Cache invalidation occurs rarely, thus the LRU chain is not updated. It 1848c2ecf20Sopenharmony_ci * fixes itself after a while. 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_cistatic void __fat_cache_inval_inode(struct inode *inode) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci struct msdos_inode_info *i = MSDOS_I(inode); 1898c2ecf20Sopenharmony_ci struct fat_cache *cache; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci while (!list_empty(&i->cache_lru)) { 1928c2ecf20Sopenharmony_ci cache = list_entry(i->cache_lru.next, 1938c2ecf20Sopenharmony_ci struct fat_cache, cache_list); 1948c2ecf20Sopenharmony_ci list_del_init(&cache->cache_list); 1958c2ecf20Sopenharmony_ci i->nr_caches--; 1968c2ecf20Sopenharmony_ci fat_cache_free(cache); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci /* Update. The copy of caches before this id is discarded. */ 1998c2ecf20Sopenharmony_ci i->cache_valid_id++; 2008c2ecf20Sopenharmony_ci if (i->cache_valid_id == FAT_CACHE_VALID) 2018c2ecf20Sopenharmony_ci i->cache_valid_id++; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_civoid fat_cache_inval_inode(struct inode *inode) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci spin_lock(&MSDOS_I(inode)->cache_lru_lock); 2078c2ecf20Sopenharmony_ci __fat_cache_inval_inode(inode); 2088c2ecf20Sopenharmony_ci spin_unlock(&MSDOS_I(inode)->cache_lru_lock); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic inline int cache_contiguous(struct fat_cache_id *cid, int dclus) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci cid->nr_contig++; 2148c2ecf20Sopenharmony_ci return ((cid->dcluster + cid->nr_contig) == dclus); 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic inline void cache_init(struct fat_cache_id *cid, int fclus, int dclus) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci cid->id = FAT_CACHE_VALID; 2208c2ecf20Sopenharmony_ci cid->fcluster = fclus; 2218c2ecf20Sopenharmony_ci cid->dcluster = dclus; 2228c2ecf20Sopenharmony_ci cid->nr_contig = 0; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ciint fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 2288c2ecf20Sopenharmony_ci struct msdos_sb_info *sbi = MSDOS_SB(sb); 2298c2ecf20Sopenharmony_ci const int limit = sb->s_maxbytes >> sbi->cluster_bits; 2308c2ecf20Sopenharmony_ci struct fat_entry fatent; 2318c2ecf20Sopenharmony_ci struct fat_cache_id cid; 2328c2ecf20Sopenharmony_ci int nr; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci BUG_ON(MSDOS_I(inode)->i_start == 0); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci *fclus = 0; 2378c2ecf20Sopenharmony_ci *dclus = MSDOS_I(inode)->i_start; 2388c2ecf20Sopenharmony_ci if (!fat_valid_entry(sbi, *dclus)) { 2398c2ecf20Sopenharmony_ci fat_fs_error_ratelimit(sb, 2408c2ecf20Sopenharmony_ci "%s: invalid start cluster (i_pos %lld, start %08x)", 2418c2ecf20Sopenharmony_ci __func__, MSDOS_I(inode)->i_pos, *dclus); 2428c2ecf20Sopenharmony_ci return -EIO; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci if (cluster == 0) 2458c2ecf20Sopenharmony_ci return 0; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (fat_cache_lookup(inode, cluster, &cid, fclus, dclus) < 0) { 2488c2ecf20Sopenharmony_ci /* 2498c2ecf20Sopenharmony_ci * dummy, always not contiguous 2508c2ecf20Sopenharmony_ci * This is reinitialized by cache_init(), later. 2518c2ecf20Sopenharmony_ci */ 2528c2ecf20Sopenharmony_ci cache_init(&cid, -1, -1); 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci fatent_init(&fatent); 2568c2ecf20Sopenharmony_ci while (*fclus < cluster) { 2578c2ecf20Sopenharmony_ci /* prevent the infinite loop of cluster chain */ 2588c2ecf20Sopenharmony_ci if (*fclus > limit) { 2598c2ecf20Sopenharmony_ci fat_fs_error_ratelimit(sb, 2608c2ecf20Sopenharmony_ci "%s: detected the cluster chain loop (i_pos %lld)", 2618c2ecf20Sopenharmony_ci __func__, MSDOS_I(inode)->i_pos); 2628c2ecf20Sopenharmony_ci nr = -EIO; 2638c2ecf20Sopenharmony_ci goto out; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci nr = fat_ent_read(inode, &fatent, *dclus); 2678c2ecf20Sopenharmony_ci if (nr < 0) 2688c2ecf20Sopenharmony_ci goto out; 2698c2ecf20Sopenharmony_ci else if (nr == FAT_ENT_FREE) { 2708c2ecf20Sopenharmony_ci fat_fs_error_ratelimit(sb, 2718c2ecf20Sopenharmony_ci "%s: invalid cluster chain (i_pos %lld)", 2728c2ecf20Sopenharmony_ci __func__, MSDOS_I(inode)->i_pos); 2738c2ecf20Sopenharmony_ci nr = -EIO; 2748c2ecf20Sopenharmony_ci goto out; 2758c2ecf20Sopenharmony_ci } else if (nr == FAT_ENT_EOF) { 2768c2ecf20Sopenharmony_ci fat_cache_add(inode, &cid); 2778c2ecf20Sopenharmony_ci goto out; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci (*fclus)++; 2808c2ecf20Sopenharmony_ci *dclus = nr; 2818c2ecf20Sopenharmony_ci if (!cache_contiguous(&cid, *dclus)) 2828c2ecf20Sopenharmony_ci cache_init(&cid, *fclus, *dclus); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci nr = 0; 2858c2ecf20Sopenharmony_ci fat_cache_add(inode, &cid); 2868c2ecf20Sopenharmony_ciout: 2878c2ecf20Sopenharmony_ci fatent_brelse(&fatent); 2888c2ecf20Sopenharmony_ci return nr; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic int fat_bmap_cluster(struct inode *inode, int cluster) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 2948c2ecf20Sopenharmony_ci int ret, fclus, dclus; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (MSDOS_I(inode)->i_start == 0) 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci ret = fat_get_cluster(inode, cluster, &fclus, &dclus); 3008c2ecf20Sopenharmony_ci if (ret < 0) 3018c2ecf20Sopenharmony_ci return ret; 3028c2ecf20Sopenharmony_ci else if (ret == FAT_ENT_EOF) { 3038c2ecf20Sopenharmony_ci fat_fs_error(sb, "%s: request beyond EOF (i_pos %lld)", 3048c2ecf20Sopenharmony_ci __func__, MSDOS_I(inode)->i_pos); 3058c2ecf20Sopenharmony_ci return -EIO; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci return dclus; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ciint fat_get_mapped_cluster(struct inode *inode, sector_t sector, 3118c2ecf20Sopenharmony_ci sector_t last_block, 3128c2ecf20Sopenharmony_ci unsigned long *mapped_blocks, sector_t *bmap) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 3158c2ecf20Sopenharmony_ci struct msdos_sb_info *sbi = MSDOS_SB(sb); 3168c2ecf20Sopenharmony_ci int cluster, offset; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits); 3198c2ecf20Sopenharmony_ci offset = sector & (sbi->sec_per_clus - 1); 3208c2ecf20Sopenharmony_ci cluster = fat_bmap_cluster(inode, cluster); 3218c2ecf20Sopenharmony_ci if (cluster < 0) 3228c2ecf20Sopenharmony_ci return cluster; 3238c2ecf20Sopenharmony_ci else if (cluster) { 3248c2ecf20Sopenharmony_ci *bmap = fat_clus_to_blknr(sbi, cluster) + offset; 3258c2ecf20Sopenharmony_ci *mapped_blocks = sbi->sec_per_clus - offset; 3268c2ecf20Sopenharmony_ci if (*mapped_blocks > last_block - sector) 3278c2ecf20Sopenharmony_ci *mapped_blocks = last_block - sector; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return 0; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic int is_exceed_eof(struct inode *inode, sector_t sector, 3348c2ecf20Sopenharmony_ci sector_t *last_block, int create) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 3378c2ecf20Sopenharmony_ci const unsigned long blocksize = sb->s_blocksize; 3388c2ecf20Sopenharmony_ci const unsigned char blocksize_bits = sb->s_blocksize_bits; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci *last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits; 3418c2ecf20Sopenharmony_ci if (sector >= *last_block) { 3428c2ecf20Sopenharmony_ci if (!create) 3438c2ecf20Sopenharmony_ci return 1; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* 3468c2ecf20Sopenharmony_ci * ->mmu_private can access on only allocation path. 3478c2ecf20Sopenharmony_ci * (caller must hold ->i_mutex) 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_ci *last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1)) 3508c2ecf20Sopenharmony_ci >> blocksize_bits; 3518c2ecf20Sopenharmony_ci if (sector >= *last_block) 3528c2ecf20Sopenharmony_ci return 1; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ciint fat_bmap(struct inode *inode, sector_t sector, sector_t *phys, 3598c2ecf20Sopenharmony_ci unsigned long *mapped_blocks, int create, bool from_bmap) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); 3628c2ecf20Sopenharmony_ci sector_t last_block; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci *phys = 0; 3658c2ecf20Sopenharmony_ci *mapped_blocks = 0; 3668c2ecf20Sopenharmony_ci if (!is_fat32(sbi) && (inode->i_ino == MSDOS_ROOT_INO)) { 3678c2ecf20Sopenharmony_ci if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits)) { 3688c2ecf20Sopenharmony_ci *phys = sector + sbi->dir_start; 3698c2ecf20Sopenharmony_ci *mapped_blocks = 1; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci return 0; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (!from_bmap) { 3758c2ecf20Sopenharmony_ci if (is_exceed_eof(inode, sector, &last_block, create)) 3768c2ecf20Sopenharmony_ci return 0; 3778c2ecf20Sopenharmony_ci } else { 3788c2ecf20Sopenharmony_ci last_block = inode->i_blocks >> 3798c2ecf20Sopenharmony_ci (inode->i_sb->s_blocksize_bits - 9); 3808c2ecf20Sopenharmony_ci if (sector >= last_block) 3818c2ecf20Sopenharmony_ci return 0; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci return fat_get_mapped_cluster(inode, sector, last_block, mapped_blocks, 3858c2ecf20Sopenharmony_ci phys); 3868c2ecf20Sopenharmony_ci} 387