Miao Xie
2012-Jan-10  03:58 UTC
[PATCH V2 2/3] Btrfs: make btrfs_truncate_inode_items() more readable
As the title said, this patch just make the functions of the truncation
more readable.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
Changes v1 -> v2:
- move return sentence out of if...else..., make the logic of the code more
  clear.
---
 fs/btrfs/inode.c |  292 ++++++++++++++++++++++++++++++------------------------
 1 files changed, 162 insertions(+), 130 deletions(-)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 85e2312..4d1d4c4 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2977,10 +2977,145 @@ out:
 	return err;
 }
 
+static int btrfs_release_and_test_inline_data_extent(
+					struct btrfs_root *root,
+					struct inode *inode,
+					struct extent_buffer *leaf,
+					struct btrfs_file_extent_item *fi,
+					u64 offset,
+					u64 new_size)
+{
+	u64 item_end;
+
+	item_end = offset + btrfs_file_extent_inline_len(leaf, fi) - 1;
+
+	if (item_end < new_size)
+		return 0;
+
+	/*
+	 * Truncate inline items is special, we have done it by
+	 *   btrfs_truncate_page();
+	 */
+	if (offset < new_size)
+		return 0;
+
+	if (root->ref_cows)
+		inode_sub_bytes(inode, item_end + 1 - offset);
+
+	return 1;
+}
+
 /*
- * this can truncate away extent items, csum items and directory items.
- * It starts at a high offset and removes keys until it can''t find
- * any higher than new_size
+ * If this function return 1, it means this item can be dropped directly.
+ * If 0 is returned, the item can not be dropped.
+ */
+static int btrfs_release_and_test_data_extent(struct btrfs_trans_handle *trans,
+					      struct btrfs_root *root,
+					      struct btrfs_path *path,
+					      struct inode *inode,
+					      u64 offset,
+					      u64 new_size)
+{
+	struct extent_buffer *leaf;
+	struct btrfs_file_extent_item *fi;
+	u64 extent_start;
+	u64 extent_offset;
+	u64 item_end;
+	u64 ino = btrfs_ino(inode);
+	u64 orig_nbytes;
+	u64 new_nbytes;
+	int extent_type;
+	int ret;
+
+	leaf = path->nodes[0];
+	fi = btrfs_item_ptr(leaf, path->slots[0],
+			    struct btrfs_file_extent_item);
+
+	extent_type = btrfs_file_extent_type(leaf, fi);
+	if (extent_type == BTRFS_FILE_EXTENT_INLINE)
+		return btrfs_release_and_test_inline_data_extent(root, inode,
+								 leaf, fi,
+								 offset,
+								 new_size);
+
+	item_end = offset + btrfs_file_extent_num_bytes(leaf, fi) - 1;
+
+	/*
+	 * If the new size is beyond the end of the extent:
+	 *   +--------------------------+
+	 *   |				|
+	 *   +--------------------------+
+	 *   				  ^ new size
+	 * so the extent should not be dropped or truncated.
+	 */
+	if (item_end < new_size)
+		return 0;
+
+	extent_start = btrfs_file_extent_disk_bytenr(leaf, fi);
+	if (offset < new_size) {
+		/*
+		 * If the new size is in the extent:
+		 *   +--------------------------+
+		 *   |				|
+		 *   +--------------------------+
+		 *   			^ new size
+		 * so this extent should be truncated, not be dropped directly.
+		 */
+		orig_nbytes = btrfs_file_extent_num_bytes(leaf, fi);
+		new_nbytes = round_up(new_size - offset, root->sectorsize);
+
+		btrfs_set_file_extent_num_bytes(leaf, fi, new_nbytes);
+
+		if (extent_start != 0 && root->ref_cows)
+			inode_sub_bytes(inode, orig_nbytes - new_nbytes);
+
+		btrfs_mark_buffer_dirty(leaf);
+
+		ret = 0;
+	} else {
+		/*
+		 * If the new size is in the font of the extent:
+		 *   +--------------------------+
+		 *   |				|
+		 *   +--------------------------+
+		 *  ^ new size
+		 * so this extent should be dropped.
+		 */
+
+		/*
+		 * It is a dummy extent, or it is in log tree, we needn''t do
+		 * anything, just drop it.
+		 */
+		if (extent_start == 0 ||
+		    !(root->ref_cows || root == root->fs_info->tree_root))
+			return 1;
+
+		/* If this file is not a free space management file... */
+		/* FIXME blocksize != 4096 */
+		if (root != root->fs_info->tree_root) {
+			orig_nbytes = btrfs_file_extent_num_bytes(leaf, fi);
+			inode_sub_bytes(inode, orig_nbytes);
+		}
+
+		orig_nbytes = btrfs_file_extent_disk_num_bytes(leaf, fi);
+		extent_offset = offset - btrfs_file_extent_offset(leaf, fi);
+		btrfs_set_path_blocking(path);
+		ret = btrfs_free_extent(trans, root, extent_start,
+					orig_nbytes, 0,
+					btrfs_header_owner(leaf),
+					ino, extent_offset);
+		BUG_ON(ret);
+		btrfs_clear_path_blocking(path, NULL, 0);
+
+		ret = 1;
+	}
+
+	return ret;
+}
+
+/*
+ * this can truncate away extent items, directory items. It starts at a high
+ * offset and removes keys until it can''t find any higher than
new_size.
  *
  * csum items that cross the new i_size are truncated to the new size
  * as well.
@@ -2989,29 +3124,21 @@ out:
  * will kill all the items on this inode, including the INODE_ITEM_KEY.
  */
 int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
-			       struct btrfs_root *root,
-			       struct inode *inode,
-			       u64 new_size, u32 min_type)
+			        struct btrfs_root *root,
+			        struct inode *inode,
+			        u64 new_size, u32 min_type)
 {
 	struct btrfs_path *path;
 	struct extent_buffer *leaf;
-	struct btrfs_file_extent_item *fi;
 	struct btrfs_key key;
 	struct btrfs_key found_key;
-	u64 extent_start = 0;
-	u64 extent_num_bytes = 0;
-	u64 extent_offset = 0;
-	u64 item_end = 0;
 	u64 mask = root->sectorsize - 1;
-	u32 found_type = (u8)-1;
-	int found_extent;
-	int del_item;
+	u64 ino = btrfs_ino(inode);
+	u32 found_type;
 	int pending_del_nr = 0;
 	int pending_del_slot = 0;
-	int extent_type = -1;
 	int ret;
 	int err = 0;
-	u64 ino = btrfs_ino(inode);
 
 	BUG_ON(new_size > 0 && min_type != BTRFS_EXTENT_DATA_KEY);
 
@@ -3019,6 +3146,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle
*trans,
 	if (!path)
 		return -ENOMEM;
 	path->reada = -1;
+	path->leave_spinning = 1;
 
 	if (root->ref_cows || root == root->fs_info->tree_root)
 		btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0);
@@ -3037,14 +3165,11 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle
*trans,
 	key.type = (u8)-1;
 
 search_again:
-	path->leave_spinning = 1;
 	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
 	if (ret < 0) {
 		err = ret;
 		goto out;
-	}
-
-	if (ret > 0) {
+	} else if (ret > 0) {
 		/* there are no items in the tree for us to truncate, we''re
 		 * done
 		 */
@@ -3053,9 +3178,8 @@ search_again:
 		path->slots[0]--;
 	}
 
+	leaf = path->nodes[0];
 	while (1) {
-		fi = NULL;
-		leaf = path->nodes[0];
 		btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
 		found_type = btrfs_key_type(&found_key);
 
@@ -3065,123 +3189,31 @@ search_again:
 		if (found_type < min_type)
 			break;
 
-		item_end = found_key.offset;
 		if (found_type == BTRFS_EXTENT_DATA_KEY) {
-			fi = btrfs_item_ptr(leaf, path->slots[0],
-					    struct btrfs_file_extent_item);
-			extent_type = btrfs_file_extent_type(leaf, fi);
-			if (extent_type != BTRFS_FILE_EXTENT_INLINE) {
-				item_end +-				    btrfs_file_extent_num_bytes(leaf, fi);
-			} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
-				item_end += btrfs_file_extent_inline_len(leaf,
-									 fi);
-			}
-			item_end--;
-		}
-		if (found_type > min_type) {
-			del_item = 1;
-		} else {
-			if (item_end < new_size)
+			ret = btrfs_release_and_test_data_extent(trans, root,
+						path, inode, found_key.offset,
+						new_size);
+			if (!ret)
 				break;
-			if (found_key.offset >= new_size)
-				del_item = 1;
-			else
-				del_item = 0;
 		}
-		found_extent = 0;
-		/* FIXME, shrink the extent if the ref count is only 1 */
-		if (found_type != BTRFS_EXTENT_DATA_KEY)
-			goto delete;
-
-		if (extent_type != BTRFS_FILE_EXTENT_INLINE) {
-			u64 num_dec;
-			extent_start = btrfs_file_extent_disk_bytenr(leaf, fi);
-			if (!del_item) {
-				u64 orig_num_bytes -					btrfs_file_extent_num_bytes(leaf, fi);
-				extent_num_bytes = new_size -
-					found_key.offset + root->sectorsize - 1;
-				extent_num_bytes = extent_num_bytes &
-					~((u64)root->sectorsize - 1);
-				btrfs_set_file_extent_num_bytes(leaf, fi,
-							 extent_num_bytes);
-				num_dec = (orig_num_bytes -
-					   extent_num_bytes);
-				if (root->ref_cows && extent_start != 0)
-					inode_sub_bytes(inode, num_dec);
-				btrfs_mark_buffer_dirty(leaf);
-			} else {
-				extent_num_bytes -					btrfs_file_extent_disk_num_bytes(leaf,
-									 fi);
-				extent_offset = found_key.offset -
-					btrfs_file_extent_offset(leaf, fi);
-
-				/* FIXME blocksize != 4096 */
-				num_dec = btrfs_file_extent_num_bytes(leaf, fi);
-				if (extent_start != 0) {
-					found_extent = 1;
-					if (root->ref_cows)
-						inode_sub_bytes(inode, num_dec);
-				}
-			}
-		} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
-			/*
-			 * we can''t truncate inline items that have had
-			 * special encodings
-			 */
-			if (!del_item &&
-			    btrfs_file_extent_compression(leaf, fi) == 0 &&
-			    btrfs_file_extent_encryption(leaf, fi) == 0 &&
-			    btrfs_file_extent_other_encoding(leaf, fi) == 0) {
-				u32 size = new_size - found_key.offset;
-
-				if (root->ref_cows) {
-					inode_sub_bytes(inode, item_end + 1 -
-							new_size);
-				}
-				size -				    btrfs_file_extent_calc_inline_size(size);
-				ret = btrfs_truncate_item(trans, root, path,
-							  size, 1);
-			} else if (root->ref_cows) {
-				inode_sub_bytes(inode, item_end + 1 -
-						found_key.offset);
-			}
-		}
-delete:
-		if (del_item) {
-			if (!pending_del_nr) {
-				/* no pending yet, add ourselves */
-				pending_del_slot = path->slots[0];
-				pending_del_nr = 1;
-			} else if (pending_del_nr &&
-				   path->slots[0] + 1 == pending_del_slot) {
-				/* hop on the pending chunk */
-				pending_del_nr++;
-				pending_del_slot = path->slots[0];
-			} else {
-				BUG();
-			}
+
+		if (!pending_del_nr) {
+			/* no pending yet, add ourselves */
+			pending_del_slot = path->slots[0];
+			pending_del_nr = 1;
+		} else if (pending_del_nr &&
+			   path->slots[0] + 1 == pending_del_slot) {
+			/* hop on the pending chunk */
+			pending_del_nr++;
+			pending_del_slot = path->slots[0];
 		} else {
-			break;
-		}
-		if (found_extent && (root->ref_cows ||
-				     root == root->fs_info->tree_root)) {
-			btrfs_set_path_blocking(path);
-			ret = btrfs_free_extent(trans, root, extent_start,
-						extent_num_bytes, 0,
-						btrfs_header_owner(leaf),
-						ino, extent_offset);
-			BUG_ON(ret);
+			BUG();
 		}
 
 		if (found_type == BTRFS_INODE_ITEM_KEY)
 			break;
 
-		if (path->slots[0] == 0 ||
-		    path->slots[0] != pending_del_slot) {
+		if (path->slots[0] == 0) {
 			if (root->ref_cows &&
 			    BTRFS_I(inode)->location.objectid ! 						BTRFS_FREE_INO_OBJECTID) {
-- 
1.7.6.5
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs"
in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html