From: Harshad Shirwadkar <harshadshirwadkar@xxxxxxxxx> Add following helpers for commit path: - jbd2_map_fc_buf() - allocates fast commit buffers for caller - jbd2_wait_on_fc_bufs() - waits on fast commit buffers allocated using jbd2_map_fc_buf() - jbd2_submit_inode_data() - submit data buffers for one inode - jbd2_wait_inode_data() - wait for inode data Signed-off-by: Harshad Shirwadkar <harshadshirwadkar@xxxxxxxxx> --- fs/jbd2/commit.c | 40 +++++++++++++++++++++++ fs/jbd2/journal.c | 76 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/jbd2.h | 6 ++++ 3 files changed, 122 insertions(+) diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 280d11591bcb..2ef2dfb029e4 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -202,6 +202,46 @@ static int journal_submit_inode_data_buffers(struct address_space *mapping, return ret; } +/* Send all the data buffers related to an inode */ +int jbd2_submit_inode_data(journal_t *journal, struct jbd2_inode *jinode) +{ + struct address_space *mapping; + loff_t dirty_start; + loff_t dirty_end; + int ret; + + if (!jinode) + return 0; + + dirty_start = jinode->i_dirty_start; + dirty_end = jinode->i_dirty_end; + + if (!(jinode->i_flags & JI_WRITE_DATA)) + return 0; + + dirty_start = jinode->i_dirty_start; + dirty_end = jinode->i_dirty_end; + + mapping = jinode->i_vfs_inode->i_mapping; + + trace_jbd2_submit_inode_data(jinode->i_vfs_inode); + ret = journal_submit_inode_data_buffers(mapping, dirty_start, + dirty_end); + + return ret; +} +EXPORT_SYMBOL(jbd2_submit_inode_data); + +int jbd2_wait_inode_data(journal_t *journal, struct jbd2_inode *jinode) +{ + if (!jinode || !(jinode->i_flags & JI_WAIT_DATA)) + return 0; + return filemap_fdatawait_range_keep_errors( + jinode->i_vfs_inode->i_mapping, jinode->i_dirty_start, + jinode->i_dirty_end); +} +EXPORT_SYMBOL(jbd2_wait_inode_data); + /* * Submit all the data buffers of inode associated with the transaction to * disk. diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index d3897d155fb9..e4e0b55dd077 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -864,6 +864,82 @@ int jbd2_journal_next_log_block(journal_t *journal, unsigned long long *retp) return jbd2_journal_bmap(journal, blocknr, retp); } +/* Map one fast commit buffer for use by the file system */ +int jbd2_map_fc_buf(journal_t *journal, struct buffer_head **bh_out) +{ + unsigned long long pblock; + unsigned long blocknr; + int ret = 0; + struct buffer_head *bh; + int fc_off; + journal_header_t *jhdr; + + write_lock(&journal->j_state_lock); + + if (journal->j_fc_off + journal->j_first_fc < journal->j_last_fc) { + fc_off = journal->j_fc_off; + blocknr = journal->j_first_fc + fc_off; + journal->j_fc_off++; + } else { + ret = -EINVAL; + } + write_unlock(&journal->j_state_lock); + + if (ret) + return ret; + + ret = jbd2_journal_bmap(journal, blocknr, &pblock); + if (ret) + return ret; + + bh = __getblk(journal->j_dev, pblock, journal->j_blocksize); + if (!bh) + return -ENOMEM; + + lock_buffer(bh); + jhdr = (journal_header_t *)bh->b_data; + jhdr->h_magic = cpu_to_be32(JBD2_MAGIC_NUMBER); + jhdr->h_blocktype = cpu_to_be32(JBD2_FC_BLOCK); + jhdr->h_sequence = cpu_to_be32(journal->j_running_transaction->t_tid); + + set_buffer_uptodate(bh); + unlock_buffer(bh); + journal->j_fc_wbuf[fc_off] = bh; + + *bh_out = bh; + + return 0; +} +EXPORT_SYMBOL(jbd2_map_fc_buf); + +/* + * Wait on fast commit buffers that were allocated by jbd2_map_fc_buf + * for completion. + */ +int jbd2_wait_on_fc_bufs(journal_t *journal, int num_blks) +{ + struct buffer_head *bh; + int i, j_fc_off; + + read_lock(&journal->j_state_lock); + j_fc_off = journal->j_fc_off; + read_unlock(&journal->j_state_lock); + + /* + * Wait in reverse order to minimize chances of us being woken up before + * all IOs have completed + */ + for (i = j_fc_off - 1; i >= j_fc_off - num_blks; i--) { + bh = journal->j_fc_wbuf[i]; + wait_on_buffer(bh); + if (unlikely(!buffer_uptodate(bh))) + return -EIO; + } + + return 0; +} +EXPORT_SYMBOL(jbd2_wait_on_fc_bufs); + /* * Conversion of logical to physical block numbers for the journal * diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 0a4d9d484528..599113bef67f 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -123,6 +123,7 @@ typedef struct journal_s journal_t; /* Journal control structure */ #define JBD2_SUPERBLOCK_V1 3 #define JBD2_SUPERBLOCK_V2 4 #define JBD2_REVOKE_BLOCK 5 +#define JBD2_FC_BLOCK 6 /* * Standard header for all descriptor blocks: @@ -1562,6 +1563,11 @@ int jbd2_start_async_fc_nowait(journal_t *journal, tid_t tid); int jbd2_start_async_fc_wait(journal_t *journal, tid_t tid); void jbd2_stop_async_fc(journal_t *journal, tid_t tid); void jbd2_init_fast_commit(journal_t *journal, int num_fc_blks); +int jbd2_map_fc_buf(journal_t *journal, struct buffer_head **bh_out); +int jbd2_wait_on_fc_bufs(journal_t *journal, int num_blks); +int jbd2_submit_inode_data(journal_t *journal, struct jbd2_inode *jinode); +int jbd2_wait_inode_data(journal_t *journal, struct jbd2_inode *jinode); + /* * is_journal_abort * -- 2.26.0.110.g2183baf09c-goog