Blame view
fs/btrfs/file-item.c
22.4 KB
6cbd55707 Btrfs: add GPLv2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ |
065631f6d Btrfs: checksum f... |
18 |
#include <linux/bio.h> |
5a0e3ad6a include cleanup: ... |
19 |
#include <linux/slab.h> |
065631f6d Btrfs: checksum f... |
20 21 |
#include <linux/pagemap.h> #include <linux/highmem.h> |
1e1d27017 Btrfs: add inode ... |
22 |
#include "ctree.h" |
dee26a9f7 btrfs_get_block, ... |
23 |
#include "disk-io.h" |
9f5fae2fe Btrfs: Add inode ... |
24 |
#include "transaction.h" |
1de037a43 Btrfs: fixup vari... |
25 |
#include "print-tree.h" |
1e1d27017 Btrfs: add inode ... |
26 |
|
d397712bc Btrfs: Fix checkp... |
27 |
#define MAX_CSUM_ITEMS(r, size) ((((BTRFS_LEAF_DATA_SIZE(r) - \ |
607d432da Btrfs: add suppor... |
28 29 |
sizeof(struct btrfs_item) * 2) / \ size) - 1)) |
07d400a6d Btrfs: tree loggi... |
30 31 32 33 34 |
#define MAX_ORDERED_SUM_BYTES(r) ((PAGE_SIZE - \ sizeof(struct btrfs_ordered_sum)) / \ sizeof(struct btrfs_sector_sum) * \ (r)->sectorsize - (r)->sectorsize) |
b18c66858 Btrfs: progress o... |
35 |
int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, |
f2eb0a241 Btrfs: Clone file... |
36 37 38 |
struct btrfs_root *root, u64 objectid, u64 pos, u64 disk_offset, u64 disk_num_bytes, |
c8b978188 Btrfs: Add zlib c... |
39 40 |
u64 num_bytes, u64 offset, u64 ram_bytes, u8 compression, u8 encryption, u16 other_encoding) |
9f5fae2fe Btrfs: Add inode ... |
41 |
{ |
dee26a9f7 btrfs_get_block, ... |
42 43 44 |
int ret = 0; struct btrfs_file_extent_item *item; struct btrfs_key file_key; |
5caf2a002 Btrfs: dynamic al... |
45 |
struct btrfs_path *path; |
5f39d397d Btrfs: Create ext... |
46 |
struct extent_buffer *leaf; |
dee26a9f7 btrfs_get_block, ... |
47 |
|
5caf2a002 Btrfs: dynamic al... |
48 |
path = btrfs_alloc_path(); |
db5b493ac Btrfs: cleanup so... |
49 50 |
if (!path) return -ENOMEM; |
dee26a9f7 btrfs_get_block, ... |
51 |
file_key.objectid = objectid; |
b18c66858 Btrfs: progress o... |
52 |
file_key.offset = pos; |
dee26a9f7 btrfs_get_block, ... |
53 |
btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); |
b9473439d Btrfs: leave btre... |
54 |
path->leave_spinning = 1; |
5caf2a002 Btrfs: dynamic al... |
55 |
ret = btrfs_insert_empty_item(trans, root, path, &file_key, |
dee26a9f7 btrfs_get_block, ... |
56 |
sizeof(*item)); |
54aa1f4df Btrfs: Audit call... |
57 58 |
if (ret < 0) goto out; |
9773a7886 Btrfs: byte offse... |
59 |
BUG_ON(ret); |
5f39d397d Btrfs: Create ext... |
60 61 |
leaf = path->nodes[0]; item = btrfs_item_ptr(leaf, path->slots[0], |
dee26a9f7 btrfs_get_block, ... |
62 |
struct btrfs_file_extent_item); |
f2eb0a241 Btrfs: Clone file... |
63 |
btrfs_set_file_extent_disk_bytenr(leaf, item, disk_offset); |
db94535db Btrfs: Allow tree... |
64 |
btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes); |
f2eb0a241 Btrfs: Clone file... |
65 |
btrfs_set_file_extent_offset(leaf, item, offset); |
db94535db Btrfs: Allow tree... |
66 |
btrfs_set_file_extent_num_bytes(leaf, item, num_bytes); |
c8b978188 Btrfs: Add zlib c... |
67 |
btrfs_set_file_extent_ram_bytes(leaf, item, ram_bytes); |
5f39d397d Btrfs: Create ext... |
68 69 |
btrfs_set_file_extent_generation(leaf, item, trans->transid); btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG); |
c8b978188 Btrfs: Add zlib c... |
70 71 72 |
btrfs_set_file_extent_compression(leaf, item, compression); btrfs_set_file_extent_encryption(leaf, item, encryption); btrfs_set_file_extent_other_encoding(leaf, item, other_encoding); |
5f39d397d Btrfs: Create ext... |
73 |
btrfs_mark_buffer_dirty(leaf); |
54aa1f4df Btrfs: Audit call... |
74 |
out: |
5caf2a002 Btrfs: dynamic al... |
75 |
btrfs_free_path(path); |
54aa1f4df Btrfs: Audit call... |
76 |
return ret; |
9f5fae2fe Btrfs: Add inode ... |
77 |
} |
dee26a9f7 btrfs_get_block, ... |
78 |
|
b18c66858 Btrfs: progress o... |
79 80 81 |
struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, |
d20f7043f Btrfs: move data ... |
82 |
u64 bytenr, int cow) |
6567e837d Btrfs: early work... |
83 84 85 86 87 |
{ int ret; struct btrfs_key file_key; struct btrfs_key found_key; struct btrfs_csum_item *item; |
5f39d397d Btrfs: Create ext... |
88 |
struct extent_buffer *leaf; |
6567e837d Btrfs: early work... |
89 |
u64 csum_offset = 0; |
6c41761fc btrfs: separate s... |
90 |
u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); |
a429e5137 Btrfs: working fi... |
91 |
int csums_in_item; |
6567e837d Btrfs: early work... |
92 |
|
d20f7043f Btrfs: move data ... |
93 94 95 |
file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; file_key.offset = bytenr; btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY); |
b18c66858 Btrfs: progress o... |
96 |
ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); |
6567e837d Btrfs: early work... |
97 98 |
if (ret < 0) goto fail; |
5f39d397d Btrfs: Create ext... |
99 |
leaf = path->nodes[0]; |
6567e837d Btrfs: early work... |
100 101 |
if (ret > 0) { ret = 1; |
70b2befd0 Btrfs: rework csu... |
102 |
if (path->slots[0] == 0) |
6567e837d Btrfs: early work... |
103 104 |
goto fail; path->slots[0]--; |
5f39d397d Btrfs: Create ext... |
105 |
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); |
d20f7043f Btrfs: move data ... |
106 |
if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY) |
6567e837d Btrfs: early work... |
107 |
goto fail; |
d20f7043f Btrfs: move data ... |
108 109 |
csum_offset = (bytenr - found_key.offset) >> |
6567e837d Btrfs: early work... |
110 |
root->fs_info->sb->s_blocksize_bits; |
5f39d397d Btrfs: Create ext... |
111 |
csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]); |
607d432da Btrfs: add suppor... |
112 |
csums_in_item /= csum_size; |
a429e5137 Btrfs: working fi... |
113 114 115 |
if (csum_offset >= csums_in_item) { ret = -EFBIG; |
6567e837d Btrfs: early work... |
116 117 118 119 |
goto fail; } } item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); |
509659cde Btrfs: switch to ... |
120 |
item = (struct btrfs_csum_item *)((unsigned char *)item + |
607d432da Btrfs: add suppor... |
121 |
csum_offset * csum_size); |
6567e837d Btrfs: early work... |
122 123 124 |
return item; fail: if (ret > 0) |
b18c66858 Btrfs: progress o... |
125 |
ret = -ENOENT; |
6567e837d Btrfs: early work... |
126 127 |
return ERR_PTR(ret); } |
dee26a9f7 btrfs_get_block, ... |
128 129 130 |
int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 objectid, |
9773a7886 Btrfs: byte offse... |
131 |
u64 offset, int mod) |
dee26a9f7 btrfs_get_block, ... |
132 133 134 135 136 137 138 |
{ int ret; struct btrfs_key file_key; int ins_len = mod < 0 ? -1 : 0; int cow = mod != 0; file_key.objectid = objectid; |
70b2befd0 Btrfs: rework csu... |
139 |
file_key.offset = offset; |
dee26a9f7 btrfs_get_block, ... |
140 141 142 143 |
btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow); return ret; } |
f254e52c1 Btrfs: verify csu... |
144 |
|
17d217fe9 Btrfs: fix nodata... |
145 |
|
4b46fce23 Btrfs: add basic ... |
146 147 148 |
static int __btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, struct bio *bio, u64 logical_offset, u32 *dst, int dio) |
61b494401 Btrfs: Fix stream... |
149 150 151 152 |
{ u32 sum; struct bio_vec *bvec = bio->bi_io_vec; int bio_index = 0; |
4b46fce23 Btrfs: add basic ... |
153 |
u64 offset = 0; |
61b494401 Btrfs: Fix stream... |
154 155 |
u64 item_start_offset = 0; u64 item_last_offset = 0; |
d20f7043f Btrfs: move data ... |
156 |
u64 disk_bytenr; |
61b494401 Btrfs: Fix stream... |
157 |
u32 diff; |
6c41761fc btrfs: separate s... |
158 |
u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); |
61b494401 Btrfs: Fix stream... |
159 160 161 162 163 164 |
int ret; struct btrfs_path *path; struct btrfs_csum_item *item = NULL; struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; path = btrfs_alloc_path(); |
c2db1073f Btrfs: check retu... |
165 166 |
if (!path) return -ENOMEM; |
4d1b5fb4d Btrfs: Lookup rea... |
167 168 |
if (bio->bi_size > PAGE_CACHE_SIZE * 8) path->reada = 2; |
61b494401 Btrfs: Fix stream... |
169 170 |
WARN_ON(bio->bi_vcnt <= 0); |
2cf8572da Btrfs: use the co... |
171 172 173 174 175 176 |
/* * the free space stuff is only read when it hasn't been * updated in the current transaction. So, we can safely * read from the commit root and sidestep a nasty deadlock * between reading the free space cache and updating the csum tree. */ |
ddf23b3fc Btrfs: skip locki... |
177 |
if (btrfs_is_free_space_inode(root, inode)) { |
2cf8572da Btrfs: use the co... |
178 |
path->search_commit_root = 1; |
ddf23b3fc Btrfs: skip locki... |
179 180 |
path->skip_locking = 1; } |
2cf8572da Btrfs: use the co... |
181 |
|
d20f7043f Btrfs: move data ... |
182 |
disk_bytenr = (u64)bio->bi_sector << 9; |
4b46fce23 Btrfs: add basic ... |
183 184 |
if (dio) offset = logical_offset; |
d397712bc Btrfs: Fix checkp... |
185 |
while (bio_index < bio->bi_vcnt) { |
4b46fce23 Btrfs: add basic ... |
186 187 |
if (!dio) offset = page_offset(bvec->bv_page) + bvec->bv_offset; |
d20f7043f Btrfs: move data ... |
188 |
ret = btrfs_find_ordered_sum(inode, offset, disk_bytenr, &sum); |
61b494401 Btrfs: Fix stream... |
189 190 |
if (ret == 0) goto found; |
d20f7043f Btrfs: move data ... |
191 192 |
if (!item || disk_bytenr < item_start_offset || disk_bytenr >= item_last_offset) { |
61b494401 Btrfs: Fix stream... |
193 194 195 196 |
struct btrfs_key found_key; u32 item_size; if (item) |
b3b4aa74b btrfs: drop unuse... |
197 |
btrfs_release_path(path); |
d20f7043f Btrfs: move data ... |
198 199 |
item = btrfs_lookup_csum(NULL, root->fs_info->csum_root, path, disk_bytenr, 0); |
61b494401 Btrfs: Fix stream... |
200 201 202 203 204 |
if (IS_ERR(item)) { ret = PTR_ERR(item); if (ret == -ENOENT || ret == -EFBIG) ret = 0; sum = 0; |
17d217fe9 Btrfs: fix nodata... |
205 206 207 208 209 210 |
if (BTRFS_I(inode)->root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID) { set_extent_bits(io_tree, offset, offset + bvec->bv_len - 1, EXTENT_NODATASUM, GFP_NOFS); } else { |
d397712bc Btrfs: Fix checkp... |
211 |
printk(KERN_INFO "btrfs no csum found " |
33345d015 Btrfs: Always use... |
212 213 214 215 |
"for inode %llu start %llu ", (unsigned long long) btrfs_ino(inode), |
17d217fe9 Btrfs: fix nodata... |
216 217 |
(unsigned long long)offset); } |
6dab81574 Btrfs: Hold csum ... |
218 |
item = NULL; |
b3b4aa74b btrfs: drop unuse... |
219 |
btrfs_release_path(path); |
61b494401 Btrfs: Fix stream... |
220 221 222 223 224 225 226 227 228 |
goto found; } btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]); item_start_offset = found_key.offset; item_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); item_last_offset = item_start_offset + |
607d432da Btrfs: add suppor... |
229 |
(item_size / csum_size) * |
61b494401 Btrfs: Fix stream... |
230 231 232 233 234 235 236 237 |
root->sectorsize; item = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_csum_item); } /* * this byte range must be able to fit inside * a single leaf so it will also fit inside a u32 */ |
d20f7043f Btrfs: move data ... |
238 |
diff = disk_bytenr - item_start_offset; |
61b494401 Btrfs: Fix stream... |
239 |
diff = diff / root->sectorsize; |
607d432da Btrfs: add suppor... |
240 |
diff = diff * csum_size; |
61b494401 Btrfs: Fix stream... |
241 242 |
read_extent_buffer(path->nodes[0], &sum, |
3de9d6b64 btrfs_lookup_bio_... |
243 |
((unsigned long)item) + diff, |
607d432da Btrfs: add suppor... |
244 |
csum_size); |
61b494401 Btrfs: Fix stream... |
245 |
found: |
d20f7043f Btrfs: move data ... |
246 247 248 249 250 |
if (dst) *dst++ = sum; else set_state_private(io_tree, offset, sum); disk_bytenr += bvec->bv_len; |
4b46fce23 Btrfs: add basic ... |
251 |
offset += bvec->bv_len; |
61b494401 Btrfs: Fix stream... |
252 253 254 255 256 257 |
bio_index++; bvec++; } btrfs_free_path(path); return 0; } |
4b46fce23 Btrfs: add basic ... |
258 259 260 261 262 263 264 265 266 267 268 |
int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, struct bio *bio, u32 *dst) { return __btrfs_lookup_bio_sums(root, inode, bio, 0, dst, 0); } int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, struct bio *bio, u64 offset, u32 *dst) { return __btrfs_lookup_bio_sums(root, inode, bio, offset, dst, 1); } |
17d217fe9 Btrfs: fix nodata... |
269 |
int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, |
a2de733c7 btrfs: scrub |
270 |
struct list_head *list, int search_commit) |
17d217fe9 Btrfs: fix nodata... |
271 272 273 274 275 276 277 278 279 280 281 |
{ struct btrfs_key key; struct btrfs_path *path; struct extent_buffer *leaf; struct btrfs_ordered_sum *sums; struct btrfs_sector_sum *sector_sum; struct btrfs_csum_item *item; unsigned long offset; int ret; size_t size; u64 csum_end; |
6c41761fc btrfs: separate s... |
282 |
u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); |
17d217fe9 Btrfs: fix nodata... |
283 284 |
path = btrfs_alloc_path(); |
d8926bb3b btrfs: don't BUG_... |
285 286 |
if (!path) return -ENOMEM; |
17d217fe9 Btrfs: fix nodata... |
287 |
|
a2de733c7 btrfs: scrub |
288 289 290 291 292 |
if (search_commit) { path->skip_locking = 1; path->reada = 2; path->search_commit_root = 1; } |
17d217fe9 Btrfs: fix nodata... |
293 294 295 |
key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; key.offset = start; key.type = BTRFS_EXTENT_CSUM_KEY; |
07d400a6d Btrfs: tree loggi... |
296 |
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
17d217fe9 Btrfs: fix nodata... |
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
if (ret < 0) goto fail; if (ret > 0 && path->slots[0] > 0) { leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1); if (key.objectid == BTRFS_EXTENT_CSUM_OBJECTID && key.type == BTRFS_EXTENT_CSUM_KEY) { offset = (start - key.offset) >> root->fs_info->sb->s_blocksize_bits; if (offset * csum_size < btrfs_item_size_nr(leaf, path->slots[0] - 1)) path->slots[0]--; } } while (start <= end) { leaf = path->nodes[0]; if (path->slots[0] >= btrfs_header_nritems(leaf)) { |
07d400a6d Btrfs: tree loggi... |
315 |
ret = btrfs_next_leaf(root, path); |
17d217fe9 Btrfs: fix nodata... |
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
if (ret < 0) goto fail; if (ret > 0) break; leaf = path->nodes[0]; } btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || key.type != BTRFS_EXTENT_CSUM_KEY) break; btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); if (key.offset > end) break; if (key.offset > start) start = key.offset; size = btrfs_item_size_nr(leaf, path->slots[0]); csum_end = key.offset + (size / csum_size) * root->sectorsize; |
87b29b208 Btrfs: properly c... |
337 338 339 340 |
if (csum_end <= start) { path->slots[0]++; continue; } |
17d217fe9 Btrfs: fix nodata... |
341 |
|
07d400a6d Btrfs: tree loggi... |
342 |
csum_end = min(csum_end, end + 1); |
17d217fe9 Btrfs: fix nodata... |
343 344 |
item = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_csum_item); |
07d400a6d Btrfs: tree loggi... |
345 346 347 348 349 350 |
while (start < csum_end) { size = min_t(size_t, csum_end - start, MAX_ORDERED_SUM_BYTES(root)); sums = kzalloc(btrfs_ordered_sum_size(root, size), GFP_NOFS); BUG_ON(!sums); |
17d217fe9 Btrfs: fix nodata... |
351 |
|
07d400a6d Btrfs: tree loggi... |
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 |
sector_sum = sums->sums; sums->bytenr = start; sums->len = size; offset = (start - key.offset) >> root->fs_info->sb->s_blocksize_bits; offset *= csum_size; while (size > 0) { read_extent_buffer(path->nodes[0], §or_sum->sum, ((unsigned long)item) + offset, csum_size); sector_sum->bytenr = start; size -= root->sectorsize; start += root->sectorsize; offset += csum_size; sector_sum++; } list_add_tail(&sums->list, list); } |
17d217fe9 Btrfs: fix nodata... |
374 375 376 377 378 379 380 |
path->slots[0]++; } ret = 0; fail: btrfs_free_path(path); return ret; } |
3edf7d33f Btrfs: Handle dat... |
381 |
int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, |
d20f7043f Btrfs: move data ... |
382 |
struct bio *bio, u64 file_start, int contig) |
e015640f9 Btrfs: Write bio ... |
383 |
{ |
e6dcd2dc9 Btrfs: New data=o... |
384 385 |
struct btrfs_ordered_sum *sums; struct btrfs_sector_sum *sector_sum; |
3edf7d33f Btrfs: Handle dat... |
386 |
struct btrfs_ordered_extent *ordered; |
e015640f9 Btrfs: Write bio ... |
387 388 389 |
char *data; struct bio_vec *bvec = bio->bi_io_vec; int bio_index = 0; |
3edf7d33f Btrfs: Handle dat... |
390 391 392 |
unsigned long total_bytes = 0; unsigned long this_sum_bytes = 0; u64 offset; |
d20f7043f Btrfs: move data ... |
393 |
u64 disk_bytenr; |
e015640f9 Btrfs: Write bio ... |
394 |
|
e6dcd2dc9 Btrfs: New data=o... |
395 396 |
WARN_ON(bio->bi_vcnt <= 0); sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS); |
e015640f9 Btrfs: Write bio ... |
397 398 |
if (!sums) return -ENOMEM; |
3edf7d33f Btrfs: Handle dat... |
399 |
|
ed98b56a6 Btrfs: Take the c... |
400 |
sector_sum = sums->sums; |
d20f7043f Btrfs: move data ... |
401 |
disk_bytenr = (u64)bio->bi_sector << 9; |
e6dcd2dc9 Btrfs: New data=o... |
402 403 |
sums->len = bio->bi_size; INIT_LIST_HEAD(&sums->list); |
d20f7043f Btrfs: move data ... |
404 405 406 407 408 409 410 |
if (contig) offset = file_start; else offset = page_offset(bvec->bv_page) + bvec->bv_offset; ordered = btrfs_lookup_ordered_extent(inode, offset); |
3edf7d33f Btrfs: Handle dat... |
411 |
BUG_ON(!ordered); |
d20f7043f Btrfs: move data ... |
412 |
sums->bytenr = ordered->start; |
e015640f9 Btrfs: Write bio ... |
413 |
|
d397712bc Btrfs: Fix checkp... |
414 |
while (bio_index < bio->bi_vcnt) { |
d20f7043f Btrfs: move data ... |
415 416 417 418 419 |
if (!contig) offset = page_offset(bvec->bv_page) + bvec->bv_offset; if (!contig && (offset >= ordered->file_offset + ordered->len || offset < ordered->file_offset)) { |
3edf7d33f Btrfs: Handle dat... |
420 421 422 423 424 425 426 427 428 429 430 |
unsigned long bytes_left; sums->len = this_sum_bytes; this_sum_bytes = 0; btrfs_add_ordered_sum(inode, ordered, sums); btrfs_put_ordered_extent(ordered); bytes_left = bio->bi_size - total_bytes; sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left), GFP_NOFS); BUG_ON(!sums); |
ed98b56a6 Btrfs: Take the c... |
431 |
sector_sum = sums->sums; |
3edf7d33f Btrfs: Handle dat... |
432 |
sums->len = bytes_left; |
d20f7043f Btrfs: move data ... |
433 |
ordered = btrfs_lookup_ordered_extent(inode, offset); |
3edf7d33f Btrfs: Handle dat... |
434 |
BUG_ON(!ordered); |
d20f7043f Btrfs: move data ... |
435 |
sums->bytenr = ordered->start; |
3edf7d33f Btrfs: Handle dat... |
436 |
} |
e015640f9 Btrfs: Write bio ... |
437 |
data = kmap_atomic(bvec->bv_page, KM_USER0); |
e6dcd2dc9 Btrfs: New data=o... |
438 439 440 441 442 |
sector_sum->sum = ~(u32)0; sector_sum->sum = btrfs_csum_data(root, data + bvec->bv_offset, sector_sum->sum, bvec->bv_len); |
e015640f9 Btrfs: Write bio ... |
443 |
kunmap_atomic(data, KM_USER0); |
e6dcd2dc9 Btrfs: New data=o... |
444 445 |
btrfs_csum_final(sector_sum->sum, (char *)§or_sum->sum); |
d20f7043f Btrfs: move data ... |
446 |
sector_sum->bytenr = disk_bytenr; |
ed98b56a6 Btrfs: Take the c... |
447 |
|
e6dcd2dc9 Btrfs: New data=o... |
448 |
sector_sum++; |
e015640f9 Btrfs: Write bio ... |
449 |
bio_index++; |
3edf7d33f Btrfs: Handle dat... |
450 451 |
total_bytes += bvec->bv_len; this_sum_bytes += bvec->bv_len; |
d20f7043f Btrfs: move data ... |
452 453 |
disk_bytenr += bvec->bv_len; offset += bvec->bv_len; |
e015640f9 Btrfs: Write bio ... |
454 455 |
bvec++; } |
ed98b56a6 Btrfs: Take the c... |
456 |
this_sum_bytes = 0; |
3edf7d33f Btrfs: Handle dat... |
457 458 |
btrfs_add_ordered_sum(inode, ordered, sums); btrfs_put_ordered_extent(ordered); |
e015640f9 Btrfs: Write bio ... |
459 460 |
return 0; } |
459931eca Btrfs: Delete csu... |
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 |
/* * helper function for csum removal, this expects the * key to describe the csum pointed to by the path, and it expects * the csum to overlap the range [bytenr, len] * * The csum should not be entirely contained in the range and the * range should not be entirely contained in the csum. * * This calls btrfs_truncate_item with the correct args based on the * overlap, and fixes up the key as required. */ static noinline int truncate_one_csum(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *key, u64 bytenr, u64 len) { struct extent_buffer *leaf; |
6c41761fc btrfs: separate s... |
479 |
u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); |
459931eca Btrfs: Delete csu... |
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 |
u64 csum_end; u64 end_byte = bytenr + len; u32 blocksize_bits = root->fs_info->sb->s_blocksize_bits; int ret; leaf = path->nodes[0]; csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; csum_end <<= root->fs_info->sb->s_blocksize_bits; csum_end += key->offset; if (key->offset < bytenr && csum_end <= end_byte) { /* * [ bytenr - len ] * [ ] * [csum ] * A simple truncate off the end of the item */ u32 new_size = (bytenr - key->offset) >> blocksize_bits; new_size *= csum_size; ret = btrfs_truncate_item(trans, root, path, new_size, 1); |
459931eca Btrfs: Delete csu... |
500 501 502 503 504 505 506 507 508 509 510 511 |
} else if (key->offset >= bytenr && csum_end > end_byte && end_byte > key->offset) { /* * [ bytenr - len ] * [ ] * [csum ] * we need to truncate from the beginning of the csum */ u32 new_size = (csum_end - end_byte) >> blocksize_bits; new_size *= csum_size; ret = btrfs_truncate_item(trans, root, path, new_size, 0); |
459931eca Btrfs: Delete csu... |
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 |
key->offset = end_byte; ret = btrfs_set_item_key_safe(trans, root, path, key); BUG_ON(ret); } else { BUG(); } return 0; } /* * deletes the csum items from the csum tree for a given * range of bytes. */ int btrfs_del_csums(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 len) { struct btrfs_path *path; struct btrfs_key key; u64 end_byte = bytenr + len; u64 csum_end; struct extent_buffer *leaf; int ret; |
6c41761fc btrfs: separate s... |
535 |
u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); |
459931eca Btrfs: Delete csu... |
536 537 538 539 540 |
int blocksize_bits = root->fs_info->sb->s_blocksize_bits; root = root->fs_info->csum_root; path = btrfs_alloc_path(); |
2a29edc6b btrfs: fix severa... |
541 542 |
if (!path) return -ENOMEM; |
459931eca Btrfs: Delete csu... |
543 |
|
d397712bc Btrfs: Fix checkp... |
544 |
while (1) { |
459931eca Btrfs: Delete csu... |
545 546 547 |
key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; key.offset = end_byte - 1; key.type = BTRFS_EXTENT_CSUM_KEY; |
b9473439d Btrfs: leave btre... |
548 |
path->leave_spinning = 1; |
459931eca Btrfs: Delete csu... |
549 550 551 |
ret = btrfs_search_slot(trans, root, &key, path, -1, 1); if (ret > 0) { if (path->slots[0] == 0) |
65a246c5f Btrfs: return err... |
552 |
break; |
459931eca Btrfs: Delete csu... |
553 |
path->slots[0]--; |
ad0397a7a Btrfs: do error c... |
554 |
} else if (ret < 0) { |
65a246c5f Btrfs: return err... |
555 |
break; |
459931eca Btrfs: Delete csu... |
556 |
} |
ad0397a7a Btrfs: do error c... |
557 |
|
459931eca Btrfs: Delete csu... |
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 |
leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || key.type != BTRFS_EXTENT_CSUM_KEY) { break; } if (key.offset >= end_byte) break; csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; csum_end <<= blocksize_bits; csum_end += key.offset; /* this csum ends before we start, we're done */ if (csum_end <= bytenr) break; /* delete the entire item, it is inside our range */ if (key.offset >= bytenr && csum_end <= end_byte) { ret = btrfs_del_item(trans, root, path); |
65a246c5f Btrfs: return err... |
580 581 |
if (ret) goto out; |
dcbdd4dcb Btrfs: delete che... |
582 583 |
if (key.offset == bytenr) break; |
459931eca Btrfs: Delete csu... |
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 |
} else if (key.offset < bytenr && csum_end > end_byte) { unsigned long offset; unsigned long shift_len; unsigned long item_offset; /* * [ bytenr - len ] * [csum ] * * Our bytes are in the middle of the csum, * we need to split this item and insert a new one. * * But we can't drop the path because the * csum could change, get removed, extended etc. * * The trick here is the max size of a csum item leaves * enough room in the tree block for a single * item header. So, we split the item in place, * adding a new header pointing to the existing * bytes. Then we loop around again and we have * a nicely formed csum item that we can neatly * truncate. */ offset = (bytenr - key.offset) >> blocksize_bits; offset *= csum_size; shift_len = (len >> blocksize_bits) * csum_size; item_offset = btrfs_item_ptr_offset(leaf, path->slots[0]); memset_extent_buffer(leaf, 0, item_offset + offset, shift_len); key.offset = bytenr; /* * btrfs_split_item returns -EAGAIN when the * item changed size or key */ ret = btrfs_split_item(trans, root, path, &key, offset); BUG_ON(ret && ret != -EAGAIN); key.offset = end_byte - 1; } else { ret = truncate_one_csum(trans, root, path, &key, bytenr, len); BUG_ON(ret); |
dcbdd4dcb Btrfs: delete che... |
630 631 |
if (key.offset < bytenr) break; |
459931eca Btrfs: Delete csu... |
632 |
} |
b3b4aa74b btrfs: drop unuse... |
633 |
btrfs_release_path(path); |
459931eca Btrfs: Delete csu... |
634 |
} |
65a246c5f Btrfs: return err... |
635 |
ret = 0; |
459931eca Btrfs: Delete csu... |
636 637 |
out: btrfs_free_path(path); |
65a246c5f Btrfs: return err... |
638 |
return ret; |
459931eca Btrfs: Delete csu... |
639 |
} |
065631f6d Btrfs: checksum f... |
640 |
int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, |
d20f7043f Btrfs: move data ... |
641 |
struct btrfs_root *root, |
e6dcd2dc9 Btrfs: New data=o... |
642 |
struct btrfs_ordered_sum *sums) |
f254e52c1 Btrfs: verify csu... |
643 |
{ |
d20f7043f Btrfs: move data ... |
644 |
u64 bytenr; |
f254e52c1 Btrfs: verify csu... |
645 646 |
int ret; struct btrfs_key file_key; |
6567e837d Btrfs: early work... |
647 |
struct btrfs_key found_key; |
065631f6d Btrfs: checksum f... |
648 |
u64 next_offset; |
e6dcd2dc9 Btrfs: New data=o... |
649 |
u64 total_bytes = 0; |
065631f6d Btrfs: checksum f... |
650 |
int found_next; |
5caf2a002 Btrfs: dynamic al... |
651 |
struct btrfs_path *path; |
f254e52c1 Btrfs: verify csu... |
652 |
struct btrfs_csum_item *item; |
065631f6d Btrfs: checksum f... |
653 |
struct btrfs_csum_item *item_end; |
ff79f8190 Btrfs: Add back f... |
654 |
struct extent_buffer *leaf = NULL; |
6567e837d Btrfs: early work... |
655 |
u64 csum_offset; |
e6dcd2dc9 Btrfs: New data=o... |
656 |
struct btrfs_sector_sum *sector_sum; |
f578d4bd7 Btrfs: Optimize c... |
657 658 |
u32 nritems; u32 ins_size; |
6c41761fc btrfs: separate s... |
659 |
u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); |
6e92f5e65 Btrfs: While doin... |
660 |
|
5caf2a002 Btrfs: dynamic al... |
661 |
path = btrfs_alloc_path(); |
d8926bb3b btrfs: don't BUG_... |
662 663 |
if (!path) return -ENOMEM; |
ed98b56a6 Btrfs: Take the c... |
664 |
sector_sum = sums->sums; |
065631f6d Btrfs: checksum f... |
665 666 667 |
again: next_offset = (u64)-1; found_next = 0; |
d20f7043f Btrfs: move data ... |
668 669 670 671 |
file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; file_key.offset = sector_sum->bytenr; bytenr = sector_sum->bytenr; btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY); |
a429e5137 Btrfs: working fi... |
672 |
|
d20f7043f Btrfs: move data ... |
673 |
item = btrfs_lookup_csum(trans, root, path, sector_sum->bytenr, 1); |
ff79f8190 Btrfs: Add back f... |
674 675 |
if (!IS_ERR(item)) { leaf = path->nodes[0]; |
639cb5867 Btrfs: Fix variab... |
676 |
ret = 0; |
a429e5137 Btrfs: working fi... |
677 |
goto found; |
ff79f8190 Btrfs: Add back f... |
678 |
} |
a429e5137 Btrfs: working fi... |
679 |
ret = PTR_ERR(item); |
4a500fd17 Btrfs: Metadata E... |
680 681 |
if (ret != -EFBIG && ret != -ENOENT) goto fail_unlock; |
a429e5137 Btrfs: working fi... |
682 683 684 |
if (ret == -EFBIG) { u32 item_size; /* we found one, but it isn't big enough yet */ |
5f39d397d Btrfs: Create ext... |
685 686 |
leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); |
607d432da Btrfs: add suppor... |
687 688 |
if ((item_size / csum_size) >= MAX_CSUM_ITEMS(root, csum_size)) { |
a429e5137 Btrfs: working fi... |
689 690 691 692 |
/* already at max size, make a new one */ goto insert; } } else { |
f578d4bd7 Btrfs: Optimize c... |
693 |
int slot = path->slots[0] + 1; |
a429e5137 Btrfs: working fi... |
694 |
/* we didn't find a csum item, insert one */ |
f578d4bd7 Btrfs: Optimize c... |
695 696 697 |
nritems = btrfs_header_nritems(path->nodes[0]); if (path->slots[0] >= nritems - 1) { ret = btrfs_next_leaf(root, path); |
b56baf5be Minor fix for btr... |
698 |
if (ret == 1) |
f578d4bd7 Btrfs: Optimize c... |
699 |
found_next = 1; |
b56baf5be Minor fix for btr... |
700 |
if (ret != 0) |
f578d4bd7 Btrfs: Optimize c... |
701 |
goto insert; |
b56baf5be Minor fix for btr... |
702 |
slot = 0; |
f578d4bd7 Btrfs: Optimize c... |
703 704 |
} btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot); |
d20f7043f Btrfs: move data ... |
705 706 |
if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || found_key.type != BTRFS_EXTENT_CSUM_KEY) { |
f578d4bd7 Btrfs: Optimize c... |
707 708 709 710 711 |
found_next = 1; goto insert; } next_offset = found_key.offset; found_next = 1; |
a429e5137 Btrfs: working fi... |
712 713 714 715 716 717 718 |
goto insert; } /* * at this point, we know the tree has an item, but it isn't big * enough yet to put our csum in. Grow it */ |
b3b4aa74b btrfs: drop unuse... |
719 |
btrfs_release_path(path); |
6567e837d Btrfs: early work... |
720 |
ret = btrfs_search_slot(trans, root, &file_key, path, |
607d432da Btrfs: add suppor... |
721 |
csum_size, 1); |
6567e837d Btrfs: early work... |
722 |
if (ret < 0) |
53863232e Btrfs: Lower cont... |
723 |
goto fail_unlock; |
459931eca Btrfs: Delete csu... |
724 725 726 727 728 |
if (ret > 0) { if (path->slots[0] == 0) goto insert; path->slots[0]--; |
6567e837d Btrfs: early work... |
729 |
} |
459931eca Btrfs: Delete csu... |
730 |
|
5f39d397d Btrfs: Create ext... |
731 732 |
leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); |
d20f7043f Btrfs: move data ... |
733 |
csum_offset = (bytenr - found_key.offset) >> |
6567e837d Btrfs: early work... |
734 |
root->fs_info->sb->s_blocksize_bits; |
459931eca Btrfs: Delete csu... |
735 |
|
d20f7043f Btrfs: move data ... |
736 737 |
if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY || found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || |
607d432da Btrfs: add suppor... |
738 |
csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) { |
6567e837d Btrfs: early work... |
739 740 |
goto insert; } |
459931eca Btrfs: Delete csu... |
741 |
|
5f39d397d Btrfs: Create ext... |
742 |
if (csum_offset >= btrfs_item_size_nr(leaf, path->slots[0]) / |
607d432da Btrfs: add suppor... |
743 744 |
csum_size) { u32 diff = (csum_offset + 1) * csum_size; |
459931eca Btrfs: Delete csu... |
745 746 747 748 749 750 751 |
/* * is the item big enough already? we dropped our lock * before and need to recheck */ if (diff < btrfs_item_size_nr(leaf, path->slots[0])) goto csum; |
5f39d397d Btrfs: Create ext... |
752 |
diff = diff - btrfs_item_size_nr(leaf, path->slots[0]); |
d397712bc Btrfs: Fix checkp... |
753 |
if (diff != csum_size) |
3a6863756 Btrfs: sparse files! |
754 |
goto insert; |
459931eca Btrfs: Delete csu... |
755 |
|
a429e5137 Btrfs: working fi... |
756 |
ret = btrfs_extend_item(trans, root, path, diff); |
6567e837d Btrfs: early work... |
757 758 759 760 |
goto csum; } insert: |
b3b4aa74b btrfs: drop unuse... |
761 |
btrfs_release_path(path); |
6567e837d Btrfs: early work... |
762 |
csum_offset = 0; |
f578d4bd7 Btrfs: Optimize c... |
763 |
if (found_next) { |
d20f7043f Btrfs: move data ... |
764 765 766 |
u64 tmp = total_bytes + root->sectorsize; u64 next_sector = sector_sum->bytenr; struct btrfs_sector_sum *next = sector_sum + 1; |
d397712bc Btrfs: Fix checkp... |
767 |
while (tmp < sums->len) { |
d20f7043f Btrfs: move data ... |
768 769 770 771 772 773 774 |
if (next_sector + root->sectorsize != next->bytenr) break; tmp += root->sectorsize; next_sector = next->bytenr; next++; } tmp = min(tmp, next_offset - file_key.offset); |
f578d4bd7 Btrfs: Optimize c... |
775 776 |
tmp >>= root->fs_info->sb->s_blocksize_bits; tmp = max((u64)1, tmp); |
607d432da Btrfs: add suppor... |
777 778 |
tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size)); ins_size = csum_size * tmp; |
f578d4bd7 Btrfs: Optimize c... |
779 |
} else { |
607d432da Btrfs: add suppor... |
780 |
ins_size = csum_size; |
f578d4bd7 Btrfs: Optimize c... |
781 |
} |
b9473439d Btrfs: leave btre... |
782 |
path->leave_spinning = 1; |
5caf2a002 Btrfs: dynamic al... |
783 |
ret = btrfs_insert_empty_item(trans, root, path, &file_key, |
f578d4bd7 Btrfs: Optimize c... |
784 |
ins_size); |
b9473439d Btrfs: leave btre... |
785 |
path->leave_spinning = 0; |
54aa1f4df Btrfs: Audit call... |
786 |
if (ret < 0) |
53863232e Btrfs: Lower cont... |
787 |
goto fail_unlock; |
a429e5137 Btrfs: working fi... |
788 |
if (ret != 0) { |
a429e5137 Btrfs: working fi... |
789 |
WARN_ON(1); |
53863232e Btrfs: Lower cont... |
790 |
goto fail_unlock; |
a429e5137 Btrfs: working fi... |
791 |
} |
6567e837d Btrfs: early work... |
792 |
csum: |
5f39d397d Btrfs: Create ext... |
793 794 |
leaf = path->nodes[0]; item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); |
f254e52c1 Btrfs: verify csu... |
795 |
ret = 0; |
509659cde Btrfs: switch to ... |
796 |
item = (struct btrfs_csum_item *)((unsigned char *)item + |
607d432da Btrfs: add suppor... |
797 |
csum_offset * csum_size); |
b18c66858 Btrfs: progress o... |
798 |
found: |
065631f6d Btrfs: checksum f... |
799 800 801 |
item_end = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); item_end = (struct btrfs_csum_item *)((unsigned char *)item_end + btrfs_item_size_nr(leaf, path->slots[0])); |
e6dcd2dc9 Btrfs: New data=o... |
802 |
next_sector: |
aadfeb6e3 Btrfs: Add some e... |
803 |
|
a65917156 Btrfs: stop using... |
804 |
write_extent_buffer(leaf, §or_sum->sum, (unsigned long)item, csum_size); |
7f3c74fb8 Btrfs: Keep exten... |
805 |
|
e6dcd2dc9 Btrfs: New data=o... |
806 807 808 |
total_bytes += root->sectorsize; sector_sum++; if (total_bytes < sums->len) { |
6e92f5e65 Btrfs: While doin... |
809 |
item = (struct btrfs_csum_item *)((char *)item + |
607d432da Btrfs: add suppor... |
810 |
csum_size); |
d20f7043f Btrfs: move data ... |
811 812 813 |
if (item < item_end && bytenr + PAGE_CACHE_SIZE == sector_sum->bytenr) { bytenr = sector_sum->bytenr; |
e6dcd2dc9 Btrfs: New data=o... |
814 |
goto next_sector; |
2e1a992e3 Btrfs: Make sure ... |
815 |
} |
065631f6d Btrfs: checksum f... |
816 |
} |
a65917156 Btrfs: stop using... |
817 |
|
5caf2a002 Btrfs: dynamic al... |
818 |
btrfs_mark_buffer_dirty(path->nodes[0]); |
e6dcd2dc9 Btrfs: New data=o... |
819 |
if (total_bytes < sums->len) { |
b3b4aa74b btrfs: drop unuse... |
820 |
btrfs_release_path(path); |
b9473439d Btrfs: leave btre... |
821 |
cond_resched(); |
065631f6d Btrfs: checksum f... |
822 823 |
goto again; } |
53863232e Btrfs: Lower cont... |
824 |
out: |
5caf2a002 Btrfs: dynamic al... |
825 |
btrfs_free_path(path); |
f254e52c1 Btrfs: verify csu... |
826 |
return ret; |
53863232e Btrfs: Lower cont... |
827 828 |
fail_unlock: |
53863232e Btrfs: Lower cont... |
829 |
goto out; |
f254e52c1 Btrfs: verify csu... |
830 |
} |