ソースを参照

Btrfs: pin freed blocks from the FS tree too

Signed-off-by: Chris Mason <chris.mason@oracle.com>
Chris Mason 18 年 前
コミット
88fd146c27
3 ファイル変更26 行追加19 行削除
  1. 7 7
      fs/btrfs/ctree.c
  2. 2 1
      fs/btrfs/ctree.h
  3. 17 11
      fs/btrfs/extent-tree.c

+ 7 - 7
fs/btrfs/ctree.c

@@ -55,13 +55,13 @@ static int btrfs_cow_block(struct btrfs_root *root,
 		root->node = cow;
 		cow->count++;
 		if (buf != root->commit_root)
-			btrfs_free_extent(root, buf->blocknr, 1);
+			btrfs_free_extent(root, buf->blocknr, 1, 1);
 		btrfs_block_release(root, buf);
 	} else {
 		btrfs_set_node_blockptr(&parent->node, parent_slot,
 					cow->blocknr);
 		BUG_ON(list_empty(&parent->dirty));
-		btrfs_free_extent(root, buf->blocknr, 1);
+		btrfs_free_extent(root, buf->blocknr, 1, 1);
 	}
 	btrfs_block_release(root, buf);
 	return 0;
@@ -311,7 +311,7 @@ static int balance_level(struct btrfs_root *root, struct btrfs_path *path,
 		/* once for the root ptr */
 		btrfs_block_release(root, mid_buf);
 		clean_tree_block(root, mid_buf);
-		return btrfs_free_extent(root, blocknr, 1);
+		return btrfs_free_extent(root, blocknr, 1, 1);
 	}
 	parent = &parent_buf->node;
 
@@ -352,7 +352,7 @@ static int balance_level(struct btrfs_root *root, struct btrfs_path *path,
 			wret = del_ptr(root, path, level + 1, pslot + 1);
 			if (wret)
 				ret = wret;
-			wret = btrfs_free_extent(root, blocknr, 1);
+			wret = btrfs_free_extent(root, blocknr, 1, 1);
 			if (wret)
 				ret = wret;
 		} else {
@@ -388,7 +388,7 @@ static int balance_level(struct btrfs_root *root, struct btrfs_path *path,
 		wret = del_ptr(root, path, level + 1, pslot);
 		if (wret)
 			ret = wret;
-		wret = btrfs_free_extent(root, blocknr, 1);
+		wret = btrfs_free_extent(root, blocknr, 1, 1);
 		if (wret)
 			ret = wret;
 	} else {
@@ -1310,7 +1310,7 @@ int btrfs_del_item(struct btrfs_root *root, struct btrfs_path *path)
 			wret = del_ptr(root, path, 1, path->slots[1]);
 			if (wret)
 				ret = wret;
-			wret = btrfs_free_extent(root, leaf_buf->blocknr, 1);
+			wret = btrfs_free_extent(root, leaf_buf->blocknr, 1, 1);
 			if (wret)
 				ret = wret;
 		}
@@ -1348,7 +1348,7 @@ int btrfs_del_item(struct btrfs_root *root, struct btrfs_path *path)
 				if (wret)
 					ret = wret;
 				btrfs_block_release(root, leaf_buf);
-				wret = btrfs_free_extent(root, blocknr, 1);
+				wret = btrfs_free_extent(root, blocknr, 1, 1);
 				if (wret)
 					ret = wret;
 			} else {

+ 2 - 1
fs/btrfs/ctree.h

@@ -658,7 +658,8 @@ static inline u8 *btrfs_leaf_data(struct btrfs_leaf *l)
 
 struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_root *root);
 int btrfs_inc_ref(struct btrfs_root *root, struct btrfs_buffer *buf);
-int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks);
+int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks,
+		      int pin);
 int btrfs_search_slot(struct btrfs_root *root, struct btrfs_key *key,
 		struct btrfs_path *p, int ins_len, int cow);
 void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p);

+ 17 - 11
fs/btrfs/extent-tree.c

@@ -95,6 +95,7 @@ int btrfs_inc_ref(struct btrfs_root *root, struct btrfs_buffer *buf)
 int btrfs_finish_extent_commit(struct btrfs_root *root)
 {
 	unsigned long gang[8];
+	u64 first = 0;
 	int ret;
 	int i;
 
@@ -104,11 +105,13 @@ int btrfs_finish_extent_commit(struct btrfs_root *root)
 						 ARRAY_SIZE(gang));
 		if (!ret)
 			break;
