Btrfs: Add fallocate support v2
This patch updates btrfs-progs for fallocate support.

fallocate is a little different in Btrfs because we need to tell the
COW system that a given preallocated extent doesn't need to be
cow'd as long as there are no snapshots of it.  This leverages the
-o nodatacow checks.
 
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>

diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 1eb69a9..8af3952 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2147,6 +2147,9 @@
 	total_needed += empty_size;
 
 	block_group = btrfs_lookup_block_group(root->fs_info, search_start);
+	if (!block_group)
+		block_group = btrfs_lookup_first_block_group(root->fs_info,
+							     search_start);
 	space_info = __find_space_info(root->fs_info, data);
 
 	down_read(&space_info->groups_sem);
@@ -3426,9 +3429,7 @@
 next:
 		level--;
 		btrfs_release_path(extent_root, path);
-		if (need_resched()) {
-			cond_resched();
-		}
+		cond_resched();
 	}
 	/* reached lowest level */
 	ret = 1;
@@ -3539,9 +3540,7 @@
 		}
 
 		btrfs_release_path(extent_root, path);
-		if (need_resched()) {
-			cond_resched();
-		}
+		cond_resched();
 	}
 	/* reached max tree level, but no tree root found. */
 	BUG();
@@ -3654,8 +3653,9 @@
 		exts[nr].encryption = btrfs_file_extent_encryption(leaf, fi);
 		exts[nr].other_encoding = btrfs_file_extent_other_encoding(leaf,
 									   fi);
-		WARN_ON(exts[nr].offset > 0);
-		WARN_ON(exts[nr].num_bytes != exts[nr].disk_num_bytes);
+		BUG_ON(exts[nr].offset > 0);
+		BUG_ON(exts[nr].compression || exts[nr].encryption);
+		BUG_ON(exts[nr].num_bytes != exts[nr].disk_num_bytes);
 
 		cur_pos += exts[nr].num_bytes;
 		nr++;
@@ -3709,6 +3709,7 @@
 	u32 nritems;
 	int nr_scaned = 0;
 	int extent_locked = 0;
+	int extent_type;
 	int ret;
 
 	memcpy(&key, leaf_key, sizeof(key));
@@ -3781,8 +3782,9 @@
 		}
 		fi = btrfs_item_ptr(leaf, path->slots[0],
 				    struct btrfs_file_extent_item);
