public inbox for linux-xfs@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5 v2] xfs: clean up xlog_recover_process_data
@ 2014-09-26  2:19 Dave Chinner
  2014-09-26  2:19 ` [PATCH 1/5] xfs: refactor xlog_recover_process_data() Dave Chinner
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Dave Chinner @ 2014-09-26  2:19 UTC (permalink / raw)
  To: xfs

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
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/5] xfs: refactor xlog_recover_process_data()
  2014-09-26  2:19 [PATCH 0/5 v2] xfs: clean up xlog_recover_process_data Dave Chinner
@ 2014-09-26  2:19 ` Dave Chinner
  2014-09-26 11:42   ` Christoph Hellwig
  2014-09-26  2:19 ` [PATCH 2/5] xfs: recovery of XLOG_UNMOUNT_TRANS leaks memory Dave Chinner
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Dave Chinner @ 2014-09-26  2:19 UTC (permalink / raw)
  To: xfs

From: Dave Chinner <dchinner@redhat.com>

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 <dchinner@redhat.com>
---
 fs/xfs/xfs_log_recover.c | 200 ++++++++++++++++++++++++++++++-----------------
 1 file changed, 127 insertions(+), 73 deletions(-)

diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index c6427b3..b5e081b 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -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--;
 	}
-- 
2.0.0

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/5] xfs: recovery of XLOG_UNMOUNT_TRANS leaks memory
  2014-09-26  2:19 [PATCH 0/5 v2] xfs: clean up xlog_recover_process_data Dave Chinner
  2014-09-26  2:19 ` [PATCH 1/5] xfs: refactor xlog_recover_process_data() Dave Chinner
@ 2014-09-26  2:19 ` Dave Chinner
  2014-09-26 12:01   ` Christoph Hellwig
  2014-09-26  2:19 ` [PATCH 3/5] xfs: fix double free in xlog_recover_commit_trans Dave Chinner
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Dave Chinner @ 2014-09-26  2:19 UTC (permalink / raw)
  To: xfs

From: Dave Chinner <dchinner@redhat.com>

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.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/xfs_log_recover.c | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index b5e081b..685e98b 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -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);
 }
 
 /*
-- 
2.0.0

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/5] xfs: fix double free in xlog_recover_commit_trans
  2014-09-26  2:19 [PATCH 0/5 v2] xfs: clean up xlog_recover_process_data Dave Chinner
  2014-09-26  2:19 ` [PATCH 1/5] xfs: refactor xlog_recover_process_data() Dave Chinner
  2014-09-26  2:19 ` [PATCH 2/5] xfs: recovery of XLOG_UNMOUNT_TRANS leaks memory Dave Chinner
@ 2014-09-26  2:19 ` Dave Chinner
  2014-09-26  2:19 ` [PATCH 4/5] xfs: reorganise transaction recovery item code Dave Chinner
  2014-09-26  2:19 ` [PATCH 5/5] xfs: refactor recovery transaction start handling Dave Chinner
  4 siblings, 0 replies; 12+ messages in thread
From: Dave Chinner @ 2014-09-26  2:19 UTC (permalink / raw)
  To: xfs

From: Dave Chinner <dchinner@redhat.com>

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.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/xfs_log_recover.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 685e98b..28eb078 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -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 */
-- 
2.0.0

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/5] xfs: reorganise transaction recovery item code
  2014-09-26  2:19 [PATCH 0/5 v2] xfs: clean up xlog_recover_process_data Dave Chinner
                   ` (2 preceding siblings ...)
  2014-09-26  2:19 ` [PATCH 3/5] xfs: fix double free in xlog_recover_commit_trans Dave Chinner
@ 2014-09-26  2:19 ` Dave Chinner
  2014-09-26 12:05   ` Christoph Hellwig
  2014-09-26  2:19 ` [PATCH 5/5] xfs: refactor recovery transaction start handling Dave Chinner
  4 siblings, 1 reply; 12+ messages in thread
From: Dave Chinner @ 2014-09-26  2:19 UTC (permalink / raw)
  To: xfs

From: Dave Chinner <dchinner@redhat.com>

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 <dchinner@redhat.com>
---
 fs/xfs/xfs_log_recover.c | 358 +++++++++++++++++++++++------------------------
 1 file changed, 179 insertions(+), 179 deletions(-)

diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 28eb078..e4fd4b1 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -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.
  */
-- 
2.0.0

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 5/5] xfs: refactor recovery transaction start handling
  2014-09-26  2:19 [PATCH 0/5 v2] xfs: clean up xlog_recover_process_data Dave Chinner
                   ` (3 preceding siblings ...)
  2014-09-26  2:19 ` [PATCH 4/5] xfs: reorganise transaction recovery item code Dave Chinner
@ 2014-09-26  2:19 ` Dave Chinner
  2014-09-26 12:08   ` Christoph Hellwig
  4 siblings, 1 reply; 12+ messages in thread
From: Dave Chinner @ 2014-09-26  2:19 UTC (permalink / raw)
  To: xfs

From: Dave Chinner <dchinner@redhat.com>

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().

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/xfs_log_recover.c | 77 +++++++++++++++++++++---------------------------
 1 file changed, 34 insertions(+), 43 deletions(-)

diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index e4fd4b1..6e861ba 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -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 void
 xlog_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;
 }
 
-- 
2.0.0

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/5] xfs: refactor xlog_recover_process_data()
  2014-09-26  2:19 ` [PATCH 1/5] xfs: refactor xlog_recover_process_data() Dave Chinner
