📄 inode.c
字号:
/* * 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/time.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/seq_file.h>#include <linux/msdos_fs.h>#include <linux/pagemap.h>#include <linux/buffer_head.h>#include <linux/mount.h>#include <linux/vfs.h>#include <linux/parser.h>#include <asm/unaligned.h>#ifndef CONFIG_FAT_DEFAULT_IOCHARSET/* if user don't select VFAT, this is undefined. */#define CONFIG_FAT_DEFAULT_IOCHARSET ""#endifstatic int fat_default_codepage = CONFIG_FAT_DEFAULT_CODEPAGE;static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET;/* * New FAT inode stuff. We do the following: * a) i_ino is constant and has nothing with on-disk location. * b) FAT manages its own cache of directory entries. * c) *This* cache is indexed by on-disk location. * d) inode has an associated directory entry, all right, but * it may be unhashed. * e) currently entries are stored within struct inode. That should * change. * f) we deal with races in the following way: * 1. readdir() and lookup() do FAT-dir-cache lookup. * 2. rename() unhashes the F-d-c entry and rehashes it in * a new place. * 3. unlink() and rmdir() unhash F-d-c entry. * 4. fat_write_inode() checks whether the thing is unhashed. * If it is we silently return. If it isn't we do bread(), * check if the location is still valid and retry if it * isn't. Otherwise we do changes. * 5. Spinlock is used to protect hash/unhash/location check/lookup * 6. fat_clear_inode() unhashes the F-d-c entry. * 7. lookup() and readdir() do igrab() if they find a F-d-c entry * 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){ int 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){ unsigned long tmp = (unsigned long)i_pos | (unsigned long) sb; tmp = tmp + (tmp >> FAT_HASH_BITS) + (tmp >> FAT_HASH_BITS * 2); return tmp & FAT_HASH_MASK;}void fat_attach(struct inode *inode, loff_t i_pos){ spin_lock(&fat_inode_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);}void fat_detach(struct inode *inode){ spin_lock(&fat_inode_lock); MSDOS_I(inode)->i_pos = 0; 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 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(&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(&fat_inode_lock); return inode;}static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de);struct inode *fat_build_inode(struct super_block *sb, struct msdos_dir_entry *de, loff_t i_pos, int *res){ struct inode *inode; *res = 0; inode = fat_iget(sb, i_pos); if (inode) goto out; inode = new_inode(sb); *res = -ENOMEM; if (!inode) goto out; inode->i_ino = iunique(sb, MSDOS_ROOT_INO); inode->i_version = 1; *res = fat_fill_inode(inode, de); if (*res < 0) { iput(inode); inode = NULL; goto out; } fat_attach(inode, i_pos); insert_inode_hash(inode);out: return inode;}void fat_delete_inode(struct inode *inode){ if (!is_bad_inode(inode)) { inode->i_size = 0; fat_truncate(inode); } clear_inode(inode);}void fat_clear_inode(struct inode *inode){ if (is_bad_inode(inode)) return; lock_kernel(); spin_lock(&fat_inode_lock); fat_cache_inval_inode(inode); list_del_init(&MSDOS_I(inode)->i_fat_hash); spin_unlock(&fat_inode_lock); unlock_kernel();}void fat_put_super(struct super_block *sb){ struct msdos_sb_info *sbi = MSDOS_SB(sb); if (!(sb->s_flags & MS_RDONLY)) fat_clusters_flush(sb); if (sbi->nls_disk) { unload_nls(sbi->nls_disk); sbi->nls_disk = NULL; sbi->options.codepage = fat_default_codepage; } if (sbi->nls_io) { unload_nls(sbi->nls_io); sbi->nls_io = NULL; } if (sbi->options.iocharset != fat_default_iocharset) { kfree(sbi->options.iocharset); sbi->options.iocharset = fat_default_iocharset; } sb->s_fs_info = NULL; kfree(sbi);}static int fat_show_options(struct seq_file *m, struct vfsmount *mnt){ struct msdos_sb_info *sbi = MSDOS_SB(mnt->mnt_sb); struct fat_mount_options *opts = &sbi->options; int isvfat = opts->isvfat; if (opts->fs_uid != 0) seq_printf(m, ",uid=%u", opts->fs_uid); if (opts->fs_gid != 0) 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) seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); if (isvfat) { if (sbi->nls_io && strcmp(opts->iocharset, fat_default_iocharset)) seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); switch (opts->shortname) { case VFAT_SFN_DISPLAY_WIN95 | VFAT_SFN_CREATE_WIN95: seq_puts(m, ",shortname=win95"); break; case VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WINNT: seq_puts(m, ",shortname=winnt"); break; case VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WIN95: seq_puts(m, ",shortname=mixed"); break; case VFAT_SFN_DISPLAY_LOWER | VFAT_SFN_CREATE_WIN95: /* seq_puts(m, ",shortname=lower"); */ break; default: seq_puts(m, ",shortname=unknown"); break; } } if (opts->name_check != 'n') seq_printf(m, ",check=%c", opts->name_check); if (opts->quiet) seq_puts(m, ",quiet"); if (opts->showexec) seq_puts(m, ",showexec"); if (opts->sys_immutable) seq_puts(m, ",sys_immutable"); if (!isvfat) { if (opts->dotsOK) seq_puts(m, ",dotsOK=yes"); if (opts->nocase) seq_puts(m, ",nocase"); } else { if (opts->utf8) seq_puts(m, ",utf8"); if (opts->unicode_xlate) seq_puts(m, ",uni_xlate"); if (!opts->numtail) seq_puts(m, ",nonumtail"); } return 0;}enum { Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask, Opt_codepage, Opt_nocase, Opt_quiet, Opt_showexec, Opt_debug, Opt_immutable, Opt_dots, Opt_nodots, Opt_charset, Opt_shortname_lower, Opt_shortname_win95, Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, Opt_obsolate, Opt_err,};static match_table_t fat_tokens = { {Opt_check_r, "check=relaxed"}, {Opt_check_s, "check=strict"}, {Opt_check_n, "check=normal"}, {Opt_check_r, "check=r"}, {Opt_check_s, "check=s"}, {Opt_check_n, "check=n"}, {Opt_uid, "uid=%u"}, {Opt_gid, "gid=%u"}, {Opt_umask, "umask=%o"}, {Opt_dmask, "dmask=%o"}, {Opt_fmask, "fmask=%o"}, {Opt_codepage, "codepage=%u"}, {Opt_nocase, "nocase"}, {Opt_quiet, "quiet"}, {Opt_showexec, "showexec"}, {Opt_debug, "debug"}, {Opt_immutable, "sys_immutable"}, {Opt_obsolate, "conv=binary"}, {Opt_obsolate, "conv=text"}, {Opt_obsolate, "conv=auto"}, {Opt_obsolate, "conv=b"}, {Opt_obsolate, "conv=t"}, {Opt_obsolate, "conv=a"}, {Opt_obsolate, "fat=%u"}, {Opt_obsolate, "blocksize=%u"}, {Opt_obsolate, "cvf_format=%20s"}, {Opt_obsolate, "cvf_options=%100s"}, {Opt_obsolate, "posix"}, {Opt_err, NULL}};static match_table_t msdos_tokens = { {Opt_nodots, "nodots"}, {Opt_nodots, "dotsOK=no"}, {Opt_dots, "dots"}, {Opt_dots, "dotsOK=yes"}, {Opt_err, NULL}};static match_table_t vfat_tokens = { {Opt_charset, "iocharset=%s"}, {Opt_shortname_lower, "shortname=lower"}, {Opt_shortname_win95, "shortname=win95"}, {Opt_shortname_winnt, "shortname=winnt"}, {Opt_shortname_mixed, "shortname=mixed"}, {Opt_utf8_no, "utf8=0"}, /* 0 or no or false */ {Opt_utf8_no, "utf8=no"}, {Opt_utf8_no, "utf8=false"}, {Opt_utf8_yes, "utf8=1"}, /* empty or 1 or yes or true */ {Opt_utf8_yes, "utf8=yes"}, {Opt_utf8_yes, "utf8=true"}, {Opt_utf8_yes, "utf8"}, {Opt_uni_xl_no, "uni_xlate=0"}, /* 0 or no or false */ {Opt_uni_xl_no, "uni_xlate=no"}, {Opt_uni_xl_no, "uni_xlate=false"}, {Opt_uni_xl_yes, "uni_xlate=1"}, /* empty or 1 or yes or true */ {Opt_uni_xl_yes, "uni_xlate=yes"}, {Opt_uni_xl_yes, "uni_xlate=true"}, {Opt_uni_xl_yes, "uni_xlate"}, {Opt_nonumtail_no, "nonumtail=0"}, /* 0 or no or false */ {Opt_nonumtail_no, "nonumtail=no"}, {Opt_nonumtail_no, "nonumtail=false"}, {Opt_nonumtail_yes, "nonumtail=1"}, /* empty or 1 or yes or true */ {Opt_nonumtail_yes, "nonumtail=yes"}, {Opt_nonumtail_yes, "nonumtail=true"}, {Opt_nonumtail_yes, "nonumtail"}, {Opt_err, NULL}};static int parse_options(char *options, int is_vfat, int *debug, struct fat_mount_options *opts){ char *p; substring_t args[MAX_OPT_ARGS]; int option; char *iocharset; opts->isvfat = is_vfat; opts->fs_uid = current->uid; opts->fs_gid = current->gid; opts->fs_fmask = opts->fs_dmask = current->fs->umask; opts->codepage = fat_default_codepage; opts->iocharset = fat_default_iocharset; if (is_vfat) opts->shortname = VFAT_SFN_DISPLAY_LOWER|VFAT_SFN_CREATE_WIN95; else opts->shortname = 0; opts->name_check = 'n'; opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK = 0; opts->utf8 = opts->unicode_xlate = 0; opts->numtail = 1; opts->nocase = 0; *debug = 0; if (!options) return 0; while ((p = strsep(&options, ",")) != NULL) { int token; if (!*p) continue; token = match_token(p, fat_tokens, args); if (token == Opt_err) { if (is_vfat) token = match_token(p, vfat_tokens, args); else token = match_token(p, msdos_tokens, args); } switch (token) { case Opt_check_s: opts->name_check = 's'; break; case Opt_check_r: opts->name_check = 'r'; break; case Opt_check_n: opts->name_check = 'n'; break; case Opt_nocase: if (!is_vfat) opts->nocase = 1; else { /* for backward compatibility */ opts->shortname = VFAT_SFN_DISPLAY_WIN95 | VFAT_SFN_CREATE_WIN95; } break; case Opt_quiet: opts->quiet = 1; break; case Opt_showexec: opts->showexec = 1; break; case Opt_debug: *debug = 1; break; case Opt_immutable: opts->sys_immutable = 1; break; case Opt_uid: if (match_int(&args[0], &option)) return 0; opts->fs_uid = option; break; case Opt_gid: if (match_int(&args[0], &option)) return 0; opts->fs_gid = option; break; case Opt_umask: if (match_octal(&args[0], &option)) return 0; opts->fs_fmask = opts->fs_dmask = option; break; case Opt_dmask: if (match_octal(&args[0], &option)) return 0; opts->fs_dmask = option; break; case Opt_fmask: if (match_octal(&args[0], &option)) return 0; opts->fs_fmask = option; break; case Opt_codepage: if (match_int(&args[0], &option)) return 0; opts->codepage = option; break; /* msdos specific */ case Opt_dots: opts->dotsOK = 1; break; case Opt_nodots: opts->dotsOK = 0; break; /* vfat specific */ case Opt_charset:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -