Commit e5a2217e authored by Chris Mason's avatar Chris Mason
Browse files

Fix btrfs_wait_ordered_extent_range to properly wait

parent 7f3c74fb
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -161,7 +161,8 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,

	while(bio_index < bio->bi_vcnt) {
		offset = page_offset(bvec->bv_page) + bvec->bv_offset;
		if (offset >= ordered->file_offset + ordered->len) {
		if (offset >= ordered->file_offset + ordered->len ||
		    offset < ordered->file_offset) {
			unsigned long bytes_left;
			sums->len = this_sum_bytes;
			this_sum_bytes = 0;
+20 −6
Original line number Diff line number Diff line
@@ -128,7 +128,9 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
		goto out;

	BUG_ON(num_bytes > btrfs_super_total_bytes(&root->fs_info->super_copy));
	mutex_lock(&BTRFS_I(inode)->extent_mutex);
	btrfs_drop_extent_cache(inode, start, start + num_bytes - 1);
	mutex_unlock(&BTRFS_I(inode)->extent_mutex);

	while(num_bytes > 0) {
		cur_alloc_size = min(num_bytes, root->fs_info->max_extent);
@@ -144,6 +146,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
		em->len = ins.offset;
		em->block_start = ins.objectid;
		em->bdev = root->fs_info->fs_devices->latest_bdev;
		mutex_lock(&BTRFS_I(inode)->extent_mutex);
		set_bit(EXTENT_FLAG_PINNED, &em->flags);
		while(1) {
			spin_lock(&em_tree->lock);
@@ -156,6 +159,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
			btrfs_drop_extent_cache(inode, start,
						start + ins.offset - 1);
		}
		mutex_unlock(&BTRFS_I(inode)->extent_mutex);

		cur_alloc_size = ins.offset;
		ret = btrfs_add_ordered_extent(inode, start, ins.objectid,
@@ -487,6 +491,8 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
	struct extent_map *em;
	u64 alloc_hint = 0;
	u64 clear_start;
	u64 clear_end;
	struct list_head list;
	struct btrfs_key ins;
	int ret;
@@ -509,12 +515,14 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
	ins.objectid = ordered_extent->start;
	ins.offset = ordered_extent->len;
	ins.type = BTRFS_EXTENT_ITEM_KEY;

	ret = btrfs_alloc_reserved_extent(trans, root, root->root_key.objectid,
					  trans->transid, inode->i_ino,
					  ordered_extent->file_offset, &ins);
	BUG_ON(ret);

	mutex_lock(&BTRFS_I(inode)->extent_mutex);

	ret = btrfs_drop_extents(trans, root, inode,
				 ordered_extent->file_offset,
				 ordered_extent->file_offset +
@@ -528,13 +536,19 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
				       ordered_extent->len, 0);
	BUG_ON(ret);


	spin_lock(&em_tree->lock);
	em = lookup_extent_mapping(em_tree, ordered_extent->file_offset,
			       ordered_extent->len);
	clear_start = ordered_extent->file_offset;
	clear_end = ordered_extent->file_offset + ordered_extent->len;
	while(clear_start < clear_end) {
		em = lookup_extent_mapping(em_tree, clear_start,
					   clear_end - clear_start);
		if (em) {
			clear_bit(EXTENT_FLAG_PINNED, &em->flags);
			clear_start = em->start + em->len;
			free_extent_map(em);
		} else {
			break;
		}
	}
	spin_unlock(&em_tree->lock);

+27 −18
Original line number Diff line number Diff line
@@ -324,22 +324,37 @@ void btrfs_start_ordered_extent(struct inode *inode,
void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
{
	u64 end;
	u64 orig_end;
	u64 wait_end;
	struct btrfs_ordered_extent *ordered;
	int found;
	int should_wait = 0;
	u64 mask = BTRFS_I(inode)->root->sectorsize - 1;

	if (start + len < start) {
		wait_end = (inode->i_size + mask) & ~mask;
		orig_end = (u64)-1;
	} else {
		orig_end = start + len - 1;
		wait_end = orig_end;
	}

	/* start IO across the range first to instantiate any delalloc
	 * extents
	 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
	do_sync_file_range(file, start, wait_end, SYNC_FILE_RANGE_WRITE);
#else
	do_sync_mapping_range(inode->i_mapping, start, wait_end,
			      SYNC_FILE_RANGE_WRITE);
#endif
	end = orig_end;
	wait_on_extent_writeback(&BTRFS_I(inode)->io_tree, start, orig_end);

again:
	if (start + len < start)
		end = (u64)-1;
	else
		end = start + len - 1;
	found = 0;
	while(1) {
		ordered = btrfs_lookup_first_ordered_extent(inode, end);
		if (!ordered) {
			break;
		}
		if (ordered->file_offset >= start + len) {
		if (ordered->file_offset > orig_end) {
			btrfs_put_ordered_extent(ordered);
			break;
		}
@@ -347,21 +362,15 @@ again:
			btrfs_put_ordered_extent(ordered);
			break;
		}
		btrfs_start_ordered_extent(inode, ordered, should_wait);
		found++;
		btrfs_start_ordered_extent(inode, ordered, 1);
		end = ordered->file_offset;
		btrfs_put_ordered_extent(ordered);
		if (end == 0)
		if (end == 0 || end == start)
			break;
		end--;
	}
	if (should_wait && found) {
		should_wait = 0;
		goto again;
	}
}


/*
 * find an ordered extent corresponding to file_offset.  return NULL if
 * nothing is found, otherwise take a reference on the extent and return it