📄 super.c
字号:
/* * linux/fs/hpfs/super.c * * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 * * mounting, unmounting, error handling */#include "hpfs_fn.h"#include <linux/module.h>#include <linux/parser.h>#include <linux/init.h>#include <linux/statfs.h>#include <linux/magic.h>#include <linux/sched.h>/* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */static void mark_dirty(struct super_block *s){ if (hpfs_sb(s)->sb_chkdsk && !(s->s_flags & MS_RDONLY)) { struct buffer_head *bh; struct hpfs_spare_block *sb; if ((sb = hpfs_map_sector(s, 17, &bh, 0))) { sb->dirty = 1; sb->old_wrote = 0; mark_buffer_dirty(bh); brelse(bh); } }}/* Mark the filesystem clean (mark it dirty for chkdsk if chkdsk==2 or if there were errors) */static void unmark_dirty(struct super_block *s){ struct buffer_head *bh; struct hpfs_spare_block *sb; if (s->s_flags & MS_RDONLY) return; if ((sb = hpfs_map_sector(s, 17, &bh, 0))) { sb->dirty = hpfs_sb(s)->sb_chkdsk > 1 - hpfs_sb(s)->sb_was_error; sb->old_wrote = hpfs_sb(s)->sb_chkdsk >= 2 && !hpfs_sb(s)->sb_was_error; mark_buffer_dirty(bh); brelse(bh); }}/* Filesystem error... */static char err_buf[1024];void hpfs_error(struct super_block *s, const char *fmt, ...){ va_list args; va_start(args, fmt); vsnprintf(err_buf, sizeof(err_buf), fmt, args); va_end(args); printk("HPFS: filesystem error: %s", err_buf); if (!hpfs_sb(s)->sb_was_error) { if (hpfs_sb(s)->sb_err == 2) { printk("; crashing the system because you wanted it\n"); mark_dirty(s); panic("HPFS panic"); } else if (hpfs_sb(s)->sb_err == 1) { if (s->s_flags & MS_RDONLY) printk("; already mounted read-only\n"); else { printk("; remounting read-only\n"); mark_dirty(s); s->s_flags |= MS_RDONLY; } } else if (s->s_flags & MS_RDONLY) printk("; going on - but anything won't be destroyed because it's read-only\n"); else printk("; corrupted filesystem mounted read/write - your computer will explode within 20 seconds ... but you wanted it so!\n"); } else printk("\n"); hpfs_sb(s)->sb_was_error = 1;}/* * A little trick to detect cycles in many hpfs structures and don't let the * kernel crash on corrupted filesystem. When first called, set c2 to 0. * * BTW. chkdsk doesn't detect cycles correctly. When I had 2 lost directories * nested each in other, chkdsk locked up happilly. */int hpfs_stop_cycles(struct super_block *s, int key, int *c1, int *c2, char *msg){ if (*c2 && *c1 == key) { hpfs_error(s, "cycle detected on key %08x in %s", key, msg); return 1; } (*c2)++; if (!((*c2 - 1) & *c2)) *c1 = key; return 0;}static void hpfs_put_super(struct super_block *s){ struct hpfs_sb_info *sbi = hpfs_sb(s); kfree(sbi->sb_cp_table); kfree(sbi->sb_bmp_dir); unmark_dirty(s); s->s_fs_info = NULL; kfree(sbi);}unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno){ struct quad_buffer_head qbh; unsigned *bits; unsigned i, count; if (!(bits = hpfs_map_4sectors(s, secno, &qbh, 4))) return 0; count = 0; for (i = 0; i < 2048 / sizeof(unsigned); i++) { unsigned b; if (!bits[i]) continue; for (b = bits[i]; b; b>>=1) count += b & 1; } hpfs_brelse4(&qbh); return count;}static unsigned count_bitmaps(struct super_block *s){ unsigned n, count, n_bands; n_bands = (hpfs_sb(s)->sb_fs_size + 0x3fff) >> 14; count = 0; for (n = 0; n < n_bands; n++) count += hpfs_count_one_bitmap(s, hpfs_sb(s)->sb_bmp_dir[n]); return count;}static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf){ struct super_block *s = dentry->d_sb; struct hpfs_sb_info *sbi = hpfs_sb(s); lock_kernel(); /*if (sbi->sb_n_free == -1) {*/ sbi->sb_n_free = count_bitmaps(s); sbi->sb_n_free_dnodes = hpfs_count_one_bitmap(s, sbi->sb_dmap); /*}*/ buf->f_type = s->s_magic; buf->f_bsize = 512; buf->f_blocks = sbi->sb_fs_size; buf->f_bfree = sbi->sb_n_free; buf->f_bavail = sbi->sb_n_free; buf->f_files = sbi->sb_dirband_size / 4; buf->f_ffree = sbi->sb_n_free_dnodes; buf->f_namelen = 254; unlock_kernel(); return 0;}static struct kmem_cache * hpfs_inode_cachep;static struct inode *hpfs_alloc_inode(struct super_block *sb){ struct hpfs_inode_info *ei; ei = (struct hpfs_inode_info *)kmem_cache_alloc(hpfs_inode_cachep, GFP_NOFS); if (!ei) return NULL; ei->vfs_inode.i_version = 1; return &ei->vfs_inode;}static void hpfs_destroy_inode(struct inode *inode){ kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode));}static void init_once(struct kmem_cache *cachep, void *foo){ struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo; mutex_init(&ei->i_mutex); mutex_init(&ei->i_parent_mutex); inode_init_once(&ei->vfs_inode);}static int init_inodecache(void){ hpfs_inode_cachep = kmem_cache_create("hpfs_inode_cache", sizeof(struct hpfs_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), init_once); if (hpfs_inode_cachep == NULL) return -ENOMEM; return 0;}static void destroy_inodecache(void){ kmem_cache_destroy(hpfs_inode_cachep);}/* * A tiny parser for option strings, stolen from dosfs. * Stolen again from read-only hpfs. * And updated for table-driven option parsing. */enum { Opt_help, Opt_uid, Opt_gid, Opt_umask, Opt_case_lower, Opt_case_asis, Opt_conv_binary, Opt_conv_text, Opt_conv_auto, Opt_check_none, Opt_check_normal, Opt_check_strict, Opt_err_cont, Opt_err_ro, Opt_err_panic, Opt_eas_no, Opt_eas_ro, Opt_eas_rw, Opt_chkdsk_no, Opt_chkdsk_errors, Opt_chkdsk_always, Opt_timeshift, Opt_err,};static match_table_t tokens = { {Opt_help, "help"}, {Opt_uid, "uid=%u"}, {Opt_gid, "gid=%u"}, {Opt_umask, "umask=%o"}, {Opt_case_lower, "case=lower"}, {Opt_case_asis, "case=asis"}, {Opt_conv_binary, "conv=binary"}, {Opt_conv_text, "conv=text"}, {Opt_conv_auto, "conv=auto"}, {Opt_check_none, "check=none"}, {Opt_check_normal, "check=normal"}, {Opt_check_strict, "check=strict"}, {Opt_err_cont, "errors=continue"}, {Opt_err_ro, "errors=remount-ro"}, {Opt_err_panic, "errors=panic"}, {Opt_eas_no, "eas=no"}, {Opt_eas_ro, "eas=ro"}, {Opt_eas_rw, "eas=rw"}, {Opt_chkdsk_no, "chkdsk=no"}, {Opt_chkdsk_errors, "chkdsk=errors"}, {Opt_chkdsk_always, "chkdsk=always"}, {Opt_timeshift, "timeshift=%d"}, {Opt_err, NULL},};static int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask, int *lowercase, int *conv, int *eas, int *chk, int *errs, int *chkdsk, int *timeshift){ char *p; int option; if (!opts) return 1; /*printk("Parsing opts: '%s'\n",opts);*/ while ((p = strsep(&opts, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; int token; if (!*p) continue; token = match_token(p, tokens, args); switch (token) { case Opt_help: return 2; case Opt_uid: if (match_int(args, &option)) return 0; *uid = option; break; case Opt_gid: if (match_int(args, &option)) return 0; *gid = option; break; case Opt_umask: if (match_octal(args, &option)) return 0; *umask = option; break; case Opt_case_lower: *lowercase = 1; break; case Opt_case_asis: *lowercase = 0; break; case Opt_conv_binary: *conv = CONV_BINARY; break; case Opt_conv_text: *conv = CONV_TEXT; break; case Opt_conv_auto: *conv = CONV_AUTO; break; case Opt_check_none: *chk = 0; break; case Opt_check_normal: *chk = 1; break; case Opt_check_strict: *chk = 2; break; case Opt_err_cont: *errs = 0; break; case Opt_err_ro: *errs = 1; break; case Opt_err_panic: *errs = 2; break; case Opt_eas_no: *eas = 0; break; case Opt_eas_ro: *eas = 1; break; case Opt_eas_rw: *eas = 2; break; case Opt_chkdsk_no: *chkdsk = 0; break; case Opt_chkdsk_errors: *chkdsk = 1; break; case Opt_chkdsk_always: *chkdsk = 2; break; case Opt_timeshift: { int m = 1; char *rhs = args[0].from; if (!rhs || !*rhs) return 0; if (*rhs == '-') m = -1; if (*rhs == '+' || *rhs == '-') rhs++; *timeshift = simple_strtoul(rhs, &rhs, 0) * m; if (*rhs) return 0; break; } default: return 0; } } return 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -