cregit-Linux how code gets into the kernel

Release 4.10 fs/fat/cache.c

Directory: fs/fat
/*
 *  linux/fs/fat/cache.c
 *
 *  Written 1992,1993 by Werner Almesberger
 *
 *  Mar 1999. AV. Changed cache, so that it uses the starting cluster instead
 *      of inode number.
 *  May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers.
 */

#include <linux/slab.h>
#include "fat.h"

/* this must be > 0. */

#define FAT_MAX_CACHE	8


struct fat_cache {
	
struct list_head cache_list;
	
int nr_contig;	/* number of contiguous clusters */
	
int fcluster;	/* cluster number in the file. */
	
int dcluster;	/* cluster number on disk. */
};


struct fat_cache_id {
	
unsigned int id;
	
int nr_contig;
	
int fcluster;
	
int dcluster;
};


static inline int fat_max_cache(struct inode *inode) { return FAT_MAX_CACHE; }

Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa1493.33%266.67%
pre-gitpre-git16.67%133.33%
Total15100.00%3100.00%

static struct kmem_cache *fat_cache_cachep;
static void init_once(void *foo) { struct fat_cache *cache = (struct fat_cache *)foo; INIT_LIST_HEAD(&cache->cache_list); }

Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa2273.33%120.00%
pre-gitpre-git516.67%360.00%
christoph lameterchristoph lameter310.00%120.00%
Total30100.00%5100.00%


