/*
* 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/module.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/time.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/blkdev.h>
#include <linux/parser.h>
#include <linux/buffer_head.h>
#include <linux/exportfs.h>
#include <linux/vfs.h>
#include <linux/random.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/quotaops.h>
#include <linux/seq_file.h>
#include <linux/log2.h>
#include <linux/cleancache.h>
#include <asm/uaccess.h>
#include "xattr.h"
#include "acl.h"
#include "namei.h"
#define CREATE_TRACE_POINTS
#include <trace/events/ext3.h>
#ifdef CONFIG_EXT3_DEFAULTS_TO_ORDERED
#define EXT3_MOUNT_DEFAULT_DATA_MODE EXT3_MOUNT_ORDERED_DATA
#else
#define EXT3_MOUNT_DEFAULT_DATA_MODE EXT3_MOUNT_WRITEBACK_DATA
#endif
static int ext3_load_journal(struct super_block *, struct ext3_super_block *,
unsigned long journal_devnum);
static int ext3_create_journal(struct super_block *, struct ext3_super_block *,
unsigned int);
static int 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);
static int ext3_sync_fs(struct super_block *sb, int wait);
static const char *ext3_decode_error(struct super_block * sb, int errno,
char nbuf[16]);
static int ext3_remount (struct super_block * sb, int * flags, char * data);
static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf);
static int ext3_unfreeze(struct super_block *sb);
static int ext3_freeze(struct super_block *sb);
/*
* Wrappers for journal_start/end.
*
* The only special thing we need to do here is to make sure that all
* journal_end calls result in the superblock being marked dirty, so
* that sync() will call the filesystem's write_super callback if
* appropriate.
*/
handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks)
{
journal_t *journal;
if (sb->s_flags & MS_RDONLY)
return ERR_PTR(-EROFS);
/* Special case here: if the journal has aborted behind our
* backs (eg. EIO in the commit thread), then we still need to
* take the FS itself readonly cleanly. */
journal = EXT3_SB(sb)->s_journal;
if (is_journal_aborted(journal)) {
ext3_abort(sb, __func__,
"Detected aborted journal");
return ERR_PTR(-EROFS);
}
return journal_start(journal, nblocks);
}
/*
* The only special thing we need to do here is to make sure that all
* journal_stop calls result in the superblock being marked dirty, so
* that sync() will call the filesystem's write_super callback if
* appropriate.
*/
int __ext3_journal_stop(const char *where, handle_t *handle)
{
struct super_block *sb;
int err;
int rc;
sb = handle->h_transaction->t_journal->j_private;
err = handle->h_err;
rc = journal_stop(handle);
if (!err)
err = rc;
if (err)
__ext3_std_error(sb, where, err);
return err;
}
void ext3_journal_abort_handle(const char *caller, const char *err_fn,
struct buffer_head *bh, handle_t *handle, int err)
{
char nbuf[16];
const char *errstr = ext3_decode_error(NULL, err, nbuf);
if (bh)
BUFFER_TRACE(bh, "abort");
if (!handle->h_err)
handle->h_err = err;
if (is_handle_aborted(handle))
return;
printk(KERN_ERR "EXT3-fs: %s: aborting transaction: %s in %s\n",
caller, errstr, err_fn);
journal_abort_handle(handle);
}
void ext3_msg(struct super_block *sb, const char *prefix,
const char *fmt, ...)
{
struct va_format vaf;
va_list args;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
printk("%sEXT3-fs (%s): %pV\n", prefix, sb->s_id, &vaf);
va_end(args);
}
/* 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 complain 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_le16(EXT3_ERROR_FS);
if (sb->s_flags & MS_RDONLY)
return;
if (!test_opt (sb, ERRORS_CONT)) {
journal_t *journal = EXT3_SB(sb)->s_journal;
set_opt(EXT3_SB(sb)->s_mount_opt, ABORT);
if (journal)
journal_abort(journal, -EIO);
}
if (test_opt (sb, ERRORS_RO)) {
ext3_msg(sb, KERN_CRIT,
"error: remounting filesystem read-only");
sb->s_flags |= MS_RDONLY;
}
ext3_commit_super(sb, es, 1);
if (test_opt(sb, ERRORS_PANIC))
panic("EXT3-fs (%s): panic forced after error\n",
sb->s_id);
}
void ext3_error(struct super_block *sb, const char *function,
const char *fmt, ...)
{
struct va_format vaf;
va_list args;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
printk(KERN_CRIT "EXT3-fs error (device %s): %s: %pV\n",
sb->s_id, function, &vaf);
va_end(args);
ext3_handle_error(sb);
}
static 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. */
|