1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
|
/*
* Copyright (C) 2019 Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
*/
#ifndef _BTREE_H
#define _BTREE_H
#include <apfs/raw.h>
#include <apfs/types.h>
#include "htable.h"
#include "object.h"
struct super_block;
struct extref_record;
struct free_queue;
/*
* Omap record data in memory
*/
struct omap_record {
struct omap_record *next; /* Next entry in linked list */
u64 xid; /* Transaction id */
u64 oid; /* Virtual object id */
u64 bno; /* Block number */
u32 flags; /* Omap record flags */
/* Was this oid-xid pair ever seen in use? */
bool seen;
/* Was it ever seen in use for the latest checkpoint? */
bool seen_for_latest;
/* If we are currently checking a snapshot, was it seen in use for it? */
bool seen_for_snap;
};
/*
* List of all omap records for a given oid
*/
struct omap_record_list {
struct htable_entry o_htable; /* Hash table entry header */
struct omap_record *o_records; /* Linked list of records */
};
/*
* In-memory representation of an APFS node
*/
struct node {
u16 flags; /* Node flags */
u32 records; /* Number of records in the node */
int level; /* Number of child levels below this node */
int toc; /* Offset of the TOC in the block */
int key; /* Offset of the key area in the block */
int free; /* Offset of the free area in the block */
int data; /* Offset of the data area in the block */
u8 *free_key_bmap; /* Free space bitmap for the key area */
u8 *free_val_bmap; /* Free space bitmap for the value area */
u8 *used_key_bmap; /* Used space bitmap for the key area */
u8 *used_val_bmap; /* Used space bitmap for the value area */
struct btree *btree; /* Btree the node belongs to */
struct apfs_btree_node_phys *raw; /* Raw node in memory */
struct object object; /* Object holding the node */
};
/**
* apfs_node_is_leaf - Check if a b-tree node is a leaf
* @node: the node to check
*/
static inline bool node_is_leaf(struct node *node)
{
return (node->flags & APFS_BTNODE_LEAF) != 0;
}
/**
* apfs_node_is_root - Check if a b-tree node is the root
* @node: the node to check
*/
static inline bool node_is_root(struct node *node)
{
return (node->flags & APFS_BTNODE_ROOT) != 0;
}
/**
* apfs_node_has_fixed_kv_size - Check if a b-tree node has fixed key/value
* sizes
* @node: the node to check
*/
static inline bool node_has_fixed_kv_size(struct node *node)
{
return (node->flags & APFS_BTNODE_FIXED_KV_SIZE) != 0;
}
/* Flags for the query structure */
#define QUERY_TREE_MASK 0017 /* Which b-tree we query */
#define QUERY_OMAP 0001 /* This is a b-tree object map query */
#define QUERY_CAT 0002 /* This is a catalog tree query */
#define QUERY_EXTENTREF 0004 /* This is an extentref tree query */
#define QUERY_FEXT 0010 /* This is an extentref tree query */
#define QUERY_MULTIPLE 0020 /* Search for multiple matches */
#define QUERY_NEXT 0040 /* Find next of multiple matches */
#define QUERY_EXACT 0100 /* Search for an exact match */
#define QUERY_DONE 0200 /* The search at this level is over */
/*
* Structure used to retrieve data from an APFS B-Tree. For now only used
* on the calalog and the object map.
*/
struct query {
struct node *node; /* Node being searched */
struct key *key; /* What the query is looking for */
struct query *parent; /* Query for parent node */
unsigned int flags;
/* Set by the query on success */
int index; /* Index of the entry in the node */
int key_off; /* Offset of the key in the node */
int key_len; /* Length of the key */
int off; /* Offset of the data in the node */
int len; /* Length of the data */
int depth; /* Put a limit on recursion */
};
/* In-memory tree types */
#define BTREE_TYPE_OMAP 1 /* The tree is an object map */
#define BTREE_TYPE_CATALOG 2 /* The tree is a catalog */
#define BTREE_TYPE_EXTENTREF 3 /* The tree is for extent references */
#define BTREE_TYPE_SNAP_META 4 /* The tree is for snapshot metadata */
#define BTREE_TYPE_FREE_QUEUE 5 /* The tree is for a free-space queue */
#define BTREE_TYPE_SNAPSHOTS 6 /* The tree is for omap snapshots */
#define BTREE_TYPE_FEXT 7 /* The tree is for file extents */
#define BTREE_TYPE_FUSION_MT 8 /* The is the fusion middle-tree */
/* In-memory structure representing a b-tree */
struct btree {
u8 type; /* Type of the tree */
struct node *root; /* Root of this b-tree */
/* Hash table for the tree's object map (can be NULL) */
struct htable_entry **omap_table;
/* B-tree stats as measured by the fsck */
u64 key_count; /* Number of keys */
u64 node_count; /* Number of nodes */
int longest_key; /* Length of longest key */
int longest_val; /* Length of longest value */
};
/**
* btree_is_free_queue - Check if a b-tree is a free-space queue
* @btree: the b-tree to check
*/
static inline bool btree_is_free_queue(struct btree *btree)
{
return btree->type == BTREE_TYPE_FREE_QUEUE;
}
static inline bool btree_is_snapshots(struct btree *btree)
{
return btree->type == BTREE_TYPE_SNAPSHOTS;
}
/**
* btree_is_omap - Check if a b-tree is an object map
* @btree: the b-tree to check
*/
static inline bool btree_is_omap(struct btree *btree)
{
return btree->type == BTREE_TYPE_OMAP;
}
/**
* btree_is_snap_meta - Check if a b-tree is for snapshot metadata
* @btree: the b-tree to check
*/
static inline bool btree_is_snap_meta(struct btree *btree)
{
return btree->type == BTREE_TYPE_SNAP_META;
}
/**
* btree_is_catalog - Check if a b-tree is a catalog
* @btree: the b-tree to check
*/
static inline bool btree_is_catalog(struct btree *btree)
{
return btree->type == BTREE_TYPE_CATALOG;
}
/**
* btree_is_extentref - Check if a b-tree is for extent references
* @btree: the b-tree to check
*/
static inline bool btree_is_extentref(struct btree *btree)
{
return btree->type == BTREE_TYPE_EXTENTREF;
}
/**
* btree_is_fext - Check if a b-tree is for file extents
* @btree: the b-tree to check
*/
static inline bool btree_is_fext(struct btree *btree)
{
return btree->type == BTREE_TYPE_FEXT;
}
/**
* btree_is_fusion_mt - Check if a b-tree is a fusion middle-tree
* @btree: the b-tree to check
*/
static inline bool btree_is_fusion_mt(struct btree *btree)
{
return btree->type == BTREE_TYPE_FUSION_MT;
}
extern struct free_queue *parse_free_queue_btree(u64 oid, int index);
extern struct btree *parse_snap_meta_btree(u64 oid);
extern struct btree *parse_extentref_btree(u64 oid);
extern struct btree *parse_omap_btree(u64 oid);
extern struct btree *parse_cat_btree(u64 oid, struct htable_entry **omap_table);
extern struct btree *parse_fext_btree(u64 oid);
extern struct btree *parse_fusion_middle_tree(u64 oid);
extern struct query *alloc_query(struct node *node, struct query *parent);
extern void free_query(struct query *query);
extern int btree_query(struct query **query);
extern struct node *omap_read_node(u64 id);
extern void free_omap_table(struct htable_entry **table);
extern struct omap_record *get_latest_omap_record(u64 oid, u64 xid, struct htable_entry **table);
extern void extentref_update_lookup(u64 bno, struct extref_record *extref);
extern int fext_tree_lookup(u64 oid, u64 logaddr, u64 *bno);
extern int file_extent_lookup(u64 oid, u64 logaddr, u64 *bno);
extern void omap_htable_clear_seen_for_snap(struct htable_entry **table);
#endif /* _BTREE_H */
|