Ejemplo n.º 1
0
/*
 * Zero the area past i_size but still within an allocated
 * cluster. This avoids exposing nonzero data on subsequent file
 * extends.
 */
static errcode_t ocfs2_zero_tail_for_truncate(ocfs2_cached_inode *ci,
					      uint64_t new_size)
{
	errcode_t ret;
	char *buf = NULL;
	ocfs2_filesys *fs = ci->ci_fs;
	uint64_t start_blk, p_blkno, contig_blocks, start_off;
	int count, byte_counts, bpc = fs->fs_clustersize /fs->fs_blocksize;
	uint16_t ext_flags;

	if (new_size == 0)
		return 0;

	start_blk = new_size / fs->fs_blocksize;

	ret = ocfs2_extent_map_get_blocks(ci, start_blk, 1,
					  &p_blkno, &contig_blocks, &ext_flags);
	if (ret)
		goto out;

	/* Tail is a hole. */
	if (!p_blkno)
		goto out;

	if (ext_flags & OCFS2_EXT_REFCOUNTED) {
		uint32_t cpos = ocfs2_blocks_to_clusters(fs, start_blk);
		ret = ocfs2_refcount_cow(ci, cpos, 1, cpos + 1);
		if (ret)
			goto out;

		ret = ocfs2_extent_map_get_blocks(ci, start_blk, 1,
						  &p_blkno, &contig_blocks,
						  &ext_flags);
		if (ret)
			goto out;

		assert(!(ext_flags & OCFS2_EXT_REFCOUNTED) && p_blkno);

	}

	/* calculate the total blocks we need to empty. */
	count = bpc - (p_blkno & (bpc - 1));
	ret = ocfs2_malloc_blocks(fs->fs_io, count, &buf);
	if (ret)
		goto out;

	ret = ocfs2_read_blocks(fs, p_blkno, count, buf);
	if (ret)
		goto out;

	/* empty the content after the new_size and within the same cluster. */
	start_off = new_size % fs->fs_blocksize;
	byte_counts = count * fs->fs_blocksize - start_off;
	memset(buf + start_off, 0, byte_counts);

	ret = io_write_block(fs->fs_io, p_blkno, count, buf);

out:
	if (buf)
		ocfs2_free(&buf);
	return ret;
}
Ejemplo n.º 2
0
static errcode_t ocfs2_file_block_write(ocfs2_cached_inode *ci,
					void *buf, uint32_t count,
					uint64_t offset, uint32_t *wrote)
{
	ocfs2_filesys	*fs = ci->ci_fs;
	errcode_t	ret = 0;
	char		*ptr = (char *) buf;
	uint32_t	wanted_blocks;
	uint64_t	contig_blocks;
	uint64_t	v_blkno;
	uint64_t	p_blkno, p_start, p_end;
	uint64_t	begin_blocks = 0, end_blocks = 0;
	uint32_t	tmp;
	uint64_t	num_blocks;
	int		bs_bits = OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits;
	uint32_t	n_clusters, cluster_begin, cluster_end;
	uint64_t	bpc = fs->fs_clustersize/fs->fs_blocksize;
	int		insert = 0;
	uint16_t	extent_flags = 0;

	/* o_direct requires aligned io */
	tmp = fs->fs_blocksize - 1;
	if ((count & tmp) || (offset & (uint64_t)tmp) ||
	    ((unsigned long)ptr & tmp))
		return OCFS2_ET_INVALID_ARGUMENT;

	wanted_blocks = count >> bs_bits;
	v_blkno = offset >> bs_bits;
	*wrote = 0;

	num_blocks = (ci->ci_inode->i_size + fs->fs_blocksize - 1) >> bs_bits;

	if (v_blkno >= num_blocks)
		return 0;

	if (v_blkno + wanted_blocks > num_blocks)
		wanted_blocks = (uint32_t) (num_blocks - v_blkno);

	if (ocfs2_refcount_tree(OCFS2_RAW_SB(fs->fs_super)) &&
	    (ci->ci_inode->i_dyn_features & OCFS2_HAS_REFCOUNT_FL)) {
		cluster_begin = ocfs2_blocks_to_clusters(fs, v_blkno);
		cluster_end = ocfs2_blocks_to_clusters(fs,
					       v_blkno + wanted_blocks - 1);
		n_clusters = cluster_end - cluster_begin + 1;
		ret = ocfs2_refcount_cow(ci, cluster_begin, n_clusters, UINT_MAX);
		if (ret)
			return ret;
	}

	while(wanted_blocks) {
		ret = ocfs2_extent_map_get_blocks(ci, v_blkno, 1,
						  &p_blkno, &contig_blocks,
						  &extent_flags);
		if (ret)
			return ret;

		if (contig_blocks > wanted_blocks)
			contig_blocks = wanted_blocks;

		begin_blocks = 0;
		end_blocks = 0;
		p_end = 0;
	 	if (!p_blkno) {
			/*
			 * We meet with a hole here, so we allocate clusters
			 * and empty the both ends in case.
			 *
			 * We will postpone the extent insertion after we
			 * successfully write the extent block, so that and
			 * problems happens in block writing would not affect
			 * the file.
			 */
			cluster_begin = ocfs2_blocks_to_clusters(fs, v_blkno);
			cluster_end = ocfs2_blocks_to_clusters(fs,
						v_blkno + contig_blocks -1);
			n_clusters = cluster_end - cluster_begin + 1;
			ret = ocfs2_new_clusters(fs, 1, n_clusters, &p_start,
						 &n_clusters);
			if (ret || n_clusters == 0)
				return ret;

			begin_blocks = v_blkno & (bpc - 1);
			p_blkno = p_start + begin_blocks;
			contig_blocks = n_clusters * bpc - begin_blocks;
			if (contig_blocks > wanted_blocks) {
				end_blocks = contig_blocks - wanted_blocks;
				contig_blocks = wanted_blocks;
				p_end = p_blkno + wanted_blocks;
			}

			insert = 1;
		} else if (extent_flags & OCFS2_EXT_UNWRITTEN) {
			begin_blocks = v_blkno & (bpc - 1);
			p_start = p_blkno - begin_blocks;
			p_end = p_blkno + wanted_blocks;
			end_blocks = (p_end & (bpc - 1)) ?
						 bpc - (p_end & (bpc - 1 )) : 0;
		}

		if (begin_blocks) {
			/*
			 * The user don't write the first blocks,
			 * so we have to empty them.
			 */
			ret = empty_blocks(fs, p_start, begin_blocks);
			if (ret)
				return ret;
		}

		if (end_blocks) {
			/*
			 * we don't need to write that many blocks,
			 * so empty the blocks at the bottom.
			 */
			ret = empty_blocks(fs, p_end, end_blocks);
			if (ret)
				return ret;
		}

		ret = io_write_block(fs->fs_io, p_blkno, contig_blocks, ptr);
		if (ret)
			return ret;

		if (insert) {
			ret = ocfs2_cached_inode_insert_extent(ci,
					ocfs2_blocks_to_clusters(fs,v_blkno),
					p_start, n_clusters, 0);
			if (ret) {
				/*
				 * XXX: We don't wan't to overwrite the error
				 * from insert_extent().  But we probably need
				 * to BE LOUDLY UPSET.
				 */
				ocfs2_free_clusters(fs, n_clusters, p_start);
				return ret;
			}

			/* save up what we have done. */
			ret = ocfs2_write_cached_inode(fs, ci);
			if (ret)
				return ret;

			ret = ocfs2_extent_map_get_blocks(ci, v_blkno, 1,
						&p_blkno, NULL, NULL);
			/* now we shouldn't find a hole. */
			if (!p_blkno || p_blkno != p_start + begin_blocks)
				ret = OCFS2_ET_INTERNAL_FAILURE;
			if (ret)
				return ret;

			insert = 0;
		} else if (extent_flags & OCFS2_EXT_UNWRITTEN) {
			cluster_begin = ocfs2_blocks_to_clusters(fs, v_blkno);
			cluster_end = ocfs2_blocks_to_clusters(fs,
						v_blkno + contig_blocks -1);
			n_clusters = cluster_end - cluster_begin + 1;
			ret = ocfs2_mark_extent_written(fs, ci->ci_inode,
					cluster_begin, n_clusters,
					p_blkno & ~(bpc - 1));
			if (ret)
				return ret;
			/*
			 * We don't cache in the library right now, so any
			 * work done in mark_extent_written won't be reflected
			 * in our now stale copy. So refresh it.
			 */
			ret = ocfs2_refresh_cached_inode(fs, ci);
			if (ret)
				return ret;
		}

		*wrote += (contig_blocks << bs_bits);
		wanted_blocks -= contig_blocks;

		if (wanted_blocks) {
			ptr += (contig_blocks << bs_bits);
			v_blkno += (uint64_t)contig_blocks;
		} else {
			if (*wrote + offset > ci->ci_inode->i_size)
				*wrote = (uint32_t) (ci->ci_inode->i_size - offset);
			/* break */
		}

	}

	return ret;
}