+		if (!first)
+			first = gang[0];
 		for (i = 0; i < ret; i++) {
 			radix_tree_delete(&root->pinned_radix, gang[i]);
 		}
 	}
-	root->last_insert.objectid = 0;
+	root->last_insert.objectid = first;
 	root->last_insert.offset = 0;
 	return 0;
 }
@@ -140,7 +143,8 @@ static int finish_current_insert(struct btrfs_root *extent_root)
 /*
  * remove an extent from the root, returns 0 on success
  */
-static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks)
+static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks,
+			 int pin)
 {
 	struct btrfs_path path;
 	struct btrfs_key key;
@@ -150,6 +154,7 @@ static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks)
 	struct btrfs_key ins;
 	u32 refs;
 
+	BUG_ON(pin && num_blocks != 1);
 	key.objectid = blocknr;
 	key.flags = 0;
 	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
@@ -170,7 +175,7 @@ static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks)
 	refs = btrfs_extent_refs(ei) - 1;
 	btrfs_set_extent_refs(ei, refs);
 	if (refs == 0) {
-		if (!root->ref_cows) {
+		if (pin) {
 			int err;
 			radix_tree_preload(GFP_KERNEL);
 			err = radix_tree_insert(&extent_root->pinned_radix,
@@ -179,8 +184,7 @@ static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks)
 			radix_tree_preload_end();
 		}
 		ret = btrfs_del_item(extent_root, &path);
-		if (root != extent_root &&
-		    extent_root->last_insert.objectid > blocknr)
+		if (!pin && extent_root->last_insert.objectid > blocknr)
 			extent_root->last_insert.objectid = blocknr;
 		if (ret)
 			BUG();
@@ -208,7 +212,8 @@ static int del_pending_extents(struct btrfs_root *extent_root)
 		if (!ret)
 			break;
 		for (i = 0; i < ret; i++) {
-			ret = __free_extent(extent_root, gang[i]->blocknr, 1);
+			ret = __free_extent(extent_root,
+					    gang[i]->blocknr, 1, 1);
 			radix_tree_tag_clear(&extent_root->cache_radix,
 						gang[i]->blocknr,
 						CTREE_EXTENT_PENDING_DEL);
@@ -230,7 +235,8 @@ static int run_pending(struct btrfs_root *extent_root)
 /*
  * remove an extent from the root, returns 0 on success
  */
-int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks)
+int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks,
+		      int pin)
 {
 	struct btrfs_root *extent_root = root->extent_root;
 	struct btrfs_buffer *t;
@@ -243,7 +249,7 @@ int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks)
 				   CTREE_EXTENT_PENDING_DEL);
 		return 0;
 	}
-	ret = __free_extent(root, blocknr, num_blocks);
+	ret = __free_extent(root, blocknr, num_blocks, pin);
 	pending_ret = run_pending(root->extent_root);
 	return ret ? ret : pending_ret;
 }
@@ -451,7 +457,7 @@ static int walk_down_tree(struct btrfs_root *root,
 		ret = lookup_block_ref(root, blocknr, &refs);
 		if (refs != 1 || *level == 1) {
 			path->slots[*level]++;
-			ret = btrfs_free_extent(root, blocknr, 1);
+			ret = btrfs_free_extent(root, blocknr, 1, 1);
 			BUG_ON(ret);
 			continue;
 		}
@@ -464,7 +470,7 @@ static int walk_down_tree(struct btrfs_root *root,
 		path->slots[*level] = 0;
 	}
 out:
-	ret = btrfs_free_extent(root, path->nodes[*level]->blocknr, 1);
+	ret = btrfs_free_extent(root, path->nodes[*level]->blocknr, 1, 1);
 	btrfs_block_release(root, path->nodes[*level]);
 	path->nodes[*level] = NULL;
 	*level += 1;
@@ -492,7 +498,7 @@ static int walk_up_tree(struct btrfs_root *root, struct btrfs_path *path,
 			return 0;
 		} else {
 			ret = btrfs_free_extent(root,
-					  path->nodes[*level]->blocknr, 1);
+					  path->nodes[*level]->blocknr, 1, 1);
 			btrfs_block_release(root, path->nodes[*level]);
 			path->nodes[*level] = NULL;
 			*level = i + 1;