struct btrfs_block_group *block_group,
struct inode *vfs_inode)
{
+ struct btrfs_truncate_control control = {
+ .new_size = 0,
+ .min_type = BTRFS_EXTENT_DATA_KEY,
+ };
struct btrfs_inode *inode = BTRFS_I(vfs_inode);
struct btrfs_root *root = inode->root;
struct extent_state *cached_state = NULL;
* We skip the throttling logic for free space cache inodes, so we don't
* need to check for -EAGAIN.
*/
- ret = btrfs_truncate_inode_items(trans, root, inode, 0,
- BTRFS_EXTENT_DATA_KEY, NULL);
+ ret = btrfs_truncate_inode_items(trans, root, inode, &control);
unlock_extent_cached(&inode->io_tree, 0, (u64)-1, &cached_state);
if (ret)
goto fail;
* @trans: A transaction handle.
* @root: The root from which to remove items.
* @inode: The inode whose items we want to remove.
- * @new_size: The new i_size for the inode. This is only applicable when
- * @min_type is BTRFS_EXTENT_DATA_KEY, must be 0 otherwise.
- * @min_type: The minimum key type to remove. All keys with a type
- * greater than this value are removed and all keys with
- * this type are removed only if their offset is >= @new_size.
- * @extents_found: Output parameter that will contain the number of file
- * extent items that were removed or adjusted to the new
- * inode i_size. The caller is responsible for initializing
- * the counter. Also, it can be NULL if the caller does not
- * need this counter.
+ * @control: The btrfs_truncate_control to control how and what we
+ * are truncating.
*
* Remove all keys associated with the inode from the given root that have a key
* with a type greater than or equals to @min_type. When @min_type has a value of
int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_inode *inode,
- u64 new_size, u32 min_type,
- u64 *extents_found)
+ struct btrfs_truncate_control *control)
{
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_path *path;
struct btrfs_file_extent_item *fi;
struct btrfs_key key;
struct btrfs_key found_key;
+ u64 new_size = control->new_size;
u64 extent_num_bytes = 0;
u64 extent_offset = 0;
u64 item_end = 0;
bool be_nice = false;
bool should_throttle = false;
- BUG_ON(new_size > 0 && min_type != BTRFS_EXTENT_DATA_KEY);
+ BUG_ON(new_size > 0 && control->min_type != BTRFS_EXTENT_DATA_KEY);
/*
* For shareable roots we want to back off from time to time, this turns
if (found_key.objectid != ino)
break;
- if (found_type < min_type)
+ if (found_type < control->min_type)
break;
item_end = found_key.offset;
}
item_end--;
}
- if (found_type > min_type) {
+ if (found_type > control->min_type) {
del_item = 1;
} else {
if (item_end < new_size)
if (found_type != BTRFS_EXTENT_DATA_KEY)
goto delete;
- if (extents_found != NULL)
- (*extents_found)++;
+ control->extents_found++;
if (extent_type != BTRFS_FILE_EXTENT_INLINE) {
u64 num_dec;
*/
#define BTRFS_NEED_TRUNCATE_BLOCK 1
+struct btrfs_truncate_control {
+ /* IN: the size we're truncating to. */
+ u64 new_size;
+
+ /* OUT: the number of extents truncated. */
+ u64 extents_found;
+
+ /*
+ * IN: minimum key type to remove. All key types with this type are
+ * removed only if their offset >= new_size.
+ */
+ u32 min_type;
+};
+
int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
- struct btrfs_inode *inode, u64 new_size,
- u32 min_type, u64 *extents_found);
+ struct btrfs_inode *inode,
+ struct btrfs_truncate_control *control);
int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
const char *name, int name_len,
btrfs_i_size_write(BTRFS_I(inode), 0);
while (1) {
+ struct btrfs_truncate_control control = {
+ .new_size = 0,
+ .min_type = 0,
+ };
+
trans = evict_refill_and_join(root, rsv);
if (IS_ERR(trans))
goto free_rsv;
trans->block_rsv = rsv;
ret = btrfs_truncate_inode_items(trans, root, BTRFS_I(inode),
- 0, 0, NULL);
+ &control);
trans->block_rsv = &fs_info->trans_block_rsv;
btrfs_end_transaction(trans);
btrfs_btree_balance_dirty(fs_info);
static int btrfs_truncate(struct inode *inode, bool skip_writeback)
{
+ struct btrfs_truncate_control control = {
+ .min_type = BTRFS_EXTENT_DATA_KEY,
+ };
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_block_rsv *rsv;
struct btrfs_trans_handle *trans;
u64 mask = fs_info->sectorsize - 1;
u64 min_size = btrfs_calc_metadata_size(fs_info, 1);
- u64 extents_found = 0;
if (!skip_writeback) {
ret = btrfs_wait_ordered_range(inode, inode->i_size & (~mask),
const u64 new_size = inode->i_size;
const u64 lock_start = ALIGN_DOWN(new_size, fs_info->sectorsize);
+ control.new_size = new_size;
lock_extent_bits(&BTRFS_I(inode)->io_tree, lock_start, (u64)-1,
&cached_state);
/*
(u64)-1, 0);
ret = btrfs_truncate_inode_items(trans, root, BTRFS_I(inode),
- inode->i_size,
- BTRFS_EXTENT_DATA_KEY,
- &extents_found);
+ &control);
unlock_extent_cached(&BTRFS_I(inode)->io_tree, lock_start,
(u64)-1, &cached_state);
* between the old i_size and the new i_size, and there were no prealloc
* extents beyond i_size to drop.
*/
- if (extents_found > 0)
+ if (control.extents_found > 0)
set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags);
return ret;
struct btrfs_inode *inode,
u64 new_size, u32 min_type)
{
+ struct btrfs_truncate_control control = {
+ .new_size = new_size,
+ .min_type = min_type,
+ };
int ret;
do {
ret = btrfs_truncate_inode_items(trans, log_root, inode,
- new_size, min_type, NULL);
+ &control);
} while (ret == -EAGAIN);
return ret;