/*
* linux/fs/fat/inode.c
*
* Written 1992,1993 by Werner Almesberger
* VFAT extensions by Gordon Chaffee, merged with msdos fs by Henrik Storner
* Rewritten for the constant inumbers support by Al Viro
*
* Fixes:
*
* Max Cohan: Fixed invalid FSINFO offset when info_sector is 0
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/slab.h>
#include <linux/seq_file.h>
#include <linux/pagemap.h>
#include <linux/mpage.h>
#include <linux/buffer_head.h>
#include <linux/mount.h>
#include <linux/aio.h>
#include <linux/vfs.h>
#include <linux/parser.h>
#include <linux/uio.h>
#include <linux/writeback.h>
#include <linux/log2.h>
#include <linux/hash.h>
#include <linux/blkdev.h>
#include <asm/unaligned.h>
#include "fat.h"
#ifndef CONFIG_FAT_DEFAULT_IOCHARSET
/* if user don't select VFAT, this is undefined. */
#define CONFIG_FAT_DEFAULT_IOCHARSET ""
#endif
static int fat_default_codepage = CONFIG_FAT_DEFAULT_CODEPAGE;
static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET;
static int fat_add_cluster(struct inode *inode)
{
int err, cluster;
err = fat_alloc_clusters(inode, &cluster, 1);
if (err)
return err;
/* FIXME: this cluster should be added after data of this
* cluster is writed */
err = fat_chain_add(inode, cluster, 1);
if (err)
fat_free_clusters(inode, cluster);
return err;
}
static inline int __fat_get_block(struct inode *inode, sector_t iblock,
unsigned long *max_blocks,
struct buffer_head *bh_result, int create)
{
struct super_block *sb = inode->i_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb);
unsigned long mapped_blocks;
sector_t phys;
int err, offset;
err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create);
if (err)
return err;
if (phys) {
map_bh(bh_result, sb, phys);
*max_blocks = min(mapped_blocks, *max_blocks);
return 0;
}
if (!create)
return 0;
if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) {
fat_fs_error(sb, "corrupted file size (i_pos %lld, %lld)",
MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private);
return -EIO;
}
offset = (unsigned long)iblock & (sbi->sec_per_clus - 1);
if (!offset) {
/* TODO: multiple cluster allocation would be desirable. */
err = fat_add_cluster(inode);
if (err)
return err;
}
/* available blocks on this cluster */
mapped_blocks = sbi->sec_per_clus - offset;
*max_blocks = min(mapped_blocks, *max_blocks);
MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits;
err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create);
if (err)
return err;
BUG_ON(!phys);
BUG_ON(*max_blocks != mapped_blocks);
set_buffer_new(bh_result);
map_bh(bh_result, sb, phys);
return 0;
}
static int fat_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int creat
|