Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f4b9aa8d authored by Chris Mason's avatar Chris Mason Committed by David Woodhouse
Browse files

btrfs_truncate

parent 71951f35
Loading
Loading
Loading
Loading
+13 −12
Original line number Diff line number Diff line
@@ -171,6 +171,7 @@ static int pin_down_block(struct btrfs_root *root, u64 blocknr, int pending)
	struct btrfs_header *header;
	struct buffer_head *bh;

	if (!pending) {
		bh = sb_find_get_block(root->fs_info->sb, blocknr);
		if (bh) {
			header = btrfs_buffer_header(bh);
@@ -181,10 +182,10 @@ static int pin_down_block(struct btrfs_root *root, u64 blocknr, int pending)
			}
			brelse(bh);
		}
	if (pending)
		err = set_radix_bit(&root->fs_info->pending_del_radix, blocknr);
	else
		err = set_radix_bit(&root->fs_info->pinned_radix, blocknr);
	} else {
		err = set_radix_bit(&root->fs_info->pending_del_radix, blocknr);
	}
	BUG_ON(err);
	return 0;
}
@@ -223,6 +224,7 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
	BUG_ON(ei->refs == 0);
	refs = btrfs_extent_refs(ei) - 1;
	btrfs_set_extent_refs(ei, refs);
	mark_buffer_dirty(path.nodes[0]);
	if (refs == 0) {
		u64 super_blocks_used;

@@ -240,7 +242,6 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
		if (ret)
			BUG();
	}
	mark_buffer_dirty(path.nodes[0]);
	btrfs_release_path(extent_root, &path);
	finish_current_insert(trans, extent_root);
	return ret;
+101 −6
Original line number Diff line number Diff line
@@ -28,11 +28,15 @@ static void btrfs_read_locked_inode(struct inode *inode)
	struct btrfs_inode_item *inode_item;
	struct btrfs_root *root = btrfs_sb(inode->i_sb);
	int ret;

	btrfs_init_path(&path);
	mutex_lock(&root->fs_info->fs_mutex);

	ret = btrfs_lookup_inode(NULL, root, &path, inode->i_ino, 0);
	if (ret) {
		make_bad_inode(inode);
		btrfs_release_path(root, &path);
		mutex_unlock(&root->fs_info->fs_mutex);
		make_bad_inode(inode);
		return;
	}
	inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]),
@@ -53,6 +57,7 @@ static void btrfs_read_locked_inode(struct inode *inode)
	inode->i_blocks = btrfs_inode_nblocks(inode_item);
	inode->i_generation = btrfs_inode_generation(inode_item);
	btrfs_release_path(root, &path);
	mutex_unlock(&root->fs_info->fs_mutex);
	switch (inode->i_mode & S_IFMT) {
#if 0
	default:
@@ -151,20 +156,85 @@ static int btrfs_free_inode(struct btrfs_trans_handle *trans,
	return ret;
}

static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
				   struct btrfs_root *root,
				   struct inode *inode)
{
	int ret;
	struct btrfs_path path;
	struct btrfs_key key;
	struct btrfs_disk_key *found_key;
	struct btrfs_leaf *leaf;
	struct btrfs_file_extent_item *fi;
	u64 extent_start;
	u64 extent_num_blocks;

	/* FIXME, add redo link to tree so we don't leak on crash */
	key.objectid = inode->i_ino;
	key.offset = (u64)-1;
	key.flags = 0;
	btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
	while(1) {
		btrfs_init_path(&path);
		ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
		if (ret < 0) {
			btrfs_release_path(root, &path);
			goto error;
		}
		if (ret > 0) {
			BUG_ON(path.slots[0] == 0);
			path.slots[0]--;
		}
		leaf = btrfs_buffer_leaf(path.nodes[0]);
		found_key = &leaf->items[path.slots[0]].key;
		if (btrfs_disk_key_objectid(found_key) != inode->i_ino)
			break;
		if (btrfs_disk_key_type(found_key) != BTRFS_EXTENT_DATA_KEY)
			break;
		if (btrfs_disk_key_offset(found_key) < inode->i_size)
			break;
		/* FIXME: add extent truncation */
		if (btrfs_disk_key_offset(found_key) < inode->i_size)
			break;
		fi = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]),
				    path.slots[0],
				    struct btrfs_file_extent_item);
		extent_start = btrfs_file_extent_disk_blocknr(fi);
		extent_num_blocks = btrfs_file_extent_disk_num_blocks(fi);
		key.offset = btrfs_disk_key_offset(found_key) - 1;
		ret = btrfs_del_item(trans, root, &path);
		BUG_ON(ret);
		inode->i_blocks -= btrfs_file_extent_num_blocks(fi) >> 9;
		btrfs_release_path(root, &path);
		ret = btrfs_free_extent(trans, root, extent_start,
					extent_num_blocks, 0);
		BUG_ON(ret);
		if (btrfs_disk_key_offset(found_key) == 0)
			break;
	}
	btrfs_release_path(root, &path);
	ret = 0;
error:
	return ret;
}

static void btrfs_delete_inode(struct inode *inode)
{
	struct btrfs_trans_handle *trans;
	struct btrfs_root *root = btrfs_sb(inode->i_sb);
	int ret;

	truncate_inode_pages(&inode->i_data, 0);
	if (is_bad_inode(inode)) {
		goto no_delete;
	}
	inode->i_size = 0;
	if (inode->i_blocks)
		WARN_ON(1);

	mutex_lock(&root->fs_info->fs_mutex);
	trans = btrfs_start_transaction(root, 1);
	if (S_ISREG(inode->i_mode)) {
		ret = btrfs_truncate_in_trans(trans, root, inode);
		BUG_ON(ret);
	}
	btrfs_free_inode(trans, root, inode);
	btrfs_end_transaction(trans, root);
	mutex_unlock(&root->fs_info->fs_mutex);
@@ -173,7 +243,6 @@ static void btrfs_delete_inode(struct inode *inode)
	clear_inode(inode);
}


static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry,
			      ino_t *ino)
{
@@ -688,6 +757,8 @@ static int btrfs_get_block(struct inode *inode, sector_t iblock,
		err = ret;
		goto out;
	}
	inode->i_blocks += inode->i_sb->s_blocksize >> 9;
	set_buffer_new(result);
	map_bh(result, inode->i_sb, blocknr);

out:
@@ -724,6 +795,30 @@ static int btrfs_writepage(struct page *page, struct writeback_control *wbc)
	return nobh_writepage(page, btrfs_get_block, wbc);
}

static void btrfs_truncate(struct inode *inode)
{
	struct btrfs_root *root = btrfs_sb(inode->i_sb);
	int ret;
	struct btrfs_trans_handle *trans;

	if (!S_ISREG(inode->i_mode))
		return;
	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
		return;

	nobh_truncate_page(inode->i_mapping, inode->i_size);

	/* FIXME, add redo link to tree so we don't leak on crash */
	mutex_lock(&root->fs_info->fs_mutex);
	trans = btrfs_start_transaction(root, 1);
	ret = btrfs_truncate_in_trans(trans, root, inode);
	BUG_ON(ret);
	ret = btrfs_end_transaction(trans, root);
	BUG_ON(ret);
	mutex_unlock(&root->fs_info->fs_mutex);
	mark_inode_dirty(inode);
}

static int btrfs_get_sb(struct file_system_type *fs_type,
	int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
@@ -772,7 +867,7 @@ static struct address_space_operations btrfs_aops = {
};

static struct inode_operations btrfs_file_inode_operations = {
	.truncate	= NULL,
	.truncate	= btrfs_truncate,
};

static struct file_operations btrfs_file_operations = {