Skip to content

Commit 3977543

Browse files
Brian Fosterdjwong
authored andcommitted
xfs: free uncommitted transactions during log recovery
Log recovery allocates in-core transaction and member item data structures on-demand as it processes the on-disk log. Transactions are allocated on first encounter on-disk and stored in a hash table structure where they are easily accessible for subsequent lookups. Transaction items are also allocated on demand and are attached to the associated transactions. When a commit record is encountered in the log, the transaction is committed to the fs and the in-core structures are freed. If a filesystem crashes or shuts down before all in-core log buffers are flushed to the log, however, not all transactions may have commit records in the log. As expected, the modifications in such an incomplete transaction are not replayed to the fs. The in-core data structures for the partial transaction are never freed, however, resulting in a memory leak. Update xlog_do_recovery_pass() to first correctly initialize the hash table array so empty lists can be distinguished from populated lists on function exit. Update xlog_recover_free_trans() to always remove the transaction from the list prior to freeing the associated memory. Finally, walk the hash table of transaction lists as the last step before it goes out of scope and free any transactions that may remain on the lists. This prevents a memory leak of partial transactions in the log. Signed-off-by: Brian Foster <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Darrick J. Wong <[email protected]> Signed-off-by: Darrick J. Wong <[email protected]>
1 parent 61d819e commit 3977543

File tree

1 file changed

+20
-1
lines changed

1 file changed

+20
-1
lines changed

fs/xfs/xfs_log_recover.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4152,7 +4152,7 @@ xlog_recover_commit_trans(
41524152

41534153
#define XLOG_RECOVER_COMMIT_QUEUE_MAX 100
41544154

4155-
hlist_del(&trans->r_list);
4155+
hlist_del_init(&trans->r_list);
41564156

41574157
error = xlog_recover_reorder_trans(log, trans, pass);
41584158
if (error)
@@ -4354,6 +4354,8 @@ xlog_recover_free_trans(
43544354
xlog_recover_item_t *item, *n;
43554355
int i;
43564356

4357+
hlist_del_init(&trans->r_list);
4358+
43574359
list_for_each_entry_safe(item, n, &trans->r_itemq, ri_list) {
43584360
/* Free the regions in the item. */
43594361
list_del(&item->ri_list);
@@ -5224,12 +5226,16 @@ xlog_do_recovery_pass(
52245226
int error2 = 0;
52255227
int bblks, split_bblks;
52265228
int hblks, split_hblks, wrapped_hblks;
5229+
int i;
52275230
struct hlist_head rhash[XLOG_RHASH_SIZE];
52285231
LIST_HEAD (buffer_list);
52295232

52305233
ASSERT(head_blk != tail_blk);
52315234
rhead_blk = 0;
52325235

5236+
for (i = 0; i < XLOG_RHASH_SIZE; i++)
5237+
INIT_HLIST_HEAD(&rhash[i]);
5238+
52335239
/*
52345240
* Read the header of the tail block and get the iclog buffer size from
52355241
* h_size. Use this to tell how many sectors make up the log header.
@@ -5466,6 +5472,19 @@ xlog_do_recovery_pass(
54665472
if (error && first_bad)
54675473
*first_bad = rhead_blk;
54685474

5475+
/*
5476+
* Transactions are freed at commit time but transactions without commit
5477+
* records on disk are never committed. Free any that may be left in the
5478+
* hash table.
5479+
*/
5480+
for (i = 0; i < XLOG_RHASH_SIZE; i++) {
5481+
struct hlist_node *tmp;
5482+
struct xlog_recover *trans;
5483+
5484+
hlist_for_each_entry_safe(trans, tmp, &rhash[i], r_list)
5485+
xlog_recover_free_trans(trans);
5486+
}
5487+
54695488
return error ? error : error2;
54705489
}
54715490

0 commit comments

Comments
 (0)