int __init fat_cache_init(void) { fat_cache_cachep = kmem_cache_create("fat_cache", sizeof(struct fat_cache), 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, init_once); if (fat_cache_cachep == NULL) return -ENOMEM; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa2866.67%233.33%
pre-gitpre-git1228.57%350.00%
paul jacksonpaul jackson24.76%116.67%
Total42100.00%6100.00%


void fat_cache_destroy(void) { kmem_cache_destroy(fat_cache_cachep); }

Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa866.67%150.00%
pre-gitpre-git433.33%150.00%
Total12100.00%2100.00%


static inline struct fat_cache *fat_cache_alloc(struct inode *inode) { return kmem_cache_alloc(fat_cache_cachep, GFP_NOFS); }

Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa1881.82%133.33%
pre-gitpre-git313.64%133.33%
linus torvaldslinus torvalds14.55%133.33%
Total22100.00%3100.00%


static inline void fat_cache_free(struct fat_cache *cache) { BUG_ON(!list_empty(&cache->cache_list)); kmem_cache_free(fat_cache_cachep, cache); }

Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa3096.77%150.00%
pre-gitpre-git13.23%150.00%
Total31100.00%2100.00%


static inline void fat_cache_update_lru(struct inode *inode, struct fat_cache *cache) { if (MSDOS_I(inode)->cache_lru.next != &cache->cache_list) list_move(&cache->cache_list, &MSDOS_I(inode)->cache_lru); }

Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa4489.80%133.33%
pre-gitpre-git510.20%266.67%
Total49100.00%3100.00%


static int fat_cache_lookup(struct inode *inode, int fclus, struct fat_cache_id *cid, int *cached_fclus, int *cached_dclus) { static struct fat_cache nohit = { .fcluster = 0, }; struct fat_cache *hit = &nohit, *p; int offset = -1; spin_lock(&MSDOS_I(inode)->cache_lru_lock); list_for_each_entry(p, &MSDOS_I(inode)->cache_lru, cache_list) { /* Find the cache of "fclus" or nearest cache. */ if (p->fcluster <= fclus && hit->fcluster < p->fcluster) { hit = p; if ((hit->fcluster + hit->nr_contig) < fclus) { offset = hit->nr_contig; } else { offset = fclus - hit->fcluster; break; } } } if (hit != &nohit) { fat_cache_update_lru(inode, hit); cid->id = MSDOS_I(inode)->cache_valid_id; cid->nr_contig = hit->nr_contig; cid->fcluster = hit->fcluster; cid->dcluster = hit->dcluster; *cached_fclus = cid->fcluster + offset; *cached_dclus = cid->dcluster + offset; } spin_unlock(&MSDOS_I(inode)->cache_lru_lock); return offset; }

Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa18484.79%444.44%
pre-gitpre-git3214.75%444.44%
linus torvaldslinus torvalds10.46%111.11%
Total217100.00%9100.00%


static struct fat_cache *fat_cache_merge(struct inode *inode, struct fat_cache_id *new) { struct fat_cache *p; list_for_each_entry(p, &MSDOS_I(inode)->cache_lru, cache_list) { /* Find the same part as "new" in cluster-chain. */ if (p->fcluster == new->fcluster) { BUG_ON(p->dcluster != new->dcluster); if (new->nr_contig > p->nr_contig) p->nr_contig = new->nr_contig; return p; } } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa6377.78%342.86%
pre-gitpre-git1619.75%342.86%
linus torvaldslinus torvalds22.47%114.29%
Total81100.00%7100.00%


static void fat_cache_add(struct inode *inode, struct fat_cache_id *new) { struct fat_cache *cache, *tmp; if (new->fcluster == -1) /* dummy cache */ return; spin_lock(&MSDOS_I(inode)->cache_lru_lock); if (new->id != FAT_CACHE_VALID && new->id != MSDOS_I(inode)->cache_valid_id) goto out; /* this cache was invalidated */ cache = fat_cache_merge(inode, new); if (cache == NULL) { if (MSDOS_I(inode)->nr_caches < fat_max_cache(inode)) { MSDOS_I(inode)->nr_caches++; spin_unlock(&MSDOS_I(inode)->cache_lru_lock); tmp = fat_cache_alloc(inode); if (!tmp) { spin_lock(&MSDOS_I(inode)->cache_lru_lock); MSDOS_I(inode)->nr_caches--; spin_unlock(&MSDOS_I(inode)->cache_lru_lock); return; } spin_lock(&MSDOS_I(inode)->cache_lru_lock); cache = fat_cache_merge(inode, new); if (cache != NULL) { MSDOS_I(inode)->nr_caches--; fat_cache_free(tmp); goto out_update_lru; } cache = tmp; } else { struct list_head *p = MSDOS_I(inode)->cache_lru.prev; cache = list_entry(p, struct fat_cache, cache_list); } cache->fcluster = new->fcluster; cache->dcluster = new->dcluster; cache->nr_contig = new->nr_contig; } out_update_lru: fat_cache_update_lru(inode, cache); out: spin_unlock(&MSDOS_I(inode)->cache_lru_lock); }

Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa24283.74%555.56%
pre-gitpre-git3612.46%333.33%
linus torvaldslinus torvalds113.81%111.11%
Total289100.00%9100.00%

/* * Cache invalidation occurs rarely, thus the LRU chain is not updated. It * fixes itself after a while. */
static void __fat_cache_inval_inode(struct inode *inode) { struct msdos_inode_info *i = MSDOS_I(inode); struct fat_cache *cache; while (!list_empty(&i->cache_lru)) { cache = list_entry(i->cache_lru.next, struct fat_cache, cache_list); list_del_init(&cache->cache_list); i->nr_caches--; fat_cache_free(cache); } /* Update. The copy of caches before this id is discarded. */ i->cache_valid_id++; if (i->cache_valid_id == FAT_CACHE_VALID) i->cache_valid_id++; }

Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa7682.61%360.00%
pre-gitpre-git1314.13%120.00%
linus torvaldslinus torvalds33.26%120.00%
Total92100.00%5100.00%


void fat_cache_inval_inode(struct inode *inode) { spin_lock(&MSDOS_I(inode)->cache_lru_lock); __fat_cache_inval_inode(inode); spin_unlock(&MSDOS_I(inode)->cache_lru_lock); }

Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa3183.78%266.67%
pre-gitpre-git616.22%133.33%
Total37100.00%3100.00%


static inline int cache_contiguous(struct fat_cache_id *cid, int dclus) { cid->nr_contig++; return ((cid->dcluster + cid->nr_contig) == dclus); }

Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa3394.29%375.00%
pre-gitpre-git25.71%125.00%
Total35100.00%4100.00%


static inline void cache_init(struct fat_cache_id *cid, int fclus, int dclus) { cid->id = FAT_CACHE_VALID; cid->fcluster = fclus; cid->dcluster = dclus; cid->nr_contig = 0; }

Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa4095.24%360.00%
pre-gitpre-git12.38%120.00%
linus torvaldslinus torvalds12.38%120.00%
Total42100.00%5100.00%


int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) { struct super_block *sb = inode->i_sb; const int limit = sb->s_maxbytes >> MSDOS_SB(sb)->cluster_bits; struct fat_entry fatent; struct fat_cache_id cid; int nr; BUG_ON(MSDOS_I(inode)->i_start == 0); *fclus = 0; *dclus = MSDOS_I(inode)->i_start; if (cluster == 0) return 0; if (fat_cache_lookup(inode, cluster, &cid, fclus, dclus) < 0) { /* * dummy, always not contiguous * This is reinitialized by cache_init(), later. */ cache_init(&cid, -1, -1); } fatent_init(&fatent); while (*fclus < cluster) { /* prevent the infinite loop of cluster chain */ if (*fclus > limit) { fat_fs_error_ratelimit(sb, "%s: detected the cluster chain loop" " (i_pos %lld)", __func__, MSDOS_I(inode)->i_pos); nr = -EIO; goto out; } nr = fat_ent_read(inode, &fatent, *dclus); if (nr < 0) goto out; else if (nr == FAT_ENT_FREE) { fat_fs_error_ratelimit(sb, "%s: invalid cluster chain (i_pos %lld)", __func__, MSDOS_I(inode)->i_pos); nr = -EIO; goto out; } else if (nr == FAT_ENT_EOF) { fat_cache_add(inode, &cid); goto out; } (*fclus)++; *dclus = nr; if (!cache_contiguous(&cid, *dclus)) cache_init(&cid, *fclus, *dclus); } nr = 0; fat_cache_add(inode, &cid); out: fatent_brelse(&fatent); return nr; }

Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa29595.78%660.00%
pre-gitpre-git103.25%220.00%
harvey harrisonharvey harrison20.65%110.00%
cruz julian bishopcruz julian bishop10.32%110.00%
Total308100.00%10100.00%


static int fat_bmap_cluster(struct inode *inode, int cluster) { struct super_block *sb = inode->i_sb; int ret, fclus, dclus; if (MSDOS_I(inode)->i_start == 0) return 0; ret = fat_get_cluster(inode, cluster, &fclus, &dclus); if (ret < 0) return ret; else if (ret == FAT_ENT_EOF) { fat_fs_error(sb, "%s: request beyond EOF (i_pos %lld)", __func__, MSDOS_I(inode)->i_pos); return -EIO; } return dclus; }

Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa6262.00%450.00%
pre-gitpre-git3636.00%225.00%
harvey harrisonharvey harrison11.00%112.50%
denis karpovdenis karpov11.00%112.50%
Total100100.00%8100.00%


int fat_get_mapped_cluster(struct inode *inode, sector_t sector, sector_t last_block, unsigned long *mapped_blocks, sector_t *bmap) { struct super_block *sb = inode->i_sb; struct msdos_sb_info *sbi = MSDOS_SB(sb); int cluster, offset; cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits); offset = sector & (sbi->sec_per_clus - 1); cluster = fat_bmap_cluster(inode, cluster); if (cluster < 0) return cluster; else if (cluster) { *bmap = fat_clus_to_blknr(sbi, cluster) + offset; *mapped_blocks = sbi->sec_per_clus - offset; if (*mapped_blocks > last_block - sector) *mapped_blocks = last_block - sector; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
namjae jeonnamjae jeon6949.29%112.50%
pre-gitpre-git3525.00%337.50%
hirofumi ogawahirofumi ogawa2316.43%337.50%
linus torvaldslinus torvalds139.29%112.50%
Total140100.00%8100.00%


static int is_exceed_eof(struct inode *inode, sector_t sector, sector_t *last_block, int create) { struct super_block *sb = inode->i_sb; const unsigned long blocksize = sb->s_blocksize; const unsigned char blocksize_bits = sb->s_blocksize_bits; *last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits; if (sector >= *last_block) { if (!create) return 1; /* * ->mmu_private can access on only allocation path. * (caller must hold ->i_mutex) */ *last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1)) >> blocksize_bits; if (sector >= *last_block) return 1; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
namjae jeonnamjae jeon5647.86%116.67%
hirofumi ogawahirofumi ogawa3529.91%116.67%
pre-gitpre-git1411.97%350.00%
linus torvaldslinus torvalds1210.26%116.67%
Total117100.00%6100.00%


int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys, unsigned long *mapped_blocks, int create, bool from_bmap) { struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); sector_t last_block; *phys = 0; *mapped_blocks = 0; if ((sbi->fat_bits != 32) && (inode->i_ino == MSDOS_ROOT_INO)) { if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits)) { *phys = sector + sbi->dir_start; *mapped_blocks = 1; } return 0; } if (!from_bmap) { if (is_exceed_eof(inode, sector, &last_block, create)) return 0; } else { last_block = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9); if (sector >= last_block) return 0; } return fat_get_mapped_cluster(inode, sector, last_block, mapped_blocks, phys); }

Contributors

PersonTokensPropCommitsCommitProp
namjae jeonnamjae jeon13779.65%116.67%
hirofumi ogawahirofumi ogawa2313.37%350.00%
pre-gitpre-git105.81%116.67%
linus torvaldslinus torvalds21.16%116.67%
Total172100.00%6100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
hirofumi ogawahirofumi ogawa131869.77%1845.00%
namjae jeonnamjae jeon26213.87%12.50%
pre-gitpre-git24813.13%1127.50%
linus torvaldslinus torvalds462.44%37.50%
christoph lameterchristoph lameter50.26%25.00%
tejun heotejun heo30.16%12.50%
harvey harrisonharvey harrison30.16%12.50%
paul jacksonpaul jackson20.11%12.50%
cruz julian bishopcruz julian bishop10.05%12.50%
denis karpovdenis karpov10.05%12.50%
Total1889100.00%40100.00%
Directory: fs/fat
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.