Skip to content

Commit 3e624fc

Browse files
committed
ext4: Replace hackish ext4_mb_poll_new_transaction with commit callback
The multiblock allocator needs to be able to release blocks (and issue a blkdev discard request) when the transaction which freed those blocks is committed. Previously this was done via a polling mechanism when blocks are allocated or freed. A much better way of doing things is to create a jbd2 callback function and attaching the list of blocks to be freed directly to the transaction structure. Signed-off-by: "Theodore Ts'o" <[email protected]>
1 parent 22359f5 commit 3e624fc

File tree

6 files changed

+29
-75
lines changed

6 files changed

+29
-75
lines changed

fs/ext4/ext4_sb.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,6 @@ struct ext4_sb_info {
9999
struct inode *s_buddy_cache;
100100
long s_blocks_reserved;
101101
spinlock_t s_reserve_lock;
102-
struct list_head s_active_transaction;
103-
struct list_head s_closed_transaction;
104-
struct list_head s_committed_transaction;
105102
spinlock_t s_md_lock;
106103
tid_t s_last_transaction;
107104
unsigned short *s_mb_offsets, *s_mb_maxs;

fs/ext4/mballoc.c

Lines changed: 15 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2523,9 +2523,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
25232523
}
25242524

25252525
spin_lock_init(&sbi->s_md_lock);
2526-
INIT_LIST_HEAD(&sbi->s_active_transaction);
2527-
INIT_LIST_HEAD(&sbi->s_closed_transaction);
2528-
INIT_LIST_HEAD(&sbi->s_committed_transaction);
25292526
spin_lock_init(&sbi->s_bal_lock);
25302527

25312528
sbi->s_mb_max_to_scan = MB_DEFAULT_MAX_TO_SCAN;
@@ -2554,6 +2551,8 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
25542551
ext4_mb_init_per_dev_proc(sb);
25552552
ext4_mb_history_init(sb);
25562553

2554+
sbi->s_journal->j_commit_callback = release_blocks_on_commit;
2555+
25572556
printk(KERN_INFO "EXT4-fs: mballoc enabled\n");
25582557
return 0;
25592558
}
@@ -2583,15 +2582,6 @@ int ext4_mb_release(struct super_block *sb)
25832582
struct ext4_group_info *grinfo;
25842583
struct ext4_sb_info *sbi = EXT4_SB(sb);
25852584

2586-
/* release freed, non-committed blocks */
2587-
spin_lock(&sbi->s_md_lock);
2588-
list_splice_init(&sbi->s_closed_transaction,
2589-
&sbi->s_committed_transaction);
2590-
list_splice_init(&sbi->s_active_transaction,
2591-
&sbi->s_committed_transaction);
2592-
spin_unlock(&sbi->s_md_lock);
2593-
ext4_mb_free_committed_blocks(sb);
2594-
25952585
if (sbi->s_group_info) {
25962586
for (i = 0; i < sbi->s_groups_count; i++) {
25972587
grinfo = ext4_get_group_info(sb, i);
@@ -2645,36 +2635,25 @@ int ext4_mb_release(struct super_block *sb)
26452635
return 0;
26462636
}
26472637

2648-
static noinline_for_stack void
2649-
ext4_mb_free_committed_blocks(struct super_block *sb)
2638+
/*
2639+
* This function is called by the jbd2 layer once the commit has finished,
2640+
* so we know we can free the blocks that were released with that commit.
2641+
*/
2642+
static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
26502643
{
2644+
struct super_block *sb = journal->j_private;
26512645
struct ext4_buddy e4b;
26522646
struct ext4_group_info *db;
2653-
struct ext4_sb_info *sbi = EXT4_SB(sb);
26542647
int err, count = 0, count2 = 0;
26552648
struct ext4_free_data *entry;
26562649
ext4_fsblk_t discard_block;
2650+
struct list_head *l, *ltmp;
26572651

2658-
if (list_empty(&sbi->s_committed_transaction))
2659-
return;
2660-
2661-
/* there is committed blocks to be freed yet */
2662-
do {
2663-
/* get next array of blocks */
2664-
entry = NULL;
2665-
spin_lock(&sbi->s_md_lock);
2666-
if (!list_empty(&sbi->s_committed_transaction)) {
2667-
entry = list_entry(sbi->s_committed_transaction.next,
2668-
struct ext4_free_data, list);
2669-
list_del(&entry->list);
2670-
}
2671-
spin_unlock(&sbi->s_md_lock);
2672-
2673-
if (entry == NULL)
2674-
break;
2652+
list_for_each_safe(l, ltmp, &txn->t_private_list) {
2653+
entry = list_entry(l, struct ext4_free_data, list);
26752654

26762655
mb_debug("gonna free %u blocks in group %lu (0x%p):",
2677-
entry->count, entry->group, entry);
2656+
entry->count, entry->group, entry);
26782657

26792658
err = ext4_mb_load_buddy(sb, entry->group, &e4b);
26802659
/* we expect to find existing buddy because it's pinned */
@@ -2706,7 +2685,7 @@ ext4_mb_free_committed_blocks(struct super_block *sb)
27062685

27072686
kmem_cache_free(ext4_free_ext_cachep, entry);
27082687
ext4_mb_release_desc(&e4b);
2709-
} while (1);
2688+
}
27102689

27112690
mb_debug("freed %u blocks in %u structures\n", count, count2);
27122691
}
@@ -4348,8 +4327,6 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
43484327
goto out1;
43494328
}
43504329

