Esempio n. 1
0
/*
 * Try to add the new entry to the inline data.
 * If succeeds, return 0. If not, extended the inline dir and copied data to
 * the new created block.
 */
int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname,
			      struct inode *dir, struct inode *inode)
{
	int ret, inline_size;
	void *inline_start;
	struct ext4_iloc iloc;

	ret = ext4_get_inode_loc(dir, &iloc);
	if (ret)
		return ret;

	down_write(&EXT4_I(dir)->xattr_sem);
	if (!ext4_has_inline_data(dir))
		goto out;

	inline_start = (void *)ext4_raw_inode(&iloc)->i_block +
						 EXT4_INLINE_DOTDOT_SIZE;
	inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DOTDOT_SIZE;

	ret = ext4_add_dirent_to_inline(handle, fname, dir, inode, &iloc,
					inline_start, inline_size);
	if (ret != -ENOSPC)
		goto out;

	/* check whether it can be inserted to inline xattr space. */
	inline_size = EXT4_I(dir)->i_inline_size -
			EXT4_MIN_INLINE_DATA_SIZE;
	if (!inline_size) {
		/* Try to use the xattr space.*/
		ret = ext4_update_inline_dir(handle, dir, &iloc);
		if (ret && ret != -ENOSPC)
			goto out;

		inline_size = EXT4_I(dir)->i_inline_size -
				EXT4_MIN_INLINE_DATA_SIZE;
	}

	if (inline_size) {
		inline_start = ext4_get_inline_xattr_pos(dir, &iloc);

		ret = ext4_add_dirent_to_inline(handle, fname, dir,
						inode, &iloc, inline_start,
						inline_size);

		if (ret != -ENOSPC)
			goto out;
	}

	/*
	 * The inline space is filled up, so create a new block for it.
	 * As the extent tree will be created, we have to save the inline
	 * dir first.
	 */
	ret = ext4_convert_inline_data_nolock(handle, dir, &iloc);

out:
	ext4_mark_inode_dirty(handle, dir);
	up_write(&EXT4_I(dir)->xattr_sem);
	brelse(iloc.bh);
	return ret;
}
Esempio n. 2
0
/*
 * Try to add the new entry to the inline data.
 * If succeeds, return 0. If not, extended the inline dir and copied data to
 * the new created block.
 */
int ext4_try_add_inline_entry(handle_t *handle, struct dentry *dentry,
			      struct inode *inode)
{
	int ret, inline_size;
	void *inline_start, *backup_buf = NULL;
	struct buffer_head *dir_block = NULL;
	struct ext4_iloc iloc;
	int blocksize = inode->i_sb->s_blocksize;
	struct inode *dir = dentry->d_parent->d_inode;

	ret = ext4_get_inode_loc(dir, &iloc);
	if (ret)
		return ret;

	down_write(&EXT4_I(dir)->xattr_sem);
	if (!ext4_has_inline_data(dir))
		goto out;

	inline_start = ext4_raw_inode(&iloc)->i_block;
	inline_size = EXT4_MIN_INLINE_DATA_SIZE;

	ret = ext4_add_dirent_to_inline(handle, dentry, inode, &iloc,
					inline_start, inline_size);
	if (ret != -ENOSPC)
		goto out;

	/* check whether it can be inserted to inline xattr space. */
	inline_size = EXT4_I(dir)->i_inline_size -
			EXT4_MIN_INLINE_DATA_SIZE;
	if (inline_size > 0) {
		inline_start = ext4_get_inline_xattr_pos(dir, &iloc);

		ret = ext4_add_dirent_to_inline(handle, dentry, inode, &iloc,
						inline_start, inline_size);
		if (ret != -ENOSPC)
			goto out;
	}

	/* Try to add more xattr space.*/
	ret = ext4_update_inline_dir(handle, dentry, dir, &iloc);
	if (ret && ret != -ENOSPC)
		goto out;
	else if (!ret) {
		inline_size = EXT4_I(dir)->i_inline_size -
				EXT4_MIN_INLINE_DATA_SIZE;
		inline_start = ext4_get_inline_xattr_pos(dir, &iloc);

		ret = ext4_add_dirent_to_inline(handle, dentry, inode, &iloc,
						inline_start, inline_size);
		if (ret != -ENOSPC)
			goto out;
	}

	/*
	 * The inline space is filled up, so create a new block for it.
	 * As the extent tree will be created, we have to save the inline
	 * dir first.
	 */
	inline_size = EXT4_I(dir)->i_inline_size;
	backup_buf = kmalloc(inline_size, GFP_NOFS);
	if (!backup_buf) {
		ret = -ENOMEM;
		goto out;
	}

	memcpy(backup_buf, (void *)ext4_raw_inode(&iloc)->i_block,
	       EXT4_MIN_INLINE_DATA_SIZE);
	if (inline_size > EXT4_MIN_INLINE_DATA_SIZE)
		memcpy(backup_buf + EXT4_MIN_INLINE_DATA_SIZE,
		       ext4_get_inline_xattr_pos(dir, &iloc),
		       inline_size - EXT4_MIN_INLINE_DATA_SIZE);

	/* clear the entry and the flag in dir now. */
	ret = ext4_destroy_inline_data_nolock(handle, dir);
	if (ret)
		goto out;

	dir->i_size = EXT4_I(dir)->i_disksize = blocksize;
	dir_block = ext4_bread(handle, dir, 0, 1, &ret);
	if (!dir_block)
		goto out;

	BUFFER_TRACE(dir_block, "get_write_access");
	ret = ext4_journal_get_write_access(handle, dir_block);
	if (ret)
		goto out;
	memcpy(dir_block->b_data, backup_buf, inline_size);

	/* Set the final de to cover the whole block. */
	ext4_update_final_de(dir_block->b_data, inline_size,
			     blocksize);

	BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata");
	ret = ext4_handle_dirty_metadata(handle, dir, dir_block);

out:
	kfree(backup_buf);
	brelse(dir_block);
	if (!ret || ret == 1)
		ext4_mark_inode_dirty(handle, dir);
	up_write(&EXT4_I(dir)->xattr_sem);
	brelse(iloc.bh);
	return ret;
}