diff options
Diffstat (limited to 'fs/btrfs/file-item.c')
-rw-r--r-- | fs/btrfs/file-item.c | 114 |
1 files changed, 111 insertions, 3 deletions
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 3ebef871ee6c..df0447632dbd 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
@@ -140,6 +140,7 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, | |||
140 | return ret; | 140 | return ret; |
141 | } | 141 | } |
142 | 142 | ||
143 | |||
143 | int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, | 144 | int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, |
144 | struct bio *bio, u32 *dst) | 145 | struct bio *bio, u32 *dst) |
145 | { | 146 | { |
@@ -185,9 +186,16 @@ int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, | |||
185 | if (ret == -ENOENT || ret == -EFBIG) | 186 | if (ret == -ENOENT || ret == -EFBIG) |
186 | ret = 0; | 187 | ret = 0; |
187 | sum = 0; | 188 | sum = 0; |
188 | printk("no csum found for inode %lu start " | 189 | if (BTRFS_I(inode)->root->root_key.objectid == |
189 | "%llu\n", inode->i_ino, | 190 | BTRFS_DATA_RELOC_TREE_OBJECTID) { |
190 | (unsigned long long)offset); | 191 | set_extent_bits(io_tree, offset, |
192 | offset + bvec->bv_len - 1, | ||
193 | EXTENT_NODATASUM, GFP_NOFS); | ||
194 | } else { | ||
195 | printk("no csum found for inode %lu " | ||
196 | "start %llu\n", inode->i_ino, | ||
197 | (unsigned long long)offset); | ||
198 | } | ||
191 | item = NULL; | 199 | item = NULL; |
192 | btrfs_release_path(root, path); | 200 | btrfs_release_path(root, path); |
193 | goto found; | 201 | goto found; |
@@ -228,6 +236,106 @@ found: | |||
228 | return 0; | 236 | return 0; |
229 | } | 237 | } |
230 | 238 | ||
239 | int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, | ||
240 | struct list_head *list) | ||
241 | { | ||
242 | struct btrfs_key key; | ||
243 | struct btrfs_path *path; | ||
244 | struct extent_buffer *leaf; | ||
245 | struct btrfs_ordered_sum *sums; | ||
246 | struct btrfs_sector_sum *sector_sum; | ||
247 | struct btrfs_csum_item *item; | ||
248 | unsigned long offset; | ||
249 | int ret; | ||
250 | size_t size; | ||
251 | u64 csum_end; | ||
252 | u16 csum_size = btrfs_super_csum_size(&root->fs_info->super_copy); | ||
253 | |||
254 | path = btrfs_alloc_path(); | ||
255 | BUG_ON(!path); | ||
256 | |||
257 | key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; | ||
258 | key.offset = start; | ||
259 | key.type = BTRFS_EXTENT_CSUM_KEY; | ||
260 | |||
261 | ret = btrfs_search_slot(NULL, root->fs_info->csum_root, | ||
262 | &key, path, 0, 0); | ||
263 | if (ret < 0) | ||
264 | goto fail; | ||
265 | if (ret > 0 && path->slots[0] > 0) { | ||
266 | leaf = path->nodes[0]; | ||
267 | btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1); | ||
268 | if (key.objectid == BTRFS_EXTENT_CSUM_OBJECTID && | ||
269 | key.type == BTRFS_EXTENT_CSUM_KEY) { | ||
270 | offset = (start - key.offset) >> | ||
271 | root->fs_info->sb->s_blocksize_bits; | ||
272 | if (offset * csum_size < | ||
273 | btrfs_item_size_nr(leaf, path->slots[0] - 1)) | ||
274 | path->slots[0]--; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | while (start <= end) { | ||
279 | leaf = path->nodes[0]; | ||
280 | if (path->slots[0] >= btrfs_header_nritems(leaf)) { | ||
281 | ret = btrfs_next_leaf(root->fs_info->csum_root, path); | ||
282 | if (ret < 0) | ||
283 | goto fail; | ||
284 | if (ret > 0) | ||
285 | break; | ||
286 | leaf = path->nodes[0]; | ||
287 | } | ||
288 | |||
289 | btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); | ||
290 | if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || | ||
291 | key.type != BTRFS_EXTENT_CSUM_KEY) | ||
292 | break; | ||
293 | |||
294 | btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); | ||
295 | if (key.offset > end) | ||
296 | break; | ||
297 | |||
298 | if (key.offset > start) | ||
299 | start = key.offset; | ||
300 | |||
301 | size = btrfs_item_size_nr(leaf, path->slots[0]); | ||
302 | csum_end = key.offset + (size / csum_size) * root->sectorsize; | ||
303 | |||
304 | size = min(csum_end, end + 1) - start; | ||
305 | sums = kzalloc(btrfs_ordered_sum_size(root, size), GFP_NOFS); | ||
306 | BUG_ON(!sums); | ||
307 | |||
308 | sector_sum = sums->sums; | ||
309 | sums->bytenr = start; | ||
310 | sums->len = size; | ||
311 | |||
312 | offset = (start - key.offset) >> | ||
313 | root->fs_info->sb->s_blocksize_bits; | ||
314 | offset *= csum_size; | ||
315 | |||
316 | item = btrfs_item_ptr(path->nodes[0], path->slots[0], | ||
317 | struct btrfs_csum_item); | ||
318 | while (size > 0) { | ||
319 | read_extent_buffer(path->nodes[0], §or_sum->sum, | ||
320 | ((unsigned long)item) + offset, | ||
321 | csum_size); | ||
322 | sector_sum->bytenr = start; | ||
323 | |||
324 | size -= root->sectorsize; | ||
325 | start += root->sectorsize; | ||
326 | offset += csum_size; | ||
327 | sector_sum++; | ||
328 | } | ||
329 | list_add_tail(&sums->list, list); | ||
330 | |||
331 | path->slots[0]++; | ||
332 | } | ||
333 | ret = 0; | ||
334 | fail: | ||
335 | btrfs_free_path(path); | ||
336 | return ret; | ||
337 | } | ||
338 | |||
231 | int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, | 339 | int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, |
232 | struct bio *bio, u64 file_start, int contig) | 340 | struct bio *bio, u64 file_start, int contig) |
233 | { | 341 | { |