aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/file-item.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/file-item.c')
-rw-r--r--fs/btrfs/file-item.c85
1 files changed, 55 insertions, 30 deletions
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index a7bfc9541803..4f53159bdb9d 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -23,6 +23,7 @@
23#include "ctree.h" 23#include "ctree.h"
24#include "disk-io.h" 24#include "disk-io.h"
25#include "transaction.h" 25#include "transaction.h"
26#include "volumes.h"
26#include "print-tree.h" 27#include "print-tree.h"
27 28
28#define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \ 29#define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \
@@ -152,28 +153,54 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
152 return ret; 153 return ret;
153} 154}
154 155
156static void btrfs_io_bio_endio_readpage(struct btrfs_io_bio *bio, int err)
157{
158 kfree(bio->csum_allocated);
159}
160
155static int __btrfs_lookup_bio_sums(struct btrfs_root *root, 161static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
156 struct inode *inode, struct bio *bio, 162 struct inode *inode, struct bio *bio,
157 u64 logical_offset, u32 *dst, int dio) 163 u64 logical_offset, u32 *dst, int dio)
158{ 164{
159 u32 sum[16];
160 int len;
161 struct bio_vec *bvec = bio->bi_io_vec; 165 struct bio_vec *bvec = bio->bi_io_vec;
162 int bio_index = 0; 166 struct btrfs_io_bio *btrfs_bio = btrfs_io_bio(bio);
167 struct btrfs_csum_item *item = NULL;
168 struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
169 struct btrfs_path *path;
170 u8 *csum;
163 u64 offset = 0; 171 u64 offset = 0;
164 u64 item_start_offset = 0; 172 u64 item_start_offset = 0;
165 u64 item_last_offset = 0; 173 u64 item_last_offset = 0;
166 u64 disk_bytenr; 174 u64 disk_bytenr;
167 u32 diff; 175 u32 diff;
168 u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 176 int nblocks;
177 int bio_index = 0;
169 int count; 178 int count;
170 struct btrfs_path *path; 179 u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
171 struct btrfs_csum_item *item = NULL;
172 struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
173 180
174 path = btrfs_alloc_path(); 181 path = btrfs_alloc_path();
175 if (!path) 182 if (!path)
176 return -ENOMEM; 183 return -ENOMEM;
184
185 nblocks = bio->bi_size >> inode->i_sb->s_blocksize_bits;
186 if (!dst) {
187 if (nblocks * csum_size > BTRFS_BIO_INLINE_CSUM_SIZE) {
188 btrfs_bio->csum_allocated = kmalloc(nblocks * csum_size,
189 GFP_NOFS);
190 if (!btrfs_bio->csum_allocated) {
191 btrfs_free_path(path);
192 return -ENOMEM;
193 }
194 btrfs_bio->csum = btrfs_bio->csum_allocated;
195 btrfs_bio->end_io = btrfs_io_bio_endio_readpage;
196 } else {
197 btrfs_bio->csum = btrfs_bio->csum_inline;
198 }
199 csum = btrfs_bio->csum;
200 } else {
201 csum = (u8 *)dst;
202 }
203
177 if (bio->bi_size > PAGE_CACHE_SIZE * 8) 204 if (bio->bi_size > PAGE_CACHE_SIZE * 8)
178 path->reada = 2; 205 path->reada = 2;
179 206
@@ -194,11 +221,10 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
194 if (dio) 221 if (dio)
195 offset = logical_offset; 222 offset = logical_offset;
196 while (bio_index < bio->bi_vcnt) { 223 while (bio_index < bio->bi_vcnt) {
197 len = min_t(int, ARRAY_SIZE(sum), bio->bi_vcnt - bio_index);
198 if (!dio) 224 if (!dio)
199 offset = page_offset(bvec->bv_page) + bvec->bv_offset; 225 offset = page_offset(bvec->bv_page) + bvec->bv_offset;
200 count = btrfs_find_ordered_sum(inode, offset, disk_bytenr, sum, 226 count = btrfs_find_ordered_sum(inode, offset, disk_bytenr,
201 len); 227 (u32 *)csum, nblocks);
202 if (count) 228 if (count)
203 goto found; 229 goto found;
204 230
@@ -213,7 +239,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
213 path, disk_bytenr, 0); 239 path, disk_bytenr, 0);
214 if (IS_ERR(item)) { 240 if (IS_ERR(item)) {
215 count = 1; 241 count = 1;
216 sum[0] = 0; 242 memset(csum, 0, csum_size);
217 if (BTRFS_I(inode)->root->root_key.objectid == 243 if (BTRFS_I(inode)->root->root_key.objectid ==
218 BTRFS_DATA_RELOC_TREE_OBJECTID) { 244 BTRFS_DATA_RELOC_TREE_OBJECTID) {
219 set_extent_bits(io_tree, offset, 245 set_extent_bits(io_tree, offset,
@@ -222,9 +248,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
222 } else { 248 } else {
223 printk(KERN_INFO "btrfs no csum found " 249 printk(KERN_INFO "btrfs no csum found "
224 "for inode %llu start %llu\n", 250 "for inode %llu start %llu\n",
225 (unsigned long long) 251 btrfs_ino(inode), offset);
226 btrfs_ino(inode),
227 (unsigned long long)offset);
228 } 252 }
229 item = NULL; 253 item = NULL;
230 btrfs_release_path(path); 254 btrfs_release_path(path);
@@ -249,23 +273,14 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
249 diff = disk_bytenr - item_start_offset; 273 diff = disk_bytenr - item_start_offset;
250 diff = diff / root->sectorsize; 274 diff = diff / root->sectorsize;
251 diff = diff * csum_size; 275 diff = diff * csum_size;
252 count = min_t(int, len, (item_last_offset - disk_bytenr) >> 276 count = min_t(int, nblocks, (item_last_offset - disk_bytenr) >>
253 inode->i_sb->s_blocksize_bits); 277 inode->i_sb->s_blocksize_bits);
254 read_extent_buffer(path->nodes[0], sum, 278 read_extent_buffer(path->nodes[0], csum,
255 ((unsigned long)item) + diff, 279 ((unsigned long)item) + diff,
256 csum_size * count); 280 csum_size * count);
257found: 281found:
258 if (dst) { 282 csum += count * csum_size;
259 memcpy(dst, sum, count * csum_size); 283 nblocks -= count;
260 dst += count;
261 } else {
262 if (dio)
263 extent_cache_csums_dio(io_tree, offset, sum,
264 count);
265 else
266 extent_cache_csums(io_tree, bio, bio_index, sum,
267 count);
268 }
269 while (count--) { 284 while (count--) {
270 disk_bytenr += bvec->bv_len; 285 disk_bytenr += bvec->bv_len;
271 offset += bvec->bv_len; 286 offset += bvec->bv_len;
@@ -284,9 +299,19 @@ int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
284} 299}
285 300
286int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, 301int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode,
287 struct bio *bio, u64 offset) 302 struct btrfs_dio_private *dip, struct bio *bio,
303 u64 offset)
288{ 304{
289 return __btrfs_lookup_bio_sums(root, inode, bio, offset, NULL, 1); 305 int len = (bio->bi_sector << 9) - dip->disk_bytenr;
306 u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
307 int ret;
308
309 len >>= inode->i_sb->s_blocksize_bits;
310 len *= csum_size;
311
312 ret = __btrfs_lookup_bio_sums(root, inode, bio, offset,
313 (u32 *)(dip->csum + len), 1);
314 return ret;
290} 315}
291 316
292int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, 317int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,