From: Mark Tinguely <tinguely@sgi.com>
To: xfs@oss.sgi.com
Subject: [PATCH 3/5] xfs: free the list of recovery items on error
Date: Wed, 02 Jul 2014 09:32:09 -0500 [thread overview]
Message-ID: <20140702144139.790241031@sgi.com> (raw)
In-Reply-To: 20140702143206.438456679@sgi.com
[-- Attachment #1: xfs-fix-log-recovery-leaks.patch --]
[-- Type: text/plain, Size: 7161 bytes --]
Recovery builds a list of items on the transaction's
r_itemq head. Normally these items are committed and freed.
But in the event of a recovery error, these allocations
are leaked.
If the error occurs during item reordering, then reconstruct
the r_itemq list before deleting the list to avoid leaking
the entries that were on one of the temporary lists.
Fix potential use-after-free of the trans structure by ensuring
they are removed from the transaction recoovery-in-progress hash
table before they are freed.
History:
My first version corrected the xlog_recover_free_trans for
the error path of xlog_recover_commit_trans.
Dave Chinner removed most of the XFS_ERROR(), changed messages
in xlog_recover_process_data and pushed the xlog_recover_free_trans
calls into the lower layers.
This has all those patches plus suggestions from Christoph Hellwig.
Signed-off-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Mark Tinguely <tinguely@sgi.com>
---
fs/xfs/xfs_log_recover.c | 88 ++++++++++++++++++++++++-----------------------
1 file changed, 45 insertions(+), 43 deletions(-)
Index: b/fs/xfs/xfs_log_recover.c
===================================================================
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -539,7 +539,7 @@ xlog_find_verify_log_record(
xfs_warn(log->l_mp,
"Log inconsistent (didn't find previous header)");
ASSERT(0);
- error = XFS_ERROR(EIO);
+ error = EIO;
goto out;
}
@@ -961,7 +961,7 @@ xlog_find_tail(
xfs_warn(log->l_mp, "%s: couldn't find sync record", __func__);
xlog_put_bp(bp);
ASSERT(0);
- return XFS_ERROR(EIO);
+ return EIO;
}
/* find blk_no of tail of log */
@@ -1551,7 +1551,7 @@ xlog_recover_add_to_trans(
xfs_warn(log->l_mp, "%s: bad header magic number",
__func__);
ASSERT(0);
- return XFS_ERROR(EIO);
+ return EIO;
}
if (len == sizeof(xfs_trans_header_t))
xlog_recover_add_item(&trans->r_itemq);
@@ -1581,7 +1581,7 @@ xlog_recover_add_to_trans(
in_f->ilf_size);
ASSERT(0);
kmem_free(ptr);
- return XFS_ERROR(EIO);
+ return EIO;
}
item->ri_total = in_f->ilf_size;
@@ -1702,7 +1702,7 @@ xlog_recover_reorder_trans(
*/
if (!list_empty(&sort_list))
list_splice_init(&sort_list, &trans->r_itemq);
- error = XFS_ERROR(EIO);
+ error = EIO;
goto out;
}
}
@@ -3395,7 +3395,7 @@ xlog_recover_commit_pass1(
xfs_warn(log->l_mp, "%s: invalid item type (%d)",
__func__, ITEM_TYPE(item));
ASSERT(0);
- return XFS_ERROR(EIO);
+ return EIO;
}
}
@@ -3431,7 +3431,7 @@ xlog_recover_commit_pass2(
xfs_warn(log->l_mp, "%s: invalid item type (%d)",
__func__, ITEM_TYPE(item));
ASSERT(0);
- return XFS_ERROR(EIO);
+ return EIO;
}
}
@@ -3478,7 +3478,7 @@ xlog_recover_commit_trans(
#define XLOG_RECOVER_COMMIT_QUEUE_MAX 100
- hlist_del(&trans->r_list);
+ hlist_del_init(&trans->r_list);
error = xlog_recover_reorder_trans(log, trans, pass);
if (error)
@@ -3503,13 +3503,14 @@ xlog_recover_commit_trans(
break;
default:
ASSERT(0);
+ error = ERANGE;
+ break;
}
if (error)
- goto out;
+ break;
}
-out:
if (!list_empty(&ra_list)) {
if (!error)
error = xlog_recover_items_pass2(log, trans,
@@ -3520,21 +3521,10 @@ 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;
}
-STATIC int
-xlog_recover_unmount_trans(
- struct xlog *log)
-{
- /* Do nothing now */
- xfs_warn(log->l_mp, "%s: Unmount LR", __func__);
- return 0;
-}
-
/*
* There are two valid states of the r_state field. 0 indicates that the
* transaction structure is in a normal state. We have either seen the
@@ -3555,9 +3545,9 @@ xlog_recover_process_data(
xfs_caddr_t lp;
int num_logops;
xlog_op_header_t *ohead;
- xlog_recover_t *trans;
+ xlog_recover_t *trans = NULL;
xlog_tid_t tid;
- int error;
+ int error = 0;
unsigned long hash;
uint flags;
@@ -3566,7 +3556,7 @@ xlog_recover_process_data(
/* check the log format matches our own - else we can't recover */
if (xlog_header_check_recover(log->l_mp, rhead))
- return (XFS_ERROR(EIO));
+ return XFS_ERROR(EIO);
while ((dp < lp) && num_logops) {
ASSERT(dp + sizeof(xlog_op_header_t) <= lp);
@@ -3574,10 +3564,12 @@ xlog_recover_process_data(
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",
+ xfs_warn(log->l_mp,
+ "%s: bad bad transaction opheader clientid 0x%x",
__func__, ohead->oh_clientid);
ASSERT(0);
- return (XFS_ERROR(EIO));
+ error = EIO;
+ goto out_error;
}
tid = be32_to_cpu(ohead->oh_tid);
hash = XLOG_RHASH(tid);
@@ -3588,10 +3580,12 @@ xlog_recover_process_data(
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",
+ xfs_warn(log->l_mp,
+ "%s: bad bad transaction opheader length 0x%x",
__func__, be32_to_cpu(ohead->oh_len));
WARN_ON(1);
- return (XFS_ERROR(EIO));
+ error = XFS_ERROR(EIO);
+ goto out_error;
}
flags = ohead->oh_flags & ~XLOG_END_TRANS;
if (flags & XLOG_WAS_CONT_TRANS)
@@ -3600,42 +3594,50 @@ xlog_recover_process_data(
case XLOG_COMMIT_TRANS:
error = xlog_recover_commit_trans(log,
trans, pass);
- break;
- case XLOG_UNMOUNT_TRANS:
- error = xlog_recover_unmount_trans(log);
+ if (error)
+ goto out_error;
+ /*
+ * xlog_recover_commit_trans removed the trans
+ * structure from the hash, so nobody else will
+ * ever find this structure again. Hence we
+ * must free it here.
+ */
+ xlog_recover_free_trans(trans);
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 = XFS_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;
+ case XLOG_UNMOUNT_TRANS:
+ xfs_warn(log->l_mp, "%s: Unmount LR", __func__);
+ break;
+ case XLOG_START_TRANS:
default:
- xfs_warn(log->l_mp, "%s: bad flag 0x%x",
+ xfs_warn(log->l_mp,
+ "%s: bad bad transaction opheader flag 0x%x",
__func__, flags);
ASSERT(0);
- error = XFS_ERROR(EIO);
+ error = EIO;
break;
}
- if (error) {
- xlog_recover_free_trans(trans);
- return error;
- }
+ if (error)
+ goto out_error;
}
dp += be32_to_cpu(ohead->oh_len);
num_logops--;
}
return 0;
+
+ out_error:
+ if (trans)
+ xlog_recover_free_trans(trans);
+ return error;
}
/*
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
next prev parent reply other threads:[~2014-07-02 14:52 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-07-02 14:32 [PATCH 0/5] Misc controversial patches Mark Tinguely
2014-07-02 14:32 ` [PATCH 1/5] xfs: remove efi from AIL in log recovery Mark Tinguely
2014-07-07 14:30 ` Brian Foster
2014-07-07 15:29 ` Mark Tinguely
2014-07-07 23:44 ` Dave Chinner
2014-07-02 14:32 ` [PATCH 2/5] xfs: free the EFI entries from AIL on forced shutdown Mark Tinguely
2014-07-02 14:32 ` Mark Tinguely [this message]
2014-07-02 14:32 ` [PATCH 4/5] xfs: free inodes on log recovery error Mark Tinguely
2014-07-07 14:30 ` Brian Foster
2014-07-07 15:18 ` Mark Tinguely
2014-07-09 9:02 ` Christoph Hellwig
2014-07-02 14:32 ` [PATCH 5/5] xfs: fix cil push sequence after log recovery Mark Tinguely
2014-07-07 15:26 ` Brian Foster
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20140702144139.790241031@sgi.com \
--to=tinguely@sgi.com \
--cc=xfs@oss.sgi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox