X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Freiserfs%2Fjournal.c;h=6f8051f2e3f012628458de3590e3693ef151ddfc;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=7ced010703195ca3c15d2c75eac24edb8ff36010;hpb=a2c21200f1c81b08cb55e417b68150bba439b646;p=linux-2.6.git diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 7ced01070..6f8051f2e 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -127,6 +127,12 @@ static int reiserfs_clean_and_file_buffer(struct buffer_head *bh) { 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 * allocate_bitmap_node(struct super_block *p_s_sb) { struct reiserfs_bitmap_node *bn ; @@ -640,6 +646,26 @@ static void submit_ordered_buffer(struct buffer_head *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) ; +} + +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]; @@ -909,6 +935,7 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list int bn ; struct buffer_head *tbh = NULL ; unsigned long trans_id = jl->j_trans_id; + int barrier = 0; reiserfs_check_lock_depth(s, "flush_commit_list") ; @@ -973,7 +1000,20 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list } 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++) { bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) + (jl->j_start + i) % SB_ONDISK_JOURNAL_SIZE(s) ; @@ -995,10 +1035,15 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list if (atomic_read(&(jl->j_commit_left)) != 1) BUG(); - if (buffer_dirty(jl->j_commit_bh)) - BUG(); - mark_buffer_dirty(jl->j_commit_bh) ; - sync_dirty_buffer(jl->j_commit_bh) ; + if (!barrier) { + if (buffer_dirty(jl->j_commit_bh)) + BUG(); + mark_buffer_dirty(jl->j_commit_bh) ; + sync_dirty_buffer(jl->j_commit_bh) ; + } 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") ; } @@ -1098,8 +1143,23 @@ 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_first_unflushed_offset = cpu_to_le32(offset) ; 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); + 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) ; + sync_dirty_buffer(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"); return -EIO ; @@ -3184,11 +3244,16 @@ void reiserfs_update_inode_transaction(struct inode *inode) { 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_transaction_handle th ; struct super_block *sb = inode->i_sb ; + int ret = 0; /* is it from the current transaction, or from an unknown transaction? */ if (id == SB_JOURNAL(sb)->j_trans_id) { @@ -3210,6 +3275,7 @@ static void __commit_trans_jl(struct inode *inode, unsigned long id, } journal_end_sync(&th, sb, 1) ; + ret = 1; } else { /* this gets tricky, we have to make sure the journal list in @@ -3218,13 +3284,21 @@ static void __commit_trans_jl(struct inode *inode, unsigned long id, */ flush_commit_only: 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) ; } } /* 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; struct reiserfs_journal_list *jl = REISERFS_I(inode)->i_jl; @@ -3237,7 +3311,7 @@ void reiserfs_commit_for_inode(struct inode *inode) { /* 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,