Commit eee1a8c4 authored by Jens Axboe's avatar Jens Axboe Committed by Linus Torvalds

[PATCH] ext3 barrier support

Mount with "mount -o barrier=1" to enable barriers.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent b63cf84e
......@@ -587,7 +587,7 @@ enum {
Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0,
Opt_ignore, Opt_err,
Opt_ignore, Opt_barrier, Opt_err,
};
static match_table_t tokens = {
......@@ -632,6 +632,7 @@ static match_table_t tokens = {
{Opt_ignore, "noquota"},
{Opt_ignore, "quota"},
{Opt_ignore, "usrquota"},
{Opt_barrier, "barrier=%u"},
{Opt_err, NULL}
};
......@@ -897,6 +898,14 @@ static int parse_options (char * options, struct super_block *sb,
case Opt_abort:
set_opt(sbi->s_mount_opt, ABORT);
break;
case Opt_barrier:
if (match_int(&args[0], &option))
return 0;
if (option)
set_opt(sbi->s_mount_opt, BARRIER);
else
clear_opt(sbi->s_mount_opt, BARRIER);
break;
case Opt_ignore:
break;
default:
......@@ -1599,16 +1608,23 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
* initial mount, once the journal has been initialised but before we've
* done any recovery; and again on any subsequent remount.
*/
static void ext3_init_journal_params(struct ext3_sb_info *sbi,
journal_t *journal)
static void ext3_init_journal_params(struct super_block *sb, journal_t *journal)
{
struct ext3_sb_info *sbi = EXT3_SB(sb);
if (sbi->s_commit_interval)
journal->j_commit_interval = sbi->s_commit_interval;
/* We could also set up an ext3-specific default for the commit
* interval here, but for now we'll just fall back to the jbd
* default. */
}
spin_lock(&journal->j_state_lock);
if (test_opt(sb, BARRIER))
journal->j_flags |= JFS_BARRIER;
else
journal->j_flags &= ~JFS_BARRIER;
spin_unlock(&journal->j_state_lock);
}
static journal_t *ext3_get_journal(struct super_block *sb, int journal_inum)
{
......@@ -1646,7 +1662,7 @@ static journal_t *ext3_get_journal(struct super_block *sb, int journal_inum)
return NULL;
}
journal->j_private = sb;
ext3_init_journal_params(EXT3_SB(sb), journal);
ext3_init_journal_params(sb, journal);
return journal;
}
......@@ -1731,7 +1747,7 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb,
goto out_journal;
}
EXT3_SB(sb)->journal_bdev = bdev;
ext3_init_journal_params(EXT3_SB(sb), journal);
ext3_init_journal_params(sb, journal);
return journal;
out_journal:
journal_destroy(journal);
......@@ -2028,7 +2044,7 @@ int ext3_remount (struct super_block * sb, int * flags, char * data)
es = sbi->s_es;
ext3_init_journal_params(sbi, sbi->s_journal);
ext3_init_journal_params(sb, sbi->s_journal);
if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
......
......@@ -639,10 +639,38 @@ void journal_commit_transaction(journal_t *journal)
JBUFFER_TRACE(descriptor, "write commit block");
{
struct buffer_head *bh = jh2bh(descriptor);
int ret;
int barrier_done = 0;
set_buffer_dirty(bh);
sync_dirty_buffer(bh);
if (unlikely(!buffer_uptodate(bh)))
if (journal->j_flags & JFS_BARRIER) {
set_buffer_ordered(bh);
barrier_done = 1;
}
ret = sync_dirty_buffer(bh);
/* is it possible for another commit to fail at roughly
* the same time as this one? If so, we don't want to
* trust the barrier flag in the super, but instead want
* to remember if we sent a barrier request
*/
if (ret == -EOPNOTSUPP && barrier_done) {
char b[BDEVNAME_SIZE];
printk(KERN_WARNING
"JBD: barrier-based sync failed on %s - "
"disabling barriers\n",
bdevname(journal->j_dev, b));
spin_lock(&journal->j_state_lock);
journal->j_flags &= ~JFS_BARRIER;
spin_unlock(&journal->j_state_lock);
/* And try again, without the barrier */
clear_buffer_ordered(bh);
set_buffer_uptodate(bh);
set_buffer_dirty(bh);
ret = sync_dirty_buffer(bh);
}
if (unlikely(ret == -EIO))
err = -EIO;
put_bh(bh); /* One for getblk() */
journal_put_journal_head(descriptor);
......
......@@ -655,6 +655,17 @@ static int submit_barrier_buffer(struct buffer_head *bh) {
return submit_bh(WRITE_BARRIER, bh) ;
}
static void check_barrier_completion(struct super_block *s,
struct buffer_head *bh) {
if (buffer_eopnotsupp(bh)) {
clear_buffer_eopnotsupp(bh);
disable_barrier(s);
set_buffer_uptodate(bh);
set_buffer_dirty(bh);
sync_dirty_buffer(bh);
}
}
#define CHUNK_SIZE 32
struct buffer_chunk {
struct buffer_head *bh[CHUNK_SIZE];
......@@ -1032,6 +1043,7 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list
} else
wait_on_buffer(jl->j_commit_bh);
check_barrier_completion(s, jl->j_commit_bh);
if (!buffer_uptodate(jl->j_commit_bh)) {
reiserfs_panic(s, "journal-615: buffer write failed\n") ;
}
......@@ -1142,6 +1154,7 @@ static int _update_journal_header_block(struct super_block *p_s_sb, unsigned lon
goto sync;
}
wait_on_buffer(SB_JOURNAL(p_s_sb)->j_header_bh);
check_barrier_completion(p_s_sb, SB_JOURNAL(p_s_sb)->j_header_bh);
} else {
sync:
set_buffer_dirty(SB_JOURNAL(p_s_sb)->j_header_bh) ;
......
......@@ -324,6 +324,7 @@ struct ext3_inode {
#define EXT3_MOUNT_NO_UID32 0x2000 /* Disable 32-bit UIDs */
#define EXT3_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */
#define EXT3_MOUNT_POSIX_ACL 0x8000 /* POSIX Access Control Lists */
#define EXT3_MOUNT_BARRIER 0x10000 /* Use block barriers */
/* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
#ifndef _LINUX_EXT2_FS_H
......
......@@ -840,6 +840,7 @@ struct journal_s
#define JFS_ACK_ERR 0x004 /* The errno in the sb has been acked */
#define JFS_FLUSHED 0x008 /* The journal superblock has been flushed */
#define JFS_LOADED 0x010 /* The journal superblock has been loaded */
#define JFS_BARRIER 0x020 /* Use IDE barriers */
/*
* Function declarations for the journaling transaction and buffer
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment