static struct rb_node * __get_cached_rbnode(struct iova_domain *iovad, unsigned long *limit_pfn) { if ((*limit_pfn != iovad->dma_32bit_pfn) || (iovad->cached32_node == NULL)) return rb_last(&iovad->rbroot); else { struct rb_node *prev_node = rb_prev(iovad->cached32_node); struct iova *curr_iova = container_of(iovad->cached32_node, struct iova, node); *limit_pfn = curr_iova->pfn_lo - 1; return prev_node; } }
/* * look for a given offset in the tree, and if it can't be found return the * first lesser offset */ static struct rb_node *__tree_search(struct rb_root *root, u64 file_offset, struct rb_node **prev_ret) { struct rb_node *n = root->rb_node; struct rb_node *prev = NULL; struct rb_node *test; struct btrfs_ordered_extent *entry; struct btrfs_ordered_extent *prev_entry = NULL; while (n) { entry = rb_entry(n, struct btrfs_ordered_extent, rb_node); prev = n; prev_entry = entry; if (file_offset < entry->file_offset) n = n->rb_left; else if (file_offset >= entry_end(entry)) n = n->rb_right; else return n; } if (!prev_ret) return NULL; while (prev && file_offset >= entry_end(prev_entry)) { test = rb_next(prev); if (!test) break; prev_entry = rb_entry(test, struct btrfs_ordered_extent, rb_node); if (file_offset < entry_end(prev_entry)) break; prev = test; } if (prev) prev_entry = rb_entry(prev, struct btrfs_ordered_extent, rb_node); while (prev && file_offset < entry_end(prev_entry)) { test = rb_prev(prev); if (!test) break; prev_entry = rb_entry(test, struct btrfs_ordered_extent, rb_node); prev = test; } *prev_ret = prev; return NULL; }
/* 取得<=key的元素 */ const h_rb_cursor_st *h_rbtree_upper_bound(const h_rbtree_st *tree, const void *key, uint32_t ksize) { rbtree_node_st *parent; int is_left; rbtree_node_st *ret = do_lookup(tree, key, ksize, &parent, &is_left); if (ret) return &(ret->cs); while (parent && tree->cmp_fn(parent->cs.key, parent->cs.ksize, key, ksize) > 0) { parent = rb_prev(parent); } return parent == NULL ? NULL : &(parent->cs); }
static int tree_insert(struct rb_root *root, struct extent_map *em) { struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; struct extent_map *entry = NULL; struct rb_node *orig_parent = NULL; u64 end = range_end(em->start, em->len); while (*p) { parent = *p; entry = rb_entry(parent, struct extent_map, rb_node); WARN_ON(!entry->in_tree); if (em->start < entry->start) p = &(*p)->rb_left; else if (em->start >= extent_map_end(entry)) p = &(*p)->rb_right; else return -EEXIST; } orig_parent = parent; while (parent && em->start >= extent_map_end(entry)) { parent = rb_next(parent); entry = rb_entry(parent, struct extent_map, rb_node); } if (parent) if (end > entry->start && em->start < extent_map_end(entry)) return -EEXIST; parent = orig_parent; entry = rb_entry(parent, struct extent_map, rb_node); while (parent && em->start < entry->start) { parent = rb_prev(parent); entry = rb_entry(parent, struct extent_map, rb_node); } if (parent) if (end > entry->start && em->start < extent_map_end(entry)) return -EEXIST; em->in_tree = 1; rb_link_node(&em->rb_node, orig_parent, p); rb_insert_color(&em->rb_node, root); return 0; }
/* * search through the tree for an extent_map with a given offset. If * it can't be found, try to find some neighboring extents */ static struct rb_node *__tree_search(struct rb_root *root, u64 offset, struct rb_node **prev_ret, struct rb_node **next_ret) { struct rb_node *n = root->rb_node; struct rb_node *prev = NULL; struct rb_node *orig_prev = NULL; struct extent_map *entry; struct extent_map *prev_entry = NULL; while (n) { entry = rb_entry(n, struct extent_map, rb_node); prev = n; prev_entry = entry; WARN_ON(!entry->in_tree); if (offset < entry->start) n = n->rb_left; else if (offset >= extent_map_end(entry)) n = n->rb_right; else return n; } if (prev_ret) { orig_prev = prev; while (prev && offset >= extent_map_end(prev_entry)) { prev = rb_next(prev); prev_entry = rb_entry(prev, struct extent_map, rb_node); } *prev_ret = prev; prev = orig_prev; } if (next_ret) { prev_entry = rb_entry(prev, struct extent_map, rb_node); while (prev && offset < prev_entry->start) { prev = rb_prev(prev); prev_entry = rb_entry(prev, struct extent_map, rb_node); } *next_ret = prev; } return NULL; }
/* Needs the lock */ static void __ocfs2_extent_map_drop(struct inode *inode, u32 new_clusters, struct rb_node **free_head, struct ocfs2_extent_map_entry **tail_ent) { struct rb_node *node, *next; struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map; struct ocfs2_extent_map_entry *ent; *free_head = NULL; ent = NULL; node = rb_last(&em->em_extents); while (node) { next = rb_prev(node); ent = rb_entry(node, struct ocfs2_extent_map_entry, e_node); if (le32_to_cpu(ent->e_rec.e_cpos) < new_clusters) break; rb_erase(&ent->e_node, &em->em_extents); node->rb_right = *free_head; *free_head = node; ent = NULL; node = next; } /* Do we have an entry straddling new_clusters? */ if (tail_ent) { if (ent && ((le32_to_cpu(ent->e_rec.e_cpos) + le32_to_cpu(ent->e_rec.e_clusters)) > new_clusters)) *tail_ent = ent; else *tail_ent = NULL; } }
/** * bfq_idle_extract - extract an entity from the idle tree. * @st: the service tree of the owning @entity. * @entity: the entity being removed. */ static void bfq_idle_extract(struct bfq_service_tree *st, struct bfq_entity *entity) { struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); struct rb_node *next; BUG_ON(entity->tree != &st->idle); if (entity == st->first_idle) { next = rb_next(&entity->rb_node); st->first_idle = bfq_entity_of(next); } if (entity == st->last_idle) { next = rb_prev(&entity->rb_node); st->last_idle = bfq_entity_of(next); } bfq_extract(&st->idle, entity); if (bfqq != NULL) list_del(&bfqq->bfqq_list); }
static struct ext2_reserve_window_node * search_reserve_window(struct rb_root *root, ext2_fsblk_t goal) { struct rb_node *n = root->rb_node; struct ext2_reserve_window_node *rsv; if (!n) return NULL; do { rsv = rb_entry(n, struct ext2_reserve_window_node, rsv_node); if (goal < rsv->rsv_start) n = n->rb_left; else if (goal > rsv->rsv_end) n = n->rb_right; else return rsv; } while (n); if (rsv->rsv_start > goal) { n = rb_prev(&rsv->rsv_node); rsv = rb_entry(n, struct ext2_reserve_window_node, rsv_node); }
/** * add_extent_mapping - add new extent map to the extent tree * @tree: tree to insert new map in * @em: map to insert * * Insert @em into @tree or perform a simple forward/backward merge with * existing mappings. The extent_map struct passed in will be inserted * into the tree directly, with an additional reference taken, or a * reference dropped if the merge attempt was sucessfull. */ int add_extent_mapping(struct extent_map_tree *tree, struct extent_map *em) { int ret = 0; struct extent_map *merge = NULL; struct rb_node *rb; struct extent_map *exist; exist = lookup_extent_mapping(tree, em->start, em->len); if (exist) { free_extent_map(exist); ret = -EEXIST; goto out; } assert_spin_locked(&tree->lock); rb = tree_insert(&tree->map, em->start, &em->rb_node); if (rb) { ret = -EEXIST; free_extent_map(merge); goto out; } atomic_inc(&em->refs); if (em->start != 0) { rb = rb_prev(&em->rb_node); if (rb) merge = rb_entry(rb, struct extent_map, rb_node); if (rb && mergable_maps(merge, em)) { em->start = merge->start; em->len += merge->len; em->block_len += merge->block_len; em->block_start = merge->block_start; merge->in_tree = 0; rb_erase(&merge->rb_node, &tree->map); free_extent_map(merge); } }
static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em) { struct extent_map *merge = NULL; struct rb_node *rb; if (em->start != 0) { rb = rb_prev(&em->rb_node); if (rb) merge = rb_entry(rb, struct extent_map, rb_node); if (rb && mergable_maps(merge, em)) { em->start = merge->start; em->orig_start = merge->orig_start; em->len += merge->len; em->block_len += merge->block_len; em->block_start = merge->block_start; merge->in_tree = 0; em->mod_len = (em->mod_len + em->mod_start) - merge->mod_start; em->mod_start = merge->mod_start; em->generation = max(em->generation, merge->generation); rb_erase(&merge->rb_node, &tree->map); free_extent_map(merge); } }
/* * lookup extent at @fofs, if hit, return the extent * if not, return NULL and * @prev_ex: extent before fofs * @next_ex: extent after fofs * @insert_p: insert point for new extent at fofs * in order to simpfy the insertion after. * tree must stay unchanged between lookup and insertion. */ static struct extent_node *__lookup_extent_tree_ret(struct extent_tree *et, unsigned int fofs, struct extent_node **prev_ex, struct extent_node **next_ex, struct rb_node ***insert_p, struct rb_node **insert_parent) { struct rb_node **pnode = &et->root.rb_node; struct rb_node *parent = NULL, *tmp_node; struct extent_node *en = et->cached_en; *insert_p = NULL; *insert_parent = NULL; *prev_ex = NULL; *next_ex = NULL; if (RB_EMPTY_ROOT(&et->root)) return NULL; if (en) { struct extent_info *cei = &en->ei; if (cei->fofs <= fofs && cei->fofs + cei->len > fofs) goto lookup_neighbors; } while (*pnode) { parent = *pnode; en = rb_entry(*pnode, struct extent_node, rb_node); if (fofs < en->ei.fofs) pnode = &(*pnode)->rb_left; else if (fofs >= en->ei.fofs + en->ei.len) pnode = &(*pnode)->rb_right; else goto lookup_neighbors; } *insert_p = pnode; *insert_parent = parent; en = rb_entry(parent, struct extent_node, rb_node); tmp_node = parent; if (parent && fofs > en->ei.fofs) tmp_node = rb_next(parent); *next_ex = tmp_node ? rb_entry(tmp_node, struct extent_node, rb_node) : NULL; tmp_node = parent; if (parent && fofs < en->ei.fofs) tmp_node = rb_prev(parent); *prev_ex = tmp_node ? rb_entry(tmp_node, struct extent_node, rb_node) : NULL; return NULL; lookup_neighbors: if (fofs == en->ei.fofs) { /* lookup prev node for merging backward later */ tmp_node = rb_prev(&en->rb_node); *prev_ex = tmp_node ? rb_entry(tmp_node, struct extent_node, rb_node) : NULL; }
/* 删除key */ int h_rbtree_delete(h_rbtree_st *tree, const void *key, uint32_t ksize) { rbtree_node_st *parent, *left, *right, *next; rb_color_t color; int is_left; rbtree_node_st *oldnode = do_lookup(tree, key, ksize, &parent, &is_left); rbtree_node_st *node; if (!oldnode) return -1; node = oldnode; left = node->left; right = node->right; if (node == tree->first) tree->first = rb_next(node); if (node == tree->last) tree->last = rb_prev(node); if (!left) next = right; else if (!right) next = left; else next = get_first(right); if (parent) set_child(next, parent, parent->left == node); else tree->root = next; if (left && right) { color = get_color(next); set_color(get_color(node), next); next->left = left; set_parent(next, left); if (next != right) { parent = get_parent(next); set_parent(get_parent(node), next); node = next->right; parent->left = node; next->right = right; set_parent(next, right); } else { set_parent(parent, next); parent = next; node = next->right; } } else { color = get_color(node); node = next; } /* * 'node' is now the sole successor's child and 'parent' its * new parent (since the successor can have been moved). */ if (node) set_parent(parent, node); /* * The 'easy' cases. */ if (color == RB_RED) goto end_delete; if (node && is_red(node)) { set_color(RB_BLACK, node); goto end_delete; } do { if (node == tree->root) break; if (node == parent->left) { rbtree_node_st *sibling = parent->right; if (is_red(sibling)) { set_color(RB_BLACK, sibling); set_color(RB_RED, parent); rotate_left(tree, parent); sibling = parent->right; } if ((!sibling->left || is_black(sibling->left)) && (!sibling->right || is_black(sibling->right))) { set_color(RB_RED, sibling); node = parent; parent = get_parent(parent); continue; } if (!sibling->right || is_black(sibling->right)) { set_color(RB_BLACK, sibling->left); set_color(RB_RED, sibling); rotate_right(tree, sibling); sibling = parent->right; } set_color(get_color(parent), sibling); set_color(RB_BLACK, parent); set_color(RB_BLACK, sibling->right); rotate_left(tree, parent); node = tree->root; break; } else { rbtree_node_st *sibling = parent->left; if (is_red(sibling)) { set_color(RB_BLACK, sibling); set_color(RB_RED, parent); rotate_right(tree, parent); sibling = parent->left; } if ((!sibling->left || is_black(sibling->left)) && (!sibling->right || is_black(sibling->right))) { set_color(RB_RED, sibling); node = parent; parent = get_parent(parent); continue; } if (!sibling->left || is_black(sibling->left)) { set_color(RB_BLACK, sibling->right); set_color(RB_RED, sibling); rotate_left(tree, sibling); sibling = parent->left; } set_color(get_color(parent), sibling); set_color(RB_BLACK, parent); set_color(RB_BLACK, sibling->left); rotate_right(tree, parent); node = tree->root; break; } } while (is_black(node)); if (node) set_color(RB_BLACK, node); end_delete: if ((void *)tree->data_free) tree->data_free(oldnode->cs.data); h_free(oldnode); tree->nelem--; return 0; }
/* * add all currently queued delayed refs from this head whose seq nr is * smaller or equal that seq to the list */ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, struct list_head *prefs) { struct btrfs_delayed_extent_op *extent_op = head->extent_op; struct rb_node *n = &head->node.rb_node; struct btrfs_key key; struct btrfs_key op_key = {0}; int sgn; int ret = 0; if (extent_op && extent_op->update_key) btrfs_disk_key_to_cpu(&op_key, &extent_op->key); while ((n = rb_prev(n))) { struct btrfs_delayed_ref_node *node; node = rb_entry(n, struct btrfs_delayed_ref_node, rb_node); if (node->bytenr != head->node.bytenr) break; WARN_ON(node->is_head); if (node->seq > seq) continue; switch (node->action) { case BTRFS_ADD_DELAYED_EXTENT: case BTRFS_UPDATE_DELAYED_HEAD: WARN_ON(1); continue; case BTRFS_ADD_DELAYED_REF: sgn = 1; break; case BTRFS_DROP_DELAYED_REF: sgn = -1; break; default: BUG_ON(1); } switch (node->type) { case BTRFS_TREE_BLOCK_REF_KEY: { struct btrfs_delayed_tree_ref *ref; ref = btrfs_delayed_node_to_tree_ref(node); ret = __add_prelim_ref(prefs, ref->root, &op_key, ref->level + 1, 0, node->bytenr, node->ref_mod * sgn); break; } case BTRFS_SHARED_BLOCK_REF_KEY: { struct btrfs_delayed_tree_ref *ref; ref = btrfs_delayed_node_to_tree_ref(node); ret = __add_prelim_ref(prefs, ref->root, NULL, ref->level + 1, ref->parent, node->bytenr, node->ref_mod * sgn); break; } case BTRFS_EXTENT_DATA_REF_KEY: { struct btrfs_delayed_data_ref *ref; ref = btrfs_delayed_node_to_data_ref(node); key.objectid = ref->objectid; key.type = BTRFS_EXTENT_DATA_KEY; key.offset = ref->offset; ret = __add_prelim_ref(prefs, ref->root, &key, 0, 0, node->bytenr, node->ref_mod * sgn); break; } case BTRFS_SHARED_DATA_REF_KEY: { struct btrfs_delayed_data_ref *ref; ref = btrfs_delayed_node_to_data_ref(node); key.objectid = ref->objectid; key.type = BTRFS_EXTENT_DATA_KEY; key.offset = ref->offset; ret = __add_prelim_ref(prefs, ref->root, &key, 0, ref->parent, node->bytenr, node->ref_mod * sgn); break; } default: WARN_ON(1); } if (ret) return ret; } return 0; }
/* 取得当前itor的上一结点 */ const h_rb_cursor_st *h_rbtree_prev(const h_rb_cursor_st *_itor) { rbtree_node_st *prev_node = rb_prev(cursor_node(_itor)); return prev_node == NULL ? NULL : &(prev_node->cs); }
int main(int argc, char *argv[]) { rb_tree_t rb_tree; rb_node_t *node; unsigned int key_pool[KEY_POOL_CAPS]; unsigned int key; for (int i = 0; i < KEY_POOL_CAPS; ++i) { add_key: key = arc4random() % 3000; for (int j = i - 1; j >= 0; j--) { if (key == key_pool[j]) { goto add_key; } } key_pool[i] = key; printf("Add %u into key pool.\n", key_pool[i]); } rb_tree_init(&rb_tree, data_compare, data_destroy); redo: for (int i = 0; i < KEY_POOL_CAPS; ++i) { data_node_t *data = (data_node_t *)malloc(sizeof(*data)); data->key = key_pool[i]; if (rb_insert(&(data->rb_node), &rb_tree)) { printf("Key %u already exist.\n", data->key); } else { printf("Add %u into tree.\n", data->key); } } printf("INIT: ************\n"); printf("Min:%u\n", rb_entry(rb_first(&rb_tree), data_node_t, rb_node)->key); printf("Max:%u\n", rb_entry(rb_last(&rb_tree), data_node_t, rb_node)->key); printf("Trav with rb_next:\n"); node = rb_first(&rb_tree); while (node) { printf("%u, ",rb_entry(node, data_node_t, rb_node)->key); node = rb_next(node); } printf("\n"); printf("Trav with rb_prev:\n"); node = rb_last(&rb_tree); while (node) { printf("%u, ",rb_entry(node, data_node_t, rb_node)->key); node = rb_prev(node); } printf("\n"); printf("ERASE: ************\n"); data_node_t search_node; for (int i = 0; i < 5; i++) { unsigned int j = arc4random() % KEY_POOL_CAPS; search_node.key = key_pool[j]; rb_node_t *to_remove = rb_find(&(search_node.rb_node), &rb_tree); if (to_remove) { printf("Remove %u from tree.\n", search_node.key); rb_remove(to_remove, &rb_tree); free(rb_entry(to_remove, data_node_t, rb_node)); } else { printf("Key %u not in tree.\n", search_node.key); } } printf("PRINT: ************\n"); printf("Min:%u\n", rb_entry(rb_first(&rb_tree), data_node_t, rb_node)->key); printf("Max:%u\n", rb_entry(rb_last(&rb_tree), data_node_t, rb_node)->key); printf("Trav with rb_next:\n"); node = rb_first(&rb_tree); while (node) { printf("%u, ",rb_entry(node, data_node_t, rb_node)->key); node = rb_next(node); } printf("\n"); printf("Trav with rb_prev:\n"); node = rb_last(&rb_tree); while (node) { printf("%u, ",rb_entry(node, data_node_t, rb_node)->key); node = rb_prev(node); } printf("\n"); rb_clear(&rb_tree); printf("PRINT2: ************\n"); node = rb_first(&rb_tree); if (node) { printf("Min:%u\n", rb_entry(node, data_node_t, rb_node)->key); } node = rb_last(&rb_tree); if (node) { printf("Max:%u\n", rb_entry(node, data_node_t, rb_node)->key); } printf("Trav with rb_next:\n"); node = rb_first(&rb_tree); while (node) { printf("%u, ",rb_entry(node, data_node_t, rb_node)->key); node = rb_next(node); } printf("\n"); printf("Trav with rb_prev:\n"); node = rb_last(&rb_tree); while (node) { printf("%u, ",rb_entry(node, data_node_t, rb_node)->key); node = rb_prev(node); } printf("\n"); goto redo; return 0; }
int defrag_file_interactive(struct defrag_ctx *c) { struct rb_node *n = rb_last(&c->free_tree_by_size); struct free_extent *f = rb_entry(n, struct free_extent, size_rb); struct inode *inode; e2_blkcnt_t biggest_size = 0; int ret, num_biggest = 0; ext2_ino_t inode_nr; char improve; print_fragged_inodes(c); if (n) biggest_size = f->end_block - f->start_block + 1; while (n && biggest_size == f->end_block - f->start_block + 1) { num_biggest++; n = rb_prev(n); f = rb_entry(n, struct free_extent, size_rb); } printf("Biggest free space: %llu blocks (%d)\n", biggest_size, num_biggest); do { long number; printf("WARNING: UNTESTED!\n"); printf("Specify inode number.\n"); printf("You can enter -1 for free space consolidation, or 0 to exit.\n"); printf("You can also precede the inode number by an 'i' to improve rather than defragment the file.\n"); printf("Inode number: "); fflush(stdout); number = getchar(); if (number == 'i' || number == 'I') { improve = 1; } else { improve = 0; ungetc(number, stdin); } if (getnumber(&number, -2, c->sb.s_inodes_count) < 0) { switch (errno) { case EDOM: printf("Not a valid number\n"); break; case ERANGE: printf("Inode number out of range\n"); break; default: printf("Error: %s\n", strerror(errno)); return -1; } number = LONG_MIN; } switch (number) { case 0: return 1; case -1: ret = consolidate_free_space(c); if (ret) printf("Error: %s\n", strerror(errno)); if (ret && errno != ENOSPC) return ret; return 0; case -2: ret = 0; while (!ret) ret = consolidate_free_space(c); if (errno == ENOSPC) return 0; return ret; case LONG_MIN: inode_nr = 0; break; default: inode_nr = number; } } while (inode_nr < EXT2_FIRST_INO(&c->sb)); inode = c->inodes[inode_nr]; if (inode == NULL || inode->data->extent_count == 0) { printf("Inode has no data associated\n"); return 0; } if (!improve) ret = do_one_inode(c, inode_nr); else while ((ret = try_improve_inode(c, inode_nr)) > 0); if (ret < 0) printf("Error: %s\n", strerror(errno)); printf("Inode now has %llu fragments\n", c->inodes[inode_nr]->data->extent_count); if (ret && errno != ENOSPC) return ret; else return 0; }
/* * Mark a range of blocks as belonging to the "system zone" --- that * is, filesystem metadata blocks which should never be used by * inodes. */ static int add_system_zone(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk, unsigned int count) { struct ext4_system_zone *new_entry = NULL, *entry; struct rb_node **n = &sbi->system_blks.rb_node, *node; struct rb_node *parent = NULL, *new_node = NULL; while (*n) { parent = *n; entry = rb_entry(parent, struct ext4_system_zone, node); if (start_blk < entry->start_blk) n = &(*n)->rb_left; else if (start_blk >= (entry->start_blk + entry->count)) n = &(*n)->rb_right; else { if (start_blk + count > (entry->start_blk + entry->count)) entry->count = (start_blk + count - entry->start_blk); new_node = *n; new_entry = rb_entry(new_node, struct ext4_system_zone, node); break; } } if (!new_entry) { new_entry = kmem_cache_alloc(ext4_system_zone_cachep, GFP_KERNEL); if (!new_entry) return -ENOMEM; new_entry->start_blk = start_blk; new_entry->count = count; new_node = &new_entry->node; rb_link_node(new_node, parent, n); rb_insert_color(new_node, &sbi->system_blks); } /* Can we merge to the left? */ node = rb_prev(new_node); if (node) { entry = rb_entry(node, struct ext4_system_zone, node); if (can_merge(entry, new_entry)) { new_entry->start_blk = entry->start_blk; new_entry->count += entry->count; rb_erase(node, &sbi->system_blks); kmem_cache_free(ext4_system_zone_cachep, entry); } } /* Can we merge to the right? */ node = rb_next(new_node); if (node) { entry = rb_entry(node, struct ext4_system_zone, node); if (can_merge(new_entry, entry)) { new_entry->count += entry->count; rb_erase(node, &sbi->system_blks); kmem_cache_free(ext4_system_zone_cachep, entry); } } return 0; }