1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/fs/fat/cache.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Written 1992,1993 by Werner Almesberger
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * Mar 1999. AV. Changed cache, so that it uses the starting cluster instead
81da177e4SLinus Torvalds * of inode number.
91da177e4SLinus Torvalds * May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers.
101da177e4SLinus Torvalds */
111da177e4SLinus Torvalds
125a0e3ad6STejun Heo #include <linux/slab.h>
139e975daeSOGAWA Hirofumi #include "fat.h"
141da177e4SLinus Torvalds
151da177e4SLinus Torvalds /* this must be > 0. */
161da177e4SLinus Torvalds #define FAT_MAX_CACHE 8
171da177e4SLinus Torvalds
181da177e4SLinus Torvalds struct fat_cache {
191da177e4SLinus Torvalds struct list_head cache_list;
201da177e4SLinus Torvalds int nr_contig; /* number of contiguous clusters */
211da177e4SLinus Torvalds int fcluster; /* cluster number in the file. */
221da177e4SLinus Torvalds int dcluster; /* cluster number on disk. */
231da177e4SLinus Torvalds };
241da177e4SLinus Torvalds
251da177e4SLinus Torvalds struct fat_cache_id {
261da177e4SLinus Torvalds unsigned int id;
271da177e4SLinus Torvalds int nr_contig;
281da177e4SLinus Torvalds int fcluster;
291da177e4SLinus Torvalds int dcluster;
301da177e4SLinus Torvalds };
311da177e4SLinus Torvalds
fat_max_cache(struct inode * inode)321da177e4SLinus Torvalds static inline int fat_max_cache(struct inode *inode)
331da177e4SLinus Torvalds {
341da177e4SLinus Torvalds return FAT_MAX_CACHE;
351da177e4SLinus Torvalds }
361da177e4SLinus Torvalds
37e18b890bSChristoph Lameter static struct kmem_cache *fat_cache_cachep;
381da177e4SLinus Torvalds
init_once(void * foo)3951cc5068SAlexey Dobriyan static void init_once(void *foo)
401da177e4SLinus Torvalds {
411da177e4SLinus Torvalds struct fat_cache *cache = (struct fat_cache *)foo;
421da177e4SLinus Torvalds
431da177e4SLinus Torvalds INIT_LIST_HEAD(&cache->cache_list);
441da177e4SLinus Torvalds }
451da177e4SLinus Torvalds
fat_cache_init(void)461da177e4SLinus Torvalds int __init fat_cache_init(void)
471da177e4SLinus Torvalds {
481da177e4SLinus Torvalds fat_cache_cachep = kmem_cache_create("fat_cache",
491da177e4SLinus Torvalds sizeof(struct fat_cache),
504b6a9316SPaul Jackson 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
5120c2df83SPaul Mundt init_once);
521da177e4SLinus Torvalds if (fat_cache_cachep == NULL)
531da177e4SLinus Torvalds return -ENOMEM;
541da177e4SLinus Torvalds return 0;
551da177e4SLinus Torvalds }
561da177e4SLinus Torvalds
fat_cache_destroy(void)57ef6689efSAndrew Morton void fat_cache_destroy(void)
581da177e4SLinus Torvalds {
591a1d92c1SAlexey Dobriyan kmem_cache_destroy(fat_cache_cachep);
601da177e4SLinus Torvalds }
611da177e4SLinus Torvalds
fat_cache_alloc(struct inode * inode)621da177e4SLinus Torvalds static inline struct fat_cache *fat_cache_alloc(struct inode *inode)
631da177e4SLinus Torvalds {
648f593427SLinus Torvalds return kmem_cache_alloc(fat_cache_cachep, GFP_NOFS);
651da177e4SLinus Torvalds }
661da177e4SLinus Torvalds
fat_cache_free(struct fat_cache * cache)671da177e4SLinus Torvalds static inline void fat_cache_free(struct fat_cache *cache)
681da177e4SLinus Torvalds {
691da177e4SLinus Torvalds BUG_ON(!list_empty(&cache->cache_list));
701da177e4SLinus Torvalds kmem_cache_free(fat_cache_cachep, cache);
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds
fat_cache_update_lru(struct inode * inode,struct fat_cache * cache)731da177e4SLinus Torvalds static inline void fat_cache_update_lru(struct inode *inode,
741da177e4SLinus Torvalds struct fat_cache *cache)
751da177e4SLinus Torvalds {
761da177e4SLinus Torvalds if (MSDOS_I(inode)->cache_lru.next != &cache->cache_list)
771da177e4SLinus Torvalds list_move(&cache->cache_list, &MSDOS_I(inode)->cache_lru);
781da177e4SLinus Torvalds }
791da177e4SLinus Torvalds
fat_cache_lookup(struct inode * inode,int fclus,struct fat_cache_id * cid,int * cached_fclus,int * cached_dclus)801da177e4SLinus Torvalds static int fat_cache_lookup(struct inode *inode, int fclus,
811da177e4SLinus Torvalds struct fat_cache_id *cid,
821da177e4SLinus Torvalds int *cached_fclus, int *cached_dclus)
831da177e4SLinus Torvalds {
841da177e4SLinus Torvalds static struct fat_cache nohit = { .fcluster = 0, };
851da177e4SLinus Torvalds
861da177e4SLinus Torvalds struct fat_cache *hit = &nohit, *p;
871da177e4SLinus Torvalds int offset = -1;
881da177e4SLinus Torvalds
891da177e4SLinus Torvalds spin_lock(&MSDOS_I(inode)->cache_lru_lock);
901da177e4SLinus Torvalds list_for_each_entry(p, &MSDOS_I(inode)->cache_lru, cache_list) {
911da177e4SLinus Torvalds /* Find the cache of "fclus" or nearest cache. */
921da177e4SLinus Torvalds if (p->fcluster <= fclus && hit->fcluster < p->fcluster) {
931da177e4SLinus Torvalds hit = p;
941da177e4SLinus Torvalds if ((hit->fcluster + hit->nr_contig) < fclus) {
951da177e4SLinus Torvalds offset = hit->nr_contig;
961da177e4SLinus Torvalds } else {
971da177e4SLinus Torvalds offset = fclus - hit->fcluster;
981da177e4SLinus Torvalds break;
991da177e4SLinus Torvalds }
1001da177e4SLinus Torvalds }
1011da177e4SLinus Torvalds }
1021da177e4SLinus Torvalds if (hit != &nohit) {
1031da177e4SLinus Torvalds fat_cache_update_lru(inode, hit);
1041da177e4SLinus Torvalds
1051da177e4SLinus Torvalds cid->id = MSDOS_I(inode)->cache_valid_id;
1061da177e4SLinus Torvalds cid->nr_contig = hit->nr_contig;
1071da177e4SLinus Torvalds cid->fcluster = hit->fcluster;
1081da177e4SLinus Torvalds cid->dcluster = hit->dcluster;
1091da177e4SLinus Torvalds *cached_fclus = cid->fcluster + offset;
1101da177e4SLinus Torvalds *cached_dclus = cid->dcluster + offset;
1111da177e4SLinus Torvalds }
1121da177e4SLinus Torvalds spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
1131da177e4SLinus Torvalds
1141da177e4SLinus Torvalds return offset;
1151da177e4SLinus Torvalds }
1161da177e4SLinus Torvalds
fat_cache_merge(struct inode * inode,struct fat_cache_id * new)1171da177e4SLinus Torvalds static struct fat_cache *fat_cache_merge(struct inode *inode,
1181da177e4SLinus Torvalds struct fat_cache_id *new)
1191da177e4SLinus Torvalds {
1201da177e4SLinus Torvalds struct fat_cache *p;
1211da177e4SLinus Torvalds
1221da177e4SLinus Torvalds list_for_each_entry(p, &MSDOS_I(inode)->cache_lru, cache_list) {
1231da177e4SLinus Torvalds /* Find the same part as "new" in cluster-chain. */
1241da177e4SLinus Torvalds if (p->fcluster == new->fcluster) {
1251da177e4SLinus Torvalds BUG_ON(p->dcluster != new->dcluster);
1261da177e4SLinus Torvalds if (new->nr_contig > p->nr_contig)
1271da177e4SLinus Torvalds p->nr_contig = new->nr_contig;
1281da177e4SLinus Torvalds return p;
1291da177e4SLinus Torvalds }
1301da177e4SLinus Torvalds }
1311da177e4SLinus Torvalds return NULL;
1321da177e4SLinus Torvalds }
1331da177e4SLinus Torvalds
fat_cache_add(struct inode * inode,struct fat_cache_id * new)1341da177e4SLinus Torvalds static void fat_cache_add(struct inode *inode, struct fat_cache_id *new)
1351da177e4SLinus Torvalds {
1361da177e4SLinus Torvalds struct fat_cache *cache, *tmp;
1371da177e4SLinus Torvalds
1381da177e4SLinus Torvalds if (new->fcluster == -1) /* dummy cache */
1391da177e4SLinus Torvalds return;
1401da177e4SLinus Torvalds
1411da177e4SLinus Torvalds spin_lock(&MSDOS_I(inode)->cache_lru_lock);
1421da177e4SLinus Torvalds if (new->id != FAT_CACHE_VALID &&
1431da177e4SLinus Torvalds new->id != MSDOS_I(inode)->cache_valid_id)
1441da177e4SLinus Torvalds goto out; /* this cache was invalidated */
1451da177e4SLinus Torvalds
1461da177e4SLinus Torvalds cache = fat_cache_merge(inode, new);
1471da177e4SLinus Torvalds if (cache == NULL) {
1481da177e4SLinus Torvalds if (MSDOS_I(inode)->nr_caches < fat_max_cache(inode)) {
1491da177e4SLinus Torvalds MSDOS_I(inode)->nr_caches++;
1501da177e4SLinus Torvalds spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
1511da177e4SLinus Torvalds
1521da177e4SLinus Torvalds tmp = fat_cache_alloc(inode);
15370030929SOGAWA Hirofumi if (!tmp) {
15470030929SOGAWA Hirofumi spin_lock(&MSDOS_I(inode)->cache_lru_lock);
15570030929SOGAWA Hirofumi MSDOS_I(inode)->nr_caches--;
15670030929SOGAWA Hirofumi spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
15770030929SOGAWA Hirofumi return;
15870030929SOGAWA Hirofumi }
15970030929SOGAWA Hirofumi
1601da177e4SLinus Torvalds spin_lock(&MSDOS_I(inode)->cache_lru_lock);
1611da177e4SLinus Torvalds cache = fat_cache_merge(inode, new);
1621da177e4SLinus Torvalds if (cache != NULL) {
1631da177e4SLinus Torvalds MSDOS_I(inode)->nr_caches--;
1641da177e4SLinus Torvalds fat_cache_free(tmp);
1651da177e4SLinus Torvalds goto out_update_lru;
1661da177e4SLinus Torvalds }
1671da177e4SLinus Torvalds cache = tmp;
1681da177e4SLinus Torvalds } else {
1691da177e4SLinus Torvalds struct list_head *p = MSDOS_I(inode)->cache_lru.prev;
1701da177e4SLinus Torvalds cache = list_entry(p, struct fat_cache, cache_list);
1711da177e4SLinus Torvalds }
1721da177e4SLinus Torvalds cache->fcluster = new->fcluster;
1731da177e4SLinus Torvalds cache->dcluster = new->dcluster;
1741da177e4SLinus Torvalds cache->nr_contig = new->nr_contig;
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds out_update_lru:
1771da177e4SLinus Torvalds fat_cache_update_lru(inode, cache);
1781da177e4SLinus Torvalds out:
1791da177e4SLinus Torvalds spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
1801da177e4SLinus Torvalds }
1811da177e4SLinus Torvalds
1821da177e4SLinus Torvalds /*
1831da177e4SLinus Torvalds * Cache invalidation occurs rarely, thus the LRU chain is not updated. It
1841da177e4SLinus Torvalds * fixes itself after a while.
1851da177e4SLinus Torvalds */
__fat_cache_inval_inode(struct inode * inode)1861da177e4SLinus Torvalds static void __fat_cache_inval_inode(struct inode *inode)
1871da177e4SLinus Torvalds {
1881da177e4SLinus Torvalds struct msdos_inode_info *i = MSDOS_I(inode);
1891da177e4SLinus Torvalds struct fat_cache *cache;
1901da177e4SLinus Torvalds
1911da177e4SLinus Torvalds while (!list_empty(&i->cache_lru)) {
192c9051829SCruz Julian Bishop cache = list_entry(i->cache_lru.next,
193c9051829SCruz Julian Bishop struct fat_cache, cache_list);
1941da177e4SLinus Torvalds list_del_init(&cache->cache_list);
1951da177e4SLinus Torvalds i->nr_caches--;
1961da177e4SLinus Torvalds fat_cache_free(cache);
1971da177e4SLinus Torvalds }
1981da177e4SLinus Torvalds /* Update. The copy of caches before this id is discarded. */
1991da177e4SLinus Torvalds i->cache_valid_id++;
2001da177e4SLinus Torvalds if (i->cache_valid_id == FAT_CACHE_VALID)
2011da177e4SLinus Torvalds i->cache_valid_id++;
2021da177e4SLinus Torvalds }
2031da177e4SLinus Torvalds
fat_cache_inval_inode(struct inode * inode)2041da177e4SLinus Torvalds void fat_cache_inval_inode(struct inode *inode)
2051da177e4SLinus Torvalds {
2061da177e4SLinus Torvalds spin_lock(&MSDOS_I(inode)->cache_lru_lock);
2071da177e4SLinus Torvalds __fat_cache_inval_inode(inode);
2081da177e4SLinus Torvalds spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
2091da177e4SLinus Torvalds }
2101da177e4SLinus Torvalds
cache_contiguous(struct fat_cache_id * cid,int dclus)2111da177e4SLinus Torvalds static inline int cache_contiguous(struct fat_cache_id *cid, int dclus)
2121da177e4SLinus Torvalds {
2131da177e4SLinus Torvalds cid->nr_contig++;
2141da177e4SLinus Torvalds return ((cid->dcluster + cid->nr_contig) == dclus);
2151da177e4SLinus Torvalds }
2161da177e4SLinus Torvalds
cache_init(struct fat_cache_id * cid,int fclus,int dclus)2171da177e4SLinus Torvalds static inline void cache_init(struct fat_cache_id *cid, int fclus, int dclus)
2181da177e4SLinus Torvalds {
2191da177e4SLinus Torvalds cid->id = FAT_CACHE_VALID;
2201da177e4SLinus Torvalds cid->fcluster = fclus;
2211da177e4SLinus Torvalds cid->dcluster = dclus;
2221da177e4SLinus Torvalds cid->nr_contig = 0;
2231da177e4SLinus Torvalds }
2241da177e4SLinus Torvalds
fat_get_cluster(struct inode * inode,int cluster,int * fclus,int * dclus)2251da177e4SLinus Torvalds int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
2261da177e4SLinus Torvalds {
2271da177e4SLinus Torvalds struct super_block *sb = inode->i_sb;
2280afa9626SOGAWA Hirofumi struct msdos_sb_info *sbi = MSDOS_SB(sb);
2290afa9626SOGAWA Hirofumi const int limit = sb->s_maxbytes >> sbi->cluster_bits;
2301da177e4SLinus Torvalds struct fat_entry fatent;
2311da177e4SLinus Torvalds struct fat_cache_id cid;
2321da177e4SLinus Torvalds int nr;
2331da177e4SLinus Torvalds
2341da177e4SLinus Torvalds BUG_ON(MSDOS_I(inode)->i_start == 0);
2351da177e4SLinus Torvalds
2361da177e4SLinus Torvalds *fclus = 0;
2371da177e4SLinus Torvalds *dclus = MSDOS_I(inode)->i_start;
2380afa9626SOGAWA Hirofumi if (!fat_valid_entry(sbi, *dclus)) {
2390afa9626SOGAWA Hirofumi fat_fs_error_ratelimit(sb,
2400afa9626SOGAWA Hirofumi "%s: invalid start cluster (i_pos %lld, start %08x)",
2410afa9626SOGAWA Hirofumi __func__, MSDOS_I(inode)->i_pos, *dclus);
2420afa9626SOGAWA Hirofumi return -EIO;
2430afa9626SOGAWA Hirofumi }
2441da177e4SLinus Torvalds if (cluster == 0)
2451da177e4SLinus Torvalds return 0;
2461da177e4SLinus Torvalds
2471da177e4SLinus Torvalds if (fat_cache_lookup(inode, cluster, &cid, fclus, dclus) < 0) {
2481da177e4SLinus Torvalds /*
2491da177e4SLinus Torvalds * dummy, always not contiguous
2501da177e4SLinus Torvalds * This is reinitialized by cache_init(), later.
2511da177e4SLinus Torvalds */
2521da177e4SLinus Torvalds cache_init(&cid, -1, -1);
2531da177e4SLinus Torvalds }
2541da177e4SLinus Torvalds
2551da177e4SLinus Torvalds fatent_init(&fatent);
2561da177e4SLinus Torvalds while (*fclus < cluster) {
2571da177e4SLinus Torvalds /* prevent the infinite loop of cluster chain */
2581da177e4SLinus Torvalds if (*fclus > limit) {
259aaa04b48SOGAWA Hirofumi fat_fs_error_ratelimit(sb,
2600afa9626SOGAWA Hirofumi "%s: detected the cluster chain loop (i_pos %lld)",
2610afa9626SOGAWA Hirofumi __func__, MSDOS_I(inode)->i_pos);
2621da177e4SLinus Torvalds nr = -EIO;
2631da177e4SLinus Torvalds goto out;
2641da177e4SLinus Torvalds }
2651da177e4SLinus Torvalds
2661da177e4SLinus Torvalds nr = fat_ent_read(inode, &fatent, *dclus);
2671da177e4SLinus Torvalds if (nr < 0)
2681da177e4SLinus Torvalds goto out;
2691da177e4SLinus Torvalds else if (nr == FAT_ENT_FREE) {
270c9051829SCruz Julian Bishop fat_fs_error_ratelimit(sb,
271c9051829SCruz Julian Bishop "%s: invalid cluster chain (i_pos %lld)",
2720afa9626SOGAWA Hirofumi __func__, MSDOS_I(inode)->i_pos);
2731da177e4SLinus Torvalds nr = -EIO;
2741da177e4SLinus Torvalds goto out;
2751da177e4SLinus Torvalds } else if (nr == FAT_ENT_EOF) {
2761da177e4SLinus Torvalds fat_cache_add(inode, &cid);
2771da177e4SLinus Torvalds goto out;
2781da177e4SLinus Torvalds }
2791da177e4SLinus Torvalds (*fclus)++;
2801da177e4SLinus Torvalds *dclus = nr;
2811da177e4SLinus Torvalds if (!cache_contiguous(&cid, *dclus))
2821da177e4SLinus Torvalds cache_init(&cid, *fclus, *dclus);
2831da177e4SLinus Torvalds }
2841da177e4SLinus Torvalds nr = 0;
2851da177e4SLinus Torvalds fat_cache_add(inode, &cid);
2861da177e4SLinus Torvalds out:
2871da177e4SLinus Torvalds fatent_brelse(&fatent);
2881da177e4SLinus Torvalds return nr;
2891da177e4SLinus Torvalds }
2901da177e4SLinus Torvalds
fat_bmap_cluster(struct inode * inode,int cluster)2911da177e4SLinus Torvalds static int fat_bmap_cluster(struct inode *inode, int cluster)
2921da177e4SLinus Torvalds {
2931da177e4SLinus Torvalds struct super_block *sb = inode->i_sb;
2941da177e4SLinus Torvalds int ret, fclus, dclus;
2951da177e4SLinus Torvalds
2961da177e4SLinus Torvalds if (MSDOS_I(inode)->i_start == 0)
2971da177e4SLinus Torvalds return 0;
2981da177e4SLinus Torvalds
2991da177e4SLinus Torvalds ret = fat_get_cluster(inode, cluster, &fclus, &dclus);
3001da177e4SLinus Torvalds if (ret < 0)
3011da177e4SLinus Torvalds return ret;
3021da177e4SLinus Torvalds else if (ret == FAT_ENT_EOF) {
30385c78591SDenis Karpov fat_fs_error(sb, "%s: request beyond EOF (i_pos %lld)",
3048e24eea7SHarvey Harrison __func__, MSDOS_I(inode)->i_pos);
3051da177e4SLinus Torvalds return -EIO;
3061da177e4SLinus Torvalds }
3071da177e4SLinus Torvalds return dclus;
3081da177e4SLinus Torvalds }
3091da177e4SLinus Torvalds
fat_get_mapped_cluster(struct inode * inode,sector_t sector,sector_t last_block,unsigned long * mapped_blocks,sector_t * bmap)31016fab201SNamjae Jeon int fat_get_mapped_cluster(struct inode *inode, sector_t sector,
31116fab201SNamjae Jeon sector_t last_block,
31216fab201SNamjae Jeon unsigned long *mapped_blocks, sector_t *bmap)
3131da177e4SLinus Torvalds {
3141da177e4SLinus Torvalds struct super_block *sb = inode->i_sb;
3151da177e4SLinus Torvalds struct msdos_sb_info *sbi = MSDOS_SB(sb);
31616fab201SNamjae Jeon int cluster, offset;
31716fab201SNamjae Jeon
31816fab201SNamjae Jeon cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits);
31916fab201SNamjae Jeon offset = sector & (sbi->sec_per_clus - 1);
32016fab201SNamjae Jeon cluster = fat_bmap_cluster(inode, cluster);
32116fab201SNamjae Jeon if (cluster < 0)
32216fab201SNamjae Jeon return cluster;
32316fab201SNamjae Jeon else if (cluster) {
32416fab201SNamjae Jeon *bmap = fat_clus_to_blknr(sbi, cluster) + offset;
32516fab201SNamjae Jeon *mapped_blocks = sbi->sec_per_clus - offset;
32616fab201SNamjae Jeon if (*mapped_blocks > last_block - sector)
32716fab201SNamjae Jeon *mapped_blocks = last_block - sector;
32816fab201SNamjae Jeon }
32916fab201SNamjae Jeon
33016fab201SNamjae Jeon return 0;
33116fab201SNamjae Jeon }
33216fab201SNamjae Jeon
is_exceed_eof(struct inode * inode,sector_t sector,sector_t * last_block,int create)33316fab201SNamjae Jeon static int is_exceed_eof(struct inode *inode, sector_t sector,
33416fab201SNamjae Jeon sector_t *last_block, int create)
33516fab201SNamjae Jeon {
33616fab201SNamjae Jeon struct super_block *sb = inode->i_sb;
3372bdf67ebSOGAWA Hirofumi const unsigned long blocksize = sb->s_blocksize;
3382bdf67ebSOGAWA Hirofumi const unsigned char blocksize_bits = sb->s_blocksize_bits;
33916fab201SNamjae Jeon
34016fab201SNamjae Jeon *last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits;
34116fab201SNamjae Jeon if (sector >= *last_block) {
34216fab201SNamjae Jeon if (!create)
34316fab201SNamjae Jeon return 1;
34416fab201SNamjae Jeon
34516fab201SNamjae Jeon /*
34616fab201SNamjae Jeon * ->mmu_private can access on only allocation path.
34716fab201SNamjae Jeon * (caller must hold ->i_mutex)
34816fab201SNamjae Jeon */
34916fab201SNamjae Jeon *last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1))
35016fab201SNamjae Jeon >> blocksize_bits;
35116fab201SNamjae Jeon if (sector >= *last_block)
35216fab201SNamjae Jeon return 1;
35316fab201SNamjae Jeon }
35416fab201SNamjae Jeon
35516fab201SNamjae Jeon return 0;
35616fab201SNamjae Jeon }
35716fab201SNamjae Jeon
fat_bmap(struct inode * inode,sector_t sector,sector_t * phys,unsigned long * mapped_blocks,int create,bool from_bmap)35816fab201SNamjae Jeon int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
35916fab201SNamjae Jeon unsigned long *mapped_blocks, int create, bool from_bmap)
36016fab201SNamjae Jeon {
36116fab201SNamjae Jeon struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
3621da177e4SLinus Torvalds sector_t last_block;
3631da177e4SLinus Torvalds
3641da177e4SLinus Torvalds *phys = 0;
365e5174baaSOGAWA Hirofumi *mapped_blocks = 0;
366*306790f7SCarmeli Tamir if (!is_fat32(sbi) && (inode->i_ino == MSDOS_ROOT_INO)) {
367e5174baaSOGAWA Hirofumi if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits)) {
3681da177e4SLinus Torvalds *phys = sector + sbi->dir_start;
369e5174baaSOGAWA Hirofumi *mapped_blocks = 1;
370e5174baaSOGAWA Hirofumi }
3711da177e4SLinus Torvalds return 0;
3721da177e4SLinus Torvalds }
3732bdf67ebSOGAWA Hirofumi
37416fab201SNamjae Jeon if (!from_bmap) {
37516fab201SNamjae Jeon if (is_exceed_eof(inode, sector, &last_block, create))
3762bdf67ebSOGAWA Hirofumi return 0;
37716fab201SNamjae Jeon } else {
37816fab201SNamjae Jeon last_block = inode->i_blocks >>
37916fab201SNamjae Jeon (inode->i_sb->s_blocksize_bits - 9);
3801da177e4SLinus Torvalds if (sector >= last_block)
3811da177e4SLinus Torvalds return 0;
3822bdf67ebSOGAWA Hirofumi }
3831da177e4SLinus Torvalds
38416fab201SNamjae Jeon return fat_get_mapped_cluster(inode, sector, last_block, mapped_blocks,
38516fab201SNamjae Jeon phys);
3861da177e4SLinus Torvalds }
387