📄 alloc.c
字号:
/* This will cause us to go off the end of our extent list. */ BUG_ON(next_free >= count); num_bytes = sizeof(struct ocfs2_extent_rec) * next_free; memmove(&el->l_recs[1], &el->l_recs[0], num_bytes);}static void ocfs2_rotate_leaf(struct ocfs2_extent_list *el, struct ocfs2_extent_rec *insert_rec){ int i, insert_index, next_free, has_empty, num_bytes; u32 insert_cpos = le32_to_cpu(insert_rec->e_cpos); struct ocfs2_extent_rec *rec; next_free = le16_to_cpu(el->l_next_free_rec); has_empty = ocfs2_is_empty_extent(&el->l_recs[0]); BUG_ON(!next_free); /* The tree code before us didn't allow enough room in the leaf. */ if (el->l_next_free_rec == el->l_count && !has_empty) BUG(); /* * The easiest way to approach this is to just remove the * empty extent and temporarily decrement next_free. */ if (has_empty) { /* * If next_free was 1 (only an empty extent), this * loop won't execute, which is fine. We still want * the decrement above to happen. */ for(i = 0; i < (next_free - 1); i++) el->l_recs[i] = el->l_recs[i+1]; next_free--; } /* * Figure out what the new record index should be. */ for(i = 0; i < next_free; i++) { rec = &el->l_recs[i]; if (insert_cpos < le32_to_cpu(rec->e_cpos)) break; } insert_index = i; mlog(0, "ins %u: index %d, has_empty %d, next_free %d, count %d\n", insert_cpos, insert_index, has_empty, next_free, le16_to_cpu(el->l_count)); BUG_ON(insert_index < 0); BUG_ON(insert_index >= le16_to_cpu(el->l_count)); BUG_ON(insert_index > next_free); /* * No need to memmove if we're just adding to the tail. */ if (insert_index != next_free) { BUG_ON(next_free >= le16_to_cpu(el->l_count)); num_bytes = next_free - insert_index; num_bytes *= sizeof(struct ocfs2_extent_rec); memmove(&el->l_recs[insert_index + 1], &el->l_recs[insert_index], num_bytes); } /* * Either we had an empty extent, and need to re-increment or * there was no empty extent on a non full rightmost leaf node, * in which case we still need to increment. */ next_free++; el->l_next_free_rec = cpu_to_le16(next_free); /* * Make sure none of the math above just messed up our tree. */ BUG_ON(le16_to_cpu(el->l_next_free_rec) > le16_to_cpu(el->l_count)); el->l_recs[insert_index] = *insert_rec;}static void ocfs2_remove_empty_extent(struct ocfs2_extent_list *el){ int size, num_recs = le16_to_cpu(el->l_next_free_rec); BUG_ON(num_recs == 0); if (ocfs2_is_empty_extent(&el->l_recs[0])) { num_recs--; size = num_recs * sizeof(struct ocfs2_extent_rec); memmove(&el->l_recs[0], &el->l_recs[1], size); memset(&el->l_recs[num_recs], 0, sizeof(struct ocfs2_extent_rec)); el->l_next_free_rec = cpu_to_le16(num_recs); }}/* * Create an empty extent record . * * l_next_free_rec may be updated. * * If an empty extent already exists do nothing. */static void ocfs2_create_empty_extent(struct ocfs2_extent_list *el){ int next_free = le16_to_cpu(el->l_next_free_rec); BUG_ON(le16_to_cpu(el->l_tree_depth) != 0); if (next_free == 0) goto set_and_inc; if (ocfs2_is_empty_extent(&el->l_recs[0])) return; mlog_bug_on_msg(el->l_count == el->l_next_free_rec, "Asked to create an empty extent in a full list:\n" "count = %u, tree depth = %u", le16_to_cpu(el->l_count), le16_to_cpu(el->l_tree_depth)); ocfs2_shift_records_right(el);set_and_inc: le16_add_cpu(&el->l_next_free_rec, 1); memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec));}/* * For a rotation which involves two leaf nodes, the "root node" is * the lowest level tree node which contains a path to both leafs. This * resulting set of information can be used to form a complete "subtree" * * This function is passed two full paths from the dinode down to a * pair of adjacent leaves. It's task is to figure out which path * index contains the subtree root - this can be the root index itself * in a worst-case rotation. * * The array index of the subtree root is passed back. */static int ocfs2_find_subtree_root(struct inode *inode, struct ocfs2_path *left, struct ocfs2_path *right){ int i = 0; /* * Check that the caller passed in two paths from the same tree. */ BUG_ON(path_root_bh(left) != path_root_bh(right)); do { i++; /* * The caller didn't pass two adjacent paths. */ mlog_bug_on_msg(i > left->p_tree_depth, "Inode %lu, left depth %u, right depth %u\n" "left leaf blk %llu, right leaf blk %llu\n", inode->i_ino, left->p_tree_depth, right->p_tree_depth, (unsigned long long)path_leaf_bh(left)->b_blocknr, (unsigned long long)path_leaf_bh(right)->b_blocknr); } while (left->p_node[i].bh->b_blocknr == right->p_node[i].bh->b_blocknr); return i - 1;}typedef void (path_insert_t)(void *, struct buffer_head *);/* * Traverse a btree path in search of cpos, starting at root_el. * * This code can be called with a cpos larger than the tree, in which * case it will return the rightmost path. */static int __ocfs2_find_path(struct inode *inode, struct ocfs2_extent_list *root_el, u32 cpos, path_insert_t *func, void *data){ int i, ret = 0; u32 range; u64 blkno; struct buffer_head *bh = NULL; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *el; struct ocfs2_extent_rec *rec; struct ocfs2_inode_info *oi = OCFS2_I(inode); el = root_el; while (el->l_tree_depth) { if (le16_to_cpu(el->l_next_free_rec) == 0) { ocfs2_error(inode->i_sb, "Inode %llu has empty extent list at " "depth %u\n", (unsigned long long)oi->ip_blkno, le16_to_cpu(el->l_tree_depth)); ret = -EROFS; goto out; } for(i = 0; i < le16_to_cpu(el->l_next_free_rec) - 1; i++) { rec = &el->l_recs[i]; /* * In the case that cpos is off the allocation * tree, this should just wind up returning the * rightmost record. */ range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec); if (cpos >= le32_to_cpu(rec->e_cpos) && cpos < range) break; } blkno = le64_to_cpu(el->l_recs[i].e_blkno); if (blkno == 0) { ocfs2_error(inode->i_sb, "Inode %llu has bad blkno in extent list " "at depth %u (index %d)\n", (unsigned long long)oi->ip_blkno, le16_to_cpu(el->l_tree_depth), i); ret = -EROFS; goto out; } brelse(bh); bh = NULL; ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno, &bh, OCFS2_BH_CACHED, inode); if (ret) { mlog_errno(ret); goto out; } eb = (struct ocfs2_extent_block *) bh->b_data; el = &eb->h_list; if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) { OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb); ret = -EIO; goto out; } if (le16_to_cpu(el->l_next_free_rec) > le16_to_cpu(el->l_count)) { ocfs2_error(inode->i_sb, "Inode %llu has bad count in extent list " "at block %llu (next free=%u, count=%u)\n", (unsigned long long)oi->ip_blkno, (unsigned long long)bh->b_blocknr, le16_to_cpu(el->l_next_free_rec), le16_to_cpu(el->l_count)); ret = -EROFS; goto out; } if (func) func(data, bh); }out: /* * Catch any trailing bh that the loop didn't handle. */ brelse(bh); return ret;}/* * Given an initialized path (that is, it has a valid root extent * list), this function will traverse the btree in search of the path * which would contain cpos. * * The path traveled is recorded in the path structure. * * Note that this will not do any comparisons on leaf node extent * records, so it will work fine in the case that we just added a tree * branch. */struct find_path_data { int index; struct ocfs2_path *path;};static void find_path_ins(void *data, struct buffer_head *bh){ struct find_path_data *fp = data; get_bh(bh); ocfs2_path_insert_eb(fp->path, fp->index, bh); fp->index++;}static int ocfs2_find_path(struct inode *inode, struct ocfs2_path *path, u32 cpos){ struct find_path_data data; data.index = 1; data.path = path; return __ocfs2_find_path(inode, path_root_el(path), cpos, find_path_ins, &data);}static void find_leaf_ins(void *data, struct buffer_head *bh){ struct ocfs2_extent_block *eb =(struct ocfs2_extent_block *)bh->b_data; struct ocfs2_extent_list *el = &eb->h_list; struct buffer_head **ret = data; /* We want to retain only the leaf block. */ if (le16_to_cpu(el->l_tree_depth) == 0) { get_bh(bh); *ret = bh; }}/* * Find the leaf block in the tree which would contain cpos. No * checking of the actual leaf is done. * * Some paths want to call this instead of allocating a path structure * and calling ocfs2_find_path(). * * This function doesn't handle non btree extent lists. */int ocfs2_find_leaf(struct inode *inode, struct ocfs2_extent_list *root_el, u32 cpos, struct buffer_head **leaf_bh){ int ret; struct buffer_head *bh = NULL; ret = __ocfs2_find_path(inode, root_el, cpos, find_leaf_ins, &bh); if (ret) { mlog_errno(ret); goto out; } *leaf_bh = bh;out: return ret;}/* * Adjust the adjacent records (left_rec, right_rec) involved in a rotation. * * Basically, we've moved stuff around at the bottom of the tree and * we need to fix up the extent records above the changes to reflect * the new changes. * * left_rec: the record on the left. * left_child_el: is the child list pointed to by left_rec * right_rec: the record to the right of left_rec * right_child_el: is the child list pointed to by right_rec * * By definition, this only works on interior nodes. */static void ocfs2_adjust_adjacent_records(struct ocfs2_extent_rec *left_rec, struct ocfs2_extent_list *left_child_el, struct ocfs2_extent_rec *right_rec, struct ocfs2_extent_list *right_child_el){ u32 left_clusters, right_end; /* * Interior nodes never have holes. Their cpos is the cpos of * the leftmost record in their child list. Their cluster * count covers the full theoretical range of their child list * - the range between their cpos and the cpos of the record * immediately to their right. */ left_clusters = le32_to_cpu(right_child_el->l_recs[0].e_cpos); if (ocfs2_is_empty_extent(&right_child_el->l_recs[0])) { BUG_ON(le16_to_cpu(right_child_el->l_next_free_rec) <= 1); left_clusters = le32_to_cpu(right_child_el->l_recs[1].e_cpos); } left_clusters -= le32_to_cpu(left_rec->e_cpos); left_rec->e_int_clusters = cpu_to_le32(left_clusters); /* * Calculate the rightmost cluster count boundary before * moving cpos - we will need to adjust clusters after * updating e_cpos to keep the same highest cluster count. */ right_end = le32_to_cpu(right_rec->e_cpos); right_end += le32_to_cpu(right_rec->e_int_clusters); right_rec->e_cpos = left_rec->e_cpos; le32_add_cpu(&right_rec->e_cpos, left_clusters); right_end -= le32_to_cpu(right_rec->e_cpos); right_rec->e_int_clusters = cpu_to_le32(right_end);}/* * Adjust the adjacent root node records involved in a * rotation. left_el_blkno is passed in as a key so that we can easily * find it's index in the root list. */static void ocfs2_adjust_root_records(struct ocfs2_extent_list *root_el, struct ocfs2_extent_list *left_el, struct ocfs2_extent_list *right_el, u64 left_el_blkno){ int i; BUG_ON(le16_to_cpu(root_el->l_tree_depth) <= le16_to_cpu(left_el->l_tree_depth)); for(i = 0; i < le16_to_cpu(root_el->l_next_free_rec) - 1; i++) { if (le64_to_cpu(root_el->l_recs[i].e_blkno) == left_el_blkno) break; } /* * The path walking code should have never returned a root and * two paths which are not adjacent. */ BUG_ON(i >= (le16_to_cpu(root_el->l_next_free_rec) - 1)); ocfs2_adjust_adjacent_records(&root_el->l_recs[i], left_el, &root_el->l_recs[i + 1], right_el);}/* * We've changed a leaf block (in right_path) and need to reflect that * change back up the subtree. * * This happens in multiple places: * - When we've moved an extent record from the left path leaf to the right * path leaf to make room for an empty extent in the left path leaf. * - When our insert into the right path leaf is at the leftmost edge * and requires an update of the path immediately to it's left. This * can occur at the end of some types of rotation and appending inserts. */static void ocfs2_complete_edge_insert(struct inode *inode, handle_t *handle, struct ocfs2_path *left_path, struct ocfs2_path *right_path, int subtree_index){ int ret, i, idx; struct ocfs2_extent_list *el, *left_el, *right_el; struct ocfs2_extent_rec *left_rec, *right_rec; struct buffer_head *root_bh = left_path->p_node[subtree_index].bh; /* * Update the counts and position values within all the * interior nodes to reflect the leaf rotation we just did. * * The root node is handled below the loop. * * We begin the loop with right_el and left_el pointing to the * leaf lists and work our way up. * * NOTE: within this loop, left_el and right_el always refer * to the *child* lists. */ left_el = path_leaf_el(left_path); right_el = path_leaf_el(right_path); for(i = left_path->p_tree_depth - 1; i > subtree_index; i--) { mlog(0, "Adjust records at index %u\n", i); /* * One nice property of knowing that all of these * nodes are below the root is that we only deal with * the leftmost right node record and the rightmost * left node record. */ el = left_path->p_node[i].el; idx = le16_to_cpu(left_el->l_next_free_rec) - 1; left_rec = &el->l_recs[idx]; el = right_path->p_node[i].el; right_rec = &el->l_recs[0]; ocfs2_adjust_adjacent_records(left_rec, left_el, right_rec, right_el); ret = ocfs2_journal_dirty(handle, left_path->p_node[i].bh); if (ret) mlog_errno(ret); ret = ocfs2_journal_dirty(handle, right_path->p_node[i].bh); if (ret) mlog_errno(ret); /* * Setup our list pointers now so that the current * parents become children in the next iteration. */ left_el = left_path->p_node[i].el; right_el = right_path->p_node[i].el; } /* * At the root node, adjust the two adjacent records which * begin our path to the leaves.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -