xfs: clean up xlog_recover_process_data
v2 cover xfs: clean up xlog_recover_process_data
Hi folks,
This is a new version of the log recovery transaction processing cleanup I first posted here:
http://oss.sgi.com/archives/xfs/2014-08/msg00367.html
It's largely the same, but there's been a couple of but fixes and rework done to it.
Version 2
- use sizeof(variable) consistently
- reworked transaction lookup factoring to encapsulate start ophdr processing completely.
- re-ordered checks for opheader length validity to so we do all the ophdr validity checks before we try to process it.
- added patch to re-integrate simple use-once functions to look up and allocate recovery transaction structures.
-Dave.
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH v2 1/5 xfs: refactor xlog_recover_process_data()
From: Dave Chinner <[email protected]>
Clean up xlog_recover_process_data() structure in preparation for fixing the allocation and freeing context of the transaction being recovered.
--- fs/xfs/xfs_log_recover.c | 200 ++++++++++++++++++++++++++++++----------------- 1 file changed, 127 insertions(+), 73 deletions(-)
fs/xfs/xfs_log_recover.c +127 -73
@@ -3533,12 +3533,122 @@ out: } STATIC int -xlog_recover_unmount_trans ( -struct xlog *log) +xlog_recovery_process_trans ( +struct xlog *log, +struct xlog_recover *trans, +xfs_caddr_t dp, +unsigned int len, +unsigned int flags, +int pass) { -/* Do nothing now */ -xfs_warn (log->l_mp,"%s: Unmount LR" , __func__); -return 0 ; +int error = -EIO ; + +/* mask off ophdr transaction container flags */ + flags &= ~XLOG_END_TRANS ; +if (flags &XLOG_WAS_CONT_TRANS ) + flags &= ~XLOG_CONTINUE_TRANS ; + +switch (flags) { +/* expected flag values */ +case 0 : +case XLOG_CONTINUE_TRANS : + error =xlog_recover_add_to_trans (log, trans, dp, len); +break ; +case XLOG_WAS_CONT_TRANS : + error =xlog_recover_add_to_cont_trans (log, trans, dp, len); +break ; +case XLOG_COMMIT_TRANS : + error =xlog_recover_commit_trans (log, trans, pass); +break ; + +/* unexpected flag values */ +case XLOG_UNMOUNT_TRANS : +xfs_warn (log->l_mp,"%s: Unmount LR" , __func__); + error =0 ;/* just skip trans */ +break ; +case XLOG_START_TRANS : +xfs_warn (log->l_mp,"%s: bad transaction" , __func__); +ASSERT (0 ); +break ; +default : +xfs_warn (log->l_mp,"%s: bad flag 0x%x" , __func__, flags); +ASSERT (0 ); +break ; + } +return error; +} + +STATIC struct xlog_recover * +xlog_recover_ophdr_to_trans ( +struct hlist_head rhash[], +struct xlog_rec_header *rhead, +struct xlog_op_header *ohead) +{ +struct xlog_recover *trans; +xlog_tid_t tid; +struct hlist_head *rhp; + + tid =be32_to_cpu (ohead->oh_tid); + rhp = &rhash[XLOG_RHASH (tid)]; + trans =xlog_recover_find_tid (rhp, tid); +if (trans) +return trans; + +/* +* If this is a new transaction, the ophdr only contains the +* start record. In that case, the only processing we need to do +* on this opheader is allocate a new recovery container to hold +* the recovery ops that will follow. +*/ +if (ohead->oh_flags &XLOG_START_TRANS ) +xlog_recover_new_tid (rhp, tid,be64_to_cpu (rhead->h_lsn)); +return NULL ; +} + +STATIC int +xlog_recover_process_ophdr ( +struct xlog *log, +struct hlist_head rhash[], +struct xlog_rec_header *rhead, +struct xlog_op_header *ohead, +xfs_caddr_t dp, +xfs_caddr_t lp, +int pass) +{ +struct xlog_recover *trans; +int error; +unsigned int len; + +/* Do we understand who wrote this op? */ +if (ohead->oh_clientid !=XFS_TRANSACTION && + ohead->oh_clientid !=XFS_LOG ) { +xfs_warn (log->l_mp,"%s: bad clientid 0x%x" , + __func__, ohead->oh_clientid); +ASSERT (0 ); +return -EIO ; + } + +/* +* Check the ophdr contains all the data it is supposed to contain. +*/ + len =be32_to_cpu (ohead->oh_len); +if (dp + len > lp) { +xfs_warn (log->l_mp,"%s: bad length 0x%x" , __func__, len); +WARN_ON (1 ); +return -EIO ; + } + + trans =xlog_recover_ophdr_to_trans (rhash, rhead, ohead); +if (!trans) { +/* nothing to do, so skip over this ophdr */ +return 0 ; + } + + error =xlog_recovery_process_trans (log, trans, dp, len, + ohead->oh_flags, pass); +if (error) +xlog_recover_free_trans (trans); +return error; }/*
@@ -3558,14 +3668,10 @@ xlog_recover_process_data( xfs_caddr_t dp, int pass) { +struct xlog_op_header *ohead;xfs_caddr_t lp;int num_logops; -xlog_op_header_t *ohead; -xlog_recover_t *trans; -xlog_tid_t tid;int error; -unsigned long hash; -uint flags; lp = dp +be32_to_cpu (rhead->h_len); num_logops =be32_to_cpu (rhead->h_num_logops);
@@ -3575,69 +3681,17 @@ xlog_recover_process_data(return -EIO ;while ((dp < lp) && num_logops) { -ASSERT (dp +sizeof (xlog_op_header_t) <= lp); - ohead = (xlog_op_header_t *)dp; - dp +=sizeof (xlog_op_header_t); -if (ohead->oh_clientid !=XFS_TRANSACTION && - ohead->oh_clientid !=XFS_LOG ) { -xfs_warn (log->l_mp,"%s: bad clientid 0x%x" , - __func__, ohead->oh_clientid); -ASSERT (0 ); -return -EIO ; - } - tid =be32_to_cpu (ohead->oh_tid); - hash =XLOG_RHASH (tid); - trans =xlog_recover_find_tid (&rhash[hash], tid); -if (trans ==NULL ) {/* not found; add new tid */ -if (ohead->oh_flags &XLOG_START_TRANS ) -xlog_recover_new_tid (&rhash[hash], tid, -be64_to_cpu (rhead->h_lsn)); - }else { -if (dp +be32_to_cpu (ohead->oh_len) > lp) { -xfs_warn (log->l_mp,"%s: bad length 0x%x" , - __func__,be32_to_cpu (ohead->oh_len)); -WARN_ON (1 ); -return -EIO ; - } - flags = ohead->oh_flags & ~XLOG_END_TRANS ; -if (flags &XLOG_WAS_CONT_TRANS ) - flags &= ~XLOG_CONTINUE_TRANS ; -switch (flags) { -case XLOG_COMMIT_TRANS : - error =xlog_recover_commit_trans (log, - trans, pass); -break ; -case XLOG_UNMOUNT_TRANS : - error =xlog_recover_unmount_trans (log); -break ; -case XLOG_WAS_CONT_TRANS : - error =xlog_recover_add_to_cont_trans (log, - trans, dp, -be32_to_cpu (ohead->oh_len)); -break ; -case XLOG_START_TRANS : -xfs_warn (log->l_mp,"%s: bad transaction" , - __func__); -ASSERT (0 ); - error = -EIO ; -break ; -case 0 : -case XLOG_CONTINUE_TRANS : - error =xlog_recover_add_to_trans (log, trans, - dp,be32_to_cpu (ohead->oh_len)); -break ; -default : -xfs_warn (log->l_mp,"%s: bad flag 0x%x" , - __func__, flags); -ASSERT (0 ); - error = -EIO ; -break ; - } -if (error) { -xlog_recover_free_trans (trans); -return error; - } - } + + ohead = (struct xlog_op_header *)dp; + dp +=sizeof (*ohead); +ASSERT (dp <= lp); + +/* errors will abort recovery */ + error =xlog_recover_process_ophdr (log, rhash, rhead, ohead, + dp, lp, pass); +if (error) +return error; + dp +=be32_to_cpu (ohead->oh_len); num_logops--; }
Signature · 6 lines
2.0.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 1/5] xfs: refactor xlog_recover_process_data()
Quoted 7 lines · Dave Chinner
From: Dave Chinner <[email protected]>
Clean up
xlog_recover_process_data()structure in preparation for fixing the allocation and freeing context of the transaction being recovered.Signed-off-by Dave Chinner <[email protected]>
Looks good. The only behavior change I could spot was that we now validate the length of an ophdr even when starting a new transaction, which seems sensible.
Nipick: maybe the lp argument to xlog_recover_process_ophdr should be called end to make it more obvious?
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 1/5] xfs: refactor xlog_recover_process_data()
Quoted 7 lines · Christoph Hellwig
Quoted 6 lines · Dave Chinner
From: Dave Chinner <[email protected]>
Clean up
xlog_recover_process_data()structure in preparation for fixing the allocation and freeing context of the transaction being recovered.
Quoted 8 lines
Quoted 1 line
Signed-off-by Dave Chinner <[email protected]>Looks good. The only behavior change I could spot was that we now validate the length of an ophdr even when starting a new transaction, which seems sensible.
Nipick: maybe the lp argument to
xlog_recover_process_ophdrshould be called end to make it more obvious?
Yes, I had that thought too. I'll change it.
Quoted 1 line
Reviewed-by Christoph Hellwig <[email protected]>
Thanks!
Signature · 7 lines
Dave Chinner [email protected] _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v2 2/5 xfs: recovery of XLOG_UNMOUNT_TRANS leaks memory
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
The XLOG_UNMOUNT_TRANS case skips the transaction, despite the fact an unmount record is always in a standalone transaction. Hence whenever we come across one of these we need to free the transaction structure associated with it as there is no commit record that follows it.
--- fs/xfs/xfs_log_recover.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-)
fs/xfs/xfs_log_recover.c +15 -12
@@ -3532,6 +3532,9 @@ out:return error ? error : error2; } +/* +* On error or completion, trans is freed. +*/ STATIC int xlog_recovery_process_trans( struct xlog *log,
@@ -3541,7 +3544,8 @@ xlog_recovery_process_trans(unsigned int flags, int pass) { - int error = -EIO; + int error = 0; +bool freeit = false;/* mask off ophdr transaction container flags */ flags &= ~XLOG_END_TRANS ;
@@ -3563,18 +3567,19 @@ xlog_recovery_process_trans(/* unexpected flag values */ case XLOG_UNMOUNT_TRANS : +/* just skip trans */ xfs_warn (log->l_mp,"%s: Unmount LR" , __func__); - error =0 ;/* just skip trans */ + freeit = true;break ;case XLOG_START_TRANS : -xfs_warn (log->l_mp,"%s: bad transaction" , __func__); -ASSERT (0 ); -break ;default :xfs_warn (log->l_mp,"%s: bad flag 0x%x" , __func__, flags);ASSERT (0 ); + error = -EIO ;break ; } +if (error || freeit) +xlog_recover_free_trans (trans);return error; }
@@ -3600,8 +3605,10 @@ xlog_recover_ophdr_to_trans(* on this opheader is allocate a new recovery container to hold * the recovery ops that will follow. */ -if (ohead->oh_flags &XLOG_START_TRANS ) +if (ohead->oh_flags &XLOG_START_TRANS ) { +ASSERT (be32_to_cpu (ohead->oh_len) ==0 );xlog_recover_new_tid (rhp, tid,be64_to_cpu (rhead->h_lsn)); + }return NULL ; }
@@ -3616,7 +3623,6 @@ xlog_recover_process_ophdr( int pass) {struct xlog_recover *trans; -int error;unsigned int len;/* Do we understand who wrote this op? */
@@ -3644,11 +3650,8 @@ xlog_recover_process_ophdr(return 0 ; } - error =xlog_recovery_process_trans (log, trans, dp, len, - ohead->oh_flags, pass); -if (error) -xlog_recover_free_trans (trans); -return error; +return xlog_recovery_process_trans (log, trans, dp, len, + ohead->oh_flags, pass); }/*
Signature · 6 lines
2.0.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 2/5] xfs: recovery of XLOG_UNMOUNT_TRANS leaks memory
Quoted 9 lines · Dave Chinner
From: Dave Chinner <[email protected]>
The
XLOG_UNMOUNT_TRANScase skips the transaction, despite the fact an unmount record is always in a standalone transaction. Hence whenever we come across one of these we need to free the transaction structure associated with it as there is no commit record that follows it.Signed-off-by Dave Chinner <[email protected]>
Looks good,
fs/xfs/xfs_log_recover.c xlog_recover_ophdr_to_trans( · line 3612
Quoted 10 lines
fs/xfs/xfs_log_recover.c +3
-1@@ -3600,8 +3605,10 @@ xlog_recover_ophdr_to_trans(* on this opheader is allocate a new recovery container to hold * the recovery ops that will follow. */ -if (ohead->oh_flags &XLOG_START_TRANS ) +if (ohead->oh_flags &XLOG_START_TRANS ) { +ASSERT (be32_to_cpu (ohead->oh_len) ==0 );xlog_recover_new_tid (rhp, tid,be64_to_cpu (rhead->h_lsn)); + }return NULL ;
.. but I suspect this hunk fits better into the previous patch. Also shouldn't we handle any sort of on disk corruption more gracefully?
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 2/5] xfs: recovery of XLOG_UNMOUNT_TRANS leaks memory
Quoted 15 lines · Christoph Hellwig
Quoted 9 lines · Dave Chinner
From: Dave Chinner <[email protected]>
The
XLOG_UNMOUNT_TRANScase skips the transaction, despite the fact an unmount record is always in a standalone transaction. Hence whenever we come across one of these we need to free the transaction structure associated with it as there is no commit record that follows it.Signed-off-by Dave Chinner <[email protected]>Looks good,
Reviewed-by Christoph Hellwig <[email protected]>
Quoted 12 lines
fs/xfs/xfs_log_recover.c xlog_recover_ophdr_to_trans( · line 3612
Quoted 10 lines
fs/xfs/xfs_log_recover.c +3
-1@@ -3600,8 +3605,10 @@ xlog_recover_ophdr_to_trans(* on this opheader is allocate a new recovery container to hold * the recovery ops that will follow. */ -if (ohead->oh_flags &XLOG_START_TRANS ) +if (ohead->oh_flags &XLOG_START_TRANS ) { +ASSERT (be32_to_cpu (ohead->oh_len) ==0 );xlog_recover_new_tid (rhp, tid,be64_to_cpu (rhead->h_lsn)); + }return NULL ;.. but I suspect this hunk fits better into the previous patch.
Folded it into the first patch.
Quoted 1 line
Also shouldn't we handle any sort of on disk corruption more gracefully?
Yes, we should. However, the recovery code is so full of this sort of ASSERT() checking that graceful handling of errors is fairly significant piece of work. It's already on my "cleanup work for a rainy day" list. ;)
Cheers,
Dave.
Signature · 7 lines
Dave Chinner [email protected] _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v2 3/5 xfs: fix double free in xlog_recover_commit_trans
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
When an error occurs during buffer submission in xlog_recover_commit_trans(), we free the trans structure twice. Fix it by only freeing the structure in the caller regardless of the success or failure of the function.
--- fs/xfs/xfs_log_recover.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
fs/xfs/xfs_log_recover.c +6 -2
@@ -3526,8 +3526,6 @@ out:if (!list_empty (&done_list))list_splice_init (&done_list, &trans->r_itemq); -xlog_recover_free_trans (trans); - error2 =xfs_buf_delwri_submit (&buffer_list);return error ? error : error2; }
@@ -3552,6 +3550,10 @@ xlog_recovery_process_trans(if (flags &XLOG_WAS_CONT_TRANS ) flags &= ~XLOG_CONTINUE_TRANS ; +/* +* Callees must not free the trans structure. We'll decide if we need to +* free it or not based on the operation being done and it's result. +*/ switch (flags) {/* expected flag values */ case 0 :
@@ -3563,6 +3565,8 @@ xlog_recovery_process_trans(break ;case XLOG_COMMIT_TRANS : error =xlog_recover_commit_trans (log, trans, pass); +/* success or fail, we are now done with this transaction. */ + freeit = true;break ;/* unexpected flag values */
Signature · 6 lines
2.0.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v2 4/5 xfs: reorganise transaction recovery item code
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
The code for managing transactions anf the items for recovery is spread across 3 different locations in the file. Move them all together so that it is easy to read the code without needing to jump long distances in the file.
--- fs/xfs/xfs_log_recover.c | 358 +++++++++++++++++++++++------------------------ 1 file changed, 179 insertions(+), 179 deletions(-)
fs/xfs/xfs_log_recover.c +179 -179
@@ -1443,160 +1443,6 @@ xlog_clear_stale_blocks(****************************************************************************** */ -STATIC xlog_recover_t * -xlog_recover_find_tid ( -struct hlist_head *head, -xlog_tid_t tid) -{ -xlog_recover_t *trans; - -hlist_for_each_entry (trans, head, r_list) { -if (trans->r_log_tid == tid) -return trans; - } -return NULL ; -} - -STATIC void -xlog_recover_new_tid ( -struct hlist_head *head, -xlog_tid_t tid, -xfs_lsn_t lsn) -{ -xlog_recover_t *trans; - - trans =kmem_zalloc (sizeof (xlog_recover_t),KM_SLEEP ); - trans->r_log_tid = tid; - trans->r_lsn = lsn; -INIT_LIST_HEAD (&trans->r_itemq); - -INIT_HLIST_NODE (&trans->r_list); -hlist_add_head (&trans->r_list, head); -} - -STATIC void -xlog_recover_add_item ( -struct list_head *head) -{ -xlog_recover_item_t *item; - - item =kmem_zalloc (sizeof (xlog_recover_item_t),KM_SLEEP ); -INIT_LIST_HEAD (&item->ri_list); -list_add_tail (&item->ri_list, head); -} - -STATIC int -xlog_recover_add_to_cont_trans ( -struct xlog *log, -struct xlog_recover *trans, -xfs_caddr_t dp, -int len) -{ -xlog_recover_item_t *item; -xfs_caddr_t ptr, old_ptr; -int old_len; - -if (list_empty (&trans->r_itemq)) { -/* finish copying rest of trans header */ -xlog_recover_add_item (&trans->r_itemq); - ptr = (xfs_caddr_t ) &trans->r_theader + -sizeof (xfs_trans_header_t) - len; -memcpy (ptr, dp, len);/* d, s, l */ -return 0 ; - } -/* take the tail entry */ - item =list_entry (trans->r_itemq.prev, xlog_recover_item_t, ri_list); - - old_ptr = item->ri_buf[item->ri_cnt-1 ].i_addr; - old_len = item->ri_buf[item->ri_cnt-1 ].i_len; - - ptr =kmem_realloc (old_ptr, len+old_len, old_len,KM_SLEEP ); -memcpy (&ptr[old_len], dp, len);/* d, s, l */ - item->ri_buf[item->ri_cnt-1 ].i_len += len; - item->ri_buf[item->ri_cnt-1 ].i_addr = ptr; -trace_xfs_log_recover_item_add_cont (log, trans, item,0 ); -return 0 ; -} - -/* -* The next region to add is the start of a new region. It could be -* a whole region or it could be the first part of a new region. Because -* of this, the assumption here is that the type and size fields of all -* format structures fit into the first 32 bits of the structure. -* -* This works because all regions must be 32 bit aligned. Therefore, we -* either have both fields or we have neither field. In the case we have -* neither field, the data part of the region is zero length. We only have -* a log_op_header and can throw away the header since a new one will appear -* later. If we have at least 4 bytes, then we can determine how many regions -* will appear in the current log item. -*/ -STATIC int -xlog_recover_add_to_trans ( -struct xlog *log, -struct xlog_recover *trans, -xfs_caddr_t dp, -int len) -{ -xfs_inode_log_format_t *in_f;/* any will do */ -xlog_recover_item_t *item; -xfs_caddr_t ptr; - -if (!len) -return 0 ; -if (list_empty (&trans->r_itemq)) { -/* we need to catch log corruptions here */ -if (*(uint *)dp !=XFS_TRANS_HEADER_MAGIC ) { -xfs_warn (log->l_mp,"%s: bad header magic number" , - __func__); -ASSERT (0 ); -return -EIO ; - } -if (len ==sizeof (xfs_trans_header_t)) -xlog_recover_add_item (&trans->r_itemq); -memcpy (&trans->r_theader, dp, len);/* d, s, l */ -return 0 ; - } - - ptr =kmem_alloc (len,KM_SLEEP ); -memcpy (ptr, dp, len); - in_f = (xfs_inode_log_format_t *)ptr; - -/* take the tail entry */ - item =list_entry (trans->r_itemq.prev, xlog_recover_item_t, ri_list); -if (item->ri_total !=0 && - item->ri_total == item->ri_cnt) { -/* tail item is in use, get a new one */ -xlog_recover_add_item (&trans->r_itemq); - item =list_entry (trans->r_itemq.prev, - xlog_recover_item_t, ri_list); - } - -if (item->ri_total ==0 ) {/* first region to be added */ -if (in_f->ilf_size ==0 || - in_f->ilf_size >XLOG_MAX_REGIONS_IN_ITEM ) { -xfs_warn (log->l_mp, -"bad number of regions (%d) in inode log format" , - in_f->ilf_size); -ASSERT (0 ); -kmem_free (ptr); -return -EIO ; - } - - item->ri_total = in_f->ilf_size; - item->ri_buf = -kmem_zalloc (item->ri_total *sizeof (xfs_log_iovec_t), -KM_SLEEP ); - } -ASSERT (item->ri_total > item->ri_cnt); -/* Description region is ri_buf[0] */ - item->ri_buf[item->ri_cnt].i_addr = ptr; - item->ri_buf[item->ri_cnt].i_len = len; - item->ri_cnt++; -trace_xfs_log_recover_item_add (log, trans, item,0 ); -return 0 ; -} -/* * Sort the log items in the transaction. *
@@ -3252,31 +3098,6 @@ xlog_recover_do_icreate_pass2(return 0 ; } -/* -* Free up any resources allocated by the transaction -* -* Remember that EFIs, EFDs, and IUNLINKs are handled later. -*/ -STATIC void -xlog_recover_free_trans ( -struct xlog_recover *trans) -{ -xlog_recover_item_t *item, *n; -int i; - -list_for_each_entry_safe (item, n, &trans->r_itemq, ri_list) { -/* Free the regions in the item. */ -list_del (&item->ri_list); -for (i =0 ; i < item->ri_cnt; i++) -kmem_free (item->ri_buf[i].i_addr); -/* Free the item itself */ -kmem_free (item->ri_buf); -kmem_free (item); - } -/* Free the transaction recover structure */ -kmem_free (trans); -} - STATIC void xlog_recover_buffer_ra_pass2( struct xlog *log,
@@ -3530,6 +3351,185 @@ out:return error ? error : error2; } + +STATIC xlog_recover_t * +xlog_recover_find_tid ( +struct hlist_head *head, +xlog_tid_t tid) +{ +xlog_recover_t *trans; + +hlist_for_each_entry (trans, head, r_list) { +if (trans->r_log_tid == tid) +return trans; + } +return NULL ; +} + +STATIC void +xlog_recover_new_tid ( +struct hlist_head *head, +xlog_tid_t tid, +xfs_lsn_t lsn) +{ +xlog_recover_t *trans; + + trans =kmem_zalloc (sizeof (xlog_recover_t),KM_SLEEP ); + trans->r_log_tid = tid; + trans->r_lsn = lsn; +INIT_LIST_HEAD (&trans->r_itemq); + +INIT_HLIST_NODE (&trans->r_list); +hlist_add_head (&trans->r_list, head); +} + +STATIC void +xlog_recover_add_item ( +struct list_head *head) +{ +xlog_recover_item_t *item; + + item =kmem_zalloc (sizeof (xlog_recover_item_t),KM_SLEEP ); +INIT_LIST_HEAD (&item->ri_list); +list_add_tail (&item->ri_list, head); +} + +STATIC int +xlog_recover_add_to_cont_trans ( +struct xlog *log, +struct xlog_recover *trans, +xfs_caddr_t dp, +int len) +{ +xlog_recover_item_t *item; +xfs_caddr_t ptr, old_ptr; +int old_len; + +if (list_empty (&trans->r_itemq)) { +/* finish copying rest of trans header */ +xlog_recover_add_item (&trans->r_itemq); + ptr = (xfs_caddr_t ) &trans->r_theader + +sizeof (xfs_trans_header_t) - len; +memcpy (ptr, dp, len); +return 0 ; + } +/* take the tail entry */ + item =list_entry (trans->r_itemq.prev, xlog_recover_item_t, ri_list); + + old_ptr = item->ri_buf[item->ri_cnt-1 ].i_addr; + old_len = item->ri_buf[item->ri_cnt-1 ].i_len; + + ptr =kmem_realloc (old_ptr, len+old_len, old_len,KM_SLEEP ); +memcpy (&ptr[old_len], dp, len); + item->ri_buf[item->ri_cnt-1 ].i_len += len; + item->ri_buf[item->ri_cnt-1 ].i_addr = ptr; +trace_xfs_log_recover_item_add_cont (log, trans, item,0 ); +return 0 ; +} + +/* +* The next region to add is the start of a new region. It could be +* a whole region or it could be the first part of a new region. Because +* of this, the assumption here is that the type and size fields of all +* format structures fit into the first 32 bits of the structure. +* +* This works because all regions must be 32 bit aligned. Therefore, we +* either have both fields or we have neither field. In the case we have +* neither field, the data part of the region is zero length. We only have +* a log_op_header and can throw away the header since a new one will appear +* later. If we have at least 4 bytes, then we can determine how many regions +* will appear in the current log item. +*/ +STATIC int +xlog_recover_add_to_trans ( +struct xlog *log, +struct xlog_recover *trans, +xfs_caddr_t dp, +int len) +{ +xfs_inode_log_format_t *in_f;/* any will do */ +xlog_recover_item_t *item; +xfs_caddr_t ptr; + +if (!len) +return 0 ; +if (list_empty (&trans->r_itemq)) { +/* we need to catch log corruptions here */ +if (*(uint *)dp !=XFS_TRANS_HEADER_MAGIC ) { +xfs_warn (log->l_mp,"%s: bad header magic number" , + __func__); +ASSERT (0 ); +return -EIO ; + } +if (len ==sizeof (xfs_trans_header_t)) +xlog_recover_add_item (&trans->r_itemq); +memcpy (&trans->r_theader, dp, len); +return 0 ; + } + + ptr =kmem_alloc (len,KM_SLEEP ); +memcpy (ptr, dp, len); + in_f = (xfs_inode_log_format_t *)ptr; + +/* take the tail entry */ + item =list_entry (trans->r_itemq.prev, xlog_recover_item_t, ri_list); +if (item->ri_total !=0 && + item->ri_total == item->ri_cnt) { +/* tail item is in use, get a new one */ +xlog_recover_add_item (&trans->r_itemq); + item =list_entry (trans->r_itemq.prev, + xlog_recover_item_t, ri_list); + } + +if (item->ri_total ==0 ) {/* first region to be added */ +if (in_f->ilf_size ==0 || + in_f->ilf_size >XLOG_MAX_REGIONS_IN_ITEM ) { +xfs_warn (log->l_mp, +"bad number of regions (%d) in inode log format" , + in_f->ilf_size); +ASSERT (0 ); +kmem_free (ptr); +return -EIO ; + } + + item->ri_total = in_f->ilf_size; + item->ri_buf = +kmem_zalloc (item->ri_total *sizeof (xfs_log_iovec_t), +KM_SLEEP ); + } +ASSERT (item->ri_total > item->ri_cnt); +/* Description region is ri_buf[0] */ + item->ri_buf[item->ri_cnt].i_addr = ptr; + item->ri_buf[item->ri_cnt].i_len = len; + item->ri_cnt++; +trace_xfs_log_recover_item_add (log, trans, item,0 ); +return 0 ; +} +/* +* Free up any resources allocated by the transaction +* +* Remember that EFIs, EFDs, and IUNLINKs are handled later. +*/ +STATIC void +xlog_recover_free_trans ( +struct xlog_recover *trans) +{ +xlog_recover_item_t *item, *n; +int i; + +list_for_each_entry_safe (item, n, &trans->r_itemq, ri_list) { +/* Free the regions in the item. */ +list_del (&item->ri_list); +for (i =0 ; i < item->ri_cnt; i++) +kmem_free (item->ri_buf[i].i_addr); +/* Free the item itself */ +kmem_free (item->ri_buf); +kmem_free (item); + } +/* Free the transaction recover structure */ +kmem_free (trans); +} +/* * On error or completion, trans is freed. */
Signature · 6 lines
2.0.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 4/5] xfs: reorganise transaction recovery item code
Quoted 8 lines · Dave Chinner
From: Dave Chinner <[email protected]>
The code for managing transactions anf the items for recovery is spread across 3 different locations in the file. Move them all together so that it is easy to read the code without needing to jump long distances in the file.
Signed-off-by Dave Chinner <[email protected]>
Looks good,
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
PATCH v2 5/5 xfs: refactor recovery transaction start handling
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
Rework the transaction lookup and allocation code in xlog_recovery_process_ophdr() to remove fold two related call-once helper functions into a single helper. Then fold in all XLOG_START_TRANS logic to that helper to clean up the remaining logic in xlog_recovery_process_ophdr().
--- fs/xfs/xfs_log_recover.c | 77 +++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 43 deletions(-)
fs/xfs/xfs_log_recover.c +34 -43
@@ -3351,38 +3351,6 @@ out:return error ? error : error2; } - -STATIC xlog_recover_t * -xlog_recover_find_tid ( -struct hlist_head *head, -xlog_tid_t tid) -{ -xlog_recover_t *trans; - -hlist_for_each_entry (trans, head, r_list) { -if (trans->r_log_tid == tid) -return trans; - } -return NULL ; -} - -STATIC void -xlog_recover_new_tid ( -struct hlist_head *head, -xlog_tid_t tid, -xfs_lsn_t lsn) -{ -xlog_recover_t *trans; - - trans =kmem_zalloc (sizeof (xlog_recover_t),KM_SLEEP ); - trans->r_log_tid = tid; - trans->r_lsn = lsn; -INIT_LIST_HEAD (&trans->r_itemq); - -INIT_HLIST_NODE (&trans->r_list); -hlist_add_head (&trans->r_list, head); -} - STATIC voidxlog_recover_add_item (struct list_head *head)
@@ -3505,6 +3473,7 @@ xlog_recover_add_to_trans(trace_xfs_log_recover_item_add (log, trans, item,0 );return 0 ; } +/* * Free up any resources allocated by the transaction *
@@ -3587,6 +3556,13 @@ xlog_recovery_process_trans(return error; } +/* +* Lookup the transaction recovery structure associated with the ID in the +* current ophdr. If the transaction doesn't exist and the start flag is set in +* the ophdr, then allocate a new transaction for future ID matches to find. +* Either way, return what we found during the lookup - an existing transaction +* or nothing. +*/ STATIC struct xlog_recover * xlog_recover_ophdr_to_trans( struct hlist_head rhash[],
@@ -3599,20 +3575,35 @@ xlog_recover_ophdr_to_trans( tid =be32_to_cpu (ohead->oh_tid); rhp = &rhash[XLOG_RHASH (tid)]; - trans =xlog_recover_find_tid (rhp, tid); -if (trans) -return trans; +hlist_for_each_entry (trans, rhp, r_list) { +if (trans->r_log_tid == tid) +return trans; + }/* -* If this is a new transaction, the ophdr only contains the -* start record. In that case, the only processing we need to do -* on this opheader is allocate a new recovery container to hold -* the recovery ops that will follow. +* skip over non-start transaction headers - we could be +* processing slack space before the next transaction starts +*/ +if (!(ohead->oh_flags &XLOG_START_TRANS )) +return NULL ; + +ASSERT (be32_to_cpu (ohead->oh_len) ==0 ); + +/* +* This is a new transaction so allocate a new recovery container to +* hold the recovery ops that will follow. +*/ + trans =kmem_zalloc (sizeof (struct xlog_recover ),KM_SLEEP ); + trans->r_log_tid = tid; + trans->r_lsn =be64_to_cpu (rhead->h_lsn); +INIT_LIST_HEAD (&trans->r_itemq); +INIT_HLIST_NODE (&trans->r_list); +hlist_add_head (&trans->r_list, rhp); + +/* +* Nothing more to do for this ophdr. Items to be added to this new +* transaction will be in subsequent ophdr containers. */ -if (ohead->oh_flags &XLOG_START_TRANS ) { -ASSERT (be32_to_cpu (ohead->oh_len) ==0 ); -xlog_recover_new_tid (rhp, tid,be64_to_cpu (rhead->h_lsn)); - }return NULL ; }
Signature · 6 lines
2.0.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Re: [PATCH 5/5] xfs: refactor recovery transaction start handling
Quoted 4 lines · Dave Chinner
From: Dave Chinner <[email protected]>
Rework the transaction lookup and allocation code in
xlog_recovery_process_ophdr()to remove fold two related call-once
s/remove //
Quoted 5 lines
helper functions into a single helper. Then fold in all
XLOG_START_TRANSlogic to that helper to clean up the remaining logic inxlog_recovery_process_ophdr().Signed-off-by Dave Chinner <[email protected]>
Looks good,
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs