📄 super.c
字号:
/* * linux/fs/ext3/super.c * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) * Laboratoire MASI - Institut Blaise Pascal * Universite Pierre et Marie Curie (Paris VI) * * from * * linux/fs/minix/inode.c * * Copyright (C) 1991, 1992 Linus Torvalds * * Big-endian to little-endian byte-swapping/bitmaps by * David S. Miller (davem@caip.rutgers.edu), 1995 */#include <linux/config.h>#include <linux/module.h>#include <linux/string.h>#include <linux/fs.h>#include <linux/sched.h>#include <linux/jbd.h>#include <linux/ext3_fs.h>#include <linux/ext3_jbd.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/locks.h>#include <linux/blkdev.h>#include <linux/smp_lock.h>#include <linux/random.h>#include <asm/uaccess.h>#ifdef CONFIG_JBD_DEBUGstatic int ext3_ro_after; /* Make fs read-only after this many jiffies */#endifstatic int ext3_load_journal(struct super_block *, struct ext3_super_block *);static int ext3_create_journal(struct super_block *, struct ext3_super_block *, int);static void ext3_commit_super (struct super_block * sb, struct ext3_super_block * es, int sync);static void ext3_mark_recovery_complete(struct super_block * sb, struct ext3_super_block * es);static void ext3_clear_journal_err(struct super_block * sb, struct ext3_super_block * es);#ifdef CONFIG_JBD_DEBUGint journal_no_write[2];/* * Debug code for turning filesystems "read-only" after a specified * amount of time. This is for crash/recovery testing. */static void make_rdonly(kdev_t dev, int *no_write){ if (dev) { printk(KERN_WARNING "Turning device %s read-only\n", bdevname(dev)); *no_write = 0xdead0000 + dev; }}static void turn_fs_readonly(unsigned long arg){ struct super_block *sb = (struct super_block *)arg; make_rdonly(sb->s_dev, &journal_no_write[0]); make_rdonly(EXT3_SB(sb)->s_journal->j_dev, &journal_no_write[1]); wake_up(&EXT3_SB(sb)->ro_wait_queue);}static void setup_ro_after(struct super_block *sb){ struct ext3_sb_info *sbi = EXT3_SB(sb); init_timer(&sbi->turn_ro_timer); if (ext3_ro_after) { printk(KERN_DEBUG "fs will go read-only in %d jiffies\n", ext3_ro_after); init_waitqueue_head(&sbi->ro_wait_queue); journal_no_write[0] = 0; journal_no_write[1] = 0; sbi->turn_ro_timer.function = turn_fs_readonly; sbi->turn_ro_timer.data = (unsigned long)sb; sbi->turn_ro_timer.expires = jiffies + ext3_ro_after; ext3_ro_after = 0; add_timer(&sbi->turn_ro_timer); }}static void clear_ro_after(struct super_block *sb){ del_timer_sync(&EXT3_SB(sb)->turn_ro_timer); journal_no_write[0] = 0; journal_no_write[1] = 0; ext3_ro_after = 0;}#else#define setup_ro_after(sb) do {} while (0)#define clear_ro_after(sb) do {} while (0)#endifstatic char error_buf[1024];/* Determine the appropriate response to ext3_error on a given filesystem */static int ext3_error_behaviour(struct super_block *sb){ /* First check for mount-time options */ if (test_opt (sb, ERRORS_PANIC)) return EXT3_ERRORS_PANIC; if (test_opt (sb, ERRORS_RO)) return EXT3_ERRORS_RO; if (test_opt (sb, ERRORS_CONT)) return EXT3_ERRORS_CONTINUE; /* If no overrides were specified on the mount, then fall back * to the default behaviour set in the filesystem's superblock * on disk. */ switch (le16_to_cpu(sb->u.ext3_sb.s_es->s_errors)) { case EXT3_ERRORS_PANIC: return EXT3_ERRORS_PANIC; case EXT3_ERRORS_RO: return EXT3_ERRORS_RO; default: break; } return EXT3_ERRORS_CONTINUE;}/* Deal with the reporting of failure conditions on a filesystem such as * inconsistencies detected or read IO failures. * * On ext2, we can store the error state of the filesystem in the * superblock. That is not possible on ext3, because we may have other * write ordering constraints on the superblock which prevent us from * writing it out straight away; and given that the journal is about to * be aborted, we can't rely on the current, or future, transactions to * write out the superblock safely. * * We'll just use the journal_abort() error code to record an error in * the journal instead. On recovery, the journal will compain about * that error until we've noted it down and cleared it. */static void ext3_handle_error(struct super_block *sb){ struct ext3_super_block *es = EXT3_SB(sb)->s_es; EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; es->s_state |= cpu_to_le32(EXT3_ERROR_FS); if (sb->s_flags & MS_RDONLY) return; if (ext3_error_behaviour(sb) != EXT3_ERRORS_CONTINUE) { EXT3_SB(sb)->s_mount_opt |= EXT3_MOUNT_ABORT; journal_abort(EXT3_SB(sb)->s_journal, -EIO); } if (ext3_error_behaviour(sb) == EXT3_ERRORS_PANIC) panic ("EXT3-fs (device %s): panic forced after error\n", bdevname(sb->s_dev)); if (ext3_error_behaviour(sb) == EXT3_ERRORS_RO) { printk (KERN_CRIT "Remounting filesystem read-only\n"); sb->s_flags |= MS_RDONLY; } ext3_commit_super(sb, es, 1);}void ext3_error (struct super_block * sb, const char * function, const char * fmt, ...){ va_list args; va_start (args, fmt); vsprintf (error_buf, fmt, args); va_end (args); printk (KERN_CRIT "EXT3-fs error (device %s): %s: %s\n", bdevname(sb->s_dev), function, error_buf); ext3_handle_error(sb);}const char *ext3_decode_error(struct super_block * sb, int errno, char nbuf[16]){ char *errstr = NULL; switch (errno) { case -EIO: errstr = "IO failure"; break; case -ENOMEM: errstr = "Out of memory"; break; case -EROFS: if (!sb || EXT3_SB(sb)->s_journal->j_flags & JFS_ABORT) errstr = "Journal has aborted"; else errstr = "Readonly filesystem"; break; default: /* If the caller passed in an extra buffer for unknown * errors, textualise them now. Else we just return * NULL. */ if (nbuf) { /* Check for truncated error codes... */ if (snprintf(nbuf, 16, "error %d", -errno) >= 0) errstr = nbuf; } break; } return errstr;}/* __ext3_std_error decodes expected errors from journaling functions * automatically and invokes the appropriate error response. */void __ext3_std_error (struct super_block * sb, const char * function, int errno){ char nbuf[16]; const char *errstr = ext3_decode_error(sb, errno, nbuf); printk (KERN_CRIT "EXT3-fs error (device %s) in %s: %s\n", bdevname(sb->s_dev), function, errstr); ext3_handle_error(sb);}/* * ext3_abort is a much stronger failure handler than ext3_error. The * abort function may be used to deal with unrecoverable failures such * as journal IO errors or ENOMEM at a critical moment in log management. * * We unconditionally force the filesystem into an ABORT|READONLY state, * unless the error response on the fs has been set to panic in which * case we take the easy way out and panic immediately. */void ext3_abort (struct super_block * sb, const char * function, const char * fmt, ...){ va_list args; printk (KERN_CRIT "ext3_abort called.\n"); va_start (args, fmt); vsprintf (error_buf, fmt, args); va_end (args); if (ext3_error_behaviour(sb) == EXT3_ERRORS_PANIC) panic ("EXT3-fs panic (device %s): %s: %s\n", bdevname(sb->s_dev), function, error_buf); printk (KERN_CRIT "EXT3-fs abort (device %s): %s: %s\n", bdevname(sb->s_dev), function, error_buf); if (sb->s_flags & MS_RDONLY) return; printk (KERN_CRIT "Remounting filesystem read-only\n"); sb->u.ext3_sb.s_mount_state |= EXT3_ERROR_FS; sb->s_flags |= MS_RDONLY; sb->u.ext3_sb.s_mount_opt |= EXT3_MOUNT_ABORT; journal_abort(EXT3_SB(sb)->s_journal, -EIO);}/* Deal with the reporting of failure conditions while running, such as * inconsistencies in operation or invalid system states. * * Use ext3_error() for cases of invalid filesystem states, as that will * record an error on disk and force a filesystem check on the next boot. */NORET_TYPE void ext3_panic (struct super_block * sb, const char * function, const char * fmt, ...){ va_list args; va_start (args, fmt); vsprintf (error_buf, fmt, args); va_end (args); /* this is to prevent panic from syncing this filesystem */ /* AKPM: is this sufficient? */ sb->s_flags |= MS_RDONLY; panic ("EXT3-fs panic (device %s): %s: %s\n", bdevname(sb->s_dev), function, error_buf);}void ext3_warning (struct super_block * sb, const char * function, const char * fmt, ...){ va_list args; va_start (args, fmt); vsprintf (error_buf, fmt, args); va_end (args); printk (KERN_WARNING "EXT3-fs warning (device %s): %s: %s\n", bdevname(sb->s_dev), function, error_buf);}void ext3_update_dynamic_rev(struct super_block *sb){ struct ext3_super_block *es = EXT3_SB(sb)->s_es; if (le32_to_cpu(es->s_rev_level) > EXT3_GOOD_OLD_REV) return; ext3_warning(sb, __FUNCTION__, "updating to rev %d because of new feature flag, " "running e2fsck is recommended", EXT3_DYNAMIC_REV); es->s_first_ino = cpu_to_le32(EXT3_GOOD_OLD_FIRST_INO); es->s_inode_size = cpu_to_le16(EXT3_GOOD_OLD_INODE_SIZE); es->s_rev_level = cpu_to_le32(EXT3_DYNAMIC_REV); /* leave es->s_feature_*compat flags alone */ /* es->s_uuid will be set by e2fsck if empty */ /* * The rest of the superblock fields should be zero, and if not it * means they are likely already in use, so leave them alone. We * can leave it up to e2fsck to clean up any inconsistencies there. */}/* * Open the external journal device */static struct block_device *ext3_blkdev_get(kdev_t dev){ struct block_device *bdev; int err = -ENODEV; bdev = bdget(kdev_t_to_nr(dev)); if (bdev == NULL) goto fail; err = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_FS); if (err < 0) goto fail; return bdev;fail: printk(KERN_ERR "EXT3: failed to open journal device %s: %d\n", bdevname(dev), err); return NULL;}/* * Release the journal device */static int ext3_blkdev_put(struct block_device *bdev){ return blkdev_put(bdev, BDEV_FS);}static int ext3_blkdev_remove(struct ext3_sb_info *sbi){ struct block_device *bdev; int ret = -ENODEV; bdev = sbi->journal_bdev; if (bdev) { ret = ext3_blkdev_put(bdev); sbi->journal_bdev = 0; } return ret;}#define orphan_list_entry(l) list_entry((l), struct inode, u.ext3_i.i_orphan)static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi){ struct list_head *l; printk(KERN_ERR "sb orphan head is %d\n", le32_to_cpu(sbi->s_es->s_last_orphan)); printk(KERN_ERR "sb_info orphan list:\n"); list_for_each(l, &sbi->s_orphan) { struct inode *inode = orphan_list_entry(l); printk(KERN_ERR " " "inode 0x%04x:%ld at %p: mode %o, nlink %d, next %d\n", inode->i_dev, inode->i_ino, inode, inode->i_mode, inode->i_nlink, le32_to_cpu(NEXT_ORPHAN(inode))); }}void ext3_put_super (struct super_block * sb){ struct ext3_sb_info *sbi = EXT3_SB(sb); struct ext3_super_block *es = sbi->s_es; kdev_t j_dev = sbi->s_journal->j_dev; int i; journal_destroy(sbi->s_journal); if (!(sb->s_flags & MS_RDONLY)) { EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); es->s_state = le16_to_cpu(sbi->s_mount_state); BUFFER_TRACE(sbi->s_sbh, "marking dirty"); mark_buffer_dirty(sbi->s_sbh); ext3_commit_super(sb, es, 1); } for (i = 0; i < sbi->s_gdb_count; i++) brelse(sbi->s_group_desc[i]); kfree(sbi->s_group_desc); for (i = 0; i < EXT3_MAX_GROUP_LOADED; i++) brelse(sbi->s_inode_bitmap[i]); for (i = 0; i < EXT3_MAX_GROUP_LOADED; i++) brelse(sbi->s_block_bitmap[i]); brelse(sbi->s_sbh); /* Debugging code just in case the in-memory inode orphan list * isn't empty. The on-disk one can be non-empty if we've * detected an error and taken the fs readonly, but the * in-memory list had better be clean by this point. */ if (!list_empty(&sbi->s_orphan)) dump_orphan_list(sb, sbi); J_ASSERT(list_empty(&sbi->s_orphan)); invalidate_buffers(sb->s_dev); if (j_dev != sb->s_dev) { /* * Invalidate the journal device's buffers. We don't want them * floating about in memory - the physical journal device may * hotswapped, and it breaks the `ro-after' testing code. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -