xref: /openbmc/linux/fs/fat/cache.c (revision 306790f7)
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;
366306790f7SCarmeli 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