1 Add support for tracking metadata blocks in the log.
3 From: Abutalib Aghayev <agayev@cs.cmu.edu>
5 This patch adds two important data structures, jmap and transaction_infos,
6 and supporting functions. Jmap is a map from a metadata block number to
7 the log block number. When a transaction commits, jmap is updated with new
8 mappings; when a block is revoked, the mapping for the block is removed
9 from the jmap. Transaction_infos is an array of transaction_info
10 structures that contain information about transactions currently present in
11 the log. It contains a linked list of live blocks in a transaction, and it
12 is updated after every commit to keep the list up-to-date.
13 Transaction_infos array will be used by the cleaner for identifying live
14 blocks and migrating them to appropriate location.
16 [ Modified by tytso to conditionalize changes on the JBD2_LAZY journal flag ]
18 Signed-off-by: Abutalib Aghayev <agayev@cs.cmu.edu>
19 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
21 fs/jbd2/Makefile | 3 +-
22 fs/jbd2/commit.c | 23 ++++
23 fs/jbd2/jmap.c | 512 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
24 fs/jbd2/journal.c | 20 ++-
25 include/linux/jbd2.h | 14 ++
26 include/linux/jmap.h | 136 ++++++++++++++++++++
27 include/trace/events/jbd2.h | 193 ++++++++++++++++++++++++++++
28 7 files changed, 896 insertions(+), 5 deletions(-)
30 diff --git a/fs/jbd2/Makefile b/fs/jbd2/Makefile
31 index 802a3413872a..a54f50b3a06e 100644
32 --- a/fs/jbd2/Makefile
33 +++ b/fs/jbd2/Makefile
36 obj-$(CONFIG_JBD2) += jbd2.o
38 -jbd2-objs := transaction.o commit.o recovery.o checkpoint.o revoke.o journal.o
39 +jbd2-objs := transaction.o commit.o recovery.o checkpoint.o revoke.o journal.o \
41 diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
42 index 8c514367ba5a..50e1a0b375c5 100644
43 --- a/fs/jbd2/commit.c
44 +++ b/fs/jbd2/commit.c
45 @@ -362,6 +362,8 @@ void jbd2_journal_commit_transaction(journal_t *journal)
48 unsigned long long blocknr;
49 + struct blk_mapping *mappings = NULL;
50 + struct blk_mapping *map_ptr = NULL;
54 @@ -563,6 +565,14 @@ void jbd2_journal_commit_transaction(journal_t *journal)
55 J_ASSERT(commit_transaction->t_nr_buffers <=
56 atomic_read(&commit_transaction->t_outstanding_credits));
58 + if (journal->j_flags & JBD2_LAZY) {
59 + int nr_mappings = commit_transaction->t_nr_buffers;
61 + map_ptr = mappings = kmalloc(sizeof(*mappings) * nr_mappings, GFP_NOFS);
63 + jbd2_journal_abort(journal, -ENOMEM);
69 @@ -661,6 +671,11 @@ void jbd2_journal_commit_transaction(journal_t *journal)
72 jbd2_file_log_bh(&io_bufs, wbuf[bufs]);
74 + map_ptr->fsblk = jh2bh(jh)->b_blocknr;
75 + map_ptr->logblk = blocknr;
79 /* Record the new block's tag in the current descriptor
81 @@ -895,6 +910,14 @@ void jbd2_journal_commit_transaction(journal_t *journal)
82 transaction can be removed from any checkpoint list it was on
86 + err = jbd2_transaction_infos_add(journal, commit_transaction,
87 + mappings, map_ptr - mappings);
89 + jbd2_journal_abort(journal, -ENOMEM);
93 jbd_debug(3, "JBD2: commit phase 6\n");
95 J_ASSERT(list_empty(&commit_transaction->t_inode_list));
96 diff --git a/fs/jbd2/jmap.c b/fs/jbd2/jmap.c
98 index 000000000000..6ff7fab450d6
102 +#include <linux/blk_types.h>
103 +#include <linux/jbd2.h>
104 +#include <linux/jmap.h>
105 +#include <trace/events/jbd2.h>
107 +static struct kmem_cache *jbd2_jmap_cache;
109 +int jbd2_journal_init_jmap_cache(void)
111 + jbd2_jmap_cache = KMEM_CACHE(jmap_entry, SLAB_RECLAIM_ACCOUNT);
112 + if (!jbd2_jmap_cache)
117 +void jbd2_journal_destroy_jmap_cache(void)
119 + kmem_cache_destroy(jbd2_jmap_cache);
120 + jbd2_jmap_cache = NULL;
124 + * Allocate an array of transaction_info structures and initialize the list
125 + * heads inside them.
127 +int jbd2_init_transaction_infos(journal_t *journal)
130 + struct transaction_infos *tis = kzalloc(sizeof(*tis), GFP_KERNEL);
134 + tis->buf = kzalloc(sizeof(*tis->buf) * MAX_LIVE_TRANSACTIONS,
141 + for (i = 0; i < MAX_LIVE_TRANSACTIONS; ++i)
142 + INIT_LIST_HEAD(&tis->buf[i].live_blks);
144 + journal->j_transaction_infos = tis;
149 + * Free the array of transaction_info structures.
151 +void jbd2_free_transaction_infos(journal_t *journal)
153 + struct transaction_infos *tis = journal->j_transaction_infos;
161 + * Fill an entry to be stored in jmap.
163 +static void fill_entry(struct jmap_entry *entry, struct blk_mapping *mapping,
164 + int t_idx, struct list_head *list)
166 + entry->mapping = *mapping;
167 + entry->fsblk_last_modified = jiffies;
168 + entry->t_idx = t_idx;
169 + list_add(&entry->list, list);
173 + * A helper function for jbd2_transaction_infos_add. Scans through the mappings
174 + * array, dropping revoked entries from jmap and updating existing entries.
175 + * Moves the new mappings to the beginning of the mappings array and returns the
176 + * number of new mappings. Should be called with a write lock on j_jmap_lock.
178 +static int process_existing_mappings(journal_t *journal,
179 + struct transaction_info *ti, int t_idx,
180 + struct blk_mapping *mappings, int nr_mappings)
182 + struct jmap_entry *je;
185 + for (i = 0; i < nr_mappings; ++i) {
186 + je = jbd2_jmap_lookup(journal, mappings[i].fsblk, __func__);
188 + mappings[nr_new++] = mappings[i];
192 + * We are either deleting the entry because it was revoked, or
193 + * we are moving it to the live blocks list of this transaction.
194 + * In either case, we remove it from its existing list.
196 + list_del(&je->list);
199 + rb_erase(&je->rb_node, &journal->j_jmap);
200 + kmem_cache_free(jbd2_jmap_cache, je);
202 + trace_jbd2_jmap_replace(je, &mappings[i], t_idx);
203 + fill_entry(je, &mappings[i], t_idx, &ti->live_blks);
210 + * A helper function for jbd2_transaction_infos_add. Allocates an array of
211 + * jmap_entry structures and returns the pointer to array if successful.
212 + * Otherwise, returns NULL.
214 +static struct jmap_entry **alloc_jmap_entries(int nr_entries)
216 + struct jmap_entry **jmap_entries;
219 + jmap_entries = kmalloc(sizeof(struct jmap_entry *) * nr_entries,
224 + for (i = 0; i < nr_entries; i++) {
225 + jmap_entries[i] = kmem_cache_zalloc(jbd2_jmap_cache, GFP_NOFS);
226 + if (!jmap_entries[i])
229 + return jmap_entries;
232 + for (i = 0; i < nr_entries && jmap_entries[i]; ++i)
233 + kmem_cache_free(jbd2_jmap_cache, jmap_entries[i]);
234 + kfree(jmap_entries);
239 + * A helper function for jbd2_transaction_infos_add. Adds new mappings to jmap
240 + * and updates the linked list of live logblks of the new transaction. Should
241 + * be called with write lock on j_jmap_lock.
243 +static void add_new_mappings(journal_t *journal, struct transaction_info *ti,
244 + int t_idx, struct blk_mapping *mappings,
245 + struct jmap_entry **new_entries, int nr_new)
247 + struct rb_node **p;
248 + struct rb_node *parent = NULL;
249 + struct jmap_entry *je;
252 + for (i = 0; i < nr_new; ++i) {
253 + p = &journal->j_jmap.rb_node;
256 + je = rb_entry(parent, struct jmap_entry, rb_node);
258 + if (mappings[i].fsblk < je->mapping.fsblk)
259 + p = &(*p)->rb_left;
260 + else if (mappings[i].fsblk > je->mapping.fsblk)
261 + p = &(*p)->rb_right;
265 + fill_entry(new_entries[i], &mappings[i], t_idx, &ti->live_blks);
266 + rb_link_node(&new_entries[i]->rb_node, parent, p);
267 + rb_insert_color(&new_entries[i]->rb_node, &journal->j_jmap);
268 + trace_jbd2_jmap_insert(&mappings[i], t_idx);
272 +void jbd2_add_new_transaction_infos(journal_t *journal, tid_t tid,
273 + unsigned long log_start)
275 + struct transaction_infos *tis = journal->j_transaction_infos;
276 + int t_idx = tis->head;
277 + struct transaction_info *ti = &tis->buf[t_idx];
280 + * We are possibly reusing space of an old transaction_info. The old
281 + * transaction should not have any live blocks in it.
283 + BUG_ON(!list_empty(&ti->live_blks));
285 + write_lock(&journal->j_jmap_lock);
287 + ti->offset = log_start;
288 + write_unlock(&journal->j_jmap_lock);
291 +int jbd2_add_mapping(journal_t *journal, struct blk_mapping *mapping)
293 + struct transaction_infos *tis = journal->j_transaction_infos;
294 + int t_idx = tis->head;
295 + struct transaction_info *ti = &tis->buf[t_idx];
296 + struct jmap_entry *new_entry;
299 + write_lock(&journal->j_jmap_lock);
300 + nr_new = process_existing_mappings(journal, ti, t_idx, mapping, 1);
301 + write_unlock(&journal->j_jmap_lock);
306 + new_entry = kmem_cache_zalloc(jbd2_jmap_cache, GFP_NOFS);
310 + write_lock(&journal->j_jmap_lock);
311 + add_new_mappings(journal, ti, t_idx, mapping, &new_entry, 1);
312 + write_unlock(&journal->j_jmap_lock);
316 +void jbd2_finish_transaction_infos(journal_t *journal)
318 + struct transaction_infos *tis = journal->j_transaction_infos;
320 + atomic_inc(&journal->j_cleaner_ctx->nr_txns_committed);
322 + write_lock(&journal->j_jmap_lock);
323 + tis->head = (tis->head + 1) & (MAX_LIVE_TRANSACTIONS - 1);
324 + write_unlock(&journal->j_jmap_lock);
328 + * This function is called after a transaction commits. It adds new
329 + * transaction_info structure to transaction_infos and populates jmap map with
330 + * the new mappings that are part of the committed transaction. It also adds
331 + * all the mappings to the linked list that is part of the transaction_info
334 +int jbd2_transaction_infos_add(journal_t *journal, transaction_t *transaction,
335 + struct blk_mapping *mappings, int nr_mappings)
337 + struct transaction_infos *tis = journal->j_transaction_infos;
338 + int t_idx = tis->head;
339 + struct transaction_info *ti = &tis->buf[t_idx];
340 + struct jmap_entry **new_entries = NULL;
344 + * We are possibly reusing space of an old transaction_info. The old
345 + * transaction should not have any live blocks in it.
347 + BUG_ON(!list_empty(&ti->live_blks));
349 + write_lock(&journal->j_jmap_lock);
350 + nr_new = process_existing_mappings(journal, ti, t_idx, mappings,
352 + write_unlock(&journal->j_jmap_lock);
357 + new_entries = alloc_jmap_entries(nr_new);
361 + write_lock(&journal->j_jmap_lock);
362 + add_new_mappings(journal, ti, t_idx, mappings, new_entries, nr_new);
363 + write_unlock(&journal->j_jmap_lock);
365 + kfree(new_entries);
368 + write_lock(&journal->j_jmap_lock);
369 + ti->tid = transaction->t_tid;
370 + ti->offset = transaction->t_log_start;
371 + tis->head = (tis->head + 1) & (MAX_LIVE_TRANSACTIONS - 1);
372 + write_unlock(&journal->j_jmap_lock);
374 + trace_jbd2_transaction_infos_add(t_idx, ti, nr_mappings);
379 + * Look up fsblk in the jmap and return the corresponding jmap entry if found.
380 + * Should be called with a read lock on j_jmap_lock.
382 +struct jmap_entry *jbd2_jmap_lookup(journal_t *journal, sector_t fsblk,
389 + for (p = journal->j_jmap.rb_node; p; ) {
390 + struct jmap_entry *je = rb_entry(p, struct jmap_entry, rb_node);
391 + if (je->mapping.fsblk > fsblk)
393 + else if (je->mapping.fsblk < fsblk)
396 + trace_jbd2_jmap_lookup(fsblk, je->mapping.logblk, func);
400 + trace_jbd2_jmap_lookup(fsblk, 0, func);
405 + * Revoke a mapping for the fsblk in the jmap. A lookup for fsblk will return
406 + * NULL and the mapping will be removed from the jmap during commit, unless
407 + * fsblk is reallocated as a metadata block.
409 +void jbd2_jmap_revoke(journal_t *journal, sector_t fsblk)
411 + struct jmap_entry *je;
413 + write_lock(&journal->j_jmap_lock);
414 + je = jbd2_jmap_lookup(journal, fsblk, __func__);
416 + * For now, since we do not construct jmap from the journal, it is
417 + * possible that a metadata block that was revoked is not in the jmap.
418 + * Eventually, this should not be the case and we should have a
419 + * BUG_ON(!je) here.
422 + if (WARN_ON(je->revoked))
423 + pr_err("JBD2: block %llu already revoked!\n",
424 + (unsigned long long) fsblk);
425 + je->revoked = true;
427 + write_unlock(&journal->j_jmap_lock);
431 + * Cancel a revoke for the fsblk in the jmap.
433 +void jbd2_jmap_cancel_revoke(journal_t *journal, sector_t fsblk)
435 + struct jmap_entry *je;
437 + write_lock(&journal->j_jmap_lock);
438 + je = jbd2_jmap_lookup(journal, fsblk, __func__);
440 + BUG_ON(!je->revoked);
441 + je->revoked = false;
442 + write_unlock(&journal->j_jmap_lock);
446 + * Read bh from its most up-to-date location, either from the file system or
449 + * If there is no mapping for the bh in jmap, this function acts like submit_bh.
450 + * Otherwise, it submits a read for the block pointed by the mapping located in
451 + * the log. Upon completion, bh will be filled with the contents of the block
452 + * read from the log.
454 +void jbd2_submit_bh(journal_t *journal, int rw, int op_flags,
455 + struct buffer_head *bh, const char *func)
457 + sector_t fsblk = bh->b_blocknr;
459 + struct jmap_entry *je;
461 + BUG_ON(!buffer_locked(bh));
463 + if (!journal || !(journal->j_flags & JBD2_LAZY)) {
464 + submit_bh(rw, op_flags, bh);
468 + read_lock(&journal->j_jmap_lock);
469 + je = jbd2_jmap_lookup(journal, fsblk, func);
471 + read_unlock(&journal->j_jmap_lock);
472 + submit_bh(rw, op_flags, bh);
475 + logblk = je->mapping.logblk;
476 + read_unlock(&journal->j_jmap_lock);
478 + BUG_ON(rw == WRITE);
479 + read_block_from_log(journal, bh, op_flags, logblk);
481 +EXPORT_SYMBOL(jbd2_submit_bh);
484 + * End_io handler for read_block_from_log that copies the contents of
485 + * log_bh read from log to the embedded bh.
487 +static void jbd2_end_log_read(struct buffer_head *log_bh, int uptodate)
489 + struct buffer_head *bh = log_bh->b_private;
491 + trace_jbd2_jmap_read_from_log(bh->b_blocknr, log_bh->b_blocknr,
494 + memcpy(bh->b_data, log_bh->b_data, log_bh->b_size);
496 + unlock_buffer(log_bh);
500 + bh->b_end_io(bh, uptodate);
504 + * This function fills |bh| with the contents of the |blk|. Assume
505 + * jmap maps metadata block 123 to log block 100123. To read the
506 + * metadata block 123, we obtain a buffer head for it and call
507 + * read_block_from_log passing the obtained buffer head as |bh| and
508 + * 100123 as |blk|. If block 100123 is cached, then we copy the
509 + * contents to |bh| and return. Otherwise, we submit a request and
510 + * end_io handler copies the contents of block 100123 to |bh|.
511 + * Returns -ENOMEM if getblk fails, 1 if block is not cached, 0 if
514 +int read_block_from_log(journal_t *journal, struct buffer_head *bh,
515 + int op_flags, sector_t blk)
517 + struct buffer_head *log_bh;
519 + BUG_ON(!buffer_locked(bh));
521 + log_bh = __getblk(journal->j_fs_dev, blk, bh->b_size);
522 + if (unlikely(!log_bh)) {
523 + bh->b_end_io(bh, 0);
527 + lock_buffer(log_bh);
528 + if (buffer_uptodate(log_bh)) {
529 + memcpy(bh->b_data, log_bh->b_data, bh->b_size);
530 + unlock_buffer(log_bh);
532 + bh->b_end_io(bh, 1);
536 + log_bh->b_end_io = jbd2_end_log_read;
537 + log_bh->b_private = bh;
539 + submit_bh(READ, op_flags, log_bh);
544 + * Copy of ll_rw_block that uses jbd2_submit_bh instead of submit_bh.
546 +void jbd2_ll_rw_block(journal_t *journal, int rw, int op_flags,
547 + int nr, struct buffer_head *bhs[], const char *func)
551 + for (i = 0; i < nr; i++) {
552 + struct buffer_head *bh = bhs[i];
554 + if (!trylock_buffer(bh))
556 + BUG_ON(rw == WRITE);
557 + if (!buffer_uptodate(bh)) {
558 + bh->b_end_io = end_buffer_read_sync;
560 + jbd2_submit_bh(journal, rw, op_flags, bh, func);
566 +EXPORT_SYMBOL(jbd2_ll_rw_block);
569 + * Copy of bh_submit_read that uses jbd2_submit_bh instead of submit_bh.
571 +int jbd2_bh_submit_read(journal_t *journal, struct buffer_head *bh,
574 + BUG_ON(!buffer_locked(bh));
576 + if (buffer_uptodate(bh)) {
582 + bh->b_end_io = end_buffer_read_sync;
583 + jbd2_submit_bh(journal, READ, 0, bh, func);
584 + wait_on_buffer(bh);
585 + if (buffer_uptodate(bh))
589 +EXPORT_SYMBOL(jbd2_bh_submit_read);
591 +int jbd2_smr_journal_init(journal_t *journal)
593 + journal->j_jmap = RB_ROOT;
594 + rwlock_init(&journal->j_jmap_lock);
595 + return jbd2_init_transaction_infos(journal);
598 +void jbd2_smr_journal_exit(journal_t *journal)
600 + jbd2_free_transaction_infos(journal);
603 +void jbd2_sb_breadahead(journal_t *journal, struct super_block *sb,
606 + struct buffer_head *bh = __getblk(sb->s_bdev, block, sb->s_blocksize);
608 + jbd2_ll_rw_block(journal, REQ_OP_READ, REQ_RAHEAD, 1,
613 +EXPORT_SYMBOL(jbd2_sb_breadahead);
614 diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
615 index eae93cdfbaa7..493b72c60335 100644
616 --- a/fs/jbd2/journal.c
617 +++ b/fs/jbd2/journal.c
618 @@ -1120,15 +1120,17 @@ static journal_t *journal_init_common(struct block_device *bdev,
619 journal->j_max_batch_time = 15000; /* 15ms */
620 atomic_set(&journal->j_reserved_credits, 0);
622 + err = jbd2_smr_journal_init(journal);
626 /* The journal is marked for error until we succeed with recovery! */
627 journal->j_flags = JBD2_ABORT;
629 /* Set up a default-sized revoke table for the new mount. */
630 err = jbd2_journal_init_revoke(journal, JOURNAL_REVOKE_DEFAULT_HASH);
638 spin_lock_init(&journal->j_history_lock);
640 @@ -1162,6 +1164,9 @@ static journal_t *journal_init_common(struct block_device *bdev,
641 journal->j_superblock = (journal_superblock_t *)bh->b_data;
649 /* jbd2_journal_init_dev and jbd2_journal_init_inode:
650 @@ -1685,6 +1690,9 @@ int jbd2_journal_destroy(journal_t *journal)
651 if (journal->j_running_transaction)
652 jbd2_journal_commit_transaction(journal);
654 + if (journal->j_flags & JBD2_LAZY)
655 + journal->j_flags |= JBD2_NO_CLEANUP;
657 if (journal->j_flags & JBD2_NO_CLEANUP) {
658 jbd2_journal_destroy_checkpoint(journal);
659 journal->j_checkpoint_transactions = NULL;
660 @@ -1741,6 +1749,7 @@ int jbd2_journal_destroy(journal_t *journal)
661 jbd2_journal_destroy_revoke(journal);
662 if (journal->j_chksum_driver)
663 crypto_free_shash(journal->j_chksum_driver);
664 + jbd2_smr_journal_exit(journal);
665 kfree(journal->j_wbuf);
668 @@ -2641,6 +2650,8 @@ static int __init journal_init_caches(void)
669 ret = jbd2_journal_init_handle_cache();
671 ret = jbd2_journal_init_transaction_cache();
673 + ret = jbd2_journal_init_jmap_cache();
677 @@ -2650,6 +2661,7 @@ static void jbd2_journal_destroy_caches(void)
678 jbd2_journal_destroy_journal_head_cache();
679 jbd2_journal_destroy_handle_cache();
680 jbd2_journal_destroy_transaction_cache();
681 + jbd2_journal_destroy_jmap_cache();
682 jbd2_journal_destroy_slabs();
685 diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
686 index 9a07b0485784..771588026353 100644
687 --- a/include/linux/jbd2.h
688 +++ b/include/linux/jbd2.h
690 #include <linux/types.h>
691 #include <linux/buffer_head.h>
692 #include <linux/journal-head.h>
693 +#include <linux/jmap.h>
694 #include <linux/stddef.h>
695 #include <linux/mutex.h>
696 #include <linux/timer.h>
697 @@ -732,6 +733,9 @@ jbd2_time_diff(unsigned long start, unsigned long end)
699 * @j_sb_buffer: First part of superblock buffer
700 * @j_superblock: Second part of superblock buffer
701 + * @j_map: A map from file system blocks to log blocks
702 + * @j_transaction_infos: An array of information structures per live transaction
703 + * @j_map_lock: Protect j_jmap and j_transaction_infos
704 * @j_format_version: Version of the superblock format
705 * @j_state_lock: Protect the various scalars in the journal
706 * @j_barrier_count: Number of processes waiting to create a barrier lock
707 @@ -807,6 +811,15 @@ struct journal_s
708 struct buffer_head *j_sb_buffer;
709 journal_superblock_t *j_superblock;
711 + /* A map from file system blocks to journal blocks */
712 + struct rb_root j_jmap;
714 + /* An array of housekeeping information about live transactions */
715 + struct transaction_infos *j_transaction_infos;
717 + /* Protect j_jmap and j_transaction_infos */
718 + rwlock_t j_jmap_lock;
720 /* Version of the superblock format */
721 int j_format_version;
723 @@ -1129,6 +1142,7 @@ JBD2_FEATURE_INCOMPAT_FUNCS(csum3, CSUM_V3)
725 #define JBD2_REC_ERR 0x080 /* The errno in the sb has been recorded */
726 #define JBD2_NO_CLEANUP 0x100 /* Don't flush empty the journal on shutdown */
727 +#define JBD2_LAZY 0x200 /* Do lazy journalling */
730 * Function declarations for the journaling transaction and buffer
731 diff --git a/include/linux/jmap.h b/include/linux/jmap.h
733 index 000000000000..638f25df8302
735 +++ b/include/linux/jmap.h
737 +#ifndef _LINUX_JMAP_H
738 +#define _LINUX_JMAP_H
740 +#include <linux/buffer_head.h>
741 +#include <linux/journal-head.h>
742 +#include <linux/list.h>
743 +#include <linux/circ_buf.h>
744 +#include <linux/completion.h>
747 + * Forward declaration for journal_t so that we don't get circular dependency
748 + * between jbd2.h and jmap.h
751 +typedef struct journal_s journal_t;
754 + * Maximum number of transactions. This guides the size of the circular buffer
755 + * in which we store housekeeping information per transaction. We start
756 + * cleaning either when the circular buffer is full or when we hit the free
757 + * space threshold, whichever happens first. For starters, we make this
758 + * constant large to make sure that we start cleaning only when we hit the free
759 + * space threshold. Later we can empirically determine a sensible value.
761 +#define MAX_LIVE_TRANSACTIONS 65536
764 + * A mapping from file system block to log block.
766 +struct blk_mapping {
772 + * An RB-tree entry wrapper for blk_mapping with extra housekeeping information.
775 + struct rb_node rb_node;
777 + /* The actual mapping information. */
778 + struct blk_mapping mapping;
781 + * If a block that is mapped gets deleted, the revoked bit is set. A
782 + * lookup for a deleted block fails. If a deleted block gets
783 + * re-allocated as a metadata block, the mapping is updated and revoked
789 + * All log blocks that are part of the same transaction in the log are
790 + * chained with a linked list. The root of the list is stored in the
791 + * transaction_info structure described below.
793 + struct list_head list;
796 + * The last time when fsblk was written again to the journal and
797 + * therefore was remapped to a different log block.
799 + unsigned long fsblk_last_modified;
802 + * Index of the transaction in the transaction_info_buffer (described
803 + * below) of which the log block is part of.
809 + * Housekeeping information about committed transaction.
811 +struct transaction_info {
812 + /* Id of the transaction */
815 + /* Offset where the transaction starts in the log */
819 + * A list of live blocks referenced in the RB-tree that belong to this
820 + * transaction. It is used during cleaning to locate live blocks and
821 + * migrate them to appropriate location. If this list is empty, then
822 + * the transaction does not contain any live blocks and we can reuse its
823 + * space. If this list is not empty, then we can quickly locate all the
824 + * live blocks in this transaction.
826 + struct list_head live_blks;
830 + * An array of transaction_info structures about all the transactions in the
831 + * log. Since there can only be a limited number of transactions in the log, we
832 + * use a circular buffer to store housekeeping information about transactions.
834 +struct transaction_infos {
835 + struct transaction_info *buf;
840 +extern int jbd2_smr_journal_init(journal_t *journal);
841 +extern void jbd2_smr_journal_exit(journal_t *journal);
843 +extern int jbd2_journal_init_jmap_cache(void);
844 +extern void jbd2_journal_destroy_jmap_cache(void);
846 +extern int jbd2_init_transaction_infos(journal_t *journal);
847 +extern void jbd2_free_transaction_infos(journal_t *journal);
848 +extern void jbd2_add_new_transaction_infos(journal_t *journal, tid_t t_tid,
849 + unsigned long log_start);
850 +extern int jbd2_add_mapping(journal_t *journal, struct blk_mapping *mapping);
851 +extern void jbd2_finish_transaction_infos(journal_t *journal);
852 +extern int jbd2_transaction_infos_add(journal_t *journal,
853 + transaction_t *transaction,
854 + struct blk_mapping *mappings,
857 +extern struct jmap_entry *jbd2_jmap_lookup(journal_t *journal, sector_t fsblk,
859 +extern void jbd2_jmap_revoke(journal_t *journal, sector_t fsblk);
860 +extern void jbd2_jmap_cancel_revoke(journal_t *journal, sector_t fsblk);
861 +extern void jbd2_submit_bh(journal_t *journal, int rw, int op_flags,
862 + struct buffer_head *bh, const char *func);
863 +extern int read_block_from_log(journal_t *journal, struct buffer_head *bh,
864 + int op_flags, sector_t blk);
865 +extern void jbd2_ll_rw_block(journal_t *journal, int rw, int op_flags, int nr,
866 + struct buffer_head *bhs[], const char *func);
867 +extern int jbd2_bh_submit_read(journal_t *journal, struct buffer_head *bh,
869 +extern void jbd2_sb_breadahead(journal_t *journal, struct super_block *sb,
873 diff --git a/include/trace/events/jbd2.h b/include/trace/events/jbd2.h
874 index c1d1f3eb242d..6d0619bc99af 100644
875 --- a/include/trace/events/jbd2.h
876 +++ b/include/trace/events/jbd2.h
877 @@ -379,6 +379,199 @@ TRACE_EVENT(jbd2_lock_buffer_stall,
881 +TRACE_EVENT(jbd2_jmap_replace,
883 + TP_PROTO(struct jmap_entry *jentry, struct blk_mapping *mapping, \
886 + TP_ARGS(jentry, mapping, t_idx),
889 + __field(sector_t, fsblk )
890 + __field(sector_t, old_logblk )
891 + __field(sector_t, new_logblk )
892 + __field(int, old_t_idx )
893 + __field(int, new_t_idx )
897 + __entry->fsblk = mapping->fsblk;
898 + __entry->old_logblk = jentry->mapping.logblk;
899 + __entry->new_logblk = mapping->logblk;
900 + __entry->old_t_idx = jentry->t_idx;
901 + __entry->new_t_idx = t_idx;
904 + TP_printk("remap %llu from %llu to %llu, move from transaction at index %d to transaction at index %d",
905 + (unsigned long long) __entry->fsblk,
906 + (unsigned long long) __entry->old_logblk,
907 + (unsigned long long) __entry->new_logblk,
908 + __entry->old_t_idx,
909 + __entry->new_t_idx)
912 +TRACE_EVENT(jbd2_jmap_insert,
914 + TP_PROTO(struct blk_mapping *mapping, int t_idx),
916 + TP_ARGS(mapping, t_idx),
919 + __field(sector_t, fsblk )
920 + __field(sector_t, logblk)
921 + __field(int, t_idx)
925 + __entry->fsblk = mapping->fsblk;
926 + __entry->logblk = mapping->logblk;
927 + __entry->t_idx = t_idx;
930 + TP_printk("map %llu to %llu, insert to transaction %d",
931 + (unsigned long long) __entry->fsblk,
932 + (unsigned long long) __entry->logblk,
936 +TRACE_EVENT(jbd2_jmap_lookup,
938 + TP_PROTO(sector_t fsblk, sector_t logblk, const char *func),
940 + TP_ARGS(fsblk, logblk, func),
943 + __field(sector_t, fsblk )
944 + __field(sector_t, logblk)
945 + __string(func, func)
949 + __entry->fsblk = fsblk;
950 + __entry->logblk = logblk;
951 + __assign_str(func, func);
954 + TP_printk("%s: lookup %llu -> %llu",
956 + (unsigned long long) __entry->fsblk,
957 + (unsigned long long) __entry->logblk)
960 +TRACE_EVENT(jbd2_jmap_read_from_log,
962 + TP_PROTO(sector_t fsblk, sector_t logblk, int uptodate),
964 + TP_ARGS(fsblk, logblk, uptodate),
967 + __field(sector_t, fsblk )
968 + __field(sector_t, logblk)
969 + __field(int, uptodate)
973 + __entry->fsblk = fsblk;
974 + __entry->logblk = logblk;
975 + __entry->uptodate = uptodate;
978 + TP_printk("fsblk %llu logblk %llu uptodate %d",
979 + (unsigned long long) __entry->fsblk,
980 + (unsigned long long) __entry->logblk,
984 +TRACE_EVENT(jbd2_jmap_printf,
986 + TP_PROTO(const char *s),
995 + __assign_str(s, s);
1002 +TRACE_EVENT(jbd2_jmap_printf1,
1004 + TP_PROTO(const char *s, sector_t fsblk),
1006 + TP_ARGS(s, fsblk),
1010 + __field(sector_t, fsblk )
1014 + __assign_str(s, s);
1015 + __entry->fsblk = fsblk;
1018 + TP_printk("%s: %llu",
1020 + (unsigned long long) __entry->fsblk)
1023 +TRACE_EVENT(jbd2_jmap_printf2,
1025 + TP_PROTO(const char *s, sector_t fsblk, sector_t logblk),
1027 + TP_ARGS(s, fsblk, logblk),
1031 + __field(sector_t, fsblk )
1032 + __field(sector_t, logblk)
1036 + __assign_str(s, s);
1037 + __entry->fsblk = fsblk;
1038 + __entry->logblk = logblk;
1041 + TP_printk("%s: %llu:%llu",
1043 + (unsigned long long) __entry->fsblk,
1044 + (unsigned long long) __entry->logblk)
1047 +TRACE_EVENT(jbd2_transaction_infos_add,
1049 + TP_PROTO(int t_idx, struct transaction_info *ti, int nr_mappings),
1051 + TP_ARGS(t_idx, ti, nr_mappings),
1054 + __field(int, t_idx )
1055 + __field(tid_t, tid )
1056 + __field(sector_t, offset)
1057 + __field(int, nr_mappings)
1061 + __entry->t_idx = t_idx;
1062 + __entry->tid = ti->tid;
1063 + __entry->offset = ti->offset;
1064 + __entry->nr_mappings = nr_mappings;
1067 + TP_printk("inserted transaction %u (offset %llu) at index %d with %d mappings",
1069 + (unsigned long long) __entry->offset,
1071 + __entry->nr_mappings)
1074 #endif /* _TRACE_JBD2_H */
1076 /* This part must be outside protection */