diff options
author | Dave Chinner <david@fromorbit.com> | 2008-11-17 01:37:10 -0500 |
---|---|---|
committer | Lachlan McIlroy <lachlan@redback.melbourne.sgi.com> | 2008-11-17 01:37:10 -0500 |
commit | cc09c0dc57de7f7d2ed89d480b5653e5f6a32f2c (patch) | |
tree | 3c6145ccb00f603c47e020cfa45f159ab76cf9bf /fs/xfs/xfs_trans.c | |
parent | 6307091fe69ae74747298bdcaf43119ad67bda3a (diff) |
[XFS] Fix double free of log tickets
When an I/O error occurs during an intermediate commit on a rolling
transaction, xfs_trans_commit() will free the transaction structure
and the related ticket. However, the duplicate transaction that
gets used as the transaction continues still contains a pointer
to the ticket. Hence when the duplicate transaction is cancelled
and freed, we free the ticket a second time.
Add reference counting to the ticket so that we hold an extra
reference to the ticket over the transaction commit. We drop the
extra reference once we have checked that the transaction commit
did not return an error, thus avoiding a double free on commit
error.
Credit to Nick Piggin for tripping over the problem.
SGI-PV: 989741
Signed-off-by: Dave Chinner <david@fromorbit.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_trans.c')
-rw-r--r-- | fs/xfs/xfs_trans.c | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index ad137efc8702..8570b826fedd 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c | |||
@@ -290,7 +290,7 @@ xfs_trans_dup( | |||
290 | ASSERT(tp->t_ticket != NULL); | 290 | ASSERT(tp->t_ticket != NULL); |
291 | 291 | ||
292 | ntp->t_flags = XFS_TRANS_PERM_LOG_RES | (tp->t_flags & XFS_TRANS_RESERVE); | 292 | ntp->t_flags = XFS_TRANS_PERM_LOG_RES | (tp->t_flags & XFS_TRANS_RESERVE); |
293 | ntp->t_ticket = tp->t_ticket; | 293 | ntp->t_ticket = xfs_log_ticket_get(tp->t_ticket); |
294 | ntp->t_blk_res = tp->t_blk_res - tp->t_blk_res_used; | 294 | ntp->t_blk_res = tp->t_blk_res - tp->t_blk_res_used; |
295 | tp->t_blk_res = tp->t_blk_res_used; | 295 | tp->t_blk_res = tp->t_blk_res_used; |
296 | ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used; | 296 | ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used; |
@@ -1260,6 +1260,13 @@ xfs_trans_roll( | |||
1260 | trans = *tpp; | 1260 | trans = *tpp; |
1261 | 1261 | ||
1262 | /* | 1262 | /* |
1263 | * transaction commit worked ok so we can drop the extra ticket | ||
1264 | * reference that we gained in xfs_trans_dup() | ||
1265 | */ | ||
1266 | xfs_log_ticket_put(trans->t_ticket); | ||
1267 | |||
1268 | |||
1269 | /* | ||
1263 | * Reserve space in the log for th next transaction. | 1270 | * Reserve space in the log for th next transaction. |
1264 | * This also pushes items in the "AIL", the list of logged items, | 1271 | * This also pushes items in the "AIL", the list of logged items, |
1265 | * out to disk if they are taking up space at the tail of the log | 1272 | * out to disk if they are taking up space at the tail of the log |