📄 alloc.c
字号:
*/ el = left_path->p_node[subtree_index].el; left_el = left_path->p_node[subtree_index + 1].el; right_el = right_path->p_node[subtree_index + 1].el; ocfs2_adjust_root_records(el, left_el, right_el, left_path->p_node[subtree_index + 1].bh->b_blocknr); root_bh = left_path->p_node[subtree_index].bh; ret = ocfs2_journal_dirty(handle, root_bh); if (ret) mlog_errno(ret);}static int ocfs2_rotate_subtree_right(struct inode *inode, handle_t *handle, struct ocfs2_path *left_path, struct ocfs2_path *right_path, int subtree_index){ int ret, i; struct buffer_head *right_leaf_bh; struct buffer_head *left_leaf_bh = NULL; struct buffer_head *root_bh; struct ocfs2_extent_list *right_el, *left_el; struct ocfs2_extent_rec move_rec; left_leaf_bh = path_leaf_bh(left_path); left_el = path_leaf_el(left_path); if (left_el->l_next_free_rec != left_el->l_count) { ocfs2_error(inode->i_sb, "Inode %llu has non-full interior leaf node %llu" "(next free = %u)", (unsigned long long)OCFS2_I(inode)->ip_blkno, (unsigned long long)left_leaf_bh->b_blocknr, le16_to_cpu(left_el->l_next_free_rec)); return -EROFS; } /* * This extent block may already have an empty record, so we * return early if so. */ if (ocfs2_is_empty_extent(&left_el->l_recs[0])) return 0; root_bh = left_path->p_node[subtree_index].bh; BUG_ON(root_bh != right_path->p_node[subtree_index].bh); ret = ocfs2_journal_access(handle, inode, root_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (ret) { mlog_errno(ret); goto out; } for(i = subtree_index + 1; i < path_num_items(right_path); i++) { ret = ocfs2_journal_access(handle, inode, right_path->p_node[i].bh, OCFS2_JOURNAL_ACCESS_WRITE); if (ret) { mlog_errno(ret); goto out; } ret = ocfs2_journal_access(handle, inode, left_path->p_node[i].bh, OCFS2_JOURNAL_ACCESS_WRITE); if (ret) { mlog_errno(ret); goto out; } } right_leaf_bh = path_leaf_bh(right_path); right_el = path_leaf_el(right_path); /* This is a code error, not a disk corruption. */ mlog_bug_on_msg(!right_el->l_next_free_rec, "Inode %llu: Rotate fails " "because rightmost leaf block %llu is empty\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, (unsigned long long)right_leaf_bh->b_blocknr); ocfs2_create_empty_extent(right_el); ret = ocfs2_journal_dirty(handle, right_leaf_bh); if (ret) { mlog_errno(ret); goto out; } /* Do the copy now. */ i = le16_to_cpu(left_el->l_next_free_rec) - 1; move_rec = left_el->l_recs[i]; right_el->l_recs[0] = move_rec; /* * Clear out the record we just copied and shift everything * over, leaving an empty extent in the left leaf. * * We temporarily subtract from next_free_rec so that the * shift will lose the tail record (which is now defunct). */ le16_add_cpu(&left_el->l_next_free_rec, -1); ocfs2_shift_records_right(left_el); memset(&left_el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec)); le16_add_cpu(&left_el->l_next_free_rec, 1); ret = ocfs2_journal_dirty(handle, left_leaf_bh); if (ret) { mlog_errno(ret); goto out; } ocfs2_complete_edge_insert(inode, handle, left_path, right_path, subtree_index);out: return ret;}/* * Given a full path, determine what cpos value would return us a path * containing the leaf immediately to the left of the current one. * * Will return zero if the path passed in is already the leftmost path. */static int ocfs2_find_cpos_for_left_leaf(struct super_block *sb, struct ocfs2_path *path, u32 *cpos){ int i, j, ret = 0; u64 blkno; struct ocfs2_extent_list *el; BUG_ON(path->p_tree_depth == 0); *cpos = 0; blkno = path_leaf_bh(path)->b_blocknr; /* Start at the tree node just above the leaf and work our way up. */ i = path->p_tree_depth - 1; while (i >= 0) { el = path->p_node[i].el; /* * Find the extent record just before the one in our * path. */ for(j = 0; j < le16_to_cpu(el->l_next_free_rec); j++) { if (le64_to_cpu(el->l_recs[j].e_blkno) == blkno) { if (j == 0) { if (i == 0) { /* * We've determined that the * path specified is already * the leftmost one - return a * cpos of zero. */ goto out; } /* * The leftmost record points to our * leaf - we need to travel up the * tree one level. */ goto next_node; } *cpos = le32_to_cpu(el->l_recs[j - 1].e_cpos); *cpos = *cpos + ocfs2_rec_clusters(el, &el->l_recs[j - 1]); *cpos = *cpos - 1; goto out; } } /* * If we got here, we never found a valid node where * the tree indicated one should be. */ ocfs2_error(sb, "Invalid extent tree at extent block %llu\n", (unsigned long long)blkno); ret = -EROFS; goto out;next_node: blkno = path->p_node[i].bh->b_blocknr; i--; }out: return ret;}/* * Extend the transaction by enough credits to complete the rotation, * and still leave at least the original number of credits allocated * to this transaction. */static int ocfs2_extend_rotate_transaction(handle_t *handle, int subtree_depth, int op_credits, struct ocfs2_path *path){ int credits = (path->p_tree_depth - subtree_depth) * 2 + 1 + op_credits; if (handle->h_buffer_credits < credits) return ocfs2_extend_trans(handle, credits); return 0;}/* * Trap the case where we're inserting into the theoretical range past * the _actual_ left leaf range. Otherwise, we'll rotate a record * whose cpos is less than ours into the right leaf. * * It's only necessary to look at the rightmost record of the left * leaf because the logic that calls us should ensure that the * theoretical ranges in the path components above the leaves are * correct. */static int ocfs2_rotate_requires_path_adjustment(struct ocfs2_path *left_path, u32 insert_cpos){ struct ocfs2_extent_list *left_el; struct ocfs2_extent_rec *rec; int next_free; left_el = path_leaf_el(left_path); next_free = le16_to_cpu(left_el->l_next_free_rec); rec = &left_el->l_recs[next_free - 1]; if (insert_cpos > le32_to_cpu(rec->e_cpos)) return 1; return 0;}static int ocfs2_leftmost_rec_contains(struct ocfs2_extent_list *el, u32 cpos){ int next_free = le16_to_cpu(el->l_next_free_rec); unsigned int range; struct ocfs2_extent_rec *rec; if (next_free == 0) return 0; rec = &el->l_recs[0]; if (ocfs2_is_empty_extent(rec)) { /* Empty list. */ if (next_free == 1) return 0; rec = &el->l_recs[1]; } range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec); if (cpos >= le32_to_cpu(rec->e_cpos) && cpos < range) return 1; return 0;}/* * Rotate all the records in a btree right one record, starting at insert_cpos. * * The path to the rightmost leaf should be passed in. * * The array is assumed to be large enough to hold an entire path (tree depth). * * Upon succesful return from this function: * * - The 'right_path' array will contain a path to the leaf block * whose range contains e_cpos. * - That leaf block will have a single empty extent in list index 0. * - In the case that the rotation requires a post-insert update, * *ret_left_path will contain a valid path which can be passed to * ocfs2_insert_path(). */static int ocfs2_rotate_tree_right(struct inode *inode, handle_t *handle, enum ocfs2_split_type split, u32 insert_cpos, struct ocfs2_path *right_path, struct ocfs2_path **ret_left_path){ int ret, start, orig_credits = handle->h_buffer_credits; u32 cpos; struct ocfs2_path *left_path = NULL; *ret_left_path = NULL; left_path = ocfs2_new_path(path_root_bh(right_path), path_root_el(right_path)); if (!left_path) { ret = -ENOMEM; mlog_errno(ret); goto out; } ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb, right_path, &cpos); if (ret) { mlog_errno(ret); goto out; } mlog(0, "Insert: %u, first left path cpos: %u\n", insert_cpos, cpos); /* * What we want to do here is: * * 1) Start with the rightmost path. * * 2) Determine a path to the leaf block directly to the left * of that leaf. * * 3) Determine the 'subtree root' - the lowest level tree node * which contains a path to both leaves. * * 4) Rotate the subtree. * * 5) Find the next subtree by considering the left path to be * the new right path. * * The check at the top of this while loop also accepts * insert_cpos == cpos because cpos is only a _theoretical_ * value to get us the left path - insert_cpos might very well * be filling that hole. * * Stop at a cpos of '0' because we either started at the * leftmost branch (i.e., a tree with one branch and a * rotation inside of it), or we've gone as far as we can in * rotating subtrees. */ while (cpos && insert_cpos <= cpos) { mlog(0, "Rotating a tree: ins. cpos: %u, left path cpos: %u\n", insert_cpos, cpos); ret = ocfs2_find_path(inode, left_path, cpos); if (ret) { mlog_errno(ret); goto out; } mlog_bug_on_msg(path_leaf_bh(left_path) == path_leaf_bh(right_path), "Inode %lu: error during insert of %u " "(left path cpos %u) results in two identical " "paths ending at %llu\n", inode->i_ino, insert_cpos, cpos, (unsigned long long) path_leaf_bh(left_path)->b_blocknr); if (split == SPLIT_NONE && ocfs2_rotate_requires_path_adjustment(left_path, insert_cpos)) { /* * We've rotated the tree as much as we * should. The rest is up to * ocfs2_insert_path() to complete, after the * record insertion. We indicate this * situation by returning the left path. * * The reason we don't adjust the records here * before the record insert is that an error * later might break the rule where a parent * record e_cpos will reflect the actual * e_cpos of the 1st nonempty record of the * child list. */ *ret_left_path = left_path; goto out_ret_path; } start = ocfs2_find_subtree_root(inode, left_path, right_path); mlog(0, "Subtree root at index %d (blk %llu, depth %d)\n", start, (unsigned long long) right_path->p_node[start].bh->b_blocknr, right_path->p_tree_depth); ret = ocfs2_extend_rotate_transaction(handle, start, orig_credits, right_path); if (ret) { mlog_errno(ret); goto out; } ret = ocfs2_rotate_subtree_right(inode, handle, left_path, right_path, start); if (ret) { mlog_errno(ret); goto out; } if (split != SPLIT_NONE && ocfs2_leftmost_rec_contains(path_leaf_el(right_path), insert_cpos)) { /* * A rotate moves the rightmost left leaf * record over to the leftmost right leaf * slot. If we're doing an extent split * instead of a real insert, then we have to * check that the extent to be split wasn't * just moved over. If it was, then we can * exit here, passing left_path back - * ocfs2_split_extent() is smart enough to * search both leaves. */ *ret_left_path = left_path; goto out_ret_path; } /* * There is no need to re-read the next right path * as we know that it'll be our current left * path. Optimize by copying values instead. */ ocfs2_mv_path(right_path, left_path); ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb, right_path, &cpos); if (ret) { mlog_errno(ret); goto out; } }out: ocfs2_free_path(left_path);out_ret_path: return ret;}static void ocfs2_update_edge_lengths(struct inode *inode, handle_t *handle, struct ocfs2_path *path){ int i, idx; struct ocfs2_extent_rec *rec; struct ocfs2_extent_list *el; struct ocfs2_extent_block *eb; u32 range; /* Path should always be rightmost. */ eb = (struct ocfs2_extent_block *)path_leaf_bh(path)->b_data; BUG_ON(eb->h_next_leaf_blk != 0ULL); el = &eb->h_list; BUG_ON(le16_to_cpu(el->l_next_free_rec) == 0); idx = le16_to_cpu(el->l_next_free_rec) - 1; rec = &el->l_recs[idx]; range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec); for (i = 0; i < path->p_tree_depth; i++) { el = path->p_node[i].el; idx = le16_to_cpu(el->l_next_free_rec) - 1; rec = &el->l_recs[idx]; rec->e_int_clusters = cpu_to_le32(range); le32_add_cpu(&rec->e_int_clusters, -le32_to_cpu(rec->e_cpos)); ocfs2_journal_dirty(handle, path->p_node[i].bh); }}static void ocfs2_unlink_path(struct inode *inode, handle_t *handle, struct ocfs2_cached_dealloc_ctxt *dealloc, struct ocfs2_path *path, int unlink_start){ int ret, i; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *el; struct buffer_head *bh; for(i = unlink_start; i < path_num_items(path); i++) { bh = path->p_node[i].bh; eb = (struct ocfs2_extent_block *)bh->b_data; /* * Not all nodes might have had their final count * decremented by the caller - handle this here. */ el = &eb->h_list; if (le16_to_cpu(el->l_next_free_rec) > 1) { mlog(ML_ERROR, "Inode %llu, attempted to remove extent block " "%llu with %u records\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, (unsigned long long)le64_to_cpu(eb->h_blkno), le16_to_cpu(el->l_next_free_rec)); ocfs2_journal_dirty(handle, bh); ocfs2_remove_from_cache(inode, bh); continue; } el->l_next_free_rec = 0; memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec)); ocfs2_journal_dirty(handle, bh);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -