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 ;
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
struct buffer_chunk {
struct buffer_head *bh[CHUNK_SIZE];
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") ;
}
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) ;
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);
+
if (!buffer_uptodate(jl->j_commit_bh)) {
reiserfs_panic(s, "journal-615: buffer write failed\n") ;
}
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);
+ } 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 ;
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) {
}
journal_end_sync(&th, sb, 1) ;
+ ret = 1;
} else {
/* this gets tricky, we have to make sure the journal list in
*/
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;
/* 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,
{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
s_mount_opt of reiserfs specific part of in-core super block */
static const arg_desc_t balloc[] = {
{"replayonly", .setmask = 1<<REPLAYONLY},
{"block-allocator", .arg_required = 'a', .values = balloc},
{"data", .arg_required = 'd', .values = logging_mode},
+ {"barrier", .arg_required = 'b', .values = barrier_mode},
{"resize", .arg_required = 'r', .values = NULL},
{"jdev", .arg_required = 'j', .values = NULL},
{"nolargeio", .arg_required = 'w', .values = NULL},
}
}
+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 )
{
struct reiserfs_super_block * rs;
safe_mask |= 1 << REISERFS_ATTRS;
safe_mask |= 1 << REISERFS_XATTRS_USER;
safe_mask |= 1 << REISERFS_POSIXACL;
+ safe_mask |= 1 << REISERFS_BARRIER_FLUSH;
+ safe_mask |= 1 << REISERFS_BARRIER_NONE;
/* Update the bitmask, taking care to keep
* the bits we're not allowed to change here */
}
handle_data_mode(s, mount_options);
+ handle_barrier_mode(s, mount_options);
REISERFS_SB(s)->s_mount_state = sb_umount_state(rs) ;
s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */
journal_begin(&th, s, 10) ;
} else {
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) ;
if( journal_init(s, jdev_name, old_format, commit_max_age) ) {