Commit b63cf84e authored by Chris Mason's avatar Chris Mason Committed by Linus Torvalds

[PATCH] reiserfs v3 barrier support

Add reiserfs support for flush barriers, mount with -o barrier=flush to enable
them.  Barriers are triggered on fsync and for log commits.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent d16b94fe
...@@ -89,15 +89,16 @@ static int reiserfs_sync_file( ...@@ -89,15 +89,16 @@ static int reiserfs_sync_file(
) { ) {
struct inode * p_s_inode = p_s_dentry->d_inode; struct inode * p_s_inode = p_s_dentry->d_inode;
int n_err; int n_err;
int barrier_done;
reiserfs_write_lock(p_s_inode->i_sb);
if (!S_ISREG(p_s_inode->i_mode)) if (!S_ISREG(p_s_inode->i_mode))
BUG (); BUG ();
n_err = sync_mapping_buffers(p_s_inode->i_mapping) ; n_err = sync_mapping_buffers(p_s_inode->i_mapping) ;
reiserfs_commit_for_inode(p_s_inode) ; reiserfs_write_lock(p_s_inode->i_sb);
barrier_done = reiserfs_commit_for_inode(p_s_inode);
reiserfs_write_unlock(p_s_inode->i_sb); reiserfs_write_unlock(p_s_inode->i_sb);
if (barrier_done != 1)
blkdev_issue_flush(p_s_inode->i_sb->s_bdev, NULL);
return ( n_err < 0 ) ? -EIO : 0; return ( n_err < 0 ) ? -EIO : 0;
} }
......
...@@ -127,6 +127,12 @@ static int reiserfs_clean_and_file_buffer(struct buffer_head *bh) { ...@@ -127,6 +127,12 @@ static int reiserfs_clean_and_file_buffer(struct buffer_head *bh) {
return 0 ; return 0 ;
} }
static void disable_barrier(struct super_block *s)
{
REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_BARRIER_FLUSH);
printk("reiserfs: disabling flush barriers on %s\n", reiserfs_bdevname(s));
}
static struct reiserfs_bitmap_node * static struct reiserfs_bitmap_node *
allocate_bitmap_node(struct super_block *p_s_sb) { allocate_bitmap_node(struct super_block *p_s_sb) {
struct reiserfs_bitmap_node *bn ; struct reiserfs_bitmap_node *bn ;
...@@ -640,6 +646,15 @@ static void submit_ordered_buffer(struct buffer_head *bh) { ...@@ -640,6 +646,15 @@ static void submit_ordered_buffer(struct buffer_head *bh) {
submit_bh(WRITE, bh) ; submit_bh(WRITE, bh) ;
} }
static int submit_barrier_buffer(struct buffer_head *bh) {
get_bh(bh) ;
bh->b_end_io = reiserfs_end_ordered_io;
clear_buffer_dirty(bh) ;
if (!buffer_uptodate(bh))
BUG();
return submit_bh(WRITE_BARRIER, bh) ;
}
#define CHUNK_SIZE 32 #define CHUNK_SIZE 32
struct buffer_chunk { struct buffer_chunk {
struct buffer_head *bh[CHUNK_SIZE]; struct buffer_head *bh[CHUNK_SIZE];
...@@ -909,6 +924,7 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list ...@@ -909,6 +924,7 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list
int bn ; int bn ;
struct buffer_head *tbh = NULL ; struct buffer_head *tbh = NULL ;
unsigned long trans_id = jl->j_trans_id; unsigned long trans_id = jl->j_trans_id;
int barrier = 0;
reiserfs_check_lock_depth(s, "flush_commit_list") ; reiserfs_check_lock_depth(s, "flush_commit_list") ;
...@@ -973,7 +989,20 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list ...@@ -973,7 +989,20 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list
} }
atomic_dec(&SB_JOURNAL(s)->j_async_throttle); atomic_dec(&SB_JOURNAL(s)->j_async_throttle);
/* wait on everything written so far before writing the commit */ /* wait on everything written so far before writing the commit
* if we are in barrier mode, send the commit down now
*/
barrier = reiserfs_barrier_flush(s);
if (barrier) {
int ret;
lock_buffer(jl->j_commit_bh);
ret = submit_barrier_buffer(jl->j_commit_bh);
if (ret == -EOPNOTSUPP) {
set_buffer_uptodate(jl->j_commit_bh);
disable_barrier(s);
barrier = 0;
}
}
for (i = 0 ; i < (jl->j_len + 1) ; i++) { for (i = 0 ; i < (jl->j_len + 1) ; i++) {
bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) + bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) +
(jl->j_start + i) % SB_ONDISK_JOURNAL_SIZE(s) ; (jl->j_start + i) % SB_ONDISK_JOURNAL_SIZE(s) ;
...@@ -995,10 +1024,14 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list ...@@ -995,10 +1024,14 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list
if (atomic_read(&(jl->j_commit_left)) != 1) if (atomic_read(&(jl->j_commit_left)) != 1)
BUG(); BUG();
if (buffer_dirty(jl->j_commit_bh)) if (!barrier) {
BUG(); if (buffer_dirty(jl->j_commit_bh))
mark_buffer_dirty(jl->j_commit_bh) ; BUG();
sync_dirty_buffer(jl->j_commit_bh) ; mark_buffer_dirty(jl->j_commit_bh) ;
sync_dirty_buffer(jl->j_commit_bh) ;
} else
wait_on_buffer(jl->j_commit_bh);
if (!buffer_uptodate(jl->j_commit_bh)) { if (!buffer_uptodate(jl->j_commit_bh)) {
reiserfs_panic(s, "journal-615: buffer write failed\n") ; reiserfs_panic(s, "journal-615: buffer write failed\n") ;
} }
...@@ -1098,8 +1131,22 @@ static int _update_journal_header_block(struct super_block *p_s_sb, unsigned lon ...@@ -1098,8 +1131,22 @@ static int _update_journal_header_block(struct super_block *p_s_sb, unsigned lon
jh->j_last_flush_trans_id = cpu_to_le32(trans_id) ; jh->j_last_flush_trans_id = cpu_to_le32(trans_id) ;
jh->j_first_unflushed_offset = cpu_to_le32(offset) ; jh->j_first_unflushed_offset = cpu_to_le32(offset) ;
jh->j_mount_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_mount_id) ; jh->j_mount_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_mount_id) ;
set_buffer_dirty(SB_JOURNAL(p_s_sb)->j_header_bh) ;
sync_dirty_buffer(SB_JOURNAL(p_s_sb)->j_header_bh) ; if (reiserfs_barrier_flush(p_s_sb)) {
int ret;
lock_buffer(SB_JOURNAL(p_s_sb)->j_header_bh);
ret = submit_barrier_buffer(SB_JOURNAL(p_s_sb)->j_header_bh);
if (ret == -EOPNOTSUPP) {
set_buffer_uptodate(SB_JOURNAL(p_s_sb)->j_header_bh);
disable_barrier(p_s_sb);
goto sync;
}
wait_on_buffer(SB_JOURNAL(p_s_sb)->j_header_bh);
} else {
sync:
set_buffer_dirty(SB_JOURNAL(p_s_sb)->j_header_bh) ;
sync_dirty_buffer(SB_JOURNAL(p_s_sb)->j_header_bh) ;
}
if (!buffer_uptodate(SB_JOURNAL(p_s_sb)->j_header_bh)) { if (!buffer_uptodate(SB_JOURNAL(p_s_sb)->j_header_bh)) {
reiserfs_warning (p_s_sb, "journal-837: IO error during journal replay"); reiserfs_warning (p_s_sb, "journal-837: IO error during journal replay");
return -EIO ; return -EIO ;
...@@ -3184,11 +3231,16 @@ void reiserfs_update_inode_transaction(struct inode *inode) { ...@@ -3184,11 +3231,16 @@ void reiserfs_update_inode_transaction(struct inode *inode) {
REISERFS_I(inode)->i_trans_id = SB_JOURNAL(inode->i_sb)->j_trans_id ; REISERFS_I(inode)->i_trans_id = SB_JOURNAL(inode->i_sb)->j_trans_id ;
} }
static void __commit_trans_jl(struct inode *inode, unsigned long id, /*
* returns -1 on error, 0 if no commits/barriers were done and 1
* if a transaction was actually committed and the barrier was done
*/
static int __commit_trans_jl(struct inode *inode, unsigned long id,
struct reiserfs_journal_list *jl) struct reiserfs_journal_list *jl)
{ {
struct reiserfs_transaction_handle th ; struct reiserfs_transaction_handle th ;
struct super_block *sb = inode->i_sb ; struct super_block *sb = inode->i_sb ;
int ret = 0;
/* is it from the current transaction, or from an unknown transaction? */ /* is it from the current transaction, or from an unknown transaction? */
if (id == SB_JOURNAL(sb)->j_trans_id) { if (id == SB_JOURNAL(sb)->j_trans_id) {
...@@ -3210,6 +3262,7 @@ static void __commit_trans_jl(struct inode *inode, unsigned long id, ...@@ -3210,6 +3262,7 @@ static void __commit_trans_jl(struct inode *inode, unsigned long id,
} }
journal_end_sync(&th, sb, 1) ; journal_end_sync(&th, sb, 1) ;
ret = 1;
} else { } else {
/* this gets tricky, we have to make sure the journal list in /* this gets tricky, we have to make sure the journal list in
...@@ -3218,13 +3271,21 @@ static void __commit_trans_jl(struct inode *inode, unsigned long id, ...@@ -3218,13 +3271,21 @@ static void __commit_trans_jl(struct inode *inode, unsigned long id,
*/ */
flush_commit_only: flush_commit_only:
if (journal_list_still_alive(inode->i_sb, id)) { if (journal_list_still_alive(inode->i_sb, id)) {
/*
* we only set ret to 1 when we know for sure
* the barrier hasn't been started yet on the commit
* block.
*/
if (atomic_read(&jl->j_commit_left) > 1)
ret = 1;
flush_commit_list(sb, jl, 1) ; flush_commit_list(sb, jl, 1) ;
} }
} }
/* otherwise the list is gone, and long since committed */ /* otherwise the list is gone, and long since committed */
return ret;
} }
void reiserfs_commit_for_inode(struct inode *inode) { int reiserfs_commit_for_inode(struct inode *inode) {
unsigned long id = REISERFS_I(inode)->i_trans_id; unsigned long id = REISERFS_I(inode)->i_trans_id;
struct reiserfs_journal_list *jl = REISERFS_I(inode)->i_jl; struct reiserfs_journal_list *jl = REISERFS_I(inode)->i_jl;
...@@ -3237,7 +3298,7 @@ void reiserfs_commit_for_inode(struct inode *inode) { ...@@ -3237,7 +3298,7 @@ void reiserfs_commit_for_inode(struct inode *inode) {
/* jl will be updated in __commit_trans_jl */ /* jl will be updated in __commit_trans_jl */
} }
__commit_trans_jl(inode, id, jl); return __commit_trans_jl(inode, id, jl);
} }
void reiserfs_restore_prepared_buffer(struct super_block *p_s_sb, void reiserfs_restore_prepared_buffer(struct super_block *p_s_sb,
......
...@@ -549,6 +549,13 @@ static const arg_desc_t logging_mode[] = { ...@@ -549,6 +549,13 @@ static const arg_desc_t logging_mode[] = {
{NULL, 0} {NULL, 0}
}; };
/* possible values for -o barrier= */
static const arg_desc_t barrier_mode[] = {
{"none", 1<<REISERFS_BARRIER_NONE, 1<<REISERFS_BARRIER_FLUSH},
{"flush", 1<<REISERFS_BARRIER_FLUSH, 1<<REISERFS_BARRIER_NONE},
{NULL, 0}
};
/* possible values for "-o block-allocator=" and bits which are to be set in /* possible values for "-o block-allocator=" and bits which are to be set in
s_mount_opt of reiserfs specific part of in-core super block */ s_mount_opt of reiserfs specific part of in-core super block */
static const arg_desc_t balloc[] = { static const arg_desc_t balloc[] = {
...@@ -711,6 +718,7 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st ...@@ -711,6 +718,7 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st
{"replayonly", .setmask = 1<<REPLAYONLY}, {"replayonly", .setmask = 1<<REPLAYONLY},
{"block-allocator", .arg_required = 'a', .values = balloc}, {"block-allocator", .arg_required = 'a', .values = balloc},
{"data", .arg_required = 'd', .values = logging_mode}, {"data", .arg_required = 'd', .values = logging_mode},
{"barrier", .arg_required = 'b', .values = barrier_mode},
{"resize", .arg_required = 'r', .values = NULL}, {"resize", .arg_required = 'r', .values = NULL},
{"jdev", .arg_required = 'j', .values = NULL}, {"jdev", .arg_required = 'j', .values = NULL},
{"nolargeio", .arg_required = 'w', .values = NULL}, {"nolargeio", .arg_required = 'w', .values = NULL},
...@@ -810,6 +818,23 @@ static void handle_data_mode(struct super_block *s, unsigned long mount_options) ...@@ -810,6 +818,23 @@ static void handle_data_mode(struct super_block *s, unsigned long mount_options)
} }
} }
static void handle_barrier_mode(struct super_block *s, unsigned long bits) {
int flush = (1 << REISERFS_BARRIER_FLUSH);
int none = (1 << REISERFS_BARRIER_NONE);
int all_barrier = flush | none;
if (bits & all_barrier) {
REISERFS_SB(s)->s_mount_opt &= ~all_barrier;
if (bits & flush) {
REISERFS_SB(s)->s_mount_opt |= flush;
printk("reiserfs: enabling write barrier flush mode\n");
} else if (bits & none) {
REISERFS_SB(s)->s_mount_opt |= none;
printk("reiserfs: write barriers turned off\n");
}
}
}
static void handle_attrs( struct super_block *s ) static void handle_attrs( struct super_block *s )
{ {
struct reiserfs_super_block * rs; struct reiserfs_super_block * rs;
...@@ -854,6 +879,8 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a ...@@ -854,6 +879,8 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
safe_mask |= 1 << REISERFS_ATTRS; safe_mask |= 1 << REISERFS_ATTRS;
safe_mask |= 1 << REISERFS_XATTRS_USER; safe_mask |= 1 << REISERFS_XATTRS_USER;
safe_mask |= 1 << REISERFS_POSIXACL; safe_mask |= 1 << REISERFS_POSIXACL;
safe_mask |= 1 << REISERFS_BARRIER_FLUSH;
safe_mask |= 1 << REISERFS_BARRIER_NONE;
/* Update the bitmask, taking care to keep /* Update the bitmask, taking care to keep
* the bits we're not allowed to change here */ * the bits we're not allowed to change here */
...@@ -900,6 +927,7 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a ...@@ -900,6 +927,7 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
} }
handle_data_mode(s, mount_options); handle_data_mode(s, mount_options);
handle_barrier_mode(s, mount_options);
REISERFS_SB(s)->s_mount_state = sb_umount_state(rs) ; REISERFS_SB(s)->s_mount_state = sb_umount_state(rs) ;
s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */ s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */
journal_begin(&th, s, 10) ; journal_begin(&th, s, 10) ;
...@@ -1413,6 +1441,9 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) ...@@ -1413,6 +1441,9 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent)
} else { } else {
reiserfs_info (s, "using writeback data mode\n"); reiserfs_info (s, "using writeback data mode\n");
} }
if (reiserfs_barrier_flush(s)) {
printk("reiserfs: using flush barriers\n");
}
// set_device_ro(s->s_dev, 1) ; // set_device_ro(s->s_dev, 1) ;
if( journal_init(s, jdev_name, old_format, commit_max_age) ) { if( journal_init(s, jdev_name, old_format, commit_max_age) ) {
......
...@@ -1777,7 +1777,8 @@ int reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *); ...@@ -1777,7 +1777,8 @@ int reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *);
int reiserfs_commit_page(struct inode *inode, struct page *page, int reiserfs_commit_page(struct inode *inode, struct page *page,
unsigned from, unsigned to); unsigned from, unsigned to);
int reiserfs_flush_old_commits(struct super_block *); int reiserfs_flush_old_commits(struct super_block *);
void reiserfs_commit_for_inode(struct inode *) ; int reiserfs_commit_for_inode(struct inode *) ;
int reiserfs_inode_needs_commit(struct inode *) ;
void reiserfs_update_inode_transaction(struct inode *) ; void reiserfs_update_inode_transaction(struct inode *) ;
void reiserfs_wait_on_write_block(struct super_block *s) ; void reiserfs_wait_on_write_block(struct super_block *s) ;
void reiserfs_block_writes(struct reiserfs_transaction_handle *th) ; void reiserfs_block_writes(struct reiserfs_transaction_handle *th) ;
......
...@@ -444,6 +444,8 @@ enum reiserfs_mount_options { ...@@ -444,6 +444,8 @@ enum reiserfs_mount_options {
REISERFS_XATTRS, REISERFS_XATTRS,
REISERFS_XATTRS_USER, REISERFS_XATTRS_USER,
REISERFS_POSIXACL, REISERFS_POSIXACL,
REISERFS_BARRIER_NONE,
REISERFS_BARRIER_FLUSH,
REISERFS_TEST1, REISERFS_TEST1,
REISERFS_TEST2, REISERFS_TEST2,
...@@ -473,6 +475,8 @@ enum reiserfs_mount_options { ...@@ -473,6 +475,8 @@ enum reiserfs_mount_options {
#define reiserfs_xattrs_user(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS_USER)) #define reiserfs_xattrs_user(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS_USER))
#define reiserfs_posixacl(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_POSIXACL)) #define reiserfs_posixacl(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_POSIXACL))
#define reiserfs_xattrs_optional(s) (reiserfs_xattrs_user(s) || reiserfs_posixacl(s)) #define reiserfs_xattrs_optional(s) (reiserfs_xattrs_user(s) || reiserfs_posixacl(s))
#define reiserfs_barrier_none(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_NONE))
#define reiserfs_barrier_flush(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_FLUSH))
void reiserfs_file_buffer (struct buffer_head * bh, int list); void reiserfs_file_buffer (struct buffer_head * bh, int list);
extern struct file_system_type reiserfs_fs_type; extern struct file_system_type reiserfs_fs_type;
......
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