📄 alloc.c
字号:
* * ocfs2_shift_tree_depth() uses this to determine the # clusters * value for the new topmost tree record. */static inline u32 ocfs2_sum_rightmost_rec(struct ocfs2_extent_list *el){ int i; i = le16_to_cpu(el->l_next_free_rec) - 1; return le32_to_cpu(el->l_recs[i].e_cpos) + ocfs2_rec_clusters(el, &el->l_recs[i]);}/* * Add an entire tree branch to our inode. eb_bh is the extent block * to start at, if we don't want to start the branch at the dinode * structure. * * last_eb_bh is required as we have to update it's next_leaf pointer * for the new last extent block. * * the new branch will be 'empty' in the sense that every block will * contain a single record with cluster count == 0. */static int ocfs2_add_branch(struct ocfs2_super *osb, handle_t *handle, struct inode *inode, struct buffer_head *fe_bh, struct buffer_head *eb_bh, struct buffer_head **last_eb_bh, struct ocfs2_alloc_context *meta_ac){ int status, new_blocks, i; u64 next_blkno, new_last_eb_blk; struct buffer_head *bh; struct buffer_head **new_eb_bhs = NULL; struct ocfs2_dinode *fe; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *eb_el; struct ocfs2_extent_list *el; u32 new_cpos; mlog_entry_void(); BUG_ON(!last_eb_bh || !*last_eb_bh); fe = (struct ocfs2_dinode *) fe_bh->b_data; if (eb_bh) { eb = (struct ocfs2_extent_block *) eb_bh->b_data; el = &eb->h_list; } else el = &fe->id2.i_list; /* we never add a branch to a leaf. */ BUG_ON(!el->l_tree_depth); new_blocks = le16_to_cpu(el->l_tree_depth); /* allocate the number of new eb blocks we need */ new_eb_bhs = kcalloc(new_blocks, sizeof(struct buffer_head *), GFP_KERNEL); if (!new_eb_bhs) { status = -ENOMEM; mlog_errno(status); goto bail; } status = ocfs2_create_new_meta_bhs(osb, handle, inode, new_blocks, meta_ac, new_eb_bhs); if (status < 0) { mlog_errno(status); goto bail; } eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data; new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list); /* Note: new_eb_bhs[new_blocks - 1] is the guy which will be * linked with the rest of the tree. * conversly, new_eb_bhs[0] is the new bottommost leaf. * * when we leave the loop, new_last_eb_blk will point to the * newest leaf, and next_blkno will point to the topmost extent * block. */ next_blkno = new_last_eb_blk = 0; for(i = 0; i < new_blocks; i++) { bh = new_eb_bhs[i]; eb = (struct ocfs2_extent_block *) bh->b_data; if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) { OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb); status = -EIO; goto bail; } eb_el = &eb->h_list; status = ocfs2_journal_access(handle, inode, bh, OCFS2_JOURNAL_ACCESS_CREATE); if (status < 0) { mlog_errno(status); goto bail; } eb->h_next_leaf_blk = 0; eb_el->l_tree_depth = cpu_to_le16(i); eb_el->l_next_free_rec = cpu_to_le16(1); /* * This actually counts as an empty extent as * c_clusters == 0 */ eb_el->l_recs[0].e_cpos = cpu_to_le32(new_cpos); eb_el->l_recs[0].e_blkno = cpu_to_le64(next_blkno); /* * eb_el isn't always an interior node, but even leaf * nodes want a zero'd flags and reserved field so * this gets the whole 32 bits regardless of use. */ eb_el->l_recs[0].e_int_clusters = cpu_to_le32(0); if (!eb_el->l_tree_depth) new_last_eb_blk = le64_to_cpu(eb->h_blkno); status = ocfs2_journal_dirty(handle, bh); if (status < 0) { mlog_errno(status); goto bail; } next_blkno = le64_to_cpu(eb->h_blkno); } /* This is a bit hairy. We want to update up to three blocks * here without leaving any of them in an inconsistent state * in case of error. We don't have to worry about * journal_dirty erroring as it won't unless we've aborted the * handle (in which case we would never be here) so reserving * the write with journal_access is all we need to do. */ status = ocfs2_journal_access(handle, inode, *last_eb_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } status = ocfs2_journal_access(handle, inode, fe_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } if (eb_bh) { status = ocfs2_journal_access(handle, inode, eb_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } } /* Link the new branch into the rest of the tree (el will * either be on the fe, or the extent block passed in. */ i = le16_to_cpu(el->l_next_free_rec); el->l_recs[i].e_blkno = cpu_to_le64(next_blkno); el->l_recs[i].e_cpos = cpu_to_le32(new_cpos); el->l_recs[i].e_int_clusters = 0; le16_add_cpu(&el->l_next_free_rec, 1); /* fe needs a new last extent block pointer, as does the * next_leaf on the previously last-extent-block. */ fe->i_last_eb_blk = cpu_to_le64(new_last_eb_blk); eb = (struct ocfs2_extent_block *) (*last_eb_bh)->b_data; eb->h_next_leaf_blk = cpu_to_le64(new_last_eb_blk); status = ocfs2_journal_dirty(handle, *last_eb_bh); if (status < 0) mlog_errno(status); status = ocfs2_journal_dirty(handle, fe_bh); if (status < 0) mlog_errno(status); if (eb_bh) { status = ocfs2_journal_dirty(handle, eb_bh); if (status < 0) mlog_errno(status); } /* * Some callers want to track the rightmost leaf so pass it * back here. */ brelse(*last_eb_bh); get_bh(new_eb_bhs[0]); *last_eb_bh = new_eb_bhs[0]; status = 0;bail: if (new_eb_bhs) { for (i = 0; i < new_blocks; i++) if (new_eb_bhs[i]) brelse(new_eb_bhs[i]); kfree(new_eb_bhs); } mlog_exit(status); return status;}/* * adds another level to the allocation tree. * returns back the new extent block so you can add a branch to it * after this call. */static int ocfs2_shift_tree_depth(struct ocfs2_super *osb, handle_t *handle, struct inode *inode, struct buffer_head *fe_bh, struct ocfs2_alloc_context *meta_ac, struct buffer_head **ret_new_eb_bh){ int status, i; u32 new_clusters; struct buffer_head *new_eb_bh = NULL; struct ocfs2_dinode *fe; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *fe_el; struct ocfs2_extent_list *eb_el; mlog_entry_void(); status = ocfs2_create_new_meta_bhs(osb, handle, inode, 1, meta_ac, &new_eb_bh); if (status < 0) { mlog_errno(status); goto bail; } eb = (struct ocfs2_extent_block *) new_eb_bh->b_data; if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) { OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb); status = -EIO; goto bail; } eb_el = &eb->h_list; fe = (struct ocfs2_dinode *) fe_bh->b_data; fe_el = &fe->id2.i_list; status = ocfs2_journal_access(handle, inode, new_eb_bh, OCFS2_JOURNAL_ACCESS_CREATE); if (status < 0) { mlog_errno(status); goto bail; } /* copy the fe data into the new extent block */ eb_el->l_tree_depth = fe_el->l_tree_depth; eb_el->l_next_free_rec = fe_el->l_next_free_rec; for(i = 0; i < le16_to_cpu(fe_el->l_next_free_rec); i++) eb_el->l_recs[i] = fe_el->l_recs[i]; status = ocfs2_journal_dirty(handle, new_eb_bh); if (status < 0) { mlog_errno(status); goto bail; } status = ocfs2_journal_access(handle, inode, fe_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } new_clusters = ocfs2_sum_rightmost_rec(eb_el); /* update fe now */ le16_add_cpu(&fe_el->l_tree_depth, 1); fe_el->l_recs[0].e_cpos = 0; fe_el->l_recs[0].e_blkno = eb->h_blkno; fe_el->l_recs[0].e_int_clusters = cpu_to_le32(new_clusters); for(i = 1; i < le16_to_cpu(fe_el->l_next_free_rec); i++) memset(&fe_el->l_recs[i], 0, sizeof(struct ocfs2_extent_rec)); fe_el->l_next_free_rec = cpu_to_le16(1); /* If this is our 1st tree depth shift, then last_eb_blk * becomes the allocated extent block */ if (fe_el->l_tree_depth == cpu_to_le16(1)) fe->i_last_eb_blk = eb->h_blkno; status = ocfs2_journal_dirty(handle, fe_bh); if (status < 0) { mlog_errno(status); goto bail; } *ret_new_eb_bh = new_eb_bh; new_eb_bh = NULL; status = 0;bail: if (new_eb_bh) brelse(new_eb_bh); mlog_exit(status); return status;}/* * Should only be called when there is no space left in any of the * leaf nodes. What we want to do is find the lowest tree depth * non-leaf extent block with room for new records. There are three * valid results of this search: * * 1) a lowest extent block is found, then we pass it back in * *lowest_eb_bh and return '0' * * 2) the search fails to find anything, but the dinode has room. We * pass NULL back in *lowest_eb_bh, but still return '0' * * 3) the search fails to find anything AND the dinode is full, in * which case we return > 0 * * return status < 0 indicates an error. */static int ocfs2_find_branch_target(struct ocfs2_super *osb, struct inode *inode, struct buffer_head *fe_bh, struct buffer_head **target_bh){ int status = 0, i; u64 blkno; struct ocfs2_dinode *fe; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *el; struct buffer_head *bh = NULL; struct buffer_head *lowest_bh = NULL; mlog_entry_void(); *target_bh = NULL; fe = (struct ocfs2_dinode *) fe_bh->b_data; el = &fe->id2.i_list; while(le16_to_cpu(el->l_tree_depth) > 1) { if (le16_to_cpu(el->l_next_free_rec) == 0) { ocfs2_error(inode->i_sb, "Dinode %llu has empty " "extent list (next_free_rec == 0)", (unsigned long long)OCFS2_I(inode)->ip_blkno); status = -EIO; goto bail; } i = le16_to_cpu(el->l_next_free_rec) - 1; blkno = le64_to_cpu(el->l_recs[i].e_blkno); if (!blkno) { ocfs2_error(inode->i_sb, "Dinode %llu has extent " "list where extent # %d has no physical " "block start", (unsigned long long)OCFS2_I(inode)->ip_blkno, i); status = -EIO; goto bail; } if (bh) { brelse(bh); bh = NULL; } status = ocfs2_read_block(osb, blkno, &bh, OCFS2_BH_CACHED, inode); if (status < 0) { mlog_errno(status); goto bail; } eb = (struct ocfs2_extent_block *) bh->b_data; if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) { OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb); status = -EIO; goto bail; } el = &eb->h_list; if (le16_to_cpu(el->l_next_free_rec) < le16_to_cpu(el->l_count)) { if (lowest_bh) brelse(lowest_bh); lowest_bh = bh; get_bh(lowest_bh); } } /* If we didn't find one and the fe doesn't have any room, * then return '1' */ if (!lowest_bh && (fe->id2.i_list.l_next_free_rec == fe->id2.i_list.l_count)) status = 1; *target_bh = lowest_bh;bail: if (bh) brelse(bh); mlog_exit(status); return status;}/* * Grow a b-tree so that it has more records. * * We might shift the tree depth in which case existing paths should * be considered invalid. * * Tree depth after the grow is returned via *final_depth. * * *last_eb_bh will be updated by ocfs2_add_branch(). */static int ocfs2_grow_tree(struct inode *inode, handle_t *handle, struct buffer_head *di_bh, int *final_depth, struct buffer_head **last_eb_bh, struct ocfs2_alloc_context *meta_ac){ int ret, shift; struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; int depth = le16_to_cpu(di->id2.i_list.l_tree_depth); struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct buffer_head *bh = NULL; BUG_ON(meta_ac == NULL); shift = ocfs2_find_branch_target(osb, inode, di_bh, &bh); if (shift < 0) { ret = shift; mlog_errno(ret); goto out; } /* We traveled all the way to the bottom of the allocation tree * and didn't find room for any more extents - we need to add * another tree level */ if (shift) { BUG_ON(bh); mlog(0, "need to shift tree depth (current = %d)\n", depth); /* ocfs2_shift_tree_depth will return us a buffer with * the new extent block (so we can pass that to * ocfs2_add_branch). */ ret = ocfs2_shift_tree_depth(osb, handle, inode, di_bh, meta_ac, &bh); if (ret < 0) { mlog_errno(ret); goto out; } depth++; if (depth == 1) { /* * Special case: we have room now if we shifted from * tree_depth 0, so no more work needs to be done. * * We won't be calling add_branch, so pass * back *last_eb_bh as the new leaf. At depth * zero, it should always be null so there's * no reason to brelse. */ BUG_ON(*last_eb_bh); get_bh(bh); *last_eb_bh = bh; goto out; } } /* call ocfs2_add_branch to add the final part of the tree with * the new data. */ mlog(0, "add branch. bh = %p\n", bh); ret = ocfs2_add_branch(osb, handle, inode, di_bh, bh, last_eb_bh, meta_ac); if (ret < 0) { mlog_errno(ret); goto out; }out: if (final_depth) *final_depth = depth; brelse(bh); return ret;}/* * This is only valid for leaf nodes, which are the only ones that can * have empty extents anyway. */static inline int ocfs2_is_empty_extent(struct ocfs2_extent_rec *rec){ return !rec->e_leaf_clusters;}/* * This function will discard the rightmost extent record. */static void ocfs2_shift_records_right(struct ocfs2_extent_list *el){ int next_free = le16_to_cpu(el->l_next_free_rec); int count = le16_to_cpu(el->l_count); unsigned int num_bytes; BUG_ON(!next_free);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -