📄 alloc.c
字号:
ret = ocfs2_cache_extent_block_free(dealloc, eb); if (ret) mlog_errno(ret); ocfs2_remove_from_cache(inode, bh); }}static void ocfs2_unlink_subtree(struct inode *inode, handle_t *handle, struct ocfs2_path *left_path, struct ocfs2_path *right_path, int subtree_index, struct ocfs2_cached_dealloc_ctxt *dealloc){ int i; struct buffer_head *root_bh = left_path->p_node[subtree_index].bh; struct ocfs2_extent_list *root_el = left_path->p_node[subtree_index].el; struct ocfs2_extent_list *el; struct ocfs2_extent_block *eb; el = path_leaf_el(left_path); eb = (struct ocfs2_extent_block *)right_path->p_node[subtree_index + 1].bh->b_data; for(i = 1; i < le16_to_cpu(root_el->l_next_free_rec); i++) if (root_el->l_recs[i].e_blkno == eb->h_blkno) break; BUG_ON(i >= le16_to_cpu(root_el->l_next_free_rec)); memset(&root_el->l_recs[i], 0, sizeof(struct ocfs2_extent_rec)); le16_add_cpu(&root_el->l_next_free_rec, -1); eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data; eb->h_next_leaf_blk = 0; ocfs2_journal_dirty(handle, root_bh); ocfs2_journal_dirty(handle, path_leaf_bh(left_path)); ocfs2_unlink_path(inode, handle, dealloc, right_path, subtree_index + 1);}static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle, struct ocfs2_path *left_path, struct ocfs2_path *right_path, int subtree_index, struct ocfs2_cached_dealloc_ctxt *dealloc, int *deleted){ int ret, i, del_right_subtree = 0, right_has_empty = 0; struct buffer_head *root_bh, *di_bh = path_root_bh(right_path); struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; struct ocfs2_extent_list *right_leaf_el, *left_leaf_el; struct ocfs2_extent_block *eb; *deleted = 0; right_leaf_el = path_leaf_el(right_path); left_leaf_el = path_leaf_el(left_path); root_bh = left_path->p_node[subtree_index].bh; BUG_ON(root_bh != right_path->p_node[subtree_index].bh); if (!ocfs2_is_empty_extent(&left_leaf_el->l_recs[0])) return 0; eb = (struct ocfs2_extent_block *)path_leaf_bh(right_path)->b_data; if (ocfs2_is_empty_extent(&right_leaf_el->l_recs[0])) { /* * It's legal for us to proceed if the right leaf is * the rightmost one and it has an empty extent. There * are two cases to handle - whether the leaf will be * empty after removal or not. If the leaf isn't empty * then just remove the empty extent up front. The * next block will handle empty leaves by flagging * them for unlink. * * Non rightmost leaves will throw -EAGAIN and the * caller can manually move the subtree and retry. */ if (eb->h_next_leaf_blk != 0ULL) return -EAGAIN; if (le16_to_cpu(right_leaf_el->l_next_free_rec) > 1) { ret = ocfs2_journal_access(handle, inode, path_leaf_bh(right_path), OCFS2_JOURNAL_ACCESS_WRITE); if (ret) { mlog_errno(ret); goto out; } ocfs2_remove_empty_extent(right_leaf_el); } else right_has_empty = 1; } if (eb->h_next_leaf_blk == 0ULL && le16_to_cpu(right_leaf_el->l_next_free_rec) == 1) { /* * We have to update i_last_eb_blk during the meta * data delete. */ ret = ocfs2_journal_access(handle, inode, di_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (ret) { mlog_errno(ret); goto out; } del_right_subtree = 1; } /* * Getting here with an empty extent in the right path implies * that it's the rightmost path and will be deleted. */ BUG_ON(right_has_empty && !del_right_subtree); 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; } } if (!right_has_empty) { /* * Only do this if we're moving a real * record. Otherwise, the action is delayed until * after removal of the right path in which case we * can do a simple shift to remove the empty extent. */ ocfs2_rotate_leaf(left_leaf_el, &right_leaf_el->l_recs[0]); memset(&right_leaf_el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec)); } if (eb->h_next_leaf_blk == 0ULL) { /* * Move recs over to get rid of empty extent, decrease * next_free. This is allowed to remove the last * extent in our leaf (setting l_next_free_rec to * zero) - the delete code below won't care. */ ocfs2_remove_empty_extent(right_leaf_el); } ret = ocfs2_journal_dirty(handle, path_leaf_bh(left_path)); if (ret) mlog_errno(ret); ret = ocfs2_journal_dirty(handle, path_leaf_bh(right_path)); if (ret) mlog_errno(ret); if (del_right_subtree) { ocfs2_unlink_subtree(inode, handle, left_path, right_path, subtree_index, dealloc); ocfs2_update_edge_lengths(inode, handle, left_path); eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data; di->i_last_eb_blk = eb->h_blkno; /* * Removal of the extent in the left leaf was skipped * above so we could delete the right path * 1st. */ if (right_has_empty) ocfs2_remove_empty_extent(left_leaf_el); ret = ocfs2_journal_dirty(handle, di_bh); if (ret) mlog_errno(ret); *deleted = 1; } else 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 right of the current one. * * Will return zero if the path passed in is already the rightmost path. * * This looks similar, but is subtly different to * ocfs2_find_cpos_for_left_leaf(). */static int ocfs2_find_cpos_for_right_leaf(struct super_block *sb, struct ocfs2_path *path, u32 *cpos){ int i, j, ret = 0; u64 blkno; struct ocfs2_extent_list *el; *cpos = 0; if (path->p_tree_depth == 0) return 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) { int next_free; el = path->p_node[i].el; /* * Find the extent record just after the one in our * path. */ next_free = le16_to_cpu(el->l_next_free_rec); 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 == (next_free - 1)) { if (i == 0) { /* * We've determined that the * path specified is already * the rightmost one - return a * cpos of zero. */ goto out; } /* * The rightmost 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); 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;}static int ocfs2_rotate_rightmost_leaf_left(struct inode *inode, handle_t *handle, struct buffer_head *bh, struct ocfs2_extent_list *el){ int ret; if (!ocfs2_is_empty_extent(&el->l_recs[0])) return 0; ret = ocfs2_journal_access(handle, inode, bh, OCFS2_JOURNAL_ACCESS_WRITE); if (ret) { mlog_errno(ret); goto out; } ocfs2_remove_empty_extent(el); ret = ocfs2_journal_dirty(handle, bh); if (ret) mlog_errno(ret);out: return ret;}static int __ocfs2_rotate_tree_left(struct inode *inode, handle_t *handle, int orig_credits, struct ocfs2_path *path, struct ocfs2_cached_dealloc_ctxt *dealloc, struct ocfs2_path **empty_extent_path){ int ret, subtree_root, deleted; u32 right_cpos; struct ocfs2_path *left_path = NULL; struct ocfs2_path *right_path = NULL; BUG_ON(!ocfs2_is_empty_extent(&(path_leaf_el(path)->l_recs[0]))); *empty_extent_path = NULL; ret = ocfs2_find_cpos_for_right_leaf(inode->i_sb, path, &right_cpos); if (ret) { mlog_errno(ret); goto out; } left_path = ocfs2_new_path(path_root_bh(path), path_root_el(path)); if (!left_path) { ret = -ENOMEM; mlog_errno(ret); goto out; } ocfs2_cp_path(left_path, path); right_path = ocfs2_new_path(path_root_bh(path), path_root_el(path)); if (!right_path) { ret = -ENOMEM; mlog_errno(ret); goto out; } while (right_cpos) { ret = ocfs2_find_path(inode, right_path, right_cpos); if (ret) { mlog_errno(ret); goto out; } subtree_root = ocfs2_find_subtree_root(inode, left_path, right_path); mlog(0, "Subtree root at index %d (blk %llu, depth %d)\n", subtree_root, (unsigned long long) right_path->p_node[subtree_root].bh->b_blocknr, right_path->p_tree_depth); ret = ocfs2_extend_rotate_transaction(handle, subtree_root, orig_credits, left_path); if (ret) { mlog_errno(ret); goto out; } /* * Caller might still want to make changes to the * tree root, so re-add it to the journal here. */ ret = ocfs2_journal_access(handle, inode, path_root_bh(left_path), OCFS2_JOURNAL_ACCESS_WRITE); if (ret) { mlog_errno(ret); goto out; } ret = ocfs2_rotate_subtree_left(inode, handle, left_path, right_path, subtree_root, dealloc, &deleted); if (ret == -EAGAIN) { /* * The rotation has to temporarily stop due to * the right subtree having an empty * extent. Pass it back to the caller for a * fixup. */ *empty_extent_path = right_path; right_path = NULL; goto out; } if (ret) { mlog_errno(ret); goto out; } /* * The subtree rotate might have removed records on * the rightmost edge. If so, then rotation is * complete. */ if (deleted) break; ocfs2_mv_path(left_path, right_path); ret = ocfs2_find_cpos_for_right_leaf(inode->i_sb, left_path, &right_cpos); if (ret) { mlog_errno(ret); goto out; } }out: ocfs2_free_path(right_path); ocfs2_free_path(left_path); return ret;}static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle, struct ocfs2_path *path, struct ocfs2_cached_dealloc_ctxt *dealloc){ int ret, subtree_index; u32 cpos; struct ocfs2_path *left_path = NULL; struct ocfs2_dinode *di; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *el; /* * XXX: This code assumes that the root is an inode, which is * true for now but may change as tree code gets generic. */ di = (struct ocfs2_dinode *)path_root_bh(path)->b_data; if (!OCFS2_IS_VALID_DINODE(di)) { ret = -EIO; ocfs2_error(inode->i_sb, "Inode %llu has invalid path root", (unsigned long long)OCFS2_I(inode)->ip_blkno); goto out; } /* * There's two ways we handle this depending on * whether path is the only existing one. */ ret = ocfs2_extend_rotate_transaction(handle, 0, handle->h_buffer_credits, path); if (ret) { mlog_errno(ret); goto out; } ret = ocfs2_journal_access_path(inode, handle, path); if (ret) { mlog_errno(ret); goto out; } ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb, path, &cpos); if (ret) { mlog_errno(ret); goto out; } if (cpos) { /* * We have a path to the left of this one - it needs * an update too. */ left_path = ocfs2_new_path(path_root_bh(path), path_root_el(path)); if (!left_path) { ret = -ENOMEM; mlog_errno(ret); goto out; } ret = ocfs2_find_path(inode, left_path, cpos); if (ret) { mlog_errno(ret); goto out; } ret = ocfs2_journal_access_path(inode, handle, left_path); if (ret) { mlog_errno(ret); goto out; } subtree_index = ocfs2_find_subtree_root(inode, left_path, path); ocfs2_unlink_subtree(inode, handle, left_path, path, subtree_index, dealloc); ocfs2_update_edge_lengths(inode,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -