From: Miao Xie <miaox@cn.fujitsu.com>
To: Linux Btrfs <linux-btrfs@vger.kernel.org>
Subject: [PATCH 2/3] Btrfs: make btrfs_truncate_inode_items() more readable
Date: Thu, 05 Jan 2012 16:32:41 +0800 [thread overview]
Message-ID: <4F056029.2080306@cn.fujitsu.com> (raw)
As the title said, this patch just make the functions of the truncation
more readable.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
fs/btrfs/inode.c | 289 ++++++++++++++++++++++++++++++------------------------
1 files changed, 159 insertions(+), 130 deletions(-)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 85e2312..df6060f 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2977,10 +2977,142 @@ 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);
+ return 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);
+
+ return 1;
+ }
+}
+
+/*
+ * 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 +3121,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 +3143,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 +3162,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 +3175,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 +3186,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.4
next reply other threads:[~2012-01-05 8:32 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-01-05 8:32 Miao Xie [this message]
2012-01-05 15:11 ` [PATCH 2/3] Btrfs: make btrfs_truncate_inode_items() more readable Josef Bacik
2012-01-06 1:35 ` Miao Xie
2012-01-06 1:14 ` Chris Mason
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=4F056029.2080306@cn.fujitsu.com \
--to=miaox@cn.fujitsu.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.