Line data Source code
1 : /*
2 : * linux/fs/fat/cache.c
3 : *
4 : * Written 1992,1993 by Werner Almesberger
5 : *
6 : * Mar 1999. AV. Changed cache, so that it uses the starting cluster instead
7 : * of inode number.
8 : * May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers.
9 : */
10 :
11 : #include <linux/fs.h>
12 : #include <linux/buffer_head.h>
13 : #include "fat.h"
14 :
15 : /* this must be > 0. */
16 : #define FAT_MAX_CACHE 8
17 :
18 : struct fat_cache {
19 : struct list_head cache_list;
20 : int nr_contig; /* number of contiguous clusters */
21 : int fcluster; /* cluster number in the file. */
22 : int dcluster; /* cluster number on disk. */
23 : };
24 1 :
25 : struct fat_cache_id {
26 : unsigned int id;
27 : int nr_contig;
28 : int fcluster;
29 : int dcluster;
30 : };
31 :
32 : static inline int fat_max_cache(struct inode *inode)
33 : {
34 146 : return FAT_MAX_CACHE;
35 : }
36 :
37 1 : static struct kmem_cache *fat_cache_cachep;
38 :
39 : static void init_once(void *foo)
40 : {
41 0 : struct fat_cache *cache = (struct fat_cache *)foo;
42 :
43 0 : INIT_LIST_HEAD(&cache->cache_list);
44 0 : }
45 :
46 : int __init fat_cache_init(void)
47 : {
48 1 : fat_cache_cachep = kmem_cache_create("fat_cache",
49 : sizeof(struct fat_cache),
50 : 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
51 : init_once);
52 2 : if (fat_cache_cachep == NULL)
53 1 : return -ENOMEM;
54 1 : return 0;
55 : }
56 :
57 : void fat_cache_destroy(void)
58 : {
59 3 : kmem_cache_destroy(fat_cache_cachep);
60 3 : }
61 :
62 : static inline struct fat_cache *fat_cache_alloc(struct inode *inode)
63 : {
64 438 : return kmem_cache_alloc(fat_cache_cachep, GFP_NOFS);
65 : }
66 :
67 : static inline void fat_cache_free(struct fat_cache *cache)
68 : {
69 1359 : BUG_ON(!list_empty(&cache->cache_list));
70 302 : kmem_cache_free(fat_cache_cachep, cache);
71 151 : }
72 :
73 : static inline void fat_cache_update_lru(struct inode *inode,
74 : struct fat_cache *cache)
75 657 : {
76 3285 : if (MSDOS_I(inode)->cache_lru.next != &cache->cache_list)
77 2628 : list_move(&cache->cache_list, &MSDOS_I(inode)->cache_lru);
78 1314 : }
79 :
80 : static int fat_cache_lookup(struct inode *inode, int fclus,
81 : struct fat_cache_id *cid,
82 : int *cached_fclus, int *cached_dclus)
83 73 : {
84 438 : static struct fat_cache nohit = { .fcluster = 0, };
85 73 :
86 146 : struct fat_cache *hit = &nohit, *p;
87 146 : int offset = -1;
88 73 :
89 365 : spin_lock(&MSDOS_I(inode)->cache_lru_lock);
90 949 : list_for_each_entry(p, &MSDOS_I(inode)->cache_lru, cache_list) {
91 219 : /* Find the cache of "fclus" or nearest cache. */
92 438 : if (p->fcluster <= fclus && hit->fcluster < p->fcluster) {
93 146 : hit = p;
94 146 : if ((hit->fcluster + hit->nr_contig) < fclus) {
95 73 : offset = hit->nr_contig;
96 73 : } else {
97 73 : offset = fclus - hit->fcluster;
98 73 : break;
99 : }
100 : }
101 : }
102 146 : if (hit != &nohit) {
103 219 : fat_cache_update_lru(inode, hit);
104 :
105 219 : cid->id = MSDOS_I(inode)->cache_valid_id;
106 73 : cid->nr_contig = hit->nr_contig;
107 73 : cid->fcluster = hit->fcluster;
108 73 : cid->dcluster = hit->dcluster;
109 73 : *cached_fclus = cid->fcluster + offset;
110 73 : *cached_dclus = cid->dcluster + offset;
111 : }
112 438 : spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
113 :
114 73 : return offset;
115 : }
116 :
117 : static struct fat_cache *fat_cache_merge(struct inode *inode,
118 : struct fat_cache_id *new)
119 438 : {
120 438 : struct fat_cache *p;
121 438 :
122 5694 : list_for_each_entry(p, &MSDOS_I(inode)->cache_lru, cache_list) {
123 1314 : /* Find the same part as "new" in cluster-chain. */
124 1752 : if (p->fcluster == new->fcluster) {
125 2628 : BUG_ON(p->dcluster != new->dcluster);
126 876 : if (new->nr_contig > p->nr_contig)
127 438 : p->nr_contig = new->nr_contig;
128 438 : return p;
129 : }
130 : }
131 438 : return NULL;
132 : }
133 :
134 : static void fat_cache_add(struct inode *inode, struct fat_cache_id *new)
135 : {
136 146 : struct fat_cache *cache, *tmp;
137 146 :
138 438 : if (new->fcluster == -1) /* dummy cache */
139 292 : return;
140 146 :
141 730 : spin_lock(&MSDOS_I(inode)->cache_lru_lock);
142 1022 : if (new->id != FAT_CACHE_VALID &&
143 146 : new->id != MSDOS_I(inode)->cache_valid_id)
144 292 : goto out; /* this cache was invalidated */
145 146 :
146 1022 : cache = fat_cache_merge(inode, new);
147 438 : if (cache == NULL) {
148 1022 : if (MSDOS_I(inode)->nr_caches < fat_max_cache(inode)) {
149 584 : MSDOS_I(inode)->nr_caches++;
150 584 : spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
151 :
152 292 : tmp = fat_cache_alloc(inode);
153 584 : spin_lock(&MSDOS_I(inode)->cache_lru_lock);
154 438 : cache = fat_cache_merge(inode, new);
155 292 : if (cache != NULL) {
156 438 : MSDOS_I(inode)->nr_caches--;
157 292 : fat_cache_free(tmp);
158 146 : goto out_update_lru;
159 : }
160 146 : cache = tmp;
161 : } else {
162 438 : struct list_head *p = MSDOS_I(inode)->cache_lru.prev;
163 292 : cache = list_entry(p, struct fat_cache, cache_list);
164 : }
165 292 : cache->fcluster = new->fcluster;
166 292 : cache->dcluster = new->dcluster;
167 292 : cache->nr_contig = new->nr_contig;
168 : }
169 : out_update_lru:
170 1752 : fat_cache_update_lru(inode, cache);
171 438 : out:
172 1022 : spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
173 146 : }
174 :
175 : /*
176 : * Cache invalidation occurs rarely, thus the LRU chain is not updated. It
177 : * fixes itself after a while.
178 : */
179 : static void __fat_cache_inval_inode(struct inode *inode)
180 : {
181 20 : struct msdos_inode_info *i = MSDOS_I(inode);
182 5 : struct fat_cache *cache;
183 5 :
184 30 : while (!list_empty(&i->cache_lru)) {
185 20 : cache = list_entry(i->cache_lru.next, struct fat_cache, cache_list);
186 15 : list_del_init(&cache->cache_list);
187 5 : i->nr_caches--;
188 10 : fat_cache_free(cache);
189 : }
190 5 : /* Update. The copy of caches before this id is discarded. */
191 5 : i->cache_valid_id++;
192 10 : if (i->cache_valid_id == FAT_CACHE_VALID)
193 5 : i->cache_valid_id++;
194 5 : }
195 :
196 : void fat_cache_inval_inode(struct inode *inode)
197 : {
198 25 : spin_lock(&MSDOS_I(inode)->cache_lru_lock);
199 15 : __fat_cache_inval_inode(inode);
200 20 : spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
201 5 : }
202 :
203 : static inline int cache_contiguous(struct fat_cache_id *cid, int dclus)
204 : {
205 73 : cid->nr_contig++;
206 73 : return ((cid->dcluster + cid->nr_contig) == dclus);
207 : }
208 :
209 : static inline void cache_init(struct fat_cache_id *cid, int fclus, int dclus)
210 : {
211 146 : cid->id = FAT_CACHE_VALID;
212 146 : cid->fcluster = fclus;
213 146 : cid->dcluster = dclus;
214 146 : cid->nr_contig = 0;
215 146 : }
216 :
217 : int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
218 : {
219 146 : struct super_block *sb = inode->i_sb;
220 365 : const int limit = sb->s_maxbytes >> MSDOS_SB(sb)->cluster_bits;
221 73 : struct fat_entry fatent;
222 73 : struct fat_cache_id cid;
223 73 : int nr;
224 73 :
225 657 : BUG_ON(MSDOS_I(inode)->i_start == 0);
226 73 :
227 146 : *fclus = 0;
228 292 : *dclus = MSDOS_I(inode)->i_start;
229 219 : if (cluster == 0)
230 146 : return 0;
231 73 :
232 292 : if (fat_cache_lookup(inode, cluster, &cid, fclus, dclus) < 0) {
233 : /*
234 : * dummy, always not contiguous
235 : * This is reinitialized by cache_init(), later.
236 : */
237 146 : cache_init(&cid, -1, -1);
238 : }
239 :
240 292 : fatent_init(&fatent);
241 219 : while (*fclus < cluster) {
242 73 : /* prevent the infinite loop of cluster chain */
243 219 : if (*fclus > limit) {
244 292 : fat_fs_error(sb, "%s: detected the cluster chain loop"
245 : " (i_pos %lld)", __func__,
246 : MSDOS_I(inode)->i_pos);
247 73 : nr = -EIO;
248 73 : goto out;
249 : }
250 :
251 292 : nr = fat_ent_read(inode, &fatent, *dclus);
252 146 : if (nr < 0)
253 73 : goto out;
254 146 : else if (nr == FAT_ENT_FREE) {
255 292 : fat_fs_error(sb, "%s: invalid cluster chain"
256 : " (i_pos %lld)", __func__,
257 : MSDOS_I(inode)->i_pos);
258 73 : nr = -EIO;
259 73 : goto out;
260 146 : } else if (nr == FAT_ENT_EOF) {
261 219 : fat_cache_add(inode, &cid);
262 73 : goto out;
263 : }
264 73 : (*fclus)++;
265 73 : *dclus = nr;
266 292 : if (!cache_contiguous(&cid, *dclus))
267 146 : cache_init(&cid, *fclus, *dclus);
268 : }
269 73 : nr = 0;
270 219 : fat_cache_add(inode, &cid);
271 : out:
272 949 : fatent_brelse(&fatent);
273 73 : return nr;
274 : }
275 :
276 : static int fat_bmap_cluster(struct inode *inode, int cluster)
277 : {
278 128 : struct super_block *sb = inode->i_sb;
279 64 : int ret, fclus, dclus;
280 64 :
281 320 : if (MSDOS_I(inode)->i_start == 0)
282 128 : return 0;
283 64 :
284 192 : ret = fat_get_cluster(inode, cluster, &fclus, &dclus);
285 128 : if (ret < 0)
286 64 : return ret;
287 128 : else if (ret == FAT_ENT_EOF) {
288 256 : fat_fs_error(sb, "%s: request beyond EOF (i_pos %lld)",
289 : __func__, MSDOS_I(inode)->i_pos);
290 64 : return -EIO;
291 : }
292 64 : return dclus;
293 : }
294 :
295 : int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
296 : unsigned long *mapped_blocks, int create)
297 : {
298 64 : struct super_block *sb = inode->i_sb;
299 128 : struct msdos_sb_info *sbi = MSDOS_SB(sb);
300 64 : const unsigned long blocksize = sb->s_blocksize;
301 64 : const unsigned char blocksize_bits = sb->s_blocksize_bits;
302 32 : sector_t last_block;
303 32 : int cluster, offset;
304 32 :
305 64 : *phys = 0;
306 64 : *mapped_blocks = 0;
307 192 : if ((sbi->fat_bits != 32) && (inode->i_ino == MSDOS_ROOT_INO)) {
308 128 : if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits)) {
309 32 : *phys = sector + sbi->dir_start;
310 32 : *mapped_blocks = 1;
311 : }
312 32 : return 0;
313 : }
314 :
315 96 : last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits;
316 64 : if (sector >= last_block) {
317 64 : if (!create)
318 32 : return 0;
319 :
320 : /*
321 : * ->mmu_private can access on only allocation path.
322 : * (caller must hold ->i_mutex)
323 : */
324 128 : last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1))
325 : >> blocksize_bits;
326 64 : if (sector >= last_block)
327 32 : return 0;
328 : }
329 :
330 192 : cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits);
331 128 : offset = sector & (sbi->sec_per_clus - 1);
332 256 : cluster = fat_bmap_cluster(inode, cluster);
333 64 : if (cluster < 0)
334 32 : return cluster;
335 64 : else if (cluster) {
336 96 : *phys = fat_clus_to_blknr(sbi, cluster) + offset;
337 64 : *mapped_blocks = sbi->sec_per_clus - offset;
338 64 : if (*mapped_blocks > last_block - sector)
339 32 : *mapped_blocks = last_block - sector;
340 : }
341 64 : return 0;
342 : }
|