📄 super.c
字号:
fsync_no_super(j_dev); invalidate_buffers(j_dev); ext3_blkdev_remove(sbi); } clear_ro_after(sb); return;}static struct super_operations ext3_sops = { read_inode: ext3_read_inode, /* BKL held */ write_inode: ext3_write_inode, /* BKL not held. Don't need */ dirty_inode: ext3_dirty_inode, /* BKL not held. We take it */ put_inode: ext3_put_inode, /* BKL not held. Don't need */ delete_inode: ext3_delete_inode, /* BKL not held. We take it */ put_super: ext3_put_super, /* BKL held */ write_super: ext3_write_super, /* BKL held */ write_super_lockfs: ext3_write_super_lockfs, /* BKL not held. Take it */ unlockfs: ext3_unlockfs, /* BKL not held. We take it */ statfs: ext3_statfs, /* BKL held */ remount_fs: ext3_remount, /* BKL held */};static int want_value(char *value, char *option){ if (!value || !*value) { printk(KERN_NOTICE "EXT3-fs: the %s option needs an argument\n", option); return -1; } return 0;}static int want_null_value(char *value, char *option){ if (*value) { printk(KERN_NOTICE "EXT3-fs: Invalid %s argument: %s\n", option, value); return -1; } return 0;}static int want_numeric(char *value, char *option, unsigned long *number){ if (want_value(value, option)) return -1; *number = simple_strtoul(value, &value, 0); if (want_null_value(value, option)) return -1; return 0;}/* * This function has been shamelessly adapted from the msdos fs */static int parse_options (char * options, unsigned long * sb_block, struct ext3_sb_info *sbi, unsigned long * inum, int is_remount){ unsigned long *mount_options = &sbi->s_mount_opt; uid_t *resuid = &sbi->s_resuid; gid_t *resgid = &sbi->s_resgid; char * this_char; char * value; if (!options) return 1; for (this_char = strtok (options, ","); this_char != NULL; this_char = strtok (NULL, ",")) { if ((value = strchr (this_char, '=')) != NULL) *value++ = 0; if (!strcmp (this_char, "bsddf")) clear_opt (*mount_options, MINIX_DF); else if (!strcmp (this_char, "nouid32")) { set_opt (*mount_options, NO_UID32); } else if (!strcmp (this_char, "abort")) set_opt (*mount_options, ABORT); else if (!strcmp (this_char, "check")) { if (!value || !*value || !strcmp (value, "none")) clear_opt (*mount_options, CHECK); else#ifdef CONFIG_EXT3_CHECK set_opt (*mount_options, CHECK);#else printk(KERN_ERR "EXT3 Check option not supported\n");#endif } else if (!strcmp (this_char, "debug")) set_opt (*mount_options, DEBUG); else if (!strcmp (this_char, "errors")) { if (want_value(value, "errors")) return 0; if (!strcmp (value, "continue")) { clear_opt (*mount_options, ERRORS_RO); clear_opt (*mount_options, ERRORS_PANIC); set_opt (*mount_options, ERRORS_CONT); } else if (!strcmp (value, "remount-ro")) { clear_opt (*mount_options, ERRORS_CONT); clear_opt (*mount_options, ERRORS_PANIC); set_opt (*mount_options, ERRORS_RO); } else if (!strcmp (value, "panic")) { clear_opt (*mount_options, ERRORS_CONT); clear_opt (*mount_options, ERRORS_RO); set_opt (*mount_options, ERRORS_PANIC); } else { printk (KERN_ERR "EXT3-fs: Invalid errors option: %s\n", value); return 0; } } else if (!strcmp (this_char, "grpid") || !strcmp (this_char, "bsdgroups")) set_opt (*mount_options, GRPID); else if (!strcmp (this_char, "minixdf")) set_opt (*mount_options, MINIX_DF); else if (!strcmp (this_char, "nocheck")) clear_opt (*mount_options, CHECK); else if (!strcmp (this_char, "nogrpid") || !strcmp (this_char, "sysvgroups")) clear_opt (*mount_options, GRPID); else if (!strcmp (this_char, "resgid")) { unsigned long v; if (want_numeric(value, "resgid", &v)) return 0; *resgid = v; } else if (!strcmp (this_char, "resuid")) { unsigned long v; if (want_numeric(value, "resuid", &v)) return 0; *resuid = v; } else if (!strcmp (this_char, "sb")) { if (want_numeric(value, "sb", sb_block)) return 0; }#ifdef CONFIG_JBD_DEBUG else if (!strcmp (this_char, "ro-after")) { unsigned long v; if (want_numeric(value, "ro-after", &v)) return 0; ext3_ro_after = v; }#endif /* Silently ignore the quota options */ else if (!strcmp (this_char, "grpquota") || !strcmp (this_char, "noquota") || !strcmp (this_char, "quota") || !strcmp (this_char, "usrquota")) /* Don't do anything ;-) */ ; else if (!strcmp (this_char, "journal")) { /* @@@ FIXME */ /* Eventually we will want to be able to create a journal file here. For now, only allow the user to specify an existing inode to be the journal file. */ if (is_remount) { printk(KERN_ERR "EXT3-fs: cannot specify " "journal on remount\n"); return 0; } if (want_value(value, "journal")) return 0; if (!strcmp (value, "update")) set_opt (*mount_options, UPDATE_JOURNAL); else if (want_numeric(value, "journal", inum)) return 0; } else if (!strcmp (this_char, "noload")) set_opt (*mount_options, NOLOAD); else if (!strcmp (this_char, "data")) { int data_opt = 0; if (want_value(value, "data")) return 0; if (!strcmp (value, "journal")) data_opt = EXT3_MOUNT_JOURNAL_DATA; else if (!strcmp (value, "ordered")) data_opt = EXT3_MOUNT_ORDERED_DATA; else if (!strcmp (value, "writeback")) data_opt = EXT3_MOUNT_WRITEBACK_DATA; else { printk (KERN_ERR "EXT3-fs: Invalid data option: %s\n", value); return 0; } if (is_remount) { if ((*mount_options & EXT3_MOUNT_DATA_FLAGS) != data_opt) { printk(KERN_ERR "EXT3-fs: cannot change data " "mode on remount\n"); return 0; } } else { *mount_options &= ~EXT3_MOUNT_DATA_FLAGS; *mount_options |= data_opt; } } else { printk (KERN_ERR "EXT3-fs: Unrecognized mount option %s\n", this_char); return 0; } } return 1;}static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es, int read_only){ struct ext3_sb_info *sbi = EXT3_SB(sb); int res = 0; if (le32_to_cpu(es->s_rev_level) > EXT3_MAX_SUPP_REV) { printk (KERN_ERR "EXT3-fs warning: revision level too high, " "forcing read-only mode\n"); res = MS_RDONLY; } if (read_only) return res; if (!(sbi->s_mount_state & EXT3_VALID_FS)) printk (KERN_WARNING "EXT3-fs warning: mounting unchecked fs, " "running e2fsck is recommended\n"); else if ((sbi->s_mount_state & EXT3_ERROR_FS)) printk (KERN_WARNING "EXT3-fs warning: mounting fs with errors, " "running e2fsck is recommended\n"); else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 && le16_to_cpu(es->s_mnt_count) >= (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) printk (KERN_WARNING "EXT3-fs warning: maximal mount count reached, " "running e2fsck is recommended\n"); else if (le32_to_cpu(es->s_checkinterval) && (le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= CURRENT_TIME)) printk (KERN_WARNING "EXT3-fs warning: checktime reached, " "running e2fsck is recommended\n");#if 0 /* @@@ We _will_ want to clear the valid bit if we find inconsistencies, to force a fsck at reboot. But for a plain journaled filesystem we can keep it set as valid forever! :) */ es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT3_VALID_FS);#endif if (!(__s16) le16_to_cpu(es->s_max_mnt_count)) es->s_max_mnt_count = (__s16) cpu_to_le16(EXT3_DFL_MAX_MNT_COUNT); es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1); es->s_mtime = cpu_to_le32(CURRENT_TIME); ext3_update_dynamic_rev(sb); EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); ext3_commit_super (sb, es, 1); if (test_opt (sb, DEBUG)) printk (KERN_INFO "[EXT3 FS %s, %s, bs=%lu, gc=%lu, " "bpg=%lu, ipg=%lu, mo=%04lx]\n", EXT3FS_VERSION, EXT3FS_DATE, sb->s_blocksize, sbi->s_groups_count, EXT3_BLOCKS_PER_GROUP(sb), EXT3_INODES_PER_GROUP(sb), sbi->s_mount_opt); printk(KERN_INFO "EXT3 FS " EXT3FS_VERSION ", " EXT3FS_DATE " on %s, ", bdevname(sb->s_dev)); if (EXT3_SB(sb)->s_journal->j_inode == NULL) { printk("external journal on %s\n", bdevname(EXT3_SB(sb)->s_journal->j_dev)); } else { printk("internal journal\n"); }#ifdef CONFIG_EXT3_CHECK if (test_opt (sb, CHECK)) { ext3_check_blocks_bitmap (sb); ext3_check_inodes_bitmap (sb); }#endif setup_ro_after(sb); return res;}static int ext3_check_descriptors (struct super_block * sb){ struct ext3_sb_info *sbi = EXT3_SB(sb); unsigned long block = le32_to_cpu(sbi->s_es->s_first_data_block); struct ext3_group_desc * gdp = NULL; int desc_block = 0; int i; ext3_debug ("Checking group descriptors"); for (i = 0; i < sbi->s_groups_count; i++) { if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0) gdp = (struct ext3_group_desc *) sbi->s_group_desc[desc_block++]->b_data; if (le32_to_cpu(gdp->bg_block_bitmap) < block || le32_to_cpu(gdp->bg_block_bitmap) >= block + EXT3_BLOCKS_PER_GROUP(sb)) { ext3_error (sb, "ext3_check_descriptors", "Block bitmap for group %d" " not in group (block %lu)!", i, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap)); return 0; } if (le32_to_cpu(gdp->bg_inode_bitmap) < block || le32_to_cpu(gdp->bg_inode_bitmap) >= block + EXT3_BLOCKS_PER_GROUP(sb)) { ext3_error (sb, "ext3_check_descriptors", "Inode bitmap for group %d" " not in group (block %lu)!", i, (unsigned long) le32_to_cpu(gdp->bg_inode_bitmap)); return 0; } if (le32_to_cpu(gdp->bg_inode_table) < block || le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group >= block + EXT3_BLOCKS_PER_GROUP(sb)) { ext3_error (sb, "ext3_check_descriptors", "Inode table for group %d" " not in group (block %lu)!", i, (unsigned long) le32_to_cpu(gdp->bg_inode_table)); return 0; } block += EXT3_BLOCKS_PER_GROUP(sb); gdp++; } return 1;}/* ext3_orphan_cleanup() walks a singly-linked list of inodes (starting at * the superblock) which were deleted from all directories, but held open by * a process at the time of a crash. We walk the list and try to delete these * inodes at recovery time (only with a read-write filesystem). * * In order to keep the orphan inode chain consistent during traversal (in * case of crash during recovery), we link each inode into the superblock * orphan list_head and handle it the same way as an inode deletion during * normal operation (which journals the operations for us). * * We only do an iget() and an iput() on each inode, which is very safe if we * accidentally point at an in-use or already deleted inode. The worst that * can happen in this case is that we get a "bit already cleared" message from * ext3_free_inode(). The only reason we would point at a wrong inode is if * e2fsck was run on this filesystem, and it must have already done the orphan * inode cleanup for us, so we can safely abort without any further action. */static void ext3_orphan_cleanup (struct super_block * sb, struct ext3_super_block * es){ unsigned int s_flags = sb->s_flags; int nr_orphans = 0, nr_truncates = 0; if (!es->s_last_orphan) { jbd_debug(4, "no orphan inodes to clean up\n"); return; } if (s_flags & MS_RDONLY) { printk(KERN_INFO "EXT3-fs: %s: orphan cleanup on readonly fs\n", bdevname(sb->s_dev)); sb->s_flags &= ~MS_RDONLY; } if (sb->u.ext3_sb.s_mount_state & EXT3_ERROR_FS) { if (es->s_last_orphan) jbd_debug(1, "Errors on filesystem, " "clearing orphan list.\n"); es->s_last_orphan = 0; jbd_debug(1, "Skipping orphan recovery on fs with errors.\n"); return; } while (es->s_last_orphan) { struct inode *inode; if (!(inode = ext3_orphan_get(sb, le32_to_cpu(es->s_last_orphan)))) { es->s_last_orphan = 0; break; } list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan); if (inode->i_nlink) { printk(KERN_DEBUG __FUNCTION__ ": truncating inode %ld to %Ld bytes\n", inode->i_ino, inode->i_size); jbd_debug(2, "truncating inode %ld to %Ld bytes\n", inode->i_ino, inode->i_size); ext3_truncate(inode); nr_truncates++; } else { printk(KERN_DEBUG __FUNCTION__ ": deleting unreferenced inode %ld\n", inode->i_ino); jbd_debug(2, "deleting unreferenced inode %ld\n", inode->i_ino); nr_orphans++; } iput(inode); /* The delete magic happens here! */ }#define PLURAL(x) (x), ((x)==1) ? "" : "s" if (nr_orphans) printk(KERN_INFO "EXT3-fs: %s: %d orphan inode%s deleted\n", bdevname(sb->s_dev), PLURAL(nr_orphans)); if (nr_truncates) printk(KERN_INFO "EXT3-fs: %s: %d truncate%s cleaned up\n", bdevname(sb->s_dev), PLURAL(nr_truncates)); sb->s_flags = s_flags; /* Restore MS_RDONLY status */}#define log2(n) ffz(~(n))/* * Maximal file size. There is a direct, and {,double-,triple-}indirect * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks. * We need to be 1 filesystem block less than the 2^32 sector limit. */static loff_t ext3_max_size(int bits){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -