On Aug 8, 2019, at 9:45 PM, Harshad Shirwadkar <harshadshirwadkar@xxxxxxxxx> wrote: > > This patch adds new helper APIs that ext4 needs for fast > commits. These new fast commit APIs are used by subsequent fast commit > patches to implement fast commits. Following new APIs are added: > > /* > * Returns when either a full commit or a fast commit > * completes > */ > int jbd2_fc_complete_commit(journal_tc *journal, tid_t tid, > tid_t tid, tid_t subtid) > > /* Send all the data buffers related to an inode */ > int journal_submit_inode_data(journal_t *journal, > struct jbd2_inode *jinode) > > /* Map one fast commit buffer for use by the file system */ > int jbd2_map_fc_buf(journal_t *journal, struct buffer_head **bh_out) > > /* Wait on fast commit buffers to complete IO */ > jbd2_wait_on_fc_bufs(journal_t *journal, int num_bufs) > > Signed-off-by: Harshad Shirwadkar <harshadshirwadkar@xxxxxxxxx> Reviewed-by: Andreas Dilger <adilger@xxxxxxxxx> > --- > > Changelog: > > V2: 1) Fixed error reported by kbuild test robot. Removed duplicate > EXPORT_SYMBOL() call. Also, added EXPORT_SYMBOL() for the new > APIs introduced. > 2) Changed jbd2_submit_fc_bufs() to jbd2_wait_on_fc_bufs(). This > gives client file system to submit JBD2 buffers according to > its own convenience. > --- > fs/jbd2/commit.c | 32 +++++++++++++++ > fs/jbd2/journal.c | 98 ++++++++++++++++++++++++++++++++++++++++++++ > include/linux/jbd2.h | 6 +++ > 3 files changed, 136 insertions(+) > > diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c > index 9281814606e7..db62a53436e3 100644 > --- a/fs/jbd2/commit.c > +++ b/fs/jbd2/commit.c > @@ -202,6 +202,38 @@ static int journal_submit_inode_data_buffers(struct address_space *mapping, > return ret; > } > > +int jbd2_submit_inode_data(journal_t *journal, struct jbd2_inode *jinode) > +{ > + struct address_space *mapping; > + loff_t dirty_start = jinode->i_dirty_start; > + loff_t dirty_end = jinode->i_dirty_end; > + int ret; > + > + if (!jinode) > + return 0; > + > + 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; > + jinode->i_flags |= JI_COMMIT_RUNNING; > + > + trace_jbd2_submit_inode_data(jinode->i_vfs_inode); > + ret = journal_submit_inode_data_buffers(mapping, dirty_start, > + dirty_end); > + > + jinode->i_flags &= ~JI_COMMIT_RUNNING; > + /* Protect JI_COMMIT_RUNNING flag */ > + smp_mb(); > + wake_up_bit(&jinode->i_flags, __JI_COMMIT_RUNNING); > + > + return ret; > +} > +EXPORT_SYMBOL(jbd2_submit_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 ab05e47ed2d4..1e15804b2c3c 100644 > --- a/fs/jbd2/journal.c > +++ b/fs/jbd2/journal.c > @@ -811,6 +811,33 @@ int jbd2_complete_transaction(journal_t *journal, tid_t tid) > } > EXPORT_SYMBOL(jbd2_complete_transaction); > > +int jbd2_fc_complete_commit(journal_t *journal, tid_t tid, tid_t subtid) > +{ > + int need_to_wait = 1; > + > + read_lock(&journal->j_state_lock); > + if (journal->j_running_transaction && > + journal->j_running_transaction->t_tid == tid) { > + /* Check if fast commit was already done */ > + if (journal->j_subtid > subtid) > + need_to_wait = 0; > + if (journal->j_commit_request != tid) { > + /* transaction not yet started, so request it */ > + read_unlock(&journal->j_state_lock); > + jbd2_log_start_commit(journal, tid, false); > + goto wait_commit; > + } > + } else if (!(journal->j_committing_transaction && > + journal->j_committing_transaction->t_tid == tid)) > + need_to_wait = 0; > + read_unlock(&journal->j_state_lock); > + if (!need_to_wait) > + return 0; > +wait_commit: > + return __jbd2_log_wait_commit(journal, tid, subtid); > +} > +EXPORT_SYMBOL(jbd2_fc_complete_commit); > + > /* > * Log buffer allocation routines: > */ > @@ -831,6 +858,77 @@ int jbd2_journal_next_log_block(journal_t *journal, unsigned long long *retp) > return jbd2_journal_bmap(journal, blocknr, retp); > } > > +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); > + > +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 535f88dff653..5362777d06f8 100644 > --- a/include/linux/jbd2.h > +++ b/include/linux/jbd2.h > @@ -124,6 +124,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: > @@ -1582,6 +1583,7 @@ int jbd2_transaction_committed(journal_t *journal, tid_t tid); > int jbd2_complete_transaction(journal_t *journal, tid_t tid); > int jbd2_log_do_checkpoint(journal_t *journal); > int jbd2_trans_will_send_data_barrier(journal_t *journal, tid_t tid); > +int jbd2_fc_complete_commit(journal_t *journal, tid_t tid, tid_t subtid); > > void __jbd2_log_wait_for_space(journal_t *journal); > extern void __jbd2_journal_drop_transaction(journal_t *, transaction_t *); > @@ -1732,6 +1734,10 @@ static inline tid_t jbd2_get_latest_transaction(journal_t *journal) > return tid; > } > > +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); > + > #ifdef __KERNEL__ > > #define buffer_trace_init(bh) do {} while (0) > -- > 2.23.0.rc1.153.gdeed80330f-goog > Cheers, Andreas
Attachment:
signature.asc
Description: Message signed with OpenPGP