linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Josef Bacik <jbacik@fusionio.com>
To: <linux-btrfs@vger.kernel.org>
Subject: [RFC] [PATCH] Btrfs: rework can_nocow_odirect
Date: Mon, 1 Oct 2012 15:00:14 -0400	[thread overview]
Message-ID: <1349118014-6319-1-git-send-email-jbacik@fusionio.com> (raw)

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 <jbacik@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


             reply	other threads:[~2012-10-01 18:54 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-10-01 19:00 Josef Bacik [this message]
2012-10-03  1:00 ` [RFC] [PATCH] Btrfs: rework can_nocow_odirect Wade Cline

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1349118014-6319-1-git-send-email-jbacik@fusionio.com \
    --to=jbacik@fusionio.com \
    --cc=linux-btrfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).