~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/fat/cache.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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/msdos_fs.h>
 12 #include <linux/kernel.h>
 13 #include <linux/errno.h>
 14 #include <linux/string.h>
 15 #include <linux/stat.h>
 16 #include <linux/fat_cvf.h>
 17 
 18 #include "msbuffer.h"
 19 
 20 #if 0
 21 #  define PRINTK(x) printk x
 22 #else
 23 #  define PRINTK(x)
 24 #endif
 25 
 26 static struct fat_cache *fat_cache,cache[FAT_CACHE];
 27 
 28 /* Returns the this'th FAT entry, -1 if it is an end-of-file entry. If
 29    new_value is != -1, that FAT entry is replaced by it. */
 30 
 31 int fat_access(struct super_block *sb,int nr,int new_value)
 32 {
 33         return MSDOS_SB(sb)->cvf_format->fat_access(sb,nr,new_value);
 34 }
 35 
 36 int fat_bmap(struct inode *inode,int sector)
 37 {
 38         return MSDOS_SB(inode->i_sb)->cvf_format->cvf_bmap(inode,sector);
 39 }
 40 
 41 int default_fat_access(struct super_block *sb,int nr,int new_value)
 42 {
 43         struct buffer_head *bh,*bh2,*c_bh,*c_bh2;
 44         unsigned char *p_first,*p_last;
 45         int copy,first,last,next,b;
 46 
 47         if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters)
 48                 return 0;
 49         if (MSDOS_SB(sb)->fat_bits == 32) {
 50                 first = last = nr*4;
 51         } else if (MSDOS_SB(sb)->fat_bits == 16) {
 52                 first = last = nr*2;
 53         } else {
 54                 first = nr*3/2;
 55                 last = first+1;
 56         }
 57         b = MSDOS_SB(sb)->fat_start + (first >> SECTOR_BITS);
 58         if (!(bh = fat_bread(sb, b))) {
 59                 printk("bread in fat_access failed\n");
 60                 return 0;
 61         }
 62         if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS)) {
 63                 bh2 = bh;
 64         } else {
 65                 if (!(bh2 = fat_bread(sb, b+1))) {
 66                         fat_brelse(sb, bh);
 67                         printk("2nd bread in fat_access failed\n");
 68                         return 0;
 69                 }
 70         }
 71         if (MSDOS_SB(sb)->fat_bits == 32) {
 72                 p_first = p_last = NULL; /* GCC needs that stuff */
 73                 next = CF_LE_L(((__u32 *) bh->b_data)[(first &
 74                     (SECTOR_SIZE-1)) >> 2]);
 75                 /* Fscking Microsoft marketing department. Their "32" is 28. */
 76                 next &= 0xfffffff;
 77                 if (next >= 0xffffff7) next = -1;
 78                 PRINTK(("fat_bread: 0x%x, nr=0x%x, first=0x%x, next=0x%x\n", b, nr, first, next));
 79 
 80         } else if (MSDOS_SB(sb)->fat_bits == 16) {
 81                 p_first = p_last = NULL; /* GCC needs that stuff */
 82                 next = CF_LE_W(((__u16 *) bh->b_data)[(first &
 83                     (SECTOR_SIZE-1)) >> 1]);
 84                 if (next >= 0xfff7) next = -1;
 85         } else {
 86                 p_first = &((__u8 *) bh->b_data)[first & (SECTOR_SIZE-1)];
 87                 p_last = &((__u8 *) bh2->b_data)[(first+1) &
 88                     (SECTOR_SIZE-1)];
 89                 if (nr & 1) next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff;
 90                 else next = (*p_first+(*p_last << 8)) & 0xfff;
 91                 if (next >= 0xff7) next = -1;
 92         }
 93         if (new_value != -1) {
 94                 if (MSDOS_SB(sb)->fat_bits == 32) {
 95                         ((__u32 *) bh->b_data)[(first & (SECTOR_SIZE-1)) >>
 96                             2] = CT_LE_L(new_value);
 97                 } else if (MSDOS_SB(sb)->fat_bits == 16) {
 98                         ((__u16 *) bh->b_data)[(first & (SECTOR_SIZE-1)) >>
 99                             1] = CT_LE_W(new_value);
100                 } else {
101                         if (nr & 1) {
102                                 *p_first = (*p_first & 0xf) | (new_value << 4);
103                                 *p_last = new_value >> 4;
104                         }
105                         else {
106                                 *p_first = new_value & 0xff;
107                                 *p_last = (*p_last & 0xf0) | (new_value >> 8);
108                         }
109                         fat_mark_buffer_dirty(sb, bh2);
110                 }
111                 fat_mark_buffer_dirty(sb, bh);
112                 for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) {
113                         b = MSDOS_SB(sb)->fat_start + (first >> SECTOR_BITS) +
114                                 MSDOS_SB(sb)->fat_length * copy;
115                         if (!(c_bh = fat_bread(sb, b)))
116                                 break;
117                         memcpy(c_bh->b_data,bh->b_data,SECTOR_SIZE);
118                         fat_mark_buffer_dirty(sb, c_bh);
119                         if (bh != bh2) {
120                                 if (!(c_bh2 = fat_bread(sb, b+1))) {
121                                         fat_brelse(sb, c_bh);
122                                         break;
123                                 }
124                                 memcpy(c_bh2->b_data,bh2->b_data,SECTOR_SIZE);
125                                 fat_brelse(sb, c_bh2);
126                         }
127                         fat_brelse(sb, c_bh);
128                 }
129         }
130         fat_brelse(sb, bh);
131         if (bh != bh2)
132                 fat_brelse(sb, bh2);
133         return next;
134 }
135 
136 
137 void fat_cache_init(void)
138 {
139         static int initialized = 0;
140         int count;
141 
142         if (initialized) return;
143         fat_cache = &cache[0];
144         for (count = 0; count < FAT_CACHE; count++) {
145                 cache[count].device = 0;
146                 cache[count].next = count == FAT_CACHE-1 ? NULL :
147                     &cache[count+1];
148         }
149         initialized = 1;
150 }
151 
152 
153 void fat_cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu)
154 {
155         struct fat_cache *walk;
156         int first = MSDOS_I(inode)->i_start;
157 
158         if (!first)
159                 return;
160         for (walk = fat_cache; walk; walk = walk->next)
161                 if (inode->i_dev == walk->device
162                     && walk->start_cluster == first
163                     && walk->file_cluster <= cluster
164                     && walk->file_cluster > *f_clu) {
165                         *d_clu = walk->disk_cluster;
166 #ifdef DEBUG
167 printk("cache hit: %d (%d)\n",walk->file_cluster,*d_clu);
168 #endif
169                         if ((*f_clu = walk->file_cluster) == cluster) return;
170                 }
171 #ifdef DEBUG
172 printk("cache miss\n");
173 #endif
174 }
175 
176 
177 #ifdef DEBUG
178 static void list_cache(void)
179 {
180         struct fat_cache *walk;
181 
182         for (walk = fat_cache; walk; walk = walk->next) {
183                 if (walk->device)
184                         printk("<%s,%d>(%d,%d) ", kdevname(walk->device),
185                                walk->start_cluster, walk->file_cluster,
186                                walk->disk_cluster);
187                 else printk("-- ");
188         }
189         printk("\n");
190 }
191 #endif
192 
193 
194 void fat_cache_add(struct inode *inode,int f_clu,int d_clu)
195 {
196         struct fat_cache *walk,*last;
197         int first = MSDOS_I(inode)->i_start;
198 
199         last = NULL;
200         for (walk = fat_cache; walk->next; walk = (last = walk)->next)
201                 if (inode->i_dev == walk->device
202                     && walk->start_cluster == first
203                     && walk->file_cluster == f_clu) {
204                         if (walk->disk_cluster != d_clu) {
205                                 printk("FAT cache corruption inode=%ld\n",
206                                         inode->i_ino);
207                                 fat_cache_inval_inode(inode);
208                                 return;
209                         }
210                         /* update LRU */
211                         if (last == NULL) return;
212                         last->next = walk->next;
213                         walk->next = fat_cache;
214                         fat_cache = walk;
215 #ifdef DEBUG
216 list_cache();
217 #endif
218                         return;
219                 }
220         walk->device = inode->i_dev;
221         walk->start_cluster = first;
222         walk->file_cluster = f_clu;
223         walk->disk_cluster = d_clu;
224         last->next = NULL;
225         walk->next = fat_cache;
226         fat_cache = walk;
227 #ifdef DEBUG
228 list_cache();
229 #endif
230 }
231 
232 
233 /* Cache invalidation occurs rarely, thus the LRU chain is not updated. It
234    fixes itself after a while. */
235 
236 void fat_cache_inval_inode(struct inode *inode)
237 {
238         struct fat_cache *walk;
239         int first = MSDOS_I(inode)->i_start;
240 
241         for (walk = fat_cache; walk; walk = walk->next)
242                 if (walk->device == inode->i_dev
243                     && walk->start_cluster == first)
244                         walk->device = 0;
245 }
246 
247 
248 void fat_cache_inval_dev(kdev_t device)
249 {
250         struct fat_cache *walk;
251 
252         for (walk = fat_cache; walk; walk = walk->next)
253                 if (walk->device == device)
254                         walk->device = 0;
255 }
256 
257 
258 int fat_get_cluster(struct inode *inode,int cluster)
259 {
260         int nr,count;
261 
262         if (!(nr = MSDOS_I(inode)->i_start)) return 0;
263         if (!cluster) return nr;
264         count = 0;
265         for (fat_cache_lookup(inode,cluster,&count,&nr); count < cluster;
266             count++) {
267                 if ((nr = fat_access(inode->i_sb,nr,-1)) == -1) return 0;
268                 if (!nr) return 0;
269         }
270         fat_cache_add(inode,cluster,nr);
271         return nr;
272 }
273 
274 int default_fat_bmap(struct inode *inode,int sector)
275 {
276         struct msdos_sb_info *sb=MSDOS_SB(inode->i_sb);
277         int cluster,offset;
278 
279         if ((sb->fat_bits != 32) &&
280             (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
281              !MSDOS_I(inode)->i_start))) {
282                 if (sector >= sb->dir_entries >> MSDOS_DPS_BITS)
283                         return 0;
284                 return sector+sb->dir_start;
285         }
286         if (sector >= (MSDOS_I(inode)->mmu_private+511)>>9)
287                 return 0;
288         cluster = sector/sb->cluster_size;
289         offset = sector % sb->cluster_size;
290         if (!(cluster = fat_get_cluster(inode,cluster))) return 0;
291         return (cluster-2)*sb->cluster_size+sb->data_start+offset;
292 }
293 
294 
295 /* Free all clusters after the skip'th cluster. Doesn't use the cache,
296    because this way we get an additional sanity check. */
297 
298 int fat_free(struct inode *inode,int skip)
299 {
300         int nr,last;
301 
302         if (!(nr = MSDOS_I(inode)->i_start)) return 0;
303         last = 0;
304         while (skip--) {
305                 last = nr;
306                 if ((nr = fat_access(inode->i_sb,nr,-1)) == -1) return 0;
307                 if (!nr) {
308                         printk("fat_free: skipped EOF\n");
309                         return -EIO;
310                 }
311         }
312         if (last) {
313                 fat_access(inode->i_sb,last,EOF_FAT(inode->i_sb));
314                 fat_cache_inval_inode(inode);
315         } else {
316                 fat_cache_inval_inode(inode);
317                 MSDOS_I(inode)->i_start = 0;
318                 MSDOS_I(inode)->i_logstart = 0;
319                 mark_inode_dirty(inode);
320         }
321         lock_fat(inode->i_sb);
322         while (nr != -1) {
323                 if (!(nr = fat_access(inode->i_sb,nr,0))) {
324                         fat_fs_panic(inode->i_sb,"fat_free: deleting beyond EOF");
325                         break;
326                 }
327                 if (MSDOS_SB(inode->i_sb)->free_clusters != -1) {
328                         MSDOS_SB(inode->i_sb)->free_clusters++;
329                         if (MSDOS_SB(inode->i_sb)->fat_bits == 32) {
330                                 fat_clusters_flush(inode->i_sb);
331                         }
332                 }
333                 inode->i_blocks -= MSDOS_SB(inode->i_sb)->cluster_size;
334         }
335         unlock_fat(inode->i_sb);
336         return 0;
337 }
338 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.