aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/extent_io.c58
-rw-r--r--fs/btrfs/extent_io.h4
-rw-r--r--fs/btrfs/file-item.c49
-rw-r--r--fs/btrfs/ordered-data.c28
-rw-r--r--fs/btrfs/ordered-data.h3
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
1780void 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
1805static 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
1812void 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
1780int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private) 1838int 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,
261int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, 261int 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);
263int set_state_private(struct extent_io_tree *tree, u64 start, u64 private); 263int set_state_private(struct extent_io_tree *tree, u64 start, u64 private);
264void extent_cache_csums_dio(struct extent_io_tree *tree, u64 start, u32 csums[],
265 int count);
266void extent_cache_csums(struct extent_io_tree *tree, struct bio *bio,
267 int bvec_index, u32 csums[], int count);
264int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private); 268int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private);
265void set_page_extent_mapped(struct page *page); 269void 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);
276found: 278found:
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 */
988int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, 988int 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,
1018out: 1024out:
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);
197int btrfs_ordered_update_i_size(struct inode *inode, u64 offset, 197int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
198 struct btrfs_ordered_extent *ordered); 198 struct btrfs_ordered_extent *ordered);
199int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, u32 *sum); 199int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
200 u32 *sum, int len);
200int btrfs_run_ordered_operations(struct btrfs_trans_handle *trans, 201int btrfs_run_ordered_operations(struct btrfs_trans_handle *trans,
201 struct btrfs_root *root, int wait); 202 struct btrfs_root *root, int wait);
202void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans, 203void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,