summaryrefslogtreecommitdiffstats
path: root/fs/ext3/super.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext3/super.c')
-rw-r--r--fs/ext3/super.c65
1 files changed, 48 insertions, 17 deletions
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 399a96a6c556..18eaa78ecb4e 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -347,7 +347,7 @@ fail:
static int ext3_blkdev_put(struct block_device *bdev)
{
bd_release(bdev);
- return blkdev_put(bdev);
+ return blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
}
static int ext3_blkdev_remove(struct ext3_sb_info *sbi)
@@ -393,7 +393,8 @@ static void ext3_put_super (struct super_block * sb)
int i;
ext3_xattr_put_super(sb);
- journal_destroy(sbi->s_journal);
+ if (journal_destroy(sbi->s_journal) < 0)
+ ext3_abort(sb, __func__, "Couldn't clean up the journal");
if (!(sb->s_flags & MS_RDONLY)) {
EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
es->s_state = cpu_to_le16(sbi->s_mount_state);
@@ -625,6 +626,9 @@ static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs)
else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)
seq_puts(seq, ",data=writeback");
+ if (test_opt(sb, DATA_ERR_ABORT))
+ seq_puts(seq, ",data_err=abort");
+
ext3_show_quota_options(seq, sb);
return 0;
@@ -754,6 +758,7 @@ enum {
Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh,
Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
+ Opt_data_err_abort, Opt_data_err_ignore,
Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
@@ -796,6 +801,8 @@ static const match_table_t tokens = {
{Opt_data_journal, "data=journal"},
{Opt_data_ordered, "data=ordered"},
{Opt_data_writeback, "data=writeback"},
+ {Opt_data_err_abort, "data_err=abort"},
+ {Opt_data_err_ignore, "data_err=ignore"},
{Opt_offusrjquota, "usrjquota="},
{Opt_usrjquota, "usrjquota=%s"},
{Opt_offgrpjquota, "grpjquota="},
@@ -1011,6 +1018,12 @@ static int parse_options (char *options, struct super_block *sb,
sbi->s_mount_opt |= data_opt;
}
break;
+ case Opt_data_err_abort:
+ set_opt(sbi->s_mount_opt, DATA_ERR_ABORT);
+ break;
+ case Opt_data_err_ignore:
+ clear_opt(sbi->s_mount_opt, DATA_ERR_ABORT);
+ break;
#ifdef CONFIG_QUOTA
case Opt_usrjquota:
qtype = USRQUOTA;
@@ -1986,6 +1999,10 @@ static void ext3_init_journal_params(struct super_block *sb, journal_t *journal)
journal->j_flags |= JFS_BARRIER;
else
journal->j_flags &= ~JFS_BARRIER;
+ if (test_opt(sb, DATA_ERR_ABORT))
+ journal->j_flags |= JFS_ABORT_ON_SYNCDATA_ERR;
+ else
+ journal->j_flags &= ~JFS_ABORT_ON_SYNCDATA_ERR;
spin_unlock(&journal->j_state_lock);
}
@@ -2050,7 +2067,7 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb,
if (bd_claim(bdev, sb)) {
printk(KERN_ERR
"EXT3: failed to claim external journal device.\n");
- blkdev_put(bdev);
+ blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
return NULL;
}
@@ -2280,7 +2297,9 @@ static void ext3_mark_recovery_complete(struct super_block * sb,
journal_t *journal = EXT3_SB(sb)->s_journal;
journal_lock_updates(journal);
- journal_flush(journal);
+ if (journal_flush(journal) < 0)
+ goto out;
+
lock_super(sb);
if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) &&
sb->s_flags & MS_RDONLY) {
@@ -2289,6 +2308,8 @@ static void ext3_mark_recovery_complete(struct super_block * sb,
ext3_commit_super(sb, es, 1);
}
unlock_super(sb);
+
+out:
journal_unlock_updates(journal);
}
@@ -2388,7 +2409,13 @@ static void ext3_write_super_lockfs(struct super_block *sb)
/* Now we set up the journal barrier. */
journal_lock_updates(journal);
- journal_flush(journal);
+
+ /*
+ * We don't want to clear needs_recovery flag when we failed
+ * to flush the journal.
+ */
+ if (journal_flush(journal) < 0)
+ return;
/* Journal blocked and flushed, clear needs_recovery flag. */
EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
@@ -2767,30 +2794,30 @@ static int ext3_quota_on_mount(struct super_block *sb, int type)
* Standard function to be called on quota_on
*/
static int ext3_quota_on(struct super_block *sb, int type, int format_id,
- char *path, int remount)
+ char *name, int remount)
{
int err;
- struct nameidata nd;
+ struct path path;
if (!test_opt(sb, QUOTA))
return -EINVAL;
- /* When remounting, no checks are needed and in fact, path is NULL */
+ /* When remounting, no checks are needed and in fact, name is NULL */
if (remount)
- return vfs_quota_on(sb, type, format_id, path, remount);
+ return vfs_quota_on(sb, type, format_id, name, remount);
- err = path_lookup(path, LOOKUP_FOLLOW, &nd);
+ err = kern_path(name, LOOKUP_FOLLOW, &path);
if (err)
return err;
/* Quotafile not on the same filesystem? */
- if (nd.path.mnt->mnt_sb != sb) {
- path_put(&nd.path);
+ if (path.mnt->mnt_sb != sb) {
+ path_put(&path);
return -EXDEV;
}
/* Journaling quota? */
if (EXT3_SB(sb)->s_qf_names[type]) {
/* Quotafile not of fs root? */
- if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode)
+ if (path.dentry->d_parent != sb->s_root)
printk(KERN_WARNING
"EXT3-fs: Quota file not on filesystem root. "
"Journaled quota will not work.\n");
@@ -2800,18 +2827,22 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,
* When we journal data on quota file, we have to flush journal to see
* all updates to the file when we bypass pagecache...
*/
- if (ext3_should_journal_data(nd.path.dentry->d_inode)) {
+ if (ext3_should_journal_data(path.dentry->d_inode)) {
/*
* We don't need to lock updates but journal_flush() could
* otherwise be livelocked...
*/
journal_lock_updates(EXT3_SB(sb)->s_journal);
- journal_flush(EXT3_SB(sb)->s_journal);
+ err = journal_flush(EXT3_SB(sb)->s_journal);
journal_unlock_updates(EXT3_SB(sb)->s_journal);
+ if (err) {
+ path_put(&path);
+ return err;
+ }
}
- err = vfs_quota_on_path(sb, type, format_id, &nd.path);
- path_put(&nd.path);
+ err = vfs_quota_on_path(sb, type, format_id, &path);
+ path_put(&path);
return err;
}