-		if ((btrfs_file_extent_type(leaf, fi) !=
-		     BTRFS_FILE_EXTENT_REG) ||
+		extent_type = btrfs_file_extent_type(leaf, fi);
+		if ((extent_type != BTRFS_FILE_EXTENT_REG &&
+		     extent_type != BTRFS_FILE_EXTENT_PREALLOC) ||
 		    (btrfs_file_extent_disk_bytenr(leaf, fi) !=
 		     extent_key->objectid)) {
 			path->slots[0]++;
@@ -3865,16 +3867,10 @@
 
 		if (nr_extents == 1) {
 			/* update extent pointer in place */
-			btrfs_set_file_extent_generation(leaf, fi,
-						trans->transid);
 			btrfs_set_file_extent_disk_bytenr(leaf, fi,
 						new_extents[0].disk_bytenr);
 			btrfs_set_file_extent_disk_num_bytes(leaf, fi,
 						new_extents[0].disk_num_bytes);
-			btrfs_set_file_extent_ram_bytes(leaf, fi,
-						new_extents[0].ram_bytes);
-			ext_offset += new_extents[0].offset;
-			btrfs_set_file_extent_offset(leaf, fi, ext_offset);
 			btrfs_mark_buffer_dirty(leaf);
 
 			btrfs_drop_extent_cache(inode, key.offset,
@@ -3901,6 +3897,8 @@
 			btrfs_release_path(root, path);
 			key.offset += num_bytes;
 		} else {
+			BUG_ON(1);
+#if 0
 			u64 alloc_hint;
 			u64 extent_len;
 			int i;
@@ -3977,6 +3975,7 @@
 					break;
 			}
 			BUG_ON(i >= nr_extents);
+#endif
 		}
 
 		if (extent_locked) {
@@ -4156,15 +4155,10 @@
 		ref->extents[ext_index].bytenr = new_extent->disk_bytenr;
 		ref->extents[ext_index].num_bytes = new_extent->disk_num_bytes;
 
-		btrfs_set_file_extent_generation(leaf, fi, trans->transid);
-		btrfs_set_file_extent_ram_bytes(leaf, fi,
-						new_extent->ram_bytes);
 		btrfs_set_file_extent_disk_bytenr(leaf, fi,
 						new_extent->disk_bytenr);
 		btrfs_set_file_extent_disk_num_bytes(leaf, fi,
 						new_extent->disk_num_bytes);
-		new_extent->offset += btrfs_file_extent_offset(leaf, fi);
-		btrfs_set_file_extent_offset(leaf, fi, new_extent->offset);
 		btrfs_mark_buffer_dirty(leaf);
 
 		ret = btrfs_inc_extent_ref(trans, root,
@@ -4625,12 +4619,15 @@
 			 */
 			if (!new_extents) {
 				u64 group_start = group->key.objectid;
+				new_extents = kmalloc(sizeof(*new_extents),
+						      GFP_NOFS);
+				nr_extents = 1;
 				ret = get_new_locations(reloc_inode,
 							extent_key,
-							group_start, 0,
+							group_start, 1,
 							&new_extents,
 							&nr_extents);
-				if (ret < 0)
+				if (ret)
 					goto out;
 			}
 			btrfs_record_root_in_trans(found_root);
@@ -4762,7 +4759,8 @@
 	btrfs_set_inode_generation(leaf, item, 1);
 	btrfs_set_inode_size(leaf, item, size);
 	btrfs_set_inode_mode(leaf, item, S_IFREG | 0600);
-	btrfs_set_inode_flags(leaf, item, BTRFS_INODE_NODATASUM);
+	btrfs_set_inode_flags(leaf, item, BTRFS_INODE_NODATASUM |
+					  BTRFS_INODE_NOCOMPRESS);
 	btrfs_mark_buffer_dirty(leaf);
 	btrfs_release_path(root, path);
 out:
@@ -4835,6 +4833,7 @@
 	struct inode *reloc_inode;
 	struct btrfs_block_group_cache *block_group;
 	struct btrfs_key key;
+	u64 skipped;
 	u64 cur_byte;
 	u64 total_found;
 	u32 nritems;
@@ -4864,6 +4863,7 @@
 	btrfs_start_delalloc_inodes(info->tree_root);
 	btrfs_wait_ordered_extents(info->tree_root, 0);
 again:
+	skipped = 0;
 	total_found = 0;
 	progress = 0;
 	key.objectid = block_group->key.objectid;
@@ -4926,6 +4926,8 @@
 		ret = relocate_one_extent(root, path, &key, block_group,
 					  reloc_inode, pass);
 		BUG_ON(ret < 0);
+		if (ret > 0)
+			skipped++;
 
 		key.objectid = cur_byte;
 		key.type = 0;
@@ -4944,6 +4946,11 @@
 		printk("btrfs found %llu extents in pass %d\n",
 		       (unsigned long long)total_found, pass);
 		pass++;
+		if (total_found == skipped && pass > 2) {
+			iput(reloc_inode);
+			reloc_inode = create_reloc_inode(info, block_group);
+			pass = 0;
+		}
 		goto again;
 	}
 
@@ -5011,17 +5018,17 @@
 	while ((n = rb_last(&info->block_group_cache_tree)) != NULL) {
 		block_group = rb_entry(n, struct btrfs_block_group_cache,
 				       cache_node);
-
-		spin_unlock(&info->block_group_cache_lock);
-		btrfs_remove_free_space_cache(block_group);
-		spin_lock(&info->block_group_cache_lock);
-
 		rb_erase(&block_group->cache_node,
 			 &info->block_group_cache_tree);
+		spin_unlock(&info->block_group_cache_lock);
+
+		btrfs_remove_free_space_cache(block_group);
 		down_write(&block_group->space_info->groups_sem);
 		list_del(&block_group->list);
 		up_write(&block_group->space_info->groups_sem);
 		kfree(block_group);
+
+		spin_lock(&info->block_group_cache_lock);
 	}
 	spin_unlock(&info->block_group_cache_lock);
 	return 0;