📄 inode.c
字号:
if (opts->iocharset != fat_default_iocharset) kfree(opts->iocharset); iocharset = match_strdup(&args[0]); if (!iocharset) return -ENOMEM; opts->iocharset = iocharset; break; case Opt_shortname_lower: opts->shortname = VFAT_SFN_DISPLAY_LOWER | VFAT_SFN_CREATE_WIN95; break; case Opt_shortname_win95: opts->shortname = VFAT_SFN_DISPLAY_WIN95 | VFAT_SFN_CREATE_WIN95; break; case Opt_shortname_winnt: opts->shortname = VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WINNT; break; case Opt_shortname_mixed: opts->shortname = VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WIN95; break; case Opt_utf8_no: /* 0 or no or false */ opts->utf8 = 0; break; case Opt_utf8_yes: /* empty or 1 or yes or true */ opts->utf8 = 1; break; case Opt_uni_xl_no: /* 0 or no or false */ opts->unicode_xlate = 0; break; case Opt_uni_xl_yes: /* empty or 1 or yes or true */ opts->unicode_xlate = 1; break; case Opt_nonumtail_no: /* 0 or no or false */ opts->numtail = 1; /* negated option */ break; case Opt_nonumtail_yes: /* empty or 1 or yes or true */ opts->numtail = 0; /* negated option */ break; /* obsolete mount options */ case Opt_obsolate: printk(KERN_INFO "FAT: \"%s\" option is obsolete, " "not supported now\n", p); break; /* unknown option */ default: printk(KERN_ERR "FAT: Unrecognized mount option \"%s\" " "or missing value\n", p); return -EINVAL; } } /* UTF8 doesn't provide FAT semantics */ if (!strcmp(opts->iocharset, "utf8")) { printk(KERN_ERR "FAT: utf8 is not a recommended IO charset" " 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 intfat_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));}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) { INIT_LIST_HEAD(&ei->i_fat_hash); inode_init_once(&ei->vfs_inode); }} 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;}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 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. */int fat_fill_super(struct super_block *sb, void *data, int silent, struct inode_operations *fs_dir_inode_ops, int isvfat){ struct inode *root_inode = NULL; struct buffer_head *bh; struct fat_boot_sector *b; struct msdos_sb_info *sbi; u16 logical_sector_size; u32 total_sectors, total_clusters, fat_clusters, rootdir_sectors; int debug, first; unsigned int media; long error; char buf[50]; sbi = kmalloc(sizeof(struct msdos_sb_info), GFP_KERNEL); if (!sbi) return -ENOMEM; sb->s_fs_info = sbi; memset(sbi, 0, sizeof(struct msdos_sb_info)); sb->s_flags |= MS_NODIRATIME; sb->s_magic = MSDOS_SUPER_MAGIC; sb->s_op = &fat_sops; sb->s_export_op = &fat_export_ops; sbi->dir_ops = fs_dir_inode_ops; error = parse_options(data, isvfat, &debug, &sbi->options); if (error) goto out_fail; fat_cache_init(sb); /* set up enough so that it can read an inode */ init_MUTEX(&sbi->fat_lock); error = -EIO; sb_min_blocksize(sb, 512); bh = sb_bread(sb, 0); if (bh == NULL) { printk(KERN_ERR "FAT: unable to read boot sector\n"); goto out_fail; } b = (struct fat_boot_sector *) bh->b_data; if (!b->reserved) { if (!silent) printk(KERN_ERR "FAT: bogus number of reserved sectors\n"); brelse(bh); goto out_invalid; } if (!b->fats) { if (!silent) printk(KERN_ERR "FAT: bogus number of FAT structure\n"); brelse(bh); goto out_invalid; } /* * Earlier we checked here that b->secs_track and b->head are nonzero, * but it turns out valid FAT filesystems can have zero there. */ media = b->media; if (!FAT_VALID_MEDIA(media)) { if (!silent) printk(KERN_ERR "FAT: invalid media value (0x%02x)\n", media); brelse(bh); goto out_invalid; } 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) || (PAGE_CACHE_SIZE < logical_sector_size)) { if (!silent) printk(KERN_ERR "FAT: bogus logical sector size %u\n", logical_sector_size); brelse(bh); goto out_invalid; } sbi->sec_per_clus = b->sec_per_clus; if (!sbi->sec_per_clus || (sbi->sec_per_clus & (sbi->sec_per_clus - 1))) { if (!silent) printk(KERN_ERR "FAT: bogus sectors per cluster %u\n", sbi->sec_per_clus); brelse(bh); goto out_invalid; } if (logical_sector_size < sb->s_blocksize) { printk(KERN_ERR "FAT: logical sector size too small for device" " (logical sector size = %u)\n", logical_sector_size); brelse(bh); goto out_fail; } if (logical_sector_size > sb->s_blocksize) { brelse(bh); if (!sb_set_blocksize(sb, logical_sector_size)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -