// SPDX-License-Identifier: GPL-2.0 #include "messages.h" #include "tree-mod-log.h" #include "disk-io.h" #include "fs.h" #include "accessors.h" #include "tree-checker.h" struct tree_mod_root { … }; struct tree_mod_elem { … }; /* * Pull a new tree mod seq number for our operation. */ static u64 btrfs_inc_tree_mod_seq(struct btrfs_fs_info *fs_info) { … } /* * This adds a new blocker to the tree mod log's blocker list if the @elem * passed does not already have a sequence number set. So when a caller expects * to record tree modifications, it should ensure to set elem->seq to zero * before calling btrfs_get_tree_mod_seq. * Returns a fresh, unused tree log modification sequence number, even if no new * blocker was added. */ u64 btrfs_get_tree_mod_seq(struct btrfs_fs_info *fs_info, struct btrfs_seq_list *elem) { … } void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info, struct btrfs_seq_list *elem) { … } /* * Key order of the log: * node/leaf start address -> sequence * * The 'start address' is the logical address of the *new* root node for root * replace operations, or the logical address of the affected block for all * other operations. */ static noinline int tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm) { … } /* * Determines if logging can be omitted. Returns true if it can. Otherwise, it * returns false with the tree_mod_log_lock acquired. The caller must hold * this until all tree mod log insertions are recorded in the rb tree and then * write unlock fs_info::tree_mod_log_lock. */ static bool tree_mod_dont_log(struct btrfs_fs_info *fs_info, struct extent_buffer *eb) { … } /* Similar to tree_mod_dont_log, but doesn't acquire any locks. */ static bool tree_mod_need_log(const struct btrfs_fs_info *fs_info, struct extent_buffer *eb) { … } static struct tree_mod_elem *alloc_tree_mod_elem(struct extent_buffer *eb, int slot, enum btrfs_mod_log_op op) { … } int btrfs_tree_mod_log_insert_key(struct extent_buffer *eb, int slot, enum btrfs_mod_log_op op) { … } static struct tree_mod_elem *tree_mod_log_alloc_move(struct extent_buffer *eb, int dst_slot, int src_slot, int nr_items) { … } int btrfs_tree_mod_log_insert_move(struct extent_buffer *eb, int dst_slot, int src_slot, int nr_items) { … } static int tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct tree_mod_elem **tm_list, int nritems) { … } int btrfs_tree_mod_log_insert_root(struct extent_buffer *old_root, struct extent_buffer *new_root, bool log_removal) { … } static struct tree_mod_elem *__tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq, bool smallest) { … } /* * This returns the element from the log with the smallest time sequence * value that's in the log (the oldest log item). Any element with a time * sequence lower than min_seq will be ignored. */ static struct tree_mod_elem *tree_mod_log_search_oldest(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq) { … } /* * This returns the element from the log with the largest time sequence * value that's in the log (the most recent log item). Any element with * a time sequence lower than min_seq will be ignored. */ static struct tree_mod_elem *tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq) { … } int btrfs_tree_mod_log_eb_copy(struct extent_buffer *dst, struct extent_buffer *src, unsigned long dst_offset, unsigned long src_offset, int nr_items) { … } int btrfs_tree_mod_log_free_eb(struct extent_buffer *eb) { … } /* * Returns the logical address of the oldest predecessor of the given root. * Entries older than time_seq are ignored. */ static struct tree_mod_elem *tree_mod_log_oldest_root(struct extent_buffer *eb_root, u64 time_seq) { … } /* * tm is a pointer to the first operation to rewind within eb. Then, all * previous operations will be rewound (until we reach something older than * time_seq). */ static void tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, u64 time_seq, struct tree_mod_elem *first_tm) { … } /* * Called with eb read locked. If the buffer cannot be rewound, the same buffer * is returned. If rewind operations happen, a fresh buffer is returned. The * returned buffer is always read-locked. If the returned buffer is not the * input buffer, the lock on the input buffer is released and the input buffer * is freed (its refcount is decremented). */ struct extent_buffer *btrfs_tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct btrfs_path *path, struct extent_buffer *eb, u64 time_seq) { … } /* * Rewind the state of @root's root node to the given @time_seq value. * If there are no changes, the current root->root_node is returned. If anything * changed in between, there's a fresh buffer allocated on which the rewind * operations are done. In any case, the returned buffer is read locked. * Returns NULL on error (with no locks held). */ struct extent_buffer *btrfs_get_old_root(struct btrfs_root *root, u64 time_seq) { … } int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq) { … } /* * Return the lowest sequence number in the tree modification log. * * Return the sequence number of the oldest tree modification log user, which * corresponds to the lowest sequence number of all existing users. If there are * no users it returns 0. */ u64 btrfs_tree_mod_log_lowest_seq(struct btrfs_fs_info *fs_info) { … }