diff options
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 52 |
1 files changed, 46 insertions, 6 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 516b90224a1b..eef9c92f86d5 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -1930,7 +1930,7 @@ again: | |||
1930 | int btrfs_truncate_item(struct btrfs_trans_handle *trans, | 1930 | int btrfs_truncate_item(struct btrfs_trans_handle *trans, |
1931 | struct btrfs_root *root, | 1931 | struct btrfs_root *root, |
1932 | struct btrfs_path *path, | 1932 | struct btrfs_path *path, |
1933 | u32 new_size) | 1933 | u32 new_size, int from_end) |
1934 | { | 1934 | { |
1935 | int ret = 0; | 1935 | int ret = 0; |
1936 | int slot; | 1936 | int slot; |
@@ -1946,13 +1946,17 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans, | |||
1946 | 1946 | ||
1947 | slot_orig = path->slots[0]; | 1947 | slot_orig = path->slots[0]; |
1948 | leaf = path->nodes[0]; | 1948 | leaf = path->nodes[0]; |
1949 | slot = path->slots[0]; | ||
1950 | |||
1951 | old_size = btrfs_item_size_nr(leaf, slot); | ||
1952 | if (old_size == new_size) | ||
1953 | return 0; | ||
1949 | 1954 | ||
1950 | nritems = btrfs_header_nritems(leaf); | 1955 | nritems = btrfs_header_nritems(leaf); |
1951 | data_end = leaf_data_end(root, leaf); | 1956 | data_end = leaf_data_end(root, leaf); |
1952 | 1957 | ||
1953 | slot = path->slots[0]; | ||
1954 | old_data_start = btrfs_item_offset_nr(leaf, slot); | 1958 | old_data_start = btrfs_item_offset_nr(leaf, slot); |
1955 | old_size = btrfs_item_size_nr(leaf, slot); BUG_ON(old_size <= new_size); | 1959 | |
1956 | size_diff = old_size - new_size; | 1960 | size_diff = old_size - new_size; |
1957 | 1961 | ||
1958 | BUG_ON(slot < 0); | 1962 | BUG_ON(slot < 0); |
@@ -1984,9 +1988,45 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans, | |||
1984 | } | 1988 | } |
1985 | 1989 | ||
1986 | /* shift the data */ | 1990 | /* shift the data */ |
1987 | memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + | 1991 | if (from_end) { |
1988 | data_end + size_diff, btrfs_leaf_data(leaf) + | 1992 | memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + |
1989 | data_end, old_data_start + new_size - data_end); | 1993 | data_end + size_diff, btrfs_leaf_data(leaf) + |
1994 | data_end, old_data_start + new_size - data_end); | ||
1995 | } else { | ||
1996 | struct btrfs_disk_key disk_key; | ||
1997 | u64 offset; | ||
1998 | |||
1999 | btrfs_item_key(leaf, &disk_key, slot); | ||
2000 | |||
2001 | if (btrfs_disk_key_type(&disk_key) == BTRFS_EXTENT_DATA_KEY) { | ||
2002 | unsigned long ptr; | ||
2003 | struct btrfs_file_extent_item *fi; | ||
2004 | |||
2005 | fi = btrfs_item_ptr(leaf, slot, | ||
2006 | struct btrfs_file_extent_item); | ||
2007 | fi = (struct btrfs_file_extent_item *)( | ||
2008 | (unsigned long)fi - size_diff); | ||
2009 | |||
2010 | if (btrfs_file_extent_type(leaf, fi) == | ||
2011 | BTRFS_FILE_EXTENT_INLINE) { | ||
2012 | ptr = btrfs_item_ptr_offset(leaf, slot); | ||
2013 | memmove_extent_buffer(leaf, ptr, | ||
2014 | (unsigned long)fi, | ||
2015 | offsetof(struct btrfs_file_extent_item, | ||
2016 | disk_bytenr)); | ||
2017 | } | ||
2018 | } | ||
2019 | |||
2020 | memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + | ||
2021 | data_end + size_diff, btrfs_leaf_data(leaf) + | ||
2022 | data_end, old_data_start - data_end); | ||
2023 | |||
2024 | offset = btrfs_disk_key_offset(&disk_key); | ||
2025 | btrfs_set_disk_key_offset(&disk_key, offset + size_diff); | ||
2026 | btrfs_set_item_key(leaf, &disk_key, slot); | ||
2027 | if (slot == 0) | ||
2028 | fixup_low_keys(trans, root, path, &disk_key, 1); | ||
2029 | } | ||
1990 | 2030 | ||
1991 | item = btrfs_item_nr(leaf, slot); | 2031 | item = btrfs_item_nr(leaf, slot); |
1992 | btrfs_set_item_size(leaf, item, new_size); | 2032 | btrfs_set_item_size(leaf, item, new_size); |