X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Ffat%2Finode.c;h=7245657c1c0a4b35bddc078a7ce5bbbcfd414926;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=88368130e79848719927c94280a8805413eb155f;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 88368130e..7245657c1 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -7,10 +7,11 @@ * * Fixes: * - * Max Cohan: Fixed invalid FSINFO offset when info_sector is 0 + * Max Cohan: Fixed invalid FSINFO offset when info_sector is 0 */ #include +#include #include #include #include @@ -31,6 +32,77 @@ 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. @@ -55,18 +127,14 @@ static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET; * 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) @@ -78,44 +146,146 @@ 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) @@ -143,7 +313,9 @@ out: 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; @@ -152,19 +324,21 @@ void fat_delete_inode(struct inode *inode) 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); @@ -185,10 +359,325 @@ void fat_put_super(struct super_block *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); @@ -201,11 +690,10 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) 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) { @@ -503,288 +991,50 @@ static int parse_options(char *options, int is_vfat, int *debug, " 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. */ @@ -797,7 +1047,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, 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]; @@ -818,8 +1068,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, 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; @@ -857,7 +1107,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, 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) @@ -906,8 +1157,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, 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; @@ -918,13 +1169,13 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, /* 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; @@ -942,12 +1193,12 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, "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); @@ -957,7 +1208,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, 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" @@ -969,9 +1221,9 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, 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; @@ -980,7 +1232,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, /* 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", @@ -989,31 +1241,20 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, 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); @@ -1072,262 +1313,28 @@ out_fail: 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");