示例#1
0
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;
}
示例#3
0
/*
 * 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;
}
示例#4
0
/*
 * 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;
}
示例#5
0
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;
}