diff options
-rw-r--r-- | fs/btrfs/extent_io.c | 58 | ||||
-rw-r--r-- | fs/btrfs/extent_io.h | 4 | ||||
-rw-r--r-- | fs/btrfs/file-item.c | 49 | ||||
-rw-r--r-- | fs/btrfs/ordered-data.c | 28 | ||||
-rw-r--r-- | fs/btrfs/ordered-data.h | 3 |
5 files changed, 111 insertions, 31 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 1e4627c33548..617b5779b95b 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -1777,6 +1777,64 @@ out: | |||
1777 | return ret; | 1777 | return ret; |
1778 | } | 1778 | } |
1779 | 1779 | ||
1780 | void extent_cache_csums_dio(struct extent_io_tree *tree, u64 start, u32 csums[], | ||
1781 | int count) | ||
1782 | { | ||
1783 | struct rb_node *node; | ||
1784 | struct extent_state *state; | ||
1785 | |||
1786 | spin_lock(&tree->lock); | ||
1787 | /* | ||
1788 | * this search will find all the extents that end after | ||
1789 | * our range starts. | ||
1790 | */ | ||
1791 | node = tree_search(tree, start); | ||
1792 | BUG_ON(!node); | ||
1793 | |||
1794 | state = rb_entry(node, struct extent_state, rb_node); | ||
1795 | BUG_ON(state->start != start); | ||
1796 | |||
1797 | while (count) { | ||
1798 | state->private = *csums++; | ||
1799 | count--; | ||
1800 | state = next_state(state); | ||
1801 | } | ||
1802 | spin_unlock(&tree->lock); | ||
1803 | } | ||
1804 | |||
1805 | static inline u64 __btrfs_get_bio_offset(struct bio *bio, int bio_index) | ||
1806 | { | ||
1807 | struct bio_vec *bvec = bio->bi_io_vec + bio_index; | ||
1808 | |||
1809 | return page_offset(bvec->bv_page) + bvec->bv_offset; | ||
1810 | } | ||
1811 | |||
1812 | void extent_cache_csums(struct extent_io_tree *tree, struct bio *bio, int bio_index, | ||
1813 | u32 csums[], int count) | ||
1814 | { | ||
1815 | struct rb_node *node; | ||
1816 | struct extent_state *state = NULL; | ||
1817 | u64 start; | ||
1818 | |||
1819 | spin_lock(&tree->lock); | ||
1820 | do { | ||
1821 | start = __btrfs_get_bio_offset(bio, bio_index); | ||
1822 | if (state == NULL || state->start != start) { | ||
1823 | node = tree_search(tree, start); | ||
1824 | BUG_ON(!node); | ||
1825 | |||
1826 | state = rb_entry(node, struct extent_state, rb_node); | ||
1827 | BUG_ON(state->start != start); | ||
1828 | } | ||
1829 | state->private = *csums++; | ||
1830 | count--; | ||
1831 | bio_index++; | ||
1832 | |||
1833 | state = next_state(state); | ||
1834 | } while (count); | ||
1835 | spin_unlock(&tree->lock); | ||
1836 | } | ||
1837 | |||
1780 | int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private) | 1838 | int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private) |
1781 | { | 1839 | { |
1782 | struct rb_node *node; | 1840 | struct rb_node *node; |
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 258c92156857..db009d80bef4 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h | |||
@@ -261,6 +261,10 @@ int extent_readpages(struct extent_io_tree *tree, | |||
261 | int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | 261 | int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, |
262 | __u64 start, __u64 len, get_extent_t *get_extent); | 262 | __u64 start, __u64 len, get_extent_t *get_extent); |
263 | int set_state_private(struct extent_io_tree *tree, u64 start, u64 private); | 263 | int set_state_private(struct extent_io_tree *tree, u64 start, u64 private); |
264 | void extent_cache_csums_dio(struct extent_io_tree *tree, u64 start, u32 csums[], | ||
265 | int count); | ||
266 | void extent_cache_csums(struct extent_io_tree *tree, struct bio *bio, | ||
267 | int bvec_index, u32 csums[], int count); | ||
264 | int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private); | 268 | int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private); |
265 | void set_page_extent_mapped(struct page *page); | 269 | void set_page_extent_mapped(struct page *page); |
266 | 270 | ||
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index ad3cd8614d29..18f12aab6ebf 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
@@ -177,7 +177,8 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | |||
177 | struct inode *inode, struct bio *bio, | 177 | struct inode *inode, struct bio *bio, |
178 | u64 logical_offset, u32 *dst, int dio) | 178 | u64 logical_offset, u32 *dst, int dio) |
179 | { | 179 | { |
180 | u32 sum; | 180 | u32 sum[16]; |
181 | int len; | ||
181 | struct bio_vec *bvec = bio->bi_io_vec; | 182 | struct bio_vec *bvec = bio->bi_io_vec; |
182 | int bio_index = 0; | 183 | int bio_index = 0; |
183 | u64 offset = 0; | 184 | u64 offset = 0; |
@@ -186,7 +187,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | |||
186 | u64 disk_bytenr; | 187 | u64 disk_bytenr; |
187 | u32 diff; | 188 | u32 diff; |
188 | u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); | 189 | u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); |
189 | int ret; | 190 | int count; |
190 | struct btrfs_path *path; | 191 | struct btrfs_path *path; |
191 | struct btrfs_csum_item *item = NULL; | 192 | struct btrfs_csum_item *item = NULL; |
192 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | 193 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; |
@@ -214,10 +215,12 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | |||
214 | if (dio) | 215 | if (dio) |
215 | offset = logical_offset; | 216 | offset = logical_offset; |
216 | while (bio_index < bio->bi_vcnt) { | 217 | while (bio_index < bio->bi_vcnt) { |
218 | len = min_t(int, ARRAY_SIZE(sum), bio->bi_vcnt - bio_index); | ||
217 | if (!dio) | 219 | if (!dio) |
218 | offset = page_offset(bvec->bv_page) + bvec->bv_offset; | 220 | offset = page_offset(bvec->bv_page) + bvec->bv_offset; |
219 | ret = btrfs_find_ordered_sum(inode, offset, disk_bytenr, &sum); | 221 | count = btrfs_find_ordered_sum(inode, offset, disk_bytenr, sum, |
220 | if (ret == 0) | 222 | len); |
223 | if (count) | ||
221 | goto found; | 224 | goto found; |
222 | 225 | ||
223 | if (!item || disk_bytenr < item_start_offset || | 226 | if (!item || disk_bytenr < item_start_offset || |
@@ -230,10 +233,8 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | |||
230 | item = btrfs_lookup_csum(NULL, root->fs_info->csum_root, | 233 | item = btrfs_lookup_csum(NULL, root->fs_info->csum_root, |
231 | path, disk_bytenr, 0); | 234 | path, disk_bytenr, 0); |
232 | if (IS_ERR(item)) { | 235 | if (IS_ERR(item)) { |
233 | ret = PTR_ERR(item); | 236 | count = 1; |
234 | if (ret == -ENOENT || ret == -EFBIG) | 237 | sum[0] = 0; |
235 | ret = 0; | ||
236 | sum = 0; | ||
237 | if (BTRFS_I(inode)->root->root_key.objectid == | 238 | if (BTRFS_I(inode)->root->root_key.objectid == |
238 | BTRFS_DATA_RELOC_TREE_OBJECTID) { | 239 | BTRFS_DATA_RELOC_TREE_OBJECTID) { |
239 | set_extent_bits(io_tree, offset, | 240 | set_extent_bits(io_tree, offset, |
@@ -269,19 +270,29 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | |||
269 | diff = disk_bytenr - item_start_offset; | 270 | diff = disk_bytenr - item_start_offset; |
270 | diff = diff / root->sectorsize; | 271 | diff = diff / root->sectorsize; |
271 | diff = diff * csum_size; | 272 | diff = diff * csum_size; |
272 | 273 | count = min_t(int, len, (item_last_offset - disk_bytenr) >> | |
273 | read_extent_buffer(path->nodes[0], &sum, | 274 | inode->i_sb->s_blocksize_bits); |
275 | read_extent_buffer(path->nodes[0], sum, | ||
274 | ((unsigned long)item) + diff, | 276 | ((unsigned long)item) + diff, |
275 | csum_size); | 277 | csum_size * count); |
276 | found: | 278 | found: |
277 | if (dst) | 279 | if (dst) { |
278 | *dst++ = sum; | 280 | memcpy(dst, sum, count * csum_size); |
279 | else | 281 | dst += count; |
280 | set_state_private(io_tree, offset, sum); | 282 | } else { |
281 | disk_bytenr += bvec->bv_len; | 283 | if (dio) |
282 | offset += bvec->bv_len; | 284 | extent_cache_csums_dio(io_tree, offset, sum, |
283 | bio_index++; | 285 | count); |
284 | bvec++; | 286 | else |
287 | extent_cache_csums(io_tree, bio, bio_index, sum, | ||
288 | count); | ||
289 | } | ||
290 | while (count--) { | ||
291 | disk_bytenr += bvec->bv_len; | ||
292 | offset += bvec->bv_len; | ||
293 | bio_index++; | ||
294 | bvec++; | ||
295 | } | ||
285 | } | 296 | } |
286 | btrfs_free_path(path); | 297 | btrfs_free_path(path); |
287 | return 0; | 298 | return 0; |
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 005c45db699e..1ddd728541ee 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c | |||
@@ -986,7 +986,7 @@ out: | |||
986 | * be reclaimed before their checksum is actually put into the btree | 986 | * be reclaimed before their checksum is actually put into the btree |
987 | */ | 987 | */ |
988 | int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, | 988 | int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, |
989 | u32 *sum) | 989 | u32 *sum, int len) |
990 | { | 990 | { |
991 | struct btrfs_ordered_sum *ordered_sum; | 991 | struct btrfs_ordered_sum *ordered_sum; |
992 | struct btrfs_sector_sum *sector_sums; | 992 | struct btrfs_sector_sum *sector_sums; |
@@ -995,22 +995,28 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, | |||
995 | unsigned long num_sectors; | 995 | unsigned long num_sectors; |
996 | unsigned long i; | 996 | unsigned long i; |
997 | u32 sectorsize = BTRFS_I(inode)->root->sectorsize; | 997 | u32 sectorsize = BTRFS_I(inode)->root->sectorsize; |
998 | int ret = 1; | 998 | int index = 0; |
999 | 999 | ||
1000 | ordered = btrfs_lookup_ordered_extent(inode, offset); | 1000 | ordered = btrfs_lookup_ordered_extent(inode, offset); |
1001 | if (!ordered) | 1001 | if (!ordered) |
1002 | return 1; | 1002 | return 0; |
1003 | 1003 | ||
1004 | spin_lock_irq(&tree->lock); | 1004 | spin_lock_irq(&tree->lock); |
1005 | list_for_each_entry_reverse(ordered_sum, &ordered->list, list) { | 1005 | list_for_each_entry_reverse(ordered_sum, &ordered->list, list) { |
1006 | if (disk_bytenr >= ordered_sum->bytenr) { | 1006 | if (disk_bytenr >= ordered_sum->bytenr && |
1007 | num_sectors = ordered_sum->len / sectorsize; | 1007 | disk_bytenr < ordered_sum->bytenr + ordered_sum->len) { |
1008 | sector_sums = ordered_sum->sums; | 1008 | i = (disk_bytenr - ordered_sum->bytenr) >> |
1009 | for (i = 0; i < num_sectors; i++) { | 1009 | inode->i_sb->s_blocksize_bits; |
1010 | sector_sums = ordered_sum->sums + i; | ||
1011 | num_sectors = ordered_sum->len >> | ||
1012 | inode->i_sb->s_blocksize_bits; | ||
1013 | for (; i < num_sectors; i++) { | ||
1010 | if (sector_sums[i].bytenr == disk_bytenr) { | 1014 | if (sector_sums[i].bytenr == disk_bytenr) { |
1011 | *sum = sector_sums[i].sum; | 1015 | sum[index] = sector_sums[i].sum; |
1012 | ret = 0; | 1016 | index++; |
1013 | goto out; | 1017 | if (index == len) |
1018 | goto out; | ||
1019 | disk_bytenr += sectorsize; | ||
1014 | } | 1020 | } |
1015 | } | 1021 | } |
1016 | } | 1022 | } |
@@ -1018,7 +1024,7 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, | |||
1018 | out: | 1024 | out: |
1019 | spin_unlock_irq(&tree->lock); | 1025 | spin_unlock_irq(&tree->lock); |
1020 | btrfs_put_ordered_extent(ordered); | 1026 | btrfs_put_ordered_extent(ordered); |
1021 | return ret; | 1027 | return index; |
1022 | } | 1028 | } |
1023 | 1029 | ||
1024 | 1030 | ||
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index 8eadfe406cdd..58b0e3b0ebad 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h | |||
@@ -196,7 +196,8 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_range(struct inode *inode, | |||
196 | u64 len); | 196 | u64 len); |
197 | int btrfs_ordered_update_i_size(struct inode *inode, u64 offset, | 197 | int btrfs_ordered_update_i_size(struct inode *inode, u64 offset, |
198 | struct btrfs_ordered_extent *ordered); | 198 | struct btrfs_ordered_extent *ordered); |
199 | int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, u32 *sum); | 199 | int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, |
200 | u32 *sum, int len); | ||
200 | int btrfs_run_ordered_operations(struct btrfs_trans_handle *trans, | 201 | int btrfs_run_ordered_operations(struct btrfs_trans_handle *trans, |
201 | struct btrfs_root *root, int wait); | 202 | struct btrfs_root *root, int wait); |
202 | void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans, | 203 | void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans, |