4351-
ext4_mb_poll_new_transaction(sb, handle);
4352-
43534330
*errp = ext4_mb_initialize_context(ac, ar);
43544331
if (*errp) {
43554332
ar->len = 0;
@@ -4408,36 +4385,6 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
44084385

44094386
return block;
44104387
}
4411-
static void ext4_mb_poll_new_transaction(struct super_block *sb,
4412-
handle_t *handle)
4413-
{
4414-
struct ext4_sb_info *sbi = EXT4_SB(sb);
4415-
4416-
if (sbi->s_last_transaction == handle->h_transaction->t_tid)
4417-
return;
4418-
4419-
/* new transaction! time to close last one and free blocks for
4420-
* committed transaction. we know that only transaction can be
4421-
* active, so previos transaction can be being logged and we
4422-
* know that transaction before previous is known to be already
4423-
* logged. this means that now we may free blocks freed in all
4424-
* transactions before previous one. hope I'm clear enough ... */
4425-
4426-
spin_lock(&sbi->s_md_lock);
4427-
if (sbi->s_last_transaction != handle->h_transaction->t_tid) {
4428-
mb_debug("new transaction %lu, old %lu\n",
4429-
(unsigned long) handle->h_transaction->t_tid,
4430-
(unsigned long) sbi->s_last_transaction);
4431-
list_splice_init(&sbi->s_closed_transaction,
4432-
&sbi->s_committed_transaction);
4433-
list_splice_init(&sbi->s_active_transaction,
4434-
&sbi->s_closed_transaction);
4435-
sbi->s_last_transaction = handle->h_transaction->t_tid;
4436-
}
4437-
spin_unlock(&sbi->s_md_lock);
4438-
4439-
ext4_mb_free_committed_blocks(sb);
4440-
}
44414388

44424389
/*
44434390
* We can merge two free data extents only if the physical blocks
@@ -4531,9 +4478,9 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
45314478
kmem_cache_free(ext4_free_ext_cachep, entry);
45324479
}
45334480
}
4534-
/* Add the extent to active_transaction list */
4481+
/* Add the extent to transaction's private list */
45354482
spin_lock(&sbi->s_md_lock);
4536-
list_add(&new_entry->list, &sbi->s_active_transaction);
4483+
list_add(&new_entry->list, &handle->h_transaction->t_private_list);
45374484
spin_unlock(&sbi->s_md_lock);
45384485
ext4_unlock_group(sb, group);
45394486
return 0;
@@ -4562,8 +4509,6 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode,
45624509

45634510
*freed = 0;
45644511

4565-
ext4_mb_poll_new_transaction(sb, handle);
4566-
45674512
sbi = EXT4_SB(sb);
45684513
es = EXT4_SB(sb)->s_es;
45694514
if (block < le32_to_cpu(es->s_first_data_block) ||

fs/ext4/mballoc.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,15 +269,14 @@ struct buffer_head *read_block_bitmap(struct super_block *, ext4_group_t);
269269

270270
static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
271271
ext4_group_t group);
272-
static void ext4_mb_poll_new_transaction(struct super_block *, handle_t *);
273-
static void ext4_mb_free_committed_blocks(struct super_block *);
274272
static void ext4_mb_return_to_preallocation(struct inode *inode,
275273
struct ext4_buddy *e4b, sector_t block,
276274
int count);
277275
static void ext4_mb_put_pa(struct ext4_allocation_context *,
278276
struct super_block *, struct ext4_prealloc_space *pa);
279277
static int ext4_mb_init_per_dev_proc(struct super_block *sb);
280278
static int ext4_mb_destroy_per_dev_proc(struct super_block *sb);
279+
static void release_blocks_on_commit(journal_t *journal, transaction_t *txn);
281280

282281

283282
static inline void ext4_lock_group(struct super_block *sb, ext4_group_t group)

fs/jbd2/commit.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,9 @@ void jbd2_journal_commit_transaction(journal_t *journal)
995995
}
996996
spin_unlock(&journal->j_list_lock);
997997

998+
if (journal->j_commit_callback)
999+
journal->j_commit_callback(journal, commit_transaction);
1000+
9981001
trace_mark(jbd2_end_commit, "dev %s transaction %d head %d",
9991002
journal->j_devname, commit_transaction->t_tid,
10001003
journal->j_tail_sequence);

fs/jbd2/transaction.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ jbd2_get_transaction(journal_t *journal, transaction_t *transaction)
5252
transaction->t_expires = jiffies + journal->j_commit_interval;
5353
spin_lock_init(&transaction->t_handle_lock);
5454
INIT_LIST_HEAD(&transaction->t_inode_list);
55+
INIT_LIST_HEAD(&transaction->t_private_list);
5556

5657
/* Set up the commit timer for the new transaction. */
5758
journal->j_commit_timer.expires = round_jiffies(transaction->t_expires);

include/linux/jbd2.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,11 @@ struct transaction_s
641641
*/
642642
int t_handle_count;
643643

644+
/*
645+
* For use by the filesystem to store fs-specific data
646+
* structures associated with the transaction
647+
*/
648+
struct list_head t_private_list;
644649
};
645650

646651
struct transaction_run_stats_s {
@@ -935,6 +940,10 @@ struct journal_s
935940

936941
pid_t j_last_sync_writer;
937942

943+
/* This function is called when a transaction is closed */
944+
void (*j_commit_callback)(journal_t *,
945+
transaction_t *);
946+
938947
/*
939948
* Journal statistics
940949
*/

0 commit comments

Comments
 (0)