Blame view
fs/fat/cache.c
8.55 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 |
/* * 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/fs.h> |
5a0e3ad6a include cleanup: ... |
12 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
13 |
#include <linux/buffer_head.h> |
9e975dae2 fat: split includ... |
14 |
#include "fat.h" |
1da177e4c Linux-2.6.12-rc2 |
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
/* 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; } |
e18b890bb [PATCH] slab: rem... |
37 |
static struct kmem_cache *fat_cache_cachep; |
1da177e4c Linux-2.6.12-rc2 |
38 |
|
51cc50685 SL*B: drop kmem c... |
39 |
static void init_once(void *foo) |
1da177e4c Linux-2.6.12-rc2 |
40 41 |
{ struct fat_cache *cache = (struct fat_cache *)foo; |
a35afb830 Remove SLAB_CTOR_... |
42 |
INIT_LIST_HEAD(&cache->cache_list); |
1da177e4c Linux-2.6.12-rc2 |
43 44 45 46 47 48 |
} int __init fat_cache_init(void) { fat_cache_cachep = kmem_cache_create("fat_cache", sizeof(struct fat_cache), |
4b6a9316f [PATCH] cpuset me... |
49 |
0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, |
20c2df83d mm: Remove slab d... |
50 |
init_once); |
1da177e4c Linux-2.6.12-rc2 |
51 52 53 54 |
if (fat_cache_cachep == NULL) return -ENOMEM; return 0; } |
ef6689eff [PATCH] fatfs sec... |
55 |
void fat_cache_destroy(void) |
1da177e4c Linux-2.6.12-rc2 |
56 |
{ |
1a1d92c10 [PATCH] Really ig... |
57 |
kmem_cache_destroy(fat_cache_cachep); |
1da177e4c Linux-2.6.12-rc2 |
58 59 60 61 |
} static inline struct fat_cache *fat_cache_alloc(struct inode *inode) { |
8f5934278 Replace BKL with ... |
62 |
return kmem_cache_alloc(fat_cache_cachep, GFP_NOFS); |
1da177e4c Linux-2.6.12-rc2 |
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
} static inline void fat_cache_free(struct fat_cache *cache) { BUG_ON(!list_empty(&cache->cache_list)); kmem_cache_free(fat_cache_cachep, cache); } 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); } 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; } 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; } 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); |
700309295 fat: Fix possible... |
151 152 153 154 155 156 |
if (!tmp) { spin_lock(&MSDOS_I(inode)->cache_lru_lock); MSDOS_I(inode)->nr_caches--; spin_unlock(&MSDOS_I(inode)->cache_lru_lock); return; } |
1da177e4c Linux-2.6.12-rc2 |
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
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); } /* * 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++; } 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); } static inline int cache_contiguous(struct fat_cache_id *cid, int dclus) { cid->nr_contig++; return ((cid->dcluster + cid->nr_contig) == dclus); } 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; } 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) { |
aaa04b487 fatfs: ratelimit ... |
248 249 250 251 |
fat_fs_error_ratelimit(sb, "%s: detected the cluster chain loop" " (i_pos %lld)", __func__, MSDOS_I(inode)->i_pos); |
1da177e4c Linux-2.6.12-rc2 |
252 253 254 255 256 257 258 259 |
nr = -EIO; goto out; } nr = fat_ent_read(inode, &fatent, *dclus); if (nr < 0) goto out; else if (nr == FAT_ENT_FREE) { |
aaa04b487 fatfs: ratelimit ... |
260 261 262 |
fat_fs_error_ratelimit(sb, "%s: invalid cluster chain" " (i_pos %lld)", __func__, MSDOS_I(inode)->i_pos); |
1da177e4c Linux-2.6.12-rc2 |
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
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; } 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) { |
85c785919 FAT: add 'errors'... |
293 |
fat_fs_error(sb, "%s: request beyond EOF (i_pos %lld)", |
8e24eea72 fs: replace remai... |
294 |
__func__, MSDOS_I(inode)->i_pos); |
1da177e4c Linux-2.6.12-rc2 |
295 296 297 298 |
return -EIO; } return dclus; } |
e5174baae [PATCH] fat: supp... |
299 |
int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys, |
2bdf67eb1 fat: mmu_private ... |
300 |
unsigned long *mapped_blocks, int create) |
1da177e4c Linux-2.6.12-rc2 |
301 302 303 |
{ struct super_block *sb = inode->i_sb; struct msdos_sb_info *sbi = MSDOS_SB(sb); |
2bdf67eb1 fat: mmu_private ... |
304 305 |
const unsigned long blocksize = sb->s_blocksize; const unsigned char blocksize_bits = sb->s_blocksize_bits; |
1da177e4c Linux-2.6.12-rc2 |
306 307 308 309 |
sector_t last_block; int cluster, offset; *phys = 0; |
e5174baae [PATCH] fat: supp... |
310 |
*mapped_blocks = 0; |
1da177e4c Linux-2.6.12-rc2 |
311 |
if ((sbi->fat_bits != 32) && (inode->i_ino == MSDOS_ROOT_INO)) { |
e5174baae [PATCH] fat: supp... |
312 |
if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits)) { |
1da177e4c Linux-2.6.12-rc2 |
313 |
*phys = sector + sbi->dir_start; |
e5174baae [PATCH] fat: supp... |
314 315 |
*mapped_blocks = 1; } |
1da177e4c Linux-2.6.12-rc2 |
316 317 |
return 0; } |
2bdf67eb1 fat: mmu_private ... |
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits; if (sector >= last_block) { if (!create) return 0; /* * ->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 0; } |
1da177e4c Linux-2.6.12-rc2 |
333 334 335 336 337 338 |
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; |
e5174baae [PATCH] fat: supp... |
339 |
else if (cluster) { |
1da177e4c Linux-2.6.12-rc2 |
340 |
*phys = fat_clus_to_blknr(sbi, cluster) + offset; |
e5174baae [PATCH] fat: supp... |
341 342 343 344 |
*mapped_blocks = sbi->sec_per_clus - offset; if (*mapped_blocks > last_block - sector) *mapped_blocks = last_block - sector; } |
1da177e4c Linux-2.6.12-rc2 |
345 346 |
return 0; } |