*
* Fixes:
*
- * Max Cohan: Fixed invalid FSINFO offset when info_sector is 0
+ * 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/smp_lock.h>
static int fat_default_codepage = CONFIG_FAT_DEFAULT_CODEPAGE;
static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET;
+
+static int fat_get_block(struct inode *inode, sector_t iblock,
+ struct buffer_head *bh_result, int create)
+{
+ struct super_block *sb = inode->i_sb;
+ sector_t phys;
+ int err;
+
+ err = fat_bmap(inode, iblock, &phys);
+ if (err)
+ return err;
+ if (phys) {
+ map_bh(bh_result, sb, phys);
+ return 0;
+ }
+ if (!create)
+ return 0;
+ if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) {
+ fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)",
+ MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private);
+ return -EIO;
+ }
+ if (!((unsigned long)iblock & (MSDOS_SB(sb)->sec_per_clus - 1))) {
+ int error;
+
+ error = fat_add_cluster(inode);
+ if (error < 0)
+ return error;
+ }
+ MSDOS_I(inode)->mmu_private += sb->s_blocksize;
+ err = fat_bmap(inode, iblock, &phys);
+ if (err)
+ return err;
+ if (!phys)
+ BUG();
+ set_buffer_new(bh_result);
+ map_bh(bh_result, sb, phys);
+ return 0;
+}
+
+static int fat_writepage(struct page *page, struct writeback_control *wbc)
+{
+ return block_write_full_page(page, fat_get_block, wbc);
+}
+
+static int fat_readpage(struct file *file, struct page *page)
+{
+ return block_read_full_page(page, fat_get_block);
+}
+
+static int fat_prepare_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+{
+ return cont_prepare_write(page, from, to, fat_get_block,
+ &MSDOS_I(page->mapping->host)->mmu_private);
+}
+
+static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
+{
+ return generic_block_bmap(mapping, block, fat_get_block);
+}
+
+static struct address_space_operations fat_aops = {
+ .readpage = fat_readpage,
+ .writepage = fat_writepage,
+ .sync_page = block_sync_page,
+ .prepare_write = fat_prepare_write,
+ .commit_write = generic_commit_write,
+ .bmap = _fat_bmap
+};
+
/*
* New FAT inode stuff. We do the following:
* a) i_ino is constant and has nothing with on-disk location.
* and consider negative result as cache miss.
*/
-#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)
+static void fat_hash_init(struct super_block *sb)
{
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
int i;
- for(i = 0; i < FAT_HASH_SIZE; i++) {
- INIT_LIST_HEAD(&fat_inode_hashtable[i]);
- }
+
+ spin_lock_init(&sbi->inode_hash_lock);
+ for (i = 0; i < FAT_HASH_SIZE; i++)
+ INIT_HLIST_HEAD(&sbi->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)
{
- spin_lock(&fat_inode_lock);
+ struct super_block *sb = inode->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+
+ spin_lock(&sbi->inode_hash_lock);
MSDOS_I(inode)->i_pos = i_pos;
- list_add(&MSDOS_I(inode)->i_fat_hash,
- fat_inode_hashtable + fat_hash(inode->i_sb, i_pos));
- spin_unlock(&fat_inode_lock);
+ hlist_add_head(&MSDOS_I(inode)->i_fat_hash,
+ sbi->inode_hashtable + fat_hash(sb, i_pos));
+ spin_unlock(&sbi->inode_hash_lock);
}
+EXPORT_SYMBOL(fat_attach);
+
void fat_detach(struct inode *inode)
{
- spin_lock(&fat_inode_lock);
+ struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+ spin_lock(&sbi->inode_hash_lock);
MSDOS_I(inode)->i_pos = 0;
- list_del_init(&MSDOS_I(inode)->i_fat_hash);
- spin_unlock(&fat_inode_lock);
+ hlist_del_init(&MSDOS_I(inode)->i_fat_hash);
+ spin_unlock(&sbi->inode_hash_lock);
}
+EXPORT_SYMBOL(fat_detach);
+
struct inode *fat_iget(struct super_block *sb, loff_t i_pos)
{
- struct list_head *p = fat_inode_hashtable + fat_hash(sb, i_pos);
- struct list_head *walk;
+ 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 msdos_inode_info *i;
struct inode *inode = NULL;
- 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;
+ spin_lock(&sbi->inode_hash_lock);
+ hlist_for_each_entry(i, _p, head, i_fat_hash) {
+ BUG_ON(i->vfs_inode.i_sb != sb);
if (i->i_pos != i_pos)
continue;
inode = igrab(&i->vfs_inode);
if (inode)
break;
}
- spin_unlock(&fat_inode_lock);
+ spin_unlock(&sbi->inode_hash_lock);
return inode;
}
-static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de);
+static int is_exec(unsigned char *extension)
+{
+ unsigned char *exe_extensions = "EXECOMBAT", *walk;
+
+ for (walk = exe_extensions; *walk; walk += 3)
+ if (!strncmp(extension, walk, 3))
+ return 1;
+ return 0;
+}
+
+static int fat_calc_dir_size(struct inode *inode)
+{
+ struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+ int ret, fclus, dclus;
+
+ inode->i_size = 0;
+ if (MSDOS_I(inode)->i_start == 0)
+ return 0;
+
+ ret = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus);
+ if (ret < 0)
+ return ret;
+ inode->i_size = (fclus + 1) << sbi->cluster_bits;
+
+ return 0;
+}
+
+/* doesn't deal with root inode */
+static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
+{
+ struct super_block *sb = inode->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ int error;
+
+ MSDOS_I(inode)->i_pos = 0;
+ inode->i_uid = sbi->options.fs_uid;
+ inode->i_gid = sbi->options.fs_gid;
+ inode->i_version++;
+ inode->i_generation = get_seconds();
+
+ if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) {
+ inode->i_generation &= ~1;
+ inode->i_mode = MSDOS_MKMODE(de->attr,
+ S_IRWXUGO & ~sbi->options.fs_dmask) | S_IFDIR;
+ inode->i_op = sbi->dir_ops;
+ inode->i_fop = &fat_dir_operations;
+
+ MSDOS_I(inode)->i_start = le16_to_cpu(de->start);
+ if (sbi->fat_bits == 32)
+ MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16);
+
+ MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
+ error = fat_calc_dir_size(inode);
+ if (error < 0)
+ return error;
+ MSDOS_I(inode)->mmu_private = inode->i_size;
+
+ inode->i_nlink = fat_subdirs(inode);
+ } else { /* not a directory */
+ inode->i_generation |= 1;
+ inode->i_mode = MSDOS_MKMODE(de->attr,
+ ((sbi->options.showexec &&
+ !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);
+ if (sbi->fat_bits == 32)
+ MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16);
+
+ MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
+ inode->i_size = le32_to_cpu(de->size);
+ inode->i_op = &fat_file_inode_operations;
+ inode->i_fop = &fat_file_operations;
+ inode->i_mapping->a_ops = &fat_aops;
+ MSDOS_I(inode)->mmu_private = inode->i_size;
+ }
+ if(de->attr & ATTR_SYS)
+ if (sbi->options.sys_immutable)
+ inode->i_flags |= S_IMMUTABLE;
+ MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED;
+ /* this is as close to the truth as we can get ... */
+ inode->i_blksize = sbi->cluster_size;
+ 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));
+ 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))
+ : 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;
+}
struct inode *fat_build_inode(struct super_block *sb,
struct msdos_dir_entry *de, loff_t i_pos, int *res)
return inode;
}
-void fat_delete_inode(struct inode *inode)
+EXPORT_SYMBOL(fat_build_inode);
+
+static void fat_delete_inode(struct inode *inode)
{
if (!is_bad_inode(inode)) {
inode->i_size = 0;
clear_inode(inode);
}
-void fat_clear_inode(struct inode *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(&fat_inode_lock);
+ spin_lock(&sbi->inode_hash_lock);
fat_cache_inval_inode(inode);
- list_del_init(&MSDOS_I(inode)->i_fat_hash);
- spin_unlock(&fat_inode_lock);
+ hlist_del_init(&MSDOS_I(inode)->i_fat_hash);
+ spin_unlock(&sbi->inode_hash_lock);
unlock_kernel();
}
-void fat_put_super(struct super_block *sb)
+static void fat_put_super(struct super_block *sb)
{
struct msdos_sb_info *sbi = MSDOS_SB(sb);
sbi->options.iocharset = fat_default_iocharset;
}
- sb->s_fs_info = NULL;
- kfree(sbi);
+ sb->s_fs_info = NULL;
+ kfree(sbi);
+}
+
+static kmem_cache_t *fat_inode_cachep;
+
+static struct inode *fat_alloc_inode(struct super_block *sb)
+{
+ struct msdos_inode_info *ei;
+ ei = kmem_cache_alloc(fat_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void fat_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(fat_inode_cachep, MSDOS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct msdos_inode_info *ei = (struct msdos_inode_info *)foo;
+
+ 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);
+ inode_init_once(&ei->vfs_inode);
+ }
+}
+
+static int __init fat_init_inodecache(void)
+{
+ fat_inode_cachep = kmem_cache_create("fat_inode_cache",
+ sizeof(struct msdos_inode_info),
+ 0, SLAB_RECLAIM_ACCOUNT,
+ init_once, NULL);
+ if (fat_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void __exit fat_destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(fat_inode_cachep))
+ printk(KERN_INFO "fat_inode_cache: not all structures were freed\n");
+}
+
+static int fat_remount(struct super_block *sb, int *flags, char *data)
+{
+ *flags |= MS_NODIRATIME;
+ return 0;
+}
+
+static int fat_statfs(struct super_block *sb, struct kstatfs *buf)
+{
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ int free, nr, ret;
+
+ if (sbi->free_clusters != -1)
+ free = sbi->free_clusters;
+ else {
+ lock_fat(sb);
+ if (sbi->free_clusters != -1)
+ free = sbi->free_clusters;
+ else {
+ free = 0;
+ for (nr = FAT_START_ENT; nr < sbi->max_cluster; nr++) {
+ ret = fat_access(sb, nr, -1);
+ if (ret < 0) {
+ unlock_fat(sb);
+ return ret;
+ } else if (ret == FAT_ENT_FREE)
+ free++;
+ }
+ sbi->free_clusters = free;
+ }
+ unlock_fat(sb);
+ }
+
+ buf->f_type = sb->s_magic;
+ buf->f_bsize = sbi->cluster_size;
+ buf->f_blocks = sbi->max_cluster - FAT_START_ENT;
+ buf->f_bfree = free;
+ buf->f_bavail = free;
+ buf->f_namelen = sbi->options.isvfat ? 260 : 12;
+
+ return 0;
+}
+
+static 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;
+
+retry:
+ i_pos = MSDOS_I(inode)->i_pos;
+ if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) {
+ return 0;
+ }
+ lock_kernel();
+ if (!(bh = sb_bread(sb, i_pos >> sbi->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);
+ if (i_pos != MSDOS_I(inode)->i_pos) {
+ spin_unlock(&sbi->inode_hash_lock);
+ brelse(bh);
+ unlock_kernel();
+ goto retry;
+ }
+
+ raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
+ [i_pos & (sbi->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->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);
+ fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, &raw_entry->date);
+ if (sbi->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);
+ mark_buffer_dirty(bh);
+ brelse(bh);
+ unlock_kernel();
+ return 0;
+}
+
+static int fat_show_options(struct seq_file *m, struct vfsmount *mnt);
+static struct super_operations fat_sops = {
+ .alloc_inode = fat_alloc_inode,
+ .destroy_inode = fat_destroy_inode,
+ .write_inode = fat_write_inode,
+ .delete_inode = fat_delete_inode,
+ .put_super = fat_put_super,
+ .statfs = fat_statfs,
+ .clear_inode = fat_clear_inode,
+ .remount_fs = fat_remount,
+
+ .read_inode = make_bad_inode,
+
+ .show_options = fat_show_options,
+};
+
+/*
+ * a FAT file handle with fhtype 3 is
+ * 0/ i_ino - for fast, reliable lookup if still in the cache
+ * 1/ i_generation - to see if i_ino is still valid
+ * bit 0 == 0 iff directory
+ * 2/ i_pos(8-39) - if ino has changed, but still in cache
+ * 3/ i_pos(4-7)|i_logstart - to semi-verify inode found at i_pos
+ * 4/ i_pos(0-3)|parent->i_logstart - maybe used to hunt for the file on disc
+ *
+ * Hack for NFSv2: Maximum FAT entry number is 28bits and maximum
+ * i_pos is 40bits (blocknr(32) + dir offset(8)), so two 4bits
+ * of i_logstart is used to store the directory entry offset.
+ */
+
+static struct dentry *
+fat_decode_fh(struct super_block *sb, __u32 *fh, int len, int fhtype,
+ int (*acceptable)(void *context, struct dentry *de),
+ void *context)
+{
+ if (fhtype != 3)
+ return ERR_PTR(-ESTALE);
+ if (len < 5)
+ return ERR_PTR(-ESTALE);
+
+ return sb->s_export_op->find_exported_dentry(sb, fh, NULL, acceptable, context);
+}
+
+static struct dentry *fat_get_dentry(struct super_block *sb, void *inump)
+{
+ struct inode *inode = NULL;
+ struct dentry *result;
+ __u32 *fh = inump;
+
+ inode = iget(sb, fh[0]);
+ if (!inode || is_bad_inode(inode) || inode->i_generation != fh[1]) {
+ if (inode)
+ iput(inode);
+ inode = NULL;
+ }
+ if (!inode) {
+ loff_t i_pos;
+ int i_logstart = fh[3] & 0x0fffffff;
+
+ i_pos = (loff_t)fh[2] << 8;
+ i_pos |= ((fh[3] >> 24) & 0xf0) | (fh[4] >> 28);
+
+ /* try 2 - see if i_pos is in F-d-c
+ * require i_logstart to be the same
+ * Will fail if you truncate and then re-write
+ */
+
+ inode = fat_iget(sb, i_pos);
+ if (inode && MSDOS_I(inode)->i_logstart != i_logstart) {
+ iput(inode);
+ inode = NULL;
+ }
+ }
+ if (!inode) {
+ /* For now, do nothing
+ * What we could do is:
+ * follow the file starting at fh[4], and record
+ * the ".." entry, and the name of the fh[2] entry.
+ * The follow the ".." file finding the next step up.
+ * This way we build a path to the root of
+ * the tree. If this works, we lookup the path and so
+ * get this inode into the cache.
+ * Finally try the fat_iget lookup again
+ * If that fails, then weare totally out of luck
+ * But all that is for another day
+ */
+ }
+ if (!inode)
+ return ERR_PTR(-ESTALE);
+
+
+ /* now to find a dentry.
+ * If possible, get a well-connected one
+ */
+ result = d_alloc_anon(inode);
+ if (result == NULL) {
+ iput(inode);
+ return ERR_PTR(-ENOMEM);
+ }
+ result->d_op = sb->s_root->d_op;
+ return result;
+}
+
+static int
+fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable)
+{
+ int len = *lenp;
+ struct inode *inode = de->d_inode;
+ u32 ipos_h, ipos_m, ipos_l;
+
+ if (len < 5)
+ return 255; /* no room */
+
+ ipos_h = MSDOS_I(inode)->i_pos >> 8;
+ ipos_m = (MSDOS_I(inode)->i_pos & 0xf0) << 24;
+ ipos_l = (MSDOS_I(inode)->i_pos & 0x0f) << 28;
+ *lenp = 5;
+ fh[0] = inode->i_ino;
+ fh[1] = inode->i_generation;
+ fh[2] = ipos_h;
+ fh[3] = ipos_m | MSDOS_I(inode)->i_logstart;
+ spin_lock(&de->d_lock);
+ fh[4] = ipos_l | MSDOS_I(de->d_parent->d_inode)->i_logstart;
+ spin_unlock(&de->d_lock);
+ return 3;
+}
+
+static struct dentry *fat_get_parent(struct dentry *child)
+{
+ struct buffer_head *bh=NULL;
+ struct msdos_dir_entry *de = NULL;
+ struct dentry *parent = NULL;
+ int res;
+ loff_t i_pos = 0;
+ struct inode *inode;
+
+ lock_kernel();
+ res = fat_scan(child->d_inode, MSDOS_DOTDOT, &bh, &de, &i_pos);
+
+ if (res < 0)
+ goto out;
+ inode = fat_build_inode(child->d_sb, de, i_pos, &res);
+ if (res)
+ goto out;
+ if (!inode)
+ res = -EACCES;
+ else {
+ parent = d_alloc_anon(inode);
+ if (!parent) {
+ iput(inode);
+ res = -ENOMEM;
+ }
+ }
+
+ out:
+ if(bh)
+ brelse(bh);
+ unlock_kernel();
+ if (res)
+ return ERR_PTR(res);
+ else
+ return parent;
}
+static struct export_operations fat_export_ops = {
+ .decode_fh = fat_decode_fh,
+ .encode_fh = fat_encode_fh,
+ .get_dentry = fat_get_dentry,
+ .get_parent = fat_get_parent,
+};
+
static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
{
struct msdos_sb_info *sbi = MSDOS_SB(mnt->mnt_sb);
seq_printf(m, ",gid=%u", opts->fs_gid);
seq_printf(m, ",fmask=%04o", opts->fs_fmask);
seq_printf(m, ",dmask=%04o", opts->fs_dmask);
- if (sbi->nls_disk && opts->codepage != fat_default_codepage)
+ if (sbi->nls_disk)
seq_printf(m, ",codepage=%s", sbi->nls_disk->charset);
if (isvfat) {
- if (sbi->nls_io &&
- strcmp(opts->iocharset, fat_default_iocharset))
+ if (sbi->nls_io)
seq_printf(m, ",iocharset=%s", sbi->nls_io->charset);
switch (opts->shortname) {
" for FAT filesystems, filesystem will be case sensitive!\n");
}
- if (opts->unicode_xlate)
- opts->utf8 = 0;
-
- return 0;
-}
-
-static int fat_calc_dir_size(struct inode *inode)
-{
- struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
- int ret, fclus, dclus;
-
- inode->i_size = 0;
- if (MSDOS_I(inode)->i_start == 0)
- return 0;
-
- ret = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus);
- if (ret < 0)
- return ret;
- inode->i_size = (fclus + 1) << sbi->cluster_bits;
-
- return 0;
-}
-
-static int fat_read_root(struct inode *inode)
-{
- struct super_block *sb = inode->i_sb;
- 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_version++;
- inode->i_generation = 0;
- inode->i_mode = (S_IRWXUGO & ~sbi->options.fs_dmask) | S_IFDIR;
- inode->i_op = sbi->dir_ops;
- inode->i_fop = &fat_dir_operations;
- if (sbi->fat_bits == 32) {
- MSDOS_I(inode)->i_start = sbi->root_cluster;
- error = fat_calc_dir_size(inode);
- if (error < 0)
- return error;
- } else {
- MSDOS_I(inode)->i_start = 0;
- inode->i_size = sbi->dir_entries * sizeof(struct msdos_dir_entry);
- }
- inode->i_blksize = sbi->cluster_size;
- inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1))
- & ~((loff_t)sbi->cluster_size - 1)) >> 9;
- MSDOS_I(inode)->i_logstart = 0;
- MSDOS_I(inode)->mmu_private = inode->i_size;
-
- MSDOS_I(inode)->i_attrs = 0;
- inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = 0;
- inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0;
- MSDOS_I(inode)->i_ctime_ms = 0;
- inode->i_nlink = fat_subdirs(inode)+2;
-
- return 0;
-}
-
-/*
- * a FAT file handle with fhtype 3 is
- * 0/ i_ino - for fast, reliable lookup if still in the cache
- * 1/ i_generation - to see if i_ino is still valid
- * bit 0 == 0 iff directory
- * 2/ i_pos(8-39) - if ino has changed, but still in cache
- * 3/ i_pos(4-7)|i_logstart - to semi-verify inode found at i_pos
- * 4/ i_pos(0-3)|parent->i_logstart - maybe used to hunt for the file on disc
- *
- * Hack for NFSv2: Maximum FAT entry number is 28bits and maximum
- * i_pos is 40bits (blocknr(32) + dir offset(8)), so two 4bits
- * of i_logstart is used to store the directory entry offset.
- */
-
-static struct dentry *
-fat_decode_fh(struct super_block *sb, __u32 *fh, int len, int fhtype,
- int (*acceptable)(void *context, struct dentry *de),
- void *context)
-{
- if (fhtype != 3)
- return ERR_PTR(-ESTALE);
- if (len < 5)
- return ERR_PTR(-ESTALE);
-
- return sb->s_export_op->find_exported_dentry(sb, fh, NULL, acceptable, context);
-}
-
-static struct dentry *fat_get_dentry(struct super_block *sb, void *inump)
-{
- struct inode *inode = NULL;
- struct dentry *result;
- __u32 *fh = inump;
-
- inode = iget(sb, fh[0]);
- if (!inode || is_bad_inode(inode) || inode->i_generation != fh[1]) {
- if (inode)
- iput(inode);
- inode = NULL;
- }
- if (!inode) {
- loff_t i_pos;
- int i_logstart = fh[3] & 0x0fffffff;
-
- i_pos = (loff_t)fh[2] << 8;
- i_pos |= ((fh[3] >> 24) & 0xf0) | (fh[4] >> 28);
-
- /* try 2 - see if i_pos is in F-d-c
- * require i_logstart to be the same
- * Will fail if you truncate and then re-write
- */
-
- inode = fat_iget(sb, i_pos);
- if (inode && MSDOS_I(inode)->i_logstart != i_logstart) {
- iput(inode);
- inode = NULL;
- }
- }
- if (!inode) {
- /* For now, do nothing
- * What we could do is:
- * follow the file starting at fh[4], and record
- * the ".." entry, and the name of the fh[2] entry.
- * The follow the ".." file finding the next step up.
- * This way we build a path to the root of
- * the tree. If this works, we lookup the path and so
- * get this inode into the cache.
- * Finally try the fat_iget lookup again
- * If that fails, then weare totally out of luck
- * But all that is for another day
- */
- }
- if (!inode)
- return ERR_PTR(-ESTALE);
-
-
- /* now to find a dentry.
- * If possible, get a well-connected one
- */
- result = d_alloc_anon(inode);
- if (result == NULL) {
- iput(inode);
- return ERR_PTR(-ENOMEM);
- }
- result->d_op = sb->s_root->d_op;
- return result;
-}
-
-static int
-fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable)
-{
- int len = *lenp;
- struct inode *inode = de->d_inode;
- u32 ipos_h, ipos_m, ipos_l;
-
- if (len < 5)
- return 255; /* no room */
-
- ipos_h = MSDOS_I(inode)->i_pos >> 8;
- ipos_m = (MSDOS_I(inode)->i_pos & 0xf0) << 24;
- ipos_l = (MSDOS_I(inode)->i_pos & 0x0f) << 28;
- *lenp = 5;
- fh[0] = inode->i_ino;
- fh[1] = inode->i_generation;
- fh[2] = ipos_h;
- fh[3] = ipos_m | MSDOS_I(inode)->i_logstart;
- spin_lock(&de->d_lock);
- fh[4] = ipos_l | MSDOS_I(de->d_parent->d_inode)->i_logstart;
- spin_unlock(&de->d_lock);
- return 3;
-}
-
-static struct dentry *fat_get_parent(struct dentry *child)
-{
- struct buffer_head *bh=NULL;
- struct msdos_dir_entry *de = NULL;
- struct dentry *parent = NULL;
- int res;
- loff_t i_pos = 0;
- struct inode *inode;
-
- lock_kernel();
- res = fat_scan(child->d_inode, MSDOS_DOTDOT, &bh, &de, &i_pos);
-
- if (res < 0)
- goto out;
- inode = fat_build_inode(child->d_sb, de, i_pos, &res);
- if (res)
- goto out;
- if (!inode)
- res = -EACCES;
- else {
- parent = d_alloc_anon(inode);
- if (!parent) {
- iput(inode);
- res = -ENOMEM;
- }
- }
-
- out:
- if(bh)
- brelse(bh);
- unlock_kernel();
- if (res)
- return ERR_PTR(res);
- else
- return parent;
-}
-
-static kmem_cache_t *fat_inode_cachep;
-
-static struct inode *fat_alloc_inode(struct super_block *sb)
-{
- struct msdos_inode_info *ei;
- ei = (struct msdos_inode_info *)kmem_cache_alloc(fat_inode_cachep, SLAB_KERNEL);
- if (!ei)
- return NULL;
- return &ei->vfs_inode;
-}
-
-static void fat_destroy_inode(struct inode *inode)
-{
- kmem_cache_free(fat_inode_cachep, MSDOS_I(inode));
+ if (opts->unicode_xlate)
+ opts->utf8 = 0;
+
+ return 0;
}
-static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+static int fat_read_root(struct inode *inode)
{
- struct msdos_inode_info *ei = (struct msdos_inode_info *) foo;
+ struct super_block *sb = inode->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ int error;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
- INIT_LIST_HEAD(&ei->i_fat_hash);
- inode_init_once(&ei->vfs_inode);
+ MSDOS_I(inode)->i_pos = 0;
+ inode->i_uid = sbi->options.fs_uid;
+ inode->i_gid = sbi->options.fs_gid;
+ inode->i_version++;
+ inode->i_generation = 0;
+ inode->i_mode = (S_IRWXUGO & ~sbi->options.fs_dmask) | S_IFDIR;
+ inode->i_op = sbi->dir_ops;
+ inode->i_fop = &fat_dir_operations;
+ if (sbi->fat_bits == 32) {
+ MSDOS_I(inode)->i_start = sbi->root_cluster;
+ error = fat_calc_dir_size(inode);
+ if (error < 0)
+ return error;
+ } else {
+ MSDOS_I(inode)->i_start = 0;
+ inode->i_size = sbi->dir_entries * sizeof(struct msdos_dir_entry);
}
-}
-
-int __init fat_init_inodecache(void)
-{
- fat_inode_cachep = kmem_cache_create("fat_inode_cache",
- sizeof(struct msdos_inode_info),
- 0, SLAB_RECLAIM_ACCOUNT,
- init_once, NULL);
- if (fat_inode_cachep == NULL)
- return -ENOMEM;
- return 0;
-}
+ inode->i_blksize = sbi->cluster_size;
+ inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1))
+ & ~((loff_t)sbi->cluster_size - 1)) >> 9;
+ MSDOS_I(inode)->i_logstart = 0;
+ MSDOS_I(inode)->mmu_private = inode->i_size;
-void __exit fat_destroy_inodecache(void)
-{
- if (kmem_cache_destroy(fat_inode_cachep))
- printk(KERN_INFO "fat_inode_cache: not all structures were freed\n");
-}
+ MSDOS_I(inode)->i_attrs = 0;
+ inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = 0;
+ inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0;
+ MSDOS_I(inode)->i_ctime_ms = 0;
+ inode->i_nlink = fat_subdirs(inode)+2;
-static int fat_remount(struct super_block *sb, int *flags, char *data)
-{
- *flags |= MS_NODIRATIME;
return 0;
}
-static struct super_operations fat_sops = {
- .alloc_inode = fat_alloc_inode,
- .destroy_inode = fat_destroy_inode,
- .write_inode = fat_write_inode,
- .delete_inode = fat_delete_inode,
- .put_super = fat_put_super,
- .statfs = fat_statfs,
- .clear_inode = fat_clear_inode,
- .remount_fs = fat_remount,
-
- .read_inode = make_bad_inode,
-
- .show_options = fat_show_options,
-};
-
-static struct export_operations fat_export_ops = {
- .decode_fh = fat_decode_fh,
- .encode_fh = fat_encode_fh,
- .get_dentry = fat_get_dentry,
- .get_parent = fat_get_parent,
-};
-
/*
* Read the super block of an MS-DOS FS.
*/
struct msdos_sb_info *sbi;
u16 logical_sector_size;
u32 total_sectors, total_clusters, fat_clusters, rootdir_sectors;
- int debug, first;
+ int debug;
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 = CF_LE_W(get_unaligned((__le16 *)&b->sector_size));
+ logical_sector_size =
+ le16_to_cpu(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 = CF_LE_W(b->reserved);
- sbi->fat_length = CF_LE_W(b->fat_length);
+ sbi->fat_start = le16_to_cpu(b->reserved);
+ sbi->fat_length = le16_to_cpu(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 = CF_LE_L(b->fat32_length);
- sbi->root_cluster = CF_LE_L(b->root_cluster);
+ sbi->fat_length = le32_to_cpu(b->fat32_length);
+ sbi->root_cluster = le32_to_cpu(b->root_cluster);
sb->s_maxbytes = 0xffffffff;
-
+
/* MC - if info_sector is 0, don't multiply by 0 */
- sbi->fsinfo_sector = CF_LE_W(b->info_sector);
+ sbi->fsinfo_sector = le16_to_cpu(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",
- CF_LE_L(fsinfo->signature1),
- CF_LE_L(fsinfo->signature2),
+ le32_to_cpu(fsinfo->signature1),
+ le32_to_cpu(fsinfo->signature2),
sbi->fsinfo_sector);
} else {
- sbi->free_clusters = CF_LE_L(fsinfo->free_clusters);
- sbi->prev_free = CF_LE_L(fsinfo->next_cluster);
+ sbi->free_clusters = le32_to_cpu(fsinfo->free_clusters);
+ sbi->prev_free = le32_to_cpu(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 = CF_LE_W(get_unaligned((__le16 *)&b->dir_entries));
+ sbi->dir_entries =
+ le16_to_cpu(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 = CF_LE_W(get_unaligned((__le16 *)&b->sectors));
+ total_sectors = le16_to_cpu(get_unaligned((__le16 *)&b->sectors));
if (total_sectors == 0)
- total_sectors = CF_LE_L(b->total_sect);
+ total_sectors = le32_to_cpu(b->total_sect);
total_clusters = (total_sectors - sbi->data_start) / sbi->sec_per_clus;
/* check that FAT table does not overflow */
fat_clusters = sbi->fat_length * sb->s_blocksize * 8 / sbi->fat_bits;
- total_clusters = min(total_clusters, fat_clusters - 2);
+ total_clusters = min(total_clusters, fat_clusters - FAT_START_ENT);
if (total_clusters > MAX_FAT(sb)) {
if (!silent)
printk(KERN_ERR "FAT: count of clusters too big (%u)\n",
goto out_invalid;
}
- sbi->clusters = total_clusters;
+ sbi->max_cluster = total_clusters + FAT_START_ENT;
+ /* check the free_clusters, it's not necessarily correct */
+ if (sbi->free_clusters != -1 && sbi->free_clusters > total_clusters)
+ sbi->free_clusters = -1;
brelse(bh);
- /* 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 == 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;
- }
+ /*
+ * 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)
+ */
error = -EINVAL;
sprintf(buf, "cp%d", sbi->options.codepage);
return error;
}
-int fat_statfs(struct super_block *sb, struct kstatfs *buf)
-{
- int free, nr, ret;
-
- if (MSDOS_SB(sb)->free_clusters != -1)
- free = MSDOS_SB(sb)->free_clusters;
- else {
- lock_fat(sb);
- if (MSDOS_SB(sb)->free_clusters != -1)
- free = MSDOS_SB(sb)->free_clusters;
- else {
- free = 0;
- for (nr = 2; nr < MSDOS_SB(sb)->clusters + 2; nr++) {
- ret = fat_access(sb, nr, -1);
- if (ret < 0) {
- unlock_fat(sb);
- return ret;
- } else if (ret == FAT_ENT_FREE)
- free++;
- }
- MSDOS_SB(sb)->free_clusters = free;
- }
- unlock_fat(sb);
- }
-
- buf->f_type = sb->s_magic;
- buf->f_bsize = MSDOS_SB(sb)->cluster_size;
- buf->f_blocks = MSDOS_SB(sb)->clusters;
- buf->f_bfree = free;
- buf->f_bavail = free;
- buf->f_namelen = MSDOS_SB(sb)->options.isvfat ? 260 : 12;
-
- return 0;
-}
-
-static int is_exec(unsigned char *extension)
-{
- unsigned char *exe_extensions = "EXECOMBAT", *walk;
-
- for (walk = exe_extensions; *walk; walk += 3)
- if (!strncmp(extension, walk, 3))
- return 1;
- return 0;
-}
-
-static int fat_writepage(struct page *page, struct writeback_control *wbc)
-{
- return block_write_full_page(page,fat_get_block, wbc);
-}
-static int fat_readpage(struct file *file, struct page *page)
-{
- return block_read_full_page(page,fat_get_block);
-}
-
-static int
-fat_prepare_write(struct file *file, struct page *page,
- unsigned from, unsigned to)
-{
- kmap(page);
- return cont_prepare_write(page,from,to,fat_get_block,
- &MSDOS_I(page->mapping->host)->mmu_private);
-}
-
-static int
-fat_commit_write(struct file *file, struct page *page,
- unsigned from, unsigned to)
-{
- kunmap(page);
- return generic_commit_write(file, page, from, to);
-}
+EXPORT_SYMBOL(fat_fill_super);
-static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
-{
- return generic_block_bmap(mapping,block,fat_get_block);
-}
-static struct address_space_operations fat_aops = {
- .readpage = fat_readpage,
- .writepage = fat_writepage,
- .sync_page = block_sync_page,
- .prepare_write = fat_prepare_write,
- .commit_write = fat_commit_write,
- .bmap = _fat_bmap
-};
+int __init fat_cache_init(void);
+void __exit fat_cache_destroy(void);
-/* doesn't deal with root inode */
-static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
+static int __init init_fat_fs(void)
{
- struct super_block *sb = inode->i_sb;
- 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_version++;
- inode->i_generation = get_seconds();
-
- if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) {
- inode->i_generation &= ~1;
- inode->i_mode = MSDOS_MKMODE(de->attr,
- S_IRWXUGO & ~sbi->options.fs_dmask) | S_IFDIR;
- inode->i_op = sbi->dir_ops;
- inode->i_fop = &fat_dir_operations;
-
- MSDOS_I(inode)->i_start = CF_LE_W(de->start);
- if (sbi->fat_bits == 32)
- 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);
- if (error < 0)
- return error;
- MSDOS_I(inode)->mmu_private = inode->i_size;
-
- inode->i_nlink = fat_subdirs(inode);
- } else { /* not a directory */
- inode->i_generation |= 1;
- inode->i_mode = MSDOS_MKMODE(de->attr,
- ((sbi->options.showexec &&
- !is_exec(de->ext))
- ? S_IRUGO|S_IWUGO : S_IRWXUGO)
- & ~sbi->options.fs_fmask) | S_IFREG;
- MSDOS_I(inode)->i_start = CF_LE_W(de->start);
- if (sbi->fat_bits == 32)
- MSDOS_I(inode)->i_start |= (CF_LE_W(de->starthi) << 16);
-
- MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
- 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;
- MSDOS_I(inode)->mmu_private = inode->i_size;
- }
- if(de->attr & ATTR_SYS)
- if (sbi->options.sys_immutable)
- inode->i_flags |= S_IMMUTABLE;
- MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED;
- /* this is as close to the truth as we can get ... */
- inode->i_blksize = sbi->cluster_size;
- 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(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(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;
+ int ret;
- return 0;
+ ret = fat_cache_init();
+ if (ret < 0)
+ return ret;
+ return fat_init_inodecache();
}
-int fat_write_inode(struct inode *inode, int wait)
+static void __exit exit_fat_fs(void)
{
- struct super_block *sb = inode->i_sb;
- struct buffer_head *bh;
- struct msdos_dir_entry *raw_entry;
- loff_t i_pos;
-
-retry:
- i_pos = MSDOS_I(inode)->i_pos;
- if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) {
- return 0;
- }
- lock_kernel();
- 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(&fat_inode_lock);
- if (i_pos != MSDOS_I(inode)->i_pos) {
- spin_unlock(&fat_inode_lock);
- brelse(bh);
- unlock_kernel();
- goto retry;
- }
-
- raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
- [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 = CT_LE_L(inode->i_size);
- }
- raw_entry->attr |= MSDOS_MKATTR(inode->i_mode) |
- MSDOS_I(inode)->i_attrs;
- 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 (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(&fat_inode_lock);
- mark_buffer_dirty(bh);
- brelse(bh);
- unlock_kernel();
- return 0;
+ fat_cache_destroy();
+ fat_destroy_inodecache();
}
+module_init(init_fat_fs)
+module_exit(exit_fat_fs)
-int fat_notify_change(struct dentry * dentry, struct iattr * attr)
-{
- struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
- struct inode *inode = dentry->d_inode;
- int mask, error = 0;
-
- lock_kernel();
-
- /* FAT cannot truncate to a longer file */
- if (attr->ia_valid & ATTR_SIZE) {
- if (attr->ia_size > inode->i_size) {
- error = -EPERM;
- goto out;
- }
- }
-
- error = inode_change_ok(inode, attr);
- if (error) {
- if (sbi->options.quiet)
- error = 0;
- goto out;
- }
-
- if (((attr->ia_valid & ATTR_UID) &&
- (attr->ia_uid != sbi->options.fs_uid)) ||
- ((attr->ia_valid & ATTR_GID) &&
- (attr->ia_gid != sbi->options.fs_gid)) ||
- ((attr->ia_valid & ATTR_MODE) &&
- (attr->ia_mode & ~MSDOS_VALID_MODE)))
- error = -EPERM;
-
- if (error) {
- if (sbi->options.quiet)
- error = 0;
- goto out;
- }
- error = inode_setattr(inode, attr);
- if (error)
- goto out;
-
- if (S_ISDIR(inode->i_mode))
- mask = sbi->options.fs_dmask;
- else
- mask = sbi->options.fs_fmask;
- inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask);
-out:
- unlock_kernel();
- return error;
-}
MODULE_LICENSE("GPL");