@ 2014-09-26 11:42   ` Christoph Hellwig
  2014-09-26 23:22     ` Dave Chinner
  0 siblings, 1 reply; 12+ messages in thread
From: Christoph Hellwig @ 2014-09-26 11:42 UTC (permalink / raw)
  To: Dave Chinner; +Cc: xfs

On Fri, Sep 26, 2014 at 12:19:08PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> 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 <dchinner@redhat.com>

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?

Reviewed-by: Christoph Hellwig <hch@lst.de>

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/5] xfs: recovery of XLOG_UNMOUNT_TRANS leaks memory
  2014-09-26  2:19 ` [PATCH 2/5] xfs: recovery of XLOG_UNMOUNT_TRANS leaks memory Dave Chinner
@ 2014-09-26 12:01   ` Christoph Hellwig
  2014-09-26 23:27     ` Dave Chinner
  0 siblings, 1 reply; 12+ messages in thread
From: Christoph Hellwig @ 2014-09-26 12:01 UTC (permalink / raw)
  To: Dave Chinner; +Cc: xfs

On Fri, Sep 26, 2014 at 12:19:09PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> 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.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

> @@ -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
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 4/5] xfs: reorganise transaction recovery item code
  2014-09-26  2:19 ` [PATCH 4/5] xfs: reorganise transaction recovery item code Dave Chinner
@ 2014-09-26 12:05   ` Christoph Hellwig
  0 siblings, 0 replies; 12+ messages in thread
From: Christoph Hellwig @ 2014-09-26 12:05 UTC (permalink / raw)
  To: Dave Chinner; +Cc: xfs

On Fri, Sep 26, 2014 at 12:19:11PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> 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 <dchinner@redhat.com>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 5/5] xfs: refactor recovery transaction start handling
  2014-09-26  2:19 ` [PATCH 5/5] xfs: refactor recovery transaction start handling Dave Chinner
@ 2014-09-26 12:08   ` Christoph Hellwig
  0 siblings, 0 replies; 12+ messages in thread
From: Christoph Hellwig @ 2014-09-26 12:08 UTC (permalink / raw)
  To: Dave Chinner; +Cc: xfs

On Fri, Sep 26, 2014 at 12:19:12PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Rework the transaction lookup and allocation code in
> xlog_recovery_process_ophdr() to remove fold two related call-once

s/remove //

> 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().
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/5] xfs: refactor xlog_recover_process_data()
  2014-09-26 11:42   ` Christoph Hellwig
@ 2014-09-26 23:22     ` Dave Chinner
  0 siblings, 0 replies; 12+ messages in thread
From: Dave Chinner @ 2014-09-26 23:22 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: xfs

On Fri, Sep 26, 2014 at 04:42:38AM -0700, Christoph Hellwig wrote:
> On Fri, Sep 26, 2014 at 12:19:08PM +1000, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > 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 <dchinner@redhat.com>
> 
> 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?

Yes, I had that thought too. I'll change it.

> Reviewed-by: Christoph Hellwig <hch@lst.de>

Thanks!

-- 
Dave Chinner
david@fromorbit.com

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/5] xfs: recovery of XLOG_UNMOUNT_TRANS leaks memory
  2014-09-26 12:01   ` Christoph Hellwig
@ 2014-09-26 23:27     ` Dave Chinner
  0 siblings, 0 replies; 12+ messages in thread
From: Dave Chinner @ 2014-09-26 23:27 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: xfs

On Fri, Sep 26, 2014 at 05:01:04AM -0700, Christoph Hellwig wrote:
> On Fri, Sep 26, 2014 at 12:19:09PM +1000, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > 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.
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> 
> Looks good,
> 
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> 
> > @@ -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.

> 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.
-- 
Dave Chinner
david@fromorbit.com

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2014-09-26 23:27 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-09-26  2:19 [PATCH 0/5 v2] xfs: clean up xlog_recover_process_data Dave Chinner
2014-09-26  2:19 ` [PATCH 1/5] xfs: refactor xlog_recover_process_data() Dave Chinner
2014-09-26 11:42   ` Christoph Hellwig
2014-09-26 23:22     ` Dave Chinner
2014-09-26  2:19 ` [PATCH 2/5] xfs: recovery of XLOG_UNMOUNT_TRANS leaks memory Dave Chinner
2014-09-26 12:01   ` Christoph Hellwig
2014-09-26 23:27     ` Dave Chinner
2014-09-26  2:19 ` [PATCH 3/5] xfs: fix double free in xlog_recover_commit_trans Dave Chinner
2014-09-26  2:19 ` [PATCH 4/5] xfs: reorganise transaction recovery item code Dave Chinner
2014-09-26 12:05   ` Christoph Hellwig
2014-09-26  2:19 ` [PATCH 5/5] xfs: refactor recovery transaction start handling Dave Chinner
2014-09-26 12:08   ` Christoph Hellwig

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox