* and consider negative result as cache miss.
*/
-static void fat_hash_init(struct super_block *sb)
+#define FAT_HASH_BITS 8
+#define FAT_HASH_SIZE (1UL << FAT_HASH_BITS)
+#define FAT_HASH_MASK (FAT_HASH_SIZE-1)
+static struct list_head fat_inode_hashtable[FAT_HASH_SIZE];
+static spinlock_t fat_inode_lock = SPIN_LOCK_UNLOCKED;
+
+void fat_hash_init(void)
{
- struct msdos_sb_info *sbi = MSDOS_SB(sb);
int i;
-
- spin_lock_init(&sbi->inode_hash_lock);
- for (i = 0; i < FAT_HASH_SIZE; i++)
- INIT_HLIST_HEAD(&sbi->inode_hashtable[i]);
+ for(i = 0; i < FAT_HASH_SIZE; i++) {
+ INIT_LIST_HEAD(&fat_inode_hashtable[i]);
+ }
}
static inline unsigned long fat_hash(struct super_block *sb, loff_t i_pos)
void fat_attach(struct inode *inode, loff_t i_pos)
{
- struct super_block *sb = inode->i_sb;
- struct msdos_sb_info *sbi = MSDOS_SB(sb);
-
- spin_lock(&sbi->inode_hash_lock);
+ spin_lock(&fat_inode_lock);
MSDOS_I(inode)->i_pos = i_pos;
- hlist_add_head(&MSDOS_I(inode)->i_fat_hash,
- sbi->inode_hashtable + fat_hash(sb, i_pos));
- spin_unlock(&sbi->inode_hash_lock);
+ list_add(&MSDOS_I(inode)->i_fat_hash,
+ fat_inode_hashtable + fat_hash(inode->i_sb, i_pos));
+ spin_unlock(&fat_inode_lock);
}
void fat_detach(struct inode *inode)
{
- struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
- spin_lock(&sbi->inode_hash_lock);
+ spin_lock(&fat_inode_lock);
MSDOS_I(inode)->i_pos = 0;
- hlist_del_init(&MSDOS_I(inode)->i_fat_hash);
- spin_unlock(&sbi->inode_hash_lock);
+ list_del_init(&MSDOS_I(inode)->i_fat_hash);
+ spin_unlock(&fat_inode_lock);
}
struct inode *fat_iget(struct super_block *sb, loff_t i_pos)
{
- struct msdos_sb_info *sbi = MSDOS_SB(sb);
- struct hlist_head *head = sbi->inode_hashtable + fat_hash(sb, i_pos);
- struct hlist_node *_p;
+ struct list_head *p = fat_inode_hashtable + fat_hash(sb, i_pos);
+ struct list_head *walk;
struct msdos_inode_info *i;
struct inode *inode = NULL;
- spin_lock(&sbi->inode_hash_lock);
- hlist_for_each_entry(i, _p, head, i_fat_hash) {
- BUG_ON(i->vfs_inode.i_sb != sb);
+ spin_lock(&fat_inode_lock);
+ list_for_each(walk, p) {
+ i = list_entry(walk, struct msdos_inode_info, i_fat_hash);
+ if (i->vfs_inode.i_sb != sb)
+ continue;
if (i->i_pos != i_pos)
continue;
inode = igrab(&i->vfs_inode);
if (inode)
break;
}
- spin_unlock(&sbi->inode_hash_lock);
+ spin_unlock(&fat_inode_lock);
return inode;
}
static void fat_clear_inode(struct inode *inode)
{
- struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
-
if (is_bad_inode(inode))
return;
lock_kernel();
- spin_lock(&sbi->inode_hash_lock);
+ spin_lock(&fat_inode_lock);
fat_cache_inval_inode(inode);
- hlist_del_init(&MSDOS_I(inode)->i_fat_hash);
- spin_unlock(&sbi->inode_hash_lock);
+ list_del_init(&MSDOS_I(inode)->i_fat_hash);
+ spin_unlock(&fat_inode_lock);
unlock_kernel();
}
struct msdos_sb_info *sbi = MSDOS_SB(sb);
int error;
+ MSDOS_I(inode)->file_cluster = MSDOS_I(inode)->disk_cluster = 0;
MSDOS_I(inode)->i_pos = 0;
inode->i_uid = sbi->options.fs_uid;
inode->i_gid = sbi->options.fs_gid;
if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
SLAB_CTOR_CONSTRUCTOR) {
- spin_lock_init(&ei->cache_lru_lock);
- ei->nr_caches = 0;
- ei->cache_valid_id = FAT_CACHE_VALID + 1;
- INIT_LIST_HEAD(&ei->cache_lru);
- INIT_HLIST_NODE(&ei->i_fat_hash);
+ INIT_LIST_HEAD(&ei->i_fat_hash);
inode_init_once(&ei->vfs_inode);
}
}
struct msdos_sb_info *sbi;
u16 logical_sector_size;
u32 total_sectors, total_clusters, fat_clusters, rootdir_sectors;
- int debug;
+ int debug, first;
unsigned int media;
long error;
char buf[50];
if (error)
goto out_fail;
+ fat_cache_init(sb);
/* set up enough so that it can read an inode */
- fat_hash_init(sb);
init_MUTEX(&sbi->fat_lock);
error = -EIO;
brelse(bh);
goto out_invalid;
}
- logical_sector_size =
- le16_to_cpu(get_unaligned((__le16 *)&b->sector_size));
+ logical_sector_size = CF_LE_W(get_unaligned((__le16 *)&b->sector_size));
if (!logical_sector_size
|| (logical_sector_size & (logical_sector_size - 1))
|| (logical_sector_size < 512)
sbi->cluster_bits = ffs(sbi->cluster_size) - 1;
sbi->fats = b->fats;
sbi->fat_bits = 0; /* Don't know yet */
- sbi->fat_start = le16_to_cpu(b->reserved);
- sbi->fat_length = le16_to_cpu(b->fat_length);
+ sbi->fat_start = CF_LE_W(b->reserved);
+ sbi->fat_length = CF_LE_W(b->fat_length);
sbi->root_cluster = 0;
sbi->free_clusters = -1; /* Don't know yet */
sbi->prev_free = -1;
/* Must be FAT32 */
sbi->fat_bits = 32;
- sbi->fat_length = le32_to_cpu(b->fat32_length);
- sbi->root_cluster = le32_to_cpu(b->root_cluster);
+ sbi->fat_length = CF_LE_L(b->fat32_length);
+ sbi->root_cluster = CF_LE_L(b->root_cluster);
sb->s_maxbytes = 0xffffffff;
/* MC - if info_sector is 0, don't multiply by 0 */
- sbi->fsinfo_sector = le16_to_cpu(b->info_sector);
+ sbi->fsinfo_sector = CF_LE_W(b->info_sector);
if (sbi->fsinfo_sector == 0)
sbi->fsinfo_sector = 1;
"FAT: Did not find valid FSINFO signature.\n"
" Found signature1 0x%08x signature2 0x%08x"
" (sector = %lu)\n",
- le32_to_cpu(fsinfo->signature1),
- le32_to_cpu(fsinfo->signature2),
+ CF_LE_L(fsinfo->signature1),
+ CF_LE_L(fsinfo->signature2),
sbi->fsinfo_sector);
} else {
- sbi->free_clusters = le32_to_cpu(fsinfo->free_clusters);
- sbi->prev_free = le32_to_cpu(fsinfo->next_cluster);
+ sbi->free_clusters = CF_LE_L(fsinfo->free_clusters);
+ sbi->prev_free = CF_LE_L(fsinfo->next_cluster);
}
brelse(fsinfo_bh);
sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1;
sbi->dir_start = sbi->fat_start + sbi->fats * sbi->fat_length;
- sbi->dir_entries =
- le16_to_cpu(get_unaligned((__le16 *)&b->dir_entries));
+ sbi->dir_entries = CF_LE_W(get_unaligned((__le16 *)&b->dir_entries));
if (sbi->dir_entries & (sbi->dir_per_block - 1)) {
if (!silent)
printk(KERN_ERR "FAT: bogus directroy-entries per block"
rootdir_sectors = sbi->dir_entries
* sizeof(struct msdos_dir_entry) / sb->s_blocksize;
sbi->data_start = sbi->dir_start + rootdir_sectors;
- total_sectors = le16_to_cpu(get_unaligned((__le16 *)&b->sectors));
+ total_sectors = CF_LE_W(get_unaligned((__le16 *)&b->sectors));
if (total_sectors == 0)
- total_sectors = le32_to_cpu(b->total_sect);
+ total_sectors = CF_LE_L(b->total_sect);
total_clusters = (total_sectors - sbi->data_start) / sbi->sec_per_clus;
}
sbi->clusters = total_clusters;
- /* check the free_clusters, it's not necessarily correct */
- if (sbi->free_clusters != -1 && sbi->free_clusters > sbi->clusters)
- sbi->free_clusters = -1;
brelse(bh);
- /*
- * The low byte of FAT's first entry must have same value with
- * media-field. But in real world, too many devices is
- * writing wrong value. So, removed that validity check.
- *
- * if (FAT_FIRST_ENT(sb, media) != first)
- */
+ /* validity check of FAT */
+ first = __fat_access(sb, 0, -1);
+ if (first < 0) {
+ error = first;
+ goto out_fail;
+ }
+ if (FAT_FIRST_ENT(sb, media) == first) {
+ /* all is as it should be */
+ } else if (media == 0xf8 && FAT_FIRST_ENT(sb, 0xfe) == first) {
+ /* bad, reported on pc9800 */
+ } else if (media == 0xf8 && FAT_FIRST_ENT(sb, 0xff) == first) {
+ /* bad, reported on Nokia phone with USB storage */
+ } else if (media == 0xf0 && FAT_FIRST_ENT(sb, 0xf8) == first) {
+ /* bad, reported with a MO disk on win95/me */
+ } else if (first == 0) {
+ /* bad, reported with a SmartMedia card */
+ } else {
+ if (!silent)
+ printk(KERN_ERR "FAT: invalid first entry of FAT "
+ "(0x%x != 0x%x)\n",
+ FAT_FIRST_ENT(sb, media), first);
+ goto out_invalid;
+ }
error = -EINVAL;
sprintf(buf, "cp%d", sbi->options.codepage);
struct msdos_sb_info *sbi = MSDOS_SB(sb);
int error;
+ MSDOS_I(inode)->file_cluster = MSDOS_I(inode)->disk_cluster = 0;
MSDOS_I(inode)->i_pos = 0;
inode->i_uid = sbi->options.fs_uid;
inode->i_gid = sbi->options.fs_gid;
inode->i_op = sbi->dir_ops;
inode->i_fop = &fat_dir_operations;
- MSDOS_I(inode)->i_start = le16_to_cpu(de->start);
+ MSDOS_I(inode)->i_start = CF_LE_W(de->start);
if (sbi->fat_bits == 32)
- MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16);
+ MSDOS_I(inode)->i_start |= (CF_LE_W(de->starthi) << 16);
MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
error = fat_calc_dir_size(inode);
!is_exec(de->ext))
? S_IRUGO|S_IWUGO : S_IRWXUGO)
& ~sbi->options.fs_fmask) | S_IFREG;
- MSDOS_I(inode)->i_start = le16_to_cpu(de->start);
+ MSDOS_I(inode)->i_start = CF_LE_W(de->start);
if (sbi->fat_bits == 32)
- MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16);
+ MSDOS_I(inode)->i_start |= (CF_LE_W(de->starthi) << 16);
MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
- inode->i_size = le32_to_cpu(de->size);
+ inode->i_size = CF_LE_L(de->size);
inode->i_op = &fat_file_inode_operations;
inode->i_fop = &fat_file_operations;
inode->i_mapping->a_ops = &fat_aops;
inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1))
& ~((loff_t)sbi->cluster_size - 1)) >> 9;
inode->i_mtime.tv_sec = inode->i_atime.tv_sec =
- date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date));
+ date_dos2unix(CF_LE_W(de->time),CF_LE_W(de->date));
inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = 0;
inode->i_ctime.tv_sec =
MSDOS_SB(sb)->options.isvfat
- ? date_dos2unix(le16_to_cpu(de->ctime), le16_to_cpu(de->cdate))
+ ? date_dos2unix(CF_LE_W(de->ctime),CF_LE_W(de->cdate))
: inode->i_mtime.tv_sec;
inode->i_ctime.tv_nsec = de->ctime_ms * 1000000;
MSDOS_I(inode)->i_ctime_ms = de->ctime_ms;
return 0;
}
-static int fat_write_inode(struct inode *inode, int wait)
+int fat_write_inode(struct inode *inode, int wait)
{
struct super_block *sb = inode->i_sb;
- struct msdos_sb_info *sbi = MSDOS_SB(sb);
struct buffer_head *bh;
struct msdos_dir_entry *raw_entry;
loff_t i_pos;
return 0;
}
lock_kernel();
- if (!(bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits))) {
+ if (!(bh = sb_bread(sb, i_pos >> MSDOS_SB(sb)->dir_per_block_bits))) {
printk(KERN_ERR "FAT: unable to read inode block "
"for updating (i_pos %lld)\n", i_pos);
unlock_kernel();
return -EIO;
}
- spin_lock(&sbi->inode_hash_lock);
+ spin_lock(&fat_inode_lock);
if (i_pos != MSDOS_I(inode)->i_pos) {
- spin_unlock(&sbi->inode_hash_lock);
+ spin_unlock(&fat_inode_lock);
brelse(bh);
unlock_kernel();
goto retry;
}
raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
- [i_pos & (sbi->dir_per_block - 1)];
+ [i_pos & (MSDOS_SB(sb)->dir_per_block - 1)];
if (S_ISDIR(inode->i_mode)) {
raw_entry->attr = ATTR_DIR;
raw_entry->size = 0;
}
else {
raw_entry->attr = ATTR_NONE;
- raw_entry->size = cpu_to_le32(inode->i_size);
+ raw_entry->size = CT_LE_L(inode->i_size);
}
raw_entry->attr |= MSDOS_MKATTR(inode->i_mode) |
MSDOS_I(inode)->i_attrs;
- raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart);
- raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16);
+ raw_entry->start = CT_LE_W(MSDOS_I(inode)->i_logstart);
+ raw_entry->starthi = CT_LE_W(MSDOS_I(inode)->i_logstart >> 16);
fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, &raw_entry->date);
- if (sbi->options.isvfat) {
+ if (MSDOS_SB(sb)->options.isvfat) {
fat_date_unix2dos(inode->i_ctime.tv_sec,&raw_entry->ctime,&raw_entry->cdate);
raw_entry->ctime_ms = MSDOS_I(inode)->i_ctime_ms; /* use i_ctime.tv_nsec? */
}
- spin_unlock(&sbi->inode_hash_lock);
+ spin_unlock(&fat_inode_lock);
mark_buffer_dirty(bh);
brelse(bh);
unlock_kernel();