/* * If the ecc fails, we return the error but otherwise * leave the filesystem running. We know any error is * local to this block.
*/
rc = ocfs2_validate_meta_ecc(sb, bh->b_data, &rb->rf_check); if (rc) {
mlog(ML_ERROR, "Checksum failed for refcount block %llu\n",
(unsignedlonglong)bh->b_blocknr); return rc;
}
if (!OCFS2_IS_VALID_REFCOUNT_BLOCK(rb)) {
rc = ocfs2_error(sb, "Refcount block #%llu has bad signature %.*s\n",
(unsignedlonglong)bh->b_blocknr, 7,
rb->rf_signature); goto out;
}
if (le64_to_cpu(rb->rf_blkno) != bh->b_blocknr) {
rc = ocfs2_error(sb, "Refcount block #%llu has an invalid rf_blkno of %llu\n",
(unsignedlonglong)bh->b_blocknr,
(unsignedlonglong)le64_to_cpu(rb->rf_blkno)); goto out;
}
if (le32_to_cpu(rb->rf_fs_generation) != OCFS2_SB(sb)->fs_generation) {
rc = ocfs2_error(sb, "Refcount block #%llu has an invalid rf_fs_generation of #%u\n",
(unsignedlonglong)bh->b_blocknr,
le32_to_cpu(rb->rf_fs_generation)); goto out;
}
out: return rc;
}
spin_lock(&osb->osb_lock); if (osb->osb_ref_tree_lru &&
osb->osb_ref_tree_lru->rf_blkno == rf_blkno)
tree = osb->osb_ref_tree_lru; else
tree = ocfs2_find_refcount_tree(osb, rf_blkno); if (tree) goto out;
spin_unlock(&osb->osb_lock);
new = ocfs2_allocate_refcount_tree(osb, rf_blkno); if (!new) {
ret = -ENOMEM;
mlog_errno(ret); return ret;
} /* * We need the generation to create the refcount tree lock and since * it isn't changed during the tree modification, we are safe here to * read without protection. * We also have to purge the cache after we create the lock since the * refcount block may have the stale data. It can only be trusted when * we hold the refcount lock.
*/
ret = ocfs2_read_refcount_block(&new->rf_ci, rf_blkno, &ref_root_bh); if (ret) {
mlog_errno(ret);
ocfs2_metadata_cache_exit(&new->rf_ci);
kfree(new); return ret;
}
staticint __ocfs2_lock_refcount_tree(struct ocfs2_super *osb, struct ocfs2_refcount_tree *tree, int rw)
{ int ret;
ret = ocfs2_refcount_lock(tree, rw); if (ret) {
mlog_errno(ret); goto out;
}
if (rw)
down_write(&tree->rf_sem); else
down_read(&tree->rf_sem);
out: return ret;
}
/* * Lock the refcount tree pointed by ref_blkno and return the tree. * In most case, we lock the tree and read the refcount block. * So read it here if the caller really needs it. * * If the tree has been re-created by other node, it will free the * old one and re-create it.
*/ int ocfs2_lock_refcount_tree(struct ocfs2_super *osb,
u64 ref_blkno, int rw, struct ocfs2_refcount_tree **ret_tree, struct buffer_head **ref_bh)
{ int ret, delete_tree = 0; struct ocfs2_refcount_tree *tree = NULL; struct buffer_head *ref_root_bh = NULL; struct ocfs2_refcount_block *rb;
again:
ret = ocfs2_get_refcount_tree(osb, ref_blkno, &tree); if (ret) {
mlog_errno(ret); return ret;
}
ocfs2_refcount_tree_get(tree);
ret = __ocfs2_lock_refcount_tree(osb, tree, rw); if (ret) {
mlog_errno(ret);
ocfs2_refcount_tree_put(tree); goto out;
}
ret = ocfs2_read_refcount_block(&tree->rf_ci, tree->rf_blkno,
&ref_root_bh); if (ret) {
mlog_errno(ret);
ocfs2_unlock_refcount_tree(osb, tree, rw); goto out;
}
rb = (struct ocfs2_refcount_block *)ref_root_bh->b_data; /* * If the refcount block has been freed and re-created, we may need * to recreate the refcount tree also. * * Here we just remove the tree from the rb-tree, and the last * kref holder will unlock and delete this refcount_tree. * Then we goto "again" and ocfs2_get_refcount_tree will create * the new refcount tree for us.
*/ if (tree->rf_generation != le32_to_cpu(rb->rf_generation)) { if (!tree->rf_removed) {
ocfs2_erase_refcount_tree_from_list(osb, tree);
tree->rf_removed = 1;
delete_tree = 1;
}
ocfs2_unlock_refcount_tree(osb, tree, rw); /* * We get an extra reference when we create the refcount * tree, so another put will destroy it.
*/ if (delete_tree)
ocfs2_refcount_tree_put(tree);
brelse(ref_root_bh);
ref_root_bh = NULL; goto again;
}
/* * We have to init the tree lock here since it will use * the generation number to create it.
*/
new_tree->rf_generation = le32_to_cpu(rb->rf_generation);
ocfs2_init_refcount_tree_lock(osb, new_tree, first_blkno,
new_tree->rf_generation);
spin_lock(&osb->osb_lock);
tree = ocfs2_find_refcount_tree(osb, first_blkno);
/* * We've just created a new refcount tree in this block. If * we found a refcount tree on the ocfs2_super, it must be * one we just deleted. We free the old tree before * inserting the new tree.
*/
BUG_ON(tree && tree->rf_generation == new_tree->rf_generation); if (tree)
ocfs2_erase_refcount_tree_from_list_no_lock(osb, tree);
ocfs2_insert_refcount_tree(osb, new_tree);
spin_unlock(&osb->osb_lock);
new_tree = NULL; if (tree)
ocfs2_refcount_tree_put(tree);
out_commit:
ocfs2_commit_trans(osb, handle);
out: if (new_tree) {
ocfs2_metadata_cache_exit(&new_tree->rf_ci);
kfree(new_tree);
}
brelse(new_bh); if (meta_ac)
ocfs2_free_alloc_context(meta_ac);
/* * If we are the last user, we need to free the block. * So lock the allocator ahead.
*/ if (le32_to_cpu(rb->rf_count) == 1) {
blk = le64_to_cpu(rb->rf_blkno);
bit = le16_to_cpu(rb->rf_suballoc_bit); if (rb->rf_suballoc_loc)
bg_blkno = le64_to_cpu(rb->rf_suballoc_loc); else
bg_blkno = ocfs2_which_suballoc_group(blk, bit);
alloc_inode = ocfs2_get_system_file_inode(osb,
EXTENT_ALLOC_SYSTEM_INODE,
le16_to_cpu(rb->rf_suballoc_slot)); if (!alloc_inode) {
ret = -ENOMEM;
mlog_errno(ret); goto out;
}
inode_lock(alloc_inode);
ret = ocfs2_inode_lock(alloc_inode, &alloc_bh, 1); if (ret) {
mlog_errno(ret); goto out_mutex;
}
credits += OCFS2_SUBALLOC_FREE;
}
handle = ocfs2_start_trans(osb, credits); if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
mlog_errno(ret); goto out_unlock;
}
ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
OCFS2_JOURNAL_ACCESS_WRITE); if (ret) {
mlog_errno(ret); goto out_commit;
}
ret = ocfs2_journal_access_rb(handle, &ref_tree->rf_ci, blk_bh,
OCFS2_JOURNAL_ACCESS_WRITE); if (ret) {
mlog_errno(ret); goto out_commit;
}
/* ok, cpos fail in this rec. Just return. */ if (ret_rec)
*ret_rec = *rec; goto out;
}
if (ret_rec) { /* We meet with a hole here, so fake the rec. */
ret_rec->r_cpos = cpu_to_le64(cpos);
ret_rec->r_refcount = 0; if (i < le16_to_cpu(rb->rf_records.rl_used) &&
le64_to_cpu(rec->r_cpos) < cpos + len)
ret_rec->r_clusters =
cpu_to_le32(le64_to_cpu(rec->r_cpos) - cpos); else
ret_rec->r_clusters = cpu_to_le32(len);
}
out:
*index = i;
}
/* * Try to remove refcount tree. The mechanism is: * 1) Check whether i_clusters == 0, if no, exit. * 2) check whether we have i_xattr_loc in dinode. if yes, exit. * 3) Check whether we have inline xattr stored outside, if yes, exit. * 4) Remove the tree.
*/ int ocfs2_try_remove_refcount_tree(struct inode *inode, struct buffer_head *di_bh)
{ int ret; struct ocfs2_inode_info *oi = OCFS2_I(inode); struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
if ((oi->ip_dyn_features & OCFS2_HAS_XATTR_FL) && di->i_xattr_loc) goto out;
if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL &&
ocfs2_has_inline_xattr_value_outside(inode, di)) goto out;
ret = ocfs2_remove_refcount_tree(inode, di_bh); if (ret)
mlog_errno(ret);
out:
up_write(&oi->ip_alloc_sem);
up_write(&oi->ip_xattr_sem); return 0;
}
/* * Find the end range for a leaf refcount block indicated by * el->l_recs[index].e_blkno.
*/ staticint ocfs2_get_refcount_cpos_end(struct ocfs2_caching_info *ci, struct buffer_head *ref_root_bh, struct ocfs2_extent_block *eb, struct ocfs2_extent_list *el, int index, u32 *cpos_end)
{ int ret, i, subtree_root;
u32 cpos;
u64 blkno; struct super_block *sb = ocfs2_metadata_cache_get_super(ci); struct ocfs2_path *left_path = NULL, *right_path = NULL; struct ocfs2_extent_tree et; struct ocfs2_extent_list *tmp_el;
if (index < le16_to_cpu(el->l_next_free_rec) - 1) { /* * We have a extent rec after index, so just use the e_cpos * of the next extent rec.
*/
*cpos_end = le32_to_cpu(el->l_recs[index+1].e_cpos); return 0;
}
if (!eb || !eb->h_next_leaf_blk) { /* * We are the last extent rec, so any high cpos should * be stored in this leaf refcount block.
*/
*cpos_end = UINT_MAX; return 0;
}
/* * If the extent block isn't the last one, we have to find * the subtree root between this extent block and the next * leaf extent block and get the corresponding e_cpos from * the subroot. Otherwise we may corrupt the b-tree.
*/
ocfs2_init_refcount_extent_tree(&et, ci, ref_root_bh);
left_path = ocfs2_new_path_from_et(&et); if (!left_path) {
ret = -ENOMEM;
mlog_errno(ret); goto out;
}
cpos = le32_to_cpu(eb->h_list.l_recs[index].e_cpos);
ret = ocfs2_find_path(ci, left_path, cpos); if (ret) {
mlog_errno(ret); goto out;
}
right_path = ocfs2_new_path_from_path(left_path); if (!right_path) {
ret = -ENOMEM;
mlog_errno(ret); goto out;
}
ret = ocfs2_find_cpos_for_right_leaf(sb, left_path, &cpos); if (ret) {
mlog_errno(ret); goto out;
}
ret = ocfs2_find_path(ci, right_path, cpos); if (ret) {
mlog_errno(ret); goto out;
}
/* * Given a cpos and len, try to find the refcount record which contains cpos. * 1. If cpos can be found in one refcount record, return the record. * 2. If cpos can't be found, return a fake record which start from cpos * and end at a small value between cpos+len and start of the next record. * This fake record has r_refcount = 0.
*/ staticint ocfs2_get_refcount_rec(struct ocfs2_caching_info *ci, struct buffer_head *ref_root_bh,
u64 cpos, unsignedint len, struct ocfs2_refcount_rec *ret_rec, int *index, struct buffer_head **ret_bh)
{ int ret = 0, i, found;
u32 low_cpos, cpos_end; struct ocfs2_extent_list *el; struct ocfs2_extent_rec *rec = NULL; struct ocfs2_extent_block *eb = NULL; struct buffer_head *eb_bh = NULL, *ref_leaf_bh = NULL; struct super_block *sb = ocfs2_metadata_cache_get_super(ci); struct ocfs2_refcount_block *rb =
(struct ocfs2_refcount_block *)ref_root_bh->b_data;
el = &rb->rf_list;
low_cpos = cpos & OCFS2_32BIT_POS_MASK;
if (el->l_tree_depth) {
ret = ocfs2_find_leaf(ci, el, low_cpos, &eb_bh); if (ret) {
mlog_errno(ret); goto out;
}
eb = (struct ocfs2_extent_block *) eb_bh->b_data;
el = &eb->h_list;
if (el->l_tree_depth) {
ret = ocfs2_error(sb, "refcount tree %llu has non zero tree depth in leaf btree tree block %llu\n",
(unsignedlonglong)ocfs2_metadata_cache_owner(ci),
(unsignedlonglong)eb_bh->b_blocknr); goto out;
}
}
found = 0; for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) {
rec = &el->l_recs[i];
if (le32_to_cpu(rec->e_cpos) <= low_cpos) {
found = 1; break;
}
}
if (found) {
ret = ocfs2_get_refcount_cpos_end(ci, ref_root_bh,
eb, el, i, &cpos_end); if (ret) {
mlog_errno(ret); goto out;
}
if (cpos_end < low_cpos + len)
len = cpos_end - low_cpos;
}
ret = ocfs2_read_refcount_block(ci, le64_to_cpu(rec->e_blkno),
&ref_leaf_bh); if (ret) {
mlog_errno(ret); goto out;
}
/* * Merge the refcount rec if we are contiguous with the adjacent recs.
*/ staticvoid ocfs2_refcount_rec_merge(struct ocfs2_refcount_block *rb, int index)
{ enum ocfs2_ref_rec_contig contig =
ocfs2_refcount_rec_contig(rb, index);
ret = ocfs2_journal_access_rb(handle, ci, ref_root_bh,
OCFS2_JOURNAL_ACCESS_WRITE); if (ret) {
mlog_errno(ret); goto out;
}
ret = ocfs2_claim_metadata(handle, meta_ac, 1, &suballoc_loc,
&suballoc_bit_start, &num_got,
&blkno); if (ret) {
mlog_errno(ret); goto out;
}
new_bh = sb_getblk(sb, blkno); if (new_bh == NULL) {
ret = -ENOMEM;
mlog_errno(ret); goto out;
}
ocfs2_set_new_buffer_uptodate(ci, new_bh);
ret = ocfs2_journal_access_rb(handle, ci, new_bh,
OCFS2_JOURNAL_ACCESS_CREATE); if (ret) {
mlog_errno(ret); goto out;
}
/* * Initialize ocfs2_refcount_block. * It should contain the same information as the old root. * so just memcpy it and change the corresponding field.
*/
memcpy(new_bh->b_data, ref_root_bh->b_data, sb->s_blocksize);
if (l_cpos > r_cpos) return 1; if (l_cpos < r_cpos) return -1; return 0;
}
/* * The refcount cpos are ordered by their 64bit cpos, * But we will use the low 32 bit to be the e_cpos in the b-tree. * So we need to make sure that this pos isn't intersected with others. * * Note: The refcount block is already sorted by their low 32 bit cpos, * So just try the middle pos first, and we will exit when we find * the good position.
*/ staticint ocfs2_find_refcount_split_pos(struct ocfs2_refcount_list *rl,
u32 *split_pos, int *split_index)
{ int num_used = le16_to_cpu(rl->rl_used); int delta, middle = num_used / 2;
/* * XXX: Improvement later. * If we know all the high 32 bit cpos is the same, no need to sort. * * In order to make the whole process safe, we do: * 1. sort the entries by their low 32 bit cpos first so that we can * find the split cpos easily. * 2. call ocfs2_insert_extent to insert the new refcount block. * 3. move the refcount rec to the new block. * 4. sort the entries by their 64 bit cpos. * 5. dirty the new_rb and rb.
*/
sort(&rl->rl_recs, le16_to_cpu(rl->rl_used), sizeof(struct ocfs2_refcount_rec),
cmp_refcount_rec_by_low_cpos, NULL);
ret = ocfs2_find_refcount_split_pos(rl, &cpos, &split_index); if (ret) {
mlog_errno(ret); return ret;
}
new_rb->rf_cpos = cpu_to_le32(cpos);
/* move refcount records starting from split_index to the new block. */
num_moved = le16_to_cpu(rl->rl_used) - split_index;
memcpy(new_rl->rl_recs, &rl->rl_recs[split_index],
num_moved * sizeof(struct ocfs2_refcount_rec));
/*ok, remove the entries we just moved over to the other block. */
memset(&rl->rl_recs[split_index], 0,
num_moved * sizeof(struct ocfs2_refcount_rec));
/* change old and new rl_used accordingly. */
le16_add_cpu(&rl->rl_used, -num_moved);
new_rl->rl_used = cpu_to_le16(num_moved);
/* Insert the new leaf block with the specific offset cpos. */
ret = ocfs2_insert_extent(handle, &ref_et, new_cpos, new_bh->b_blocknr,
1, 0, meta_ac); if (ret)
mlog_errno(ret);
if (ref_root_bh == ref_leaf_bh) { /* * the old root bh hasn't been expanded to a b-tree, * so expand it first.
*/
ret = ocfs2_expand_inline_ref_root(handle, ci, ref_root_bh,
&expand_bh, meta_ac); if (ret) {
mlog_errno(ret); goto out;
}
} else {
expand_bh = ref_leaf_bh;
get_bh(expand_bh);
}
/* Now add a new refcount block into the tree.*/
ret = ocfs2_new_leaf_refcount_block(handle, ci, ref_root_bh,
expand_bh, meta_ac); if (ret)
mlog_errno(ret);
out:
brelse(expand_bh); return ret;
}
/* * Adjust the extent rec in b-tree representing ref_leaf_bh. * * Only called when we have inserted a new refcount rec at index 0 * which means ocfs2_extent_rec.e_cpos may need some change.
*/ staticint ocfs2_adjust_refcount_rec(handle_t *handle, struct ocfs2_caching_info *ci, struct buffer_head *ref_root_bh, struct buffer_head *ref_leaf_bh, struct ocfs2_refcount_rec *rec)
{ int ret = 0, i;
u32 new_cpos, old_cpos; struct ocfs2_path *path = NULL; struct ocfs2_extent_tree et; struct ocfs2_refcount_block *rb =
(struct ocfs2_refcount_block *)ref_root_bh->b_data; struct ocfs2_extent_list *el;
if (!(le32_to_cpu(rb->rf_flags) & OCFS2_REFCOUNT_TREE_FL)) goto out;
path = ocfs2_new_path_from_et(&et); if (!path) {
ret = -ENOMEM;
mlog_errno(ret); goto out;
}
ret = ocfs2_find_path(ci, path, old_cpos); if (ret) {
mlog_errno(ret); goto out;
}
/* * 2 more credits, one for the leaf refcount block, one for * the extent block contains the extent rec.
*/
ret = ocfs2_extend_trans(handle, 2); if (ret < 0) {
mlog_errno(ret); goto out;
}
ret = ocfs2_journal_access_rb(handle, ci, ref_leaf_bh,
OCFS2_JOURNAL_ACCESS_WRITE); if (ret < 0) {
mlog_errno(ret); goto out;
}
ret = ocfs2_journal_access_eb(handle, ci, path_leaf_bh(path),
OCFS2_JOURNAL_ACCESS_WRITE); if (ret < 0) {
mlog_errno(ret); goto out;
}
/* change the leaf extent block first. */
el = path_leaf_el(path);
for (i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) if (le32_to_cpu(el->l_recs[i].e_cpos) == old_cpos) break;
BUG_ON(i == le16_to_cpu(el->l_next_free_rec));
el->l_recs[i].e_cpos = cpu_to_le32(new_cpos);
/* change the r_cpos in the leaf block. */
rb->rf_cpos = cpu_to_le32(new_cpos);
if (index == 0) {
ret = ocfs2_adjust_refcount_rec(handle, ci,
ref_root_bh,
ref_leaf_bh, rec); if (ret)
mlog_errno(ret);
}
out:
brelse(new_bh); return ret;
}
/* * Split the refcount_rec indexed by "index" in ref_leaf_bh. * This is much simple than our b-tree code. * split_rec is the new refcount rec we want to insert. * If split_rec->r_refcount > 0, we are changing the refcount(in case we * increase refcount or decrease a refcount to non-zero). * If split_rec->r_refcount == 0, we are punching a hole in current refcount * rec( in case we decrease a refcount to zero).
*/ staticint ocfs2_split_refcount_rec(handle_t *handle, struct ocfs2_caching_info *ci, struct buffer_head *ref_root_bh, struct buffer_head *ref_leaf_bh, struct ocfs2_refcount_rec *split_rec, int index, int merge, struct ocfs2_alloc_context *meta_ac, struct ocfs2_cached_dealloc_ctxt *dealloc)
{ int ret, recs_need;
u32 len; struct ocfs2_refcount_block *rb =
(struct ocfs2_refcount_block *)ref_leaf_bh->b_data; struct ocfs2_refcount_list *rf_list = &rb->rf_records; struct ocfs2_refcount_rec *orig_rec = &rf_list->rl_recs[index]; struct ocfs2_refcount_rec *tail_rec = NULL; struct buffer_head *new_bh = NULL;
/* * If we just need to split the header or tail clusters, * no more recs are needed, just split is OK. * Otherwise we at least need one new recs.
*/ if (!split_rec->r_refcount &&
(split_rec->r_cpos == orig_rec->r_cpos ||
le64_to_cpu(split_rec->r_cpos) +
le32_to_cpu(split_rec->r_clusters) ==
le64_to_cpu(orig_rec->r_cpos) + le32_to_cpu(orig_rec->r_clusters)))
recs_need = 0; else
recs_need = 1;
/* * We need one more rec if we split in the middle and the new rec have * some refcount in it.
*/ if (split_rec->r_refcount &&
(split_rec->r_cpos != orig_rec->r_cpos &&
le64_to_cpu(split_rec->r_cpos) +
le32_to_cpu(split_rec->r_clusters) !=
le64_to_cpu(orig_rec->r_cpos) + le32_to_cpu(orig_rec->r_clusters)))
recs_need++;
/* If the leaf block don't have enough record, expand it. */ if (le16_to_cpu(rf_list->rl_used) + recs_need >
le16_to_cpu(rf_list->rl_count)) { struct ocfs2_refcount_rec tmp_rec;
u64 cpos = le64_to_cpu(orig_rec->r_cpos);
len = le32_to_cpu(orig_rec->r_clusters);
ret = ocfs2_expand_refcount_tree(handle, ci, ref_root_bh,
ref_leaf_bh, meta_ac); if (ret) {
mlog_errno(ret); goto out;
}
/* * We have to re-get it since now cpos may be moved to * another leaf block.
*/
ret = ocfs2_get_refcount_rec(ci, ref_root_bh,
cpos, len, &tmp_rec, &index,
&new_bh); if (ret) {
mlog_errno(ret); goto out;
}
ret = ocfs2_journal_access_rb(handle, ci, ref_leaf_bh,
OCFS2_JOURNAL_ACCESS_WRITE); if (ret) {
mlog_errno(ret); goto out;
}
/* * We have calculated out how many new records we need and store * in recs_need, so spare enough space first by moving the records * after "index" to the end.
*/ if (index != le16_to_cpu(rf_list->rl_used) - 1)
memmove(&rf_list->rl_recs[index + 1 + recs_need],
&rf_list->rl_recs[index + 1],
(le16_to_cpu(rf_list->rl_used) - index - 1) * sizeof(struct ocfs2_refcount_rec));
len = (le64_to_cpu(orig_rec->r_cpos) +
le32_to_cpu(orig_rec->r_clusters)) -
(le64_to_cpu(split_rec->r_cpos) +
le32_to_cpu(split_rec->r_clusters));
/* * If we have "len", the we will split in the tail and move it * to the end of the space we have just spared.
*/ if (len) {
tail_rec = &rf_list->rl_recs[index + recs_need];
/* * If the split pos isn't the same as the original one, we need to * split in the head. * * Note: We have the chance that split_rec.r_refcount = 0, * recs_need = 0 and len > 0, which means we just cut the head from * the orig_rec and in that case we have done some modification in * orig_rec above, so the check for r_cpos is faked.
*/ if (split_rec->r_cpos != orig_rec->r_cpos && tail_rec != orig_rec) {
len = le64_to_cpu(split_rec->r_cpos) -
le64_to_cpu(orig_rec->r_cpos);
orig_rec->r_clusters = cpu_to_le32(len);
index++;
}
while (len) {
ret = ocfs2_get_refcount_rec(ci, ref_root_bh,
cpos, len, &rec, &index,
&ref_leaf_bh); if (ret) {
mlog_errno(ret); goto out;
}
set_len = le32_to_cpu(rec.r_clusters);
/* * Here we may meet with 3 situations: * * 1. If we find an already existing record, and the length * is the same, cool, we just need to increase the r_refcount * and it is OK. * 2. If we find a hole, just insert it with r_refcount = 1. * 3. If we are in the middle of one extent record, split * it.
*/ if (rec.r_refcount && le64_to_cpu(rec.r_cpos) == cpos &&
set_len <= len) {
trace_ocfs2_increase_refcount_change(
(unsignedlonglong)cpos, set_len,
le32_to_cpu(rec.r_refcount));
ret = ocfs2_change_refcount_rec(handle, ci,
ref_leaf_bh, index,
merge, 1); if (ret) {
mlog_errno(ret); goto out;
}
} elseif (!rec.r_refcount) {
rec.r_refcount = cpu_to_le32(1);
ocfs2_init_refcount_extent_tree(&et, ci, ref_root_bh);
ret = ocfs2_remove_extent(handle, &et, le32_to_cpu(rb->rf_cpos),
1, meta_ac, dealloc); if (ret) {
mlog_errno(ret); goto out;
}
ocfs2_remove_from_cache(ci, ref_leaf_bh);
/* * add the freed block to the dealloc so that it will be freed * when we run dealloc.
*/
ret = ocfs2_cache_block_dealloc(dealloc, EXTENT_ALLOC_SYSTEM_INODE,
le16_to_cpu(rb->rf_suballoc_slot),
le64_to_cpu(rb->rf_suballoc_loc),
le64_to_cpu(rb->rf_blkno),
le16_to_cpu(rb->rf_suballoc_bit)); if (ret) {
mlog_errno(ret); goto out;
}
ret = ocfs2_journal_access_rb(handle, ci, ref_root_bh,
OCFS2_JOURNAL_ACCESS_WRITE); if (ret) {
mlog_errno(ret); goto out;
}
/* * check whether we need to restore the root refcount block if * there is no leaf extent block at atll.
*/ if (!rb->rf_list.l_next_free_rec) {
BUG_ON(rb->rf_clusters);
/* Remove the leaf refcount block if it contains no refcount record. */ if (!rb->rf_records.rl_used && ref_leaf_bh != ref_root_bh) {
ret = ocfs2_remove_refcount_extent(handle, ci, ref_root_bh,
ref_leaf_bh, meta_ac,
dealloc); if (ret)
mlog_errno(ret);
}
/* Caller must hold refcount tree lock. */ int ocfs2_decrease_refcount(struct inode *inode,
handle_t *handle, u32 cpos, u32 len, struct ocfs2_alloc_context *meta_ac, struct ocfs2_cached_dealloc_ctxt *dealloc, intdelete)
{ int ret;
u64 ref_blkno; struct buffer_head *ref_root_bh = NULL; struct ocfs2_refcount_tree *tree;
BUG_ON(!ocfs2_is_refcount_inode(inode));
ret = ocfs2_get_refcount_block(inode, &ref_blkno); if (ret) {
mlog_errno(ret); goto out;
}
ret = ocfs2_get_refcount_tree(OCFS2_SB(inode->i_sb), ref_blkno, &tree); if (ret) {
mlog_errno(ret); goto out;
}
ret = ocfs2_read_refcount_block(&tree->rf_ci, tree->rf_blkno,
&ref_root_bh); if (ret) {
mlog_errno(ret); goto out;
}
ret = __ocfs2_decrease_refcount(handle, &tree->rf_ci, ref_root_bh,
cpos, len, meta_ac, dealloc, delete); if (ret)
mlog_errno(ret);
out:
brelse(ref_root_bh); return ret;
}
/* * Mark the already-existing extent at cpos as refcounted for len clusters. * This adds the refcount extent flag. * * If the existing extent is larger than the request, initiate a * split. An attempt will be made at merging with adjacent extents. * * The caller is responsible for passing down meta_ac if we'll need it.
*/ staticint ocfs2_mark_extent_refcounted(struct inode *inode, struct ocfs2_extent_tree *et,
handle_t *handle, u32 cpos,
u32 len, u32 phys, struct ocfs2_alloc_context *meta_ac, struct ocfs2_cached_dealloc_ctxt *dealloc)
{ int ret;
if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) {
ret = ocfs2_error(inode->i_sb, "Inode %lu want to use refcount tree, but the feature bit is not set in the super block\n",
inode->i_ino); goto out;
}
ret = ocfs2_change_extent_flag(handle, et, cpos,
len, phys, meta_ac, dealloc,
OCFS2_EXT_REFCOUNTED, 0); if (ret)
mlog_errno(ret);
out: return ret;
}
/* * Given some contiguous physical clusters, calculate what we need * for modifying their refcount.
*/ staticint ocfs2_calc_refcount_meta_credits(struct super_block *sb, struct ocfs2_caching_info *ci, struct buffer_head *ref_root_bh,
u64 start_cpos,
u32 clusters, int *meta_add, int *credits)
{ int ret = 0, index, ref_blocks = 0, recs_add = 0;
u64 cpos = start_cpos; struct ocfs2_refcount_block *rb; struct ocfs2_refcount_rec rec; struct buffer_head *ref_leaf_bh = NULL, *prev_bh = NULL;
u32 len;
while (clusters) {
ret = ocfs2_get_refcount_rec(ci, ref_root_bh,
cpos, clusters, &rec,
&index, &ref_leaf_bh); if (ret) {
mlog_errno(ret); goto out;
}
if (ref_leaf_bh != prev_bh) { /* * Now we encounter a new leaf block, so calculate * whether we need to extend the old leaf.
*/ if (prev_bh) {
rb = (struct ocfs2_refcount_block *)
prev_bh->b_data;
if (le16_to_cpu(rb->rf_records.rl_used) +
recs_add >
le16_to_cpu(rb->rf_records.rl_count))
ref_blocks++;
}
len = min((u64)cpos + clusters, le64_to_cpu(rec.r_cpos) +
le32_to_cpu(rec.r_clusters)) - cpos; /* * We record all the records which will be inserted to the * same refcount block, so that we can tell exactly whether * we need a new refcount block or not. * * If we will insert a new one, this is easy and only happens * during adding refcounted flag to the extent, so we don't * have a chance of splitting. We just need one record. * * If the refcount rec already exists, that would be a little * complicated. we may have to: * 1) split at the beginning if the start pos isn't aligned. * we need 1 more record in this case. * 2) split int the end if the end pos isn't aligned. * we need 1 more record in this case. * 3) split in the middle because of file system fragmentation. * we need 2 more records in this case(we can't detect this * beforehand, so always think of the worst case).
*/ if (rec.r_refcount) {
recs_add += 2; /* Check whether we need a split at the beginning. */ if (cpos == start_cpos &&
cpos != le64_to_cpu(rec.r_cpos))
recs_add++;
/* Check whether we need a split in the end. */ if (cpos + clusters < le64_to_cpu(rec.r_cpos) +
le32_to_cpu(rec.r_clusters))
recs_add++;
} else
recs_add++;
if (prev_bh) {
rb = (struct ocfs2_refcount_block *)prev_bh->b_data;
if (le16_to_cpu(rb->rf_records.rl_used) + recs_add >
le16_to_cpu(rb->rf_records.rl_count))
ref_blocks++;
*credits += 1;
}
if (!ref_blocks) goto out;
*meta_add += ref_blocks;
*credits += ref_blocks;
/* * So we may need ref_blocks to insert into the tree. * That also means we need to change the b-tree and add that number * of records since we never merge them. * We need one more block for expansion since the new created leaf * block is also full and needs split.
*/
rb = (struct ocfs2_refcount_block *)ref_root_bh->b_data; if (le32_to_cpu(rb->rf_flags) & OCFS2_REFCOUNT_TREE_FL) { struct ocfs2_extent_tree et;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.