Fix btrfs_wait_ordered_extent_range to properly wait
authorChris Mason <chris.mason@oracle.com>
Sat, 19 Jul 2008 00:42:20 +0000 (20:42 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:04:05 +0000 (11:04 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/file-item.c
fs/btrfs/inode.c
fs/btrfs/ordered-data.c

index d9c69e1..45127e4 100644 (file)
@@ -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;
index 08dbe73..50ee4be 100644 (file)
@@ -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);
-       if (em) {
-               clear_bit(EXTENT_FLAG_PINNED, &em->flags);
-               free_extent_map(em);
+       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);
 
index 1ddb7bc..c2b4a9c 100644 (file)
@@ -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;
-
-again:
-       if (start + len < start)
-               end = (u64)-1;
-       else
-               end = start + len - 1;
-       found = 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);
+
        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