errcode_t ocfs2_get_last_cluster_offset(ocfs2_filesys *fs, struct ocfs2_dinode *di, uint32_t *v_cluster) { errcode_t ret = 0; char *buf = NULL; struct ocfs2_extent_list *el = NULL; struct ocfs2_extent_rec *er = NULL; el = &di->id2.i_list; *v_cluster = 0; if (!el->l_next_free_rec) return 0; if (el->l_tree_depth) { ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto bail; ret = ocfs2_read_extent_block(fs, di->i_last_eb_blk, buf); if (ret) goto bail; el = &((struct ocfs2_extent_block *)buf)->h_list; if (!el->l_next_free_rec || (el->l_next_free_rec == 1 && ocfs2_is_empty_extent(&el->l_recs[0]))) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto bail; } } er = &el->l_recs[el->l_next_free_rec - 1]; *v_cluster = er->e_cpos + er->e_leaf_clusters - 1; bail: if (buf) ocfs2_free(&buf); return ret; }
static errcode_t change_sub_alloc_slot(ocfs2_filesys *fs, uint64_t blkno, struct relink_ctxt *ctxt) { errcode_t ret; struct ocfs2_dinode *di = NULL; struct ocfs2_extent_block *eb = NULL; if (ctxt->inode_type == EXTENT_ALLOC_SYSTEM_INODE) { /* change sub alloc bit in the extent block. */ ret = ocfs2_read_extent_block(fs, blkno, ctxt->ex_buf); if (ret) goto bail; eb = (struct ocfs2_extent_block *)ctxt->ex_buf; eb->h_suballoc_slot = ctxt->new_slot; ret = ocfs2_write_extent_block(fs, blkno, ctxt->ex_buf); if (ret) goto bail; } else { /* change sub alloc bit in the inode. */ ret = ocfs2_read_inode(fs, blkno, ctxt->ex_buf); if (ret) goto bail; di = (struct ocfs2_dinode *)ctxt->ex_buf; di->i_suballoc_slot = ctxt->new_slot; ret = ocfs2_write_inode(fs, blkno, ctxt->ex_buf); if (ret) goto bail; } bail: return ret; }
/* * Delete and free clusters if needed. This only works with DEPTH_TRAVERSE. */ static int truncate_iterate(ocfs2_filesys *fs, struct ocfs2_extent_rec *rec, int tree_depth, uint32_t ccount, uint64_t ref_blkno, int ref_recno, void *priv_data) { struct truncate_ctxt *ctxt = (struct truncate_ctxt *)priv_data; uint32_t len = 0, new_size_in_clusters = ctxt->new_size_in_clusters; uint64_t start = 0; errcode_t ret; int func_ret = OCFS2_EXTENT_ERROR; char *buf = NULL; struct ocfs2_extent_list *el = NULL; int cleanup_rec = 0; if ((rec->e_cpos + ocfs2_rec_clusters(tree_depth, rec)) <= new_size_in_clusters) return 0; if (rec->e_cpos >= new_size_in_clusters) { /* the rec is entirely outside the new size, free it */ if (!tree_depth) { start = rec->e_blkno; len = ocfs2_rec_clusters(tree_depth, rec); } else { /* here we meet with a full empty extent block, delete * it. The extent list it contains should already be * iterated and all the clusters have been freed. */ ret = ocfs2_delete_extent_block(fs, rec->e_blkno); if (ret) goto bail; } cleanup_rec = 1; } else { /* we're truncating into the middle of the rec */ len = rec->e_cpos + ocfs2_rec_clusters(tree_depth, rec); len -= new_size_in_clusters; if (!tree_depth) { ocfs2_set_rec_clusters(tree_depth, rec, new_size_in_clusters - rec->e_cpos); start = rec->e_blkno + ocfs2_clusters_to_blocks(fs, ocfs2_rec_clusters(tree_depth, rec)); } else { ocfs2_set_rec_clusters(tree_depth, rec, new_size_in_clusters - rec->e_cpos); /* * For a sparse file, we may meet with another * situation here: * The start of the left most extent rec is greater * than the new size we truncate the file to, but the * start of the extent block is less than that size. * In this case, actually all the extent records in * this extent block have been removed. So we have * to remove the extent block also. * In this function, we have to reread the extent list * to see whether the extent block is empty or not. */ ret = ocfs2_malloc_block(fs->fs_io, &buf); if (ret) goto bail; ret = ocfs2_read_extent_block(fs, rec->e_blkno, buf); if (ret) goto bail; el = &((struct ocfs2_extent_block *)buf)->h_list; if (el->l_next_free_rec == 0) { ret = ocfs2_delete_extent_block(fs, rec->e_blkno); if (ret) goto bail; cleanup_rec = 1; } } } if (start) { if (ctxt->free_clusters) ret = ctxt->free_clusters(fs, len, start, ctxt->free_data); else ret = ocfs2_truncate_clusters(fs, rec, ctxt->ino, len, start); if (ret) goto bail; ctxt->new_i_clusters -= len; } func_ret = OCFS2_EXTENT_CHANGED; bail: if (cleanup_rec) memset(rec, 0, sizeof(struct ocfs2_extent_rec)); if (buf) ocfs2_free(&buf); return func_ret; }
/* * Figure out the size of a hole which starts at v_cluster within the given * extent list. * * If there is no more allocation past v_cluster, we return the maximum * cluster size minus v_cluster. * * If we have in-inode extents, then el points to the dinode list and * eb_buf is NULL. Otherwise, eb_buf should point to the extent block * containing el. */ static int ocfs2_figure_hole_clusters(ocfs2_cached_inode *cinode, struct ocfs2_extent_list *el, char *eb_buf, uint32_t v_cluster, uint32_t *num_clusters) { int ret, i; char *next_eb_buf = NULL; struct ocfs2_extent_block *eb, *next_eb; i = ocfs2_search_for_hole_index(el, v_cluster); if (i == el->l_next_free_rec && eb_buf) { eb = (struct ocfs2_extent_block *)eb_buf; /* * Check the next leaf for any extents. */ if (eb->h_next_leaf_blk == 0) goto no_more_extents; ret = ocfs2_malloc_block(cinode->ci_fs->fs_io, &next_eb_buf); if (ret) goto out; ret = ocfs2_read_extent_block(cinode->ci_fs, eb->h_next_leaf_blk, next_eb_buf); if (ret) goto out; next_eb = (struct ocfs2_extent_block *)next_eb_buf; el = &next_eb->h_list; i = ocfs2_search_for_hole_index(el, v_cluster); if (i > 0) { if ((i > 1) || ocfs2_rec_clusters(el->l_tree_depth, &el->l_recs[0])) { ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK; goto out; } } } no_more_extents: if (i == el->l_next_free_rec) { /* * We're at the end of our existing allocation. Just * return the maximum number of clusters we could * possibly allocate. */ *num_clusters = UINT32_MAX - v_cluster; } else *num_clusters = el->l_recs[i].e_cpos - v_cluster; ret = 0; out: if (next_eb_buf) ocfs2_free(&next_eb_buf); return ret; }
static int extent_iterate_eb(struct ocfs2_extent_rec *eb_rec, int ref_tree_depth, uint64_t ref_blkno, int ref_recno, struct extent_context *ctxt) { int iret = 0, changed = 0, flags; int tree_depth = ref_tree_depth - 1; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *el; if (!(ctxt->flags & OCFS2_EXTENT_FLAG_DEPTH_TRAVERSE) && !(ctxt->flags & OCFS2_EXTENT_FLAG_DATA_ONLY)) iret = (*ctxt->func)(ctxt->fs, eb_rec, ref_tree_depth, ctxt->ccount, ref_blkno, ref_recno, ctxt->priv_data); if (!eb_rec->e_blkno || (iret & OCFS2_EXTENT_ABORT)) goto out; if ((eb_rec->e_blkno < OCFS2_SUPER_BLOCK_BLKNO) || (eb_rec->e_blkno > ctxt->fs->fs_blocks)) { ctxt->errcode = OCFS2_ET_BAD_BLKNO; iret |= OCFS2_EXTENT_ERROR; goto out; } ctxt->errcode = ocfs2_read_extent_block(ctxt->fs, eb_rec->e_blkno, ctxt->eb_bufs[tree_depth]); if (ctxt->errcode) { iret |= OCFS2_EXTENT_ERROR; goto out; } eb = (struct ocfs2_extent_block *)ctxt->eb_bufs[tree_depth]; el = &eb->h_list; if ((el->l_tree_depth != tree_depth) || (eb->h_blkno != eb_rec->e_blkno)) { ctxt->errcode = OCFS2_ET_CORRUPT_EXTENT_BLOCK; iret |= OCFS2_EXTENT_ERROR; goto out; } flags = extent_iterate_el(el, eb_rec->e_blkno, ctxt); changed |= flags; if (flags & (OCFS2_EXTENT_ABORT | OCFS2_EXTENT_ERROR)) iret |= flags & (OCFS2_EXTENT_ABORT | OCFS2_EXTENT_ERROR); /* * If the list was changed, we should write the changes to disk. * Note: * For a sparse file, we may have an empty extent block. */ if (changed & OCFS2_EXTENT_CHANGED) { ctxt->errcode = ocfs2_write_extent_block(ctxt->fs, eb_rec->e_blkno, ctxt->eb_bufs[tree_depth]); if (ctxt->errcode) { iret |= OCFS2_EXTENT_ERROR; goto out; } } if ((ctxt->flags & OCFS2_EXTENT_FLAG_DEPTH_TRAVERSE) && !(ctxt->flags & OCFS2_EXTENT_FLAG_DATA_ONLY) && !(iret & (OCFS2_EXTENT_ABORT|OCFS2_EXTENT_ERROR))) iret = (*ctxt->func)(ctxt->fs, eb_rec, ref_tree_depth, ctxt->ccount, ref_blkno, ref_recno, ctxt->priv_data); out: return iret; }