|
|
1.1 ! root 1: /* ! 2: * linux/fs/msdos/fat.c ! 3: * ! 4: * Written 1992 by Werner Almesberger ! 5: */ ! 6: ! 7: #include <linux/msdos_fs.h> ! 8: #include <linux/kernel.h> ! 9: #include <linux/errno.h> ! 10: #include <linux/stat.h> ! 11: ! 12: static struct fat_cache *fat_cache,cache[FAT_CACHE]; ! 13: ! 14: /* Returns the this'th FAT entry, -1 if it is an end-of-file entry. If ! 15: new_value is != -1, that FAT entry is replaced by it. */ ! 16: ! 17: int fat_access(struct super_block *sb,int this,int new_value) ! 18: { ! 19: struct buffer_head *bh,*bh2,*c_bh,*c_bh2; ! 20: unsigned char *p_first,*p_last; ! 21: void *data,*data2,*c_data,*c_data2; ! 22: int first,last,next,copy; ! 23: ! 24: if (MSDOS_SB(sb)->fat_bits == 16) first = last = this*2; ! 25: else { ! 26: first = this*3/2; ! 27: last = first+1; ! 28: } ! 29: if (!(bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >> ! 30: SECTOR_BITS),&data))) { ! 31: printk("bread in fat_access failed\r\n"); ! 32: return 0; ! 33: } ! 34: if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS)) { ! 35: bh2 = bh; ! 36: data2 = data; ! 37: } ! 38: else { ! 39: if (!(bh2 = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last ! 40: >> SECTOR_BITS),&data2))) { ! 41: brelse(bh); ! 42: printk("bread in fat_access failed\r\n"); ! 43: return 0; ! 44: } ! 45: } ! 46: if (MSDOS_SB(sb)->fat_bits == 16) { ! 47: next = ((unsigned short *) data)[(first & (SECTOR_SIZE-1)) ! 48: >> 1]; ! 49: if (next >= 0xfff8) next = -1; ! 50: } ! 51: else { ! 52: p_first = &((unsigned char *) data)[first & (SECTOR_SIZE-1)]; ! 53: p_last = &((unsigned char *) data2)[(first+1) & ! 54: (SECTOR_SIZE-1)]; ! 55: if (this & 1) next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff; ! 56: else next = (*p_first+(*p_last << 8)) & 0xfff; ! 57: if (next >= 0xff8) next = -1; ! 58: } ! 59: if (new_value != -1) { ! 60: if (MSDOS_SB(sb)->fat_bits == 16) ! 61: ((unsigned short *) data)[(first & (SECTOR_SIZE-1)) >> ! 62: 1] = new_value; ! 63: else { ! 64: if (this & 1) { ! 65: *p_first = (*p_first & 0xf) | (new_value << 4); ! 66: *p_last = new_value >> 4; ! 67: } ! 68: else { ! 69: *p_first = new_value & 0xff; ! 70: *p_last = (*p_last & 0xf0) | (new_value >> 8); ! 71: } ! 72: bh2->b_dirt = 1; ! 73: } ! 74: bh->b_dirt = 1; ! 75: for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) { ! 76: if (!(c_bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)-> ! 77: fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)-> ! 78: fat_length*copy,&c_data))) break; ! 79: memcpy(c_data,data,SECTOR_SIZE); ! 80: c_bh->b_dirt = 1; ! 81: if (data != data2 || bh != bh2) { ! 82: if (!(c_bh2 = msdos_sread(sb->s_dev, ! 83: MSDOS_SB(sb)->fat_start+(first >> ! 84: SECTOR_BITS)+MSDOS_SB(sb)->fat_length*copy ! 85: +1,&c_data2))) { ! 86: brelse(c_bh); ! 87: break; ! 88: } ! 89: memcpy(c_data2,data2,SECTOR_SIZE); ! 90: brelse(c_bh2); ! 91: } ! 92: brelse(c_bh); ! 93: } ! 94: } ! 95: brelse(bh); ! 96: if (data != data2) brelse(bh2); ! 97: return next; ! 98: } ! 99: ! 100: ! 101: void cache_init(void) ! 102: { ! 103: static int initialized = 0; ! 104: int count; ! 105: ! 106: if (initialized) return; ! 107: fat_cache = &cache[0]; ! 108: for (count = 0; count < FAT_CACHE; count++) { ! 109: cache[count].device = 0; ! 110: cache[count].next = count == FAT_CACHE-1 ? NULL : ! 111: &cache[count+1]; ! 112: } ! 113: initialized = 1; ! 114: } ! 115: ! 116: ! 117: void cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu) ! 118: { ! 119: struct fat_cache *walk; ! 120: ! 121: #ifdef DEBUG ! 122: printk("cache lookup: %d\r\n",*f_clu); ! 123: #endif ! 124: for (walk = fat_cache; walk; walk = walk->next) ! 125: if (inode->i_dev == walk->device && walk->ino == inode->i_ino && ! 126: walk->file_cluster <= cluster && walk->file_cluster > ! 127: *f_clu) { ! 128: *d_clu = walk->disk_cluster; ! 129: #ifdef DEBUG ! 130: printk("cache hit: %d (%d)\r\n",walk->file_cluster,*d_clu); ! 131: #endif ! 132: if ((*f_clu = walk->file_cluster) == cluster) return; ! 133: } ! 134: } ! 135: ! 136: ! 137: #ifdef DEBUG ! 138: static void list_cache(void) ! 139: { ! 140: struct fat_cache *walk; ! 141: ! 142: for (walk = fat_cache; walk; walk = walk->next) { ! 143: if (walk->device) printk("(%d,%d) ",walk->file_cluster, ! 144: walk->disk_cluster); ! 145: else printk("-- "); ! 146: } ! 147: printk("\r\n"); ! 148: } ! 149: #endif ! 150: ! 151: ! 152: void cache_add(struct inode *inode,int f_clu,int d_clu) ! 153: { ! 154: struct fat_cache *walk,*last; ! 155: ! 156: #ifdef DEBUG ! 157: printk("cache add: %d (%d)\r\n",f_clu,d_clu); ! 158: #endif ! 159: last = NULL; ! 160: for (walk = fat_cache; walk->next; walk = (last = walk)->next) ! 161: if (inode->i_dev == walk->device && walk->ino == inode->i_ino && ! 162: walk->file_cluster == f_clu) { ! 163: if (walk->disk_cluster != d_clu) ! 164: panic("FAT cache corruption"); ! 165: /* update LRU */ ! 166: if (last == NULL) return; ! 167: last->next = walk->next; ! 168: walk->next = fat_cache; ! 169: fat_cache = walk; ! 170: #ifdef DEBUG ! 171: list_cache(); ! 172: #endif ! 173: return; ! 174: } ! 175: walk->device = inode->i_dev; ! 176: walk->ino = inode->i_ino; ! 177: walk->file_cluster = f_clu; ! 178: walk->disk_cluster = d_clu; ! 179: last->next = NULL; ! 180: walk->next = fat_cache; ! 181: fat_cache = walk; ! 182: #ifdef DEBUG ! 183: list_cache(); ! 184: #endif ! 185: } ! 186: ! 187: ! 188: /* Cache invalidation occurs rarely, thus the LRU chain is not updated. It ! 189: fixes itself after a while. */ ! 190: ! 191: void cache_inval_inode(struct inode *inode) ! 192: { ! 193: struct fat_cache *walk; ! 194: ! 195: for (walk = fat_cache; walk; walk = walk->next) ! 196: if (walk->device == inode->i_dev && walk->ino == inode->i_ino) ! 197: walk->device = 0; ! 198: } ! 199: ! 200: ! 201: void cache_inval_dev(int device) ! 202: { ! 203: struct fat_cache *walk; ! 204: ! 205: for (walk = fat_cache; walk; walk = walk->next) ! 206: if (walk->device == device) walk->device = 0; ! 207: } ! 208: ! 209: ! 210: int get_cluster(struct inode *inode,int cluster) ! 211: { ! 212: int this,count; ! 213: ! 214: if (!(this = inode->i_data[D_START])) return 0; ! 215: if (!cluster) return this; ! 216: count = 0; ! 217: for (cache_lookup(inode,cluster,&count,&this); count < cluster; ! 218: count++) { ! 219: if ((this = fat_access(inode->i_sb,this,-1)) == -1) return 0; ! 220: if (!this) return 0; ! 221: } ! 222: cache_add(inode,cluster,this); ! 223: return this; ! 224: } ! 225: ! 226: ! 227: int msdos_smap(struct inode *inode,int sector) ! 228: { ! 229: struct msdos_sb_info *sb; ! 230: int cluster,offset; ! 231: ! 232: sb = MSDOS_SB(inode->i_sb); ! 233: if (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) && ! 234: !inode->i_data[D_START])) { ! 235: if (sector >= sb->dir_entries >> MSDOS_DPS_BITS) return 0; ! 236: return sector+sb->dir_start; ! 237: } ! 238: cluster = sector/sb->cluster_size; ! 239: offset = sector % sb->cluster_size; ! 240: if (!(cluster = get_cluster(inode,cluster))) return 0; ! 241: return (cluster-2)*sb->cluster_size+sb->data_start+offset; ! 242: } ! 243: ! 244: ! 245: /* Free all clusters after the skip'th cluster. Doesn't use the cache, ! 246: because this way we get an additional sanity check. */ ! 247: ! 248: int fat_free(struct inode *inode,int skip) ! 249: { ! 250: int this,last; ! 251: ! 252: if (!(this = inode->i_data[D_START])) return 0; ! 253: last = 0; ! 254: while (skip--) { ! 255: last = this; ! 256: if ((this = fat_access(inode->i_sb,this,-1)) == -1) ! 257: return 0; ! 258: if (!this) { ! 259: printk("fat_free: skipped EOF\r\n"); ! 260: return -EIO; ! 261: } ! 262: } ! 263: if (last) ! 264: fat_access(inode->i_sb,last,MSDOS_SB(inode->i_sb)->fat_bits == ! 265: 12 ? 0xff8 : 0xfff8); ! 266: else { ! 267: inode->i_data[D_START] = 0; ! 268: inode->i_dirt = 1; ! 269: } ! 270: while (this != -1) ! 271: if (!(this = fat_access(inode->i_sb,this,0))) ! 272: panic("fat_free: deleting beyond EOF"); ! 273: cache_inval_inode(inode); ! 274: return 0; ! 275: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.