I need everybody to go over this with a fine toothed comb since it is a pretty big change. I think it is right and it seems to come out right, but if it's not it will mean we screw up O_DIRECT on snapshotted files with preallocated extents, so please, make sure it is correct :).
--- Subject: [PATCH] Btrfs: rework can_nocow_odirect We are always doing the file extent lookup in here even though we've already done the btrfs_get_extent which does the exact same thing. So re-work can_nocow_odirect to get the same information out of the extent_map we already have and then do the cross ref check and csum checks as appropriate. This reduces the number of allocations and searches we do for every O_DIRECT write and man it helps a lot. Thanks, Signed-off-by: Josef Bacik <jba...@fusionio.com> --- fs/btrfs/inode.c | 93 ++++++++++++++--------------------------------------- 1 files changed, 25 insertions(+), 68 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 2c785c0..1cd7a6b 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6352,79 +6352,42 @@ out: * block must be cow'd */ static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans, - struct inode *inode, u64 offset, u64 len) + struct inode *inode, + struct extent_map *em, u64 offset, + u64 len) { - struct btrfs_path *path; - int ret; - struct extent_buffer *leaf; struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_file_extent_item *fi; - struct btrfs_key key; u64 disk_bytenr; u64 backref_offset; u64 extent_end; u64 num_bytes; - int slot; - int found_type; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - ret = btrfs_lookup_file_extent(trans, root, path, btrfs_ino(inode), - offset, 0); - if (ret < 0) - goto out; - slot = path->slots[0]; - if (ret == 1) { - if (slot == 0) { - /* can't find the item, must cow */ - ret = 0; - goto out; - } - slot--; - } - ret = 0; - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, slot); - if (key.objectid != btrfs_ino(inode) || - key.type != BTRFS_EXTENT_DATA_KEY) { - /* not our file or wrong item type, must cow */ - goto out; - } - - if (key.offset > offset) { - /* Wrong offset, must cow */ - goto out; - } - - fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); - found_type = btrfs_file_extent_type(leaf, fi); - if (found_type != BTRFS_FILE_EXTENT_REG && - found_type != BTRFS_FILE_EXTENT_PREALLOC) { - /* not a regular extent, must cow */ - goto out; - } - disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); - backref_offset = btrfs_file_extent_offset(leaf, fi); + if (em->block_start == EXTENT_MAP_INLINE || + em->block_start == EXTENT_MAP_HOLE) + return 0; - extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi); - if (extent_end < offset + len) { - /* extent doesn't include our full range, must cow */ - goto out; - } + /* + * The em's disk_bytenr is already adjusted for its offset so we need to + * adjust it accordingly. + */ + backref_offset = em->start - em->orig_start; + disk_bytenr = em->block_start - backref_offset; + extent_end = em->start + em->len; if (btrfs_extent_readonly(root, disk_bytenr)) - goto out; + return 0; /* * look for other files referencing this extent, if we * find any we must cow */ if (btrfs_cross_ref_exist(trans, root, btrfs_ino(inode), - key.offset - backref_offset, disk_bytenr)) - goto out; + em->orig_start, disk_bytenr)) + return 0; + + /* No prealloc, we won't have csums */ + if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) + return 1; /* * adjust disk_bytenr and num_bytes to cover just the bytes @@ -6433,18 +6396,12 @@ static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans, * to keep the csums correct */ disk_bytenr += backref_offset; - disk_bytenr += offset - key.offset; + disk_bytenr += offset - em->start; num_bytes = min(offset + len, extent_end) - offset; if (csum_exist_in_range(root, disk_bytenr, num_bytes)) - goto out; - /* - * all of the above have passed, it is safe to overwrite this extent - * without cow - */ - ret = 1; -out: - btrfs_free_path(path); - return ret; + return 0; + + return 1; } static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend, @@ -6663,7 +6620,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, if (IS_ERR(trans)) goto must_cow; - if (can_nocow_odirect(trans, inode, start, len) == 1) { + if (can_nocow_odirect(trans, inode, em, start, len) == 1) { u64 orig_start = em->start; if (type == BTRFS_ORDERED_PREALLOC) { -- 1.7.7.6 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html