summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/file.c
diff options
context:
space:
mode:
authorChris Mason2007-11-01 16:28:41 +0100
committerChris Mason2008-09-25 17:03:57 +0200
commit179e29e488cc74f1e9bd67bc45f70b832740e9ec (patch)
treeaa055d77b8d3f2b4bc59b1bb8a5b98ec0b223fb5 /fs/btrfs/file.c
parentBtrfs: Fix PAGE_CACHE_SHIFT shifts on 32 bit machines (diff)
downloadkernel-qcow2-linux-179e29e488cc74f1e9bd67bc45f70b832740e9ec.tar.gz
kernel-qcow2-linux-179e29e488cc74f1e9bd67bc45f70b832740e9ec.tar.xz
kernel-qcow2-linux-179e29e488cc74f1e9bd67bc45f70b832740e9ec.zip
Btrfs: Fix a number of inline extent problems that Yan Zheng reported.
The fixes do a number of things: 1) Most btrfs_drop_extent callers will try to leave the inline extents in place. It can truncate bytes off the beginning of the inline extent if required. 2) writepage can now update the inline extent, allowing mmap writes to go directly into the inline extent. 3) btrfs_truncate_in_transaction truncates inline extents 4) extent_map.c fixed to not merge inline extent mappings and hole mappings together Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r--fs/btrfs/file.c36
1 files changed, 30 insertions, 6 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index abdd9caad94e..4e52f7ec1cbe 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -115,8 +115,20 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans,
goto fail;
}
if (ret == 1) {
+ struct btrfs_key found_key;
+
+ if (path->slots[0] == 0)
+ goto insert;
+
path->slots[0]--;
leaf = path->nodes[0];
+ btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
+
+ if (found_key.objectid != inode->i_ino)
+ goto insert;
+
+ if (found_key.type != BTRFS_EXTENT_DATA_KEY)
+ goto insert;
ei = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
@@ -152,6 +164,7 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans,
ret = btrfs_search_slot(trans, root, &key, path,
offset + size - found_end, 1);
BUG_ON(ret != 0);
+
ret = btrfs_extend_item(trans, root, path,
offset + size - found_end);
if (ret) {
@@ -292,7 +305,7 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
*/
inline_size = end_pos;
if (isize >= BTRFS_MAX_INLINE_DATA_SIZE(root) ||
- inline_size > 8192 ||
+ inline_size > 32768 ||
inline_size >= BTRFS_MAX_INLINE_DATA_SIZE(root)) {
u64 last_end;
@@ -312,7 +325,7 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
aligned_end = (pos + write_bytes + root->sectorsize - 1) &
~((u64)root->sectorsize - 1);
err = btrfs_drop_extents(trans, root, inode, start_pos,
- aligned_end, end_pos, &hint_byte);
+ aligned_end, aligned_end, &hint_byte);
if (err)
goto failed;
err = insert_inline_extent(trans, root, inode, start_pos,
@@ -456,13 +469,15 @@ next_slot:
goto next_slot;
}
- /* FIXME, there's only one inline extent allowed right now */
if (found_inline) {
u64 mask = root->sectorsize - 1;
search_start = (extent_end + mask) & ~mask;
} else
search_start = extent_end;
+ if (end <= extent_end && start >= key.offset && found_inline) {
+ *hint_byte = EXTENT_MAP_INLINE;
+ }
if (end < extent_end && end >= key.offset) {
if (found_extent) {
u64 disk_bytenr =
@@ -479,8 +494,10 @@ next_slot:
BUG_ON(ret);
}
}
- if (!found_inline)
- bookend = 1;
+ bookend = 1;
+ if (found_inline && start <= key.offset &&
+ inline_end < extent_end)
+ keep = 1;
}
/* truncate existing extent */
if (start > key.offset) {
@@ -510,7 +527,7 @@ next_slot:
new_size = btrfs_file_extent_calc_inline_size(
inline_end - key.offset);
btrfs_truncate_item(trans, root, path,
- new_size);
+ new_size, 1);
}
}
/* delete the entire extent */
@@ -551,6 +568,13 @@ next_slot:
if (!bookend)
continue;
}
+ if (bookend && found_inline && start <= key.offset &&
+ inline_end < extent_end) {
+ u32 new_size;
+ new_size = btrfs_file_extent_calc_inline_size(
+ extent_end - inline_end);
+ btrfs_truncate_item(trans, root, path, new_size, 0);
+ }
/* create bookend, splitting the extent in two */
if (bookend && found_extent) {
struct btrfs_key ins;