diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-10-15 16:15:53 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:56 -0400 |
commit | db94535db75e67fab12ccbb7f5ee548e33fed891 (patch) | |
tree | 1ad7dfc82b003294a94ee87d7329b24b902b369f /fs/btrfs/file.c | |
parent | 1a5bc167f6707542b79a55452075525620ed43f5 (diff) |
Btrfs: Allow tree blocks larger than the page size
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r-- | fs/btrfs/file.c | 126 |
1 files changed, 60 insertions, 66 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 1734ca695555..844d8807e44a 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -120,9 +120,9 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans, | |||
120 | btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE); | 120 | btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE); |
121 | ptr = btrfs_file_extent_inline_start(ei); | 121 | ptr = btrfs_file_extent_inline_start(ei); |
122 | 122 | ||
123 | kaddr = kmap_atomic(page, KM_USER0); | 123 | kaddr = kmap_atomic(page, KM_USER1); |
124 | write_extent_buffer(leaf, kaddr + page_offset, ptr, size); | 124 | write_extent_buffer(leaf, kaddr + page_offset, ptr, size); |
125 | kunmap_atomic(kaddr, KM_USER0); | 125 | kunmap_atomic(kaddr, KM_USER1); |
126 | btrfs_mark_buffer_dirty(leaf); | 126 | btrfs_mark_buffer_dirty(leaf); |
127 | fail: | 127 | fail: |
128 | btrfs_free_path(path); | 128 | btrfs_free_path(path); |
@@ -142,11 +142,12 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
142 | struct inode *inode = file->f_path.dentry->d_inode; | 142 | struct inode *inode = file->f_path.dentry->d_inode; |
143 | struct extent_map *em; | 143 | struct extent_map *em; |
144 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | 144 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; |
145 | u64 hint_block; | 145 | u64 hint_byte; |
146 | u64 num_blocks; | 146 | u64 num_bytes; |
147 | u64 start_pos; | 147 | u64 start_pos; |
148 | u64 end_of_last_block; | 148 | u64 end_of_last_block; |
149 | u64 end_pos = pos + write_bytes; | 149 | u64 end_pos = pos + write_bytes; |
150 | u32 inline_size; | ||
150 | loff_t isize = i_size_read(inode); | 151 | loff_t isize = i_size_read(inode); |
151 | 152 | ||
152 | em = alloc_extent_map(GFP_NOFS); | 153 | em = alloc_extent_map(GFP_NOFS); |
@@ -156,11 +157,12 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
156 | em->bdev = inode->i_sb->s_bdev; | 157 | em->bdev = inode->i_sb->s_bdev; |
157 | 158 | ||
158 | start_pos = pos & ~((u64)root->sectorsize - 1); | 159 | start_pos = pos & ~((u64)root->sectorsize - 1); |
159 | num_blocks = (write_bytes + pos - start_pos + root->sectorsize - 1) >> | 160 | num_bytes = (write_bytes + pos - start_pos + |
160 | inode->i_blkbits; | 161 | root->sectorsize - 1) & ~((u64)root->sectorsize - 1); |
161 | 162 | ||
162 | down_read(&BTRFS_I(inode)->root->snap_sem); | 163 | down_read(&BTRFS_I(inode)->root->snap_sem); |
163 | end_of_last_block = start_pos + (num_blocks << inode->i_blkbits) - 1; | 164 | end_of_last_block = start_pos + num_bytes - 1; |
165 | |||
164 | lock_extent(em_tree, start_pos, end_of_last_block, GFP_NOFS); | 166 | lock_extent(em_tree, start_pos, end_of_last_block, GFP_NOFS); |
165 | mutex_lock(&root->fs_info->fs_mutex); | 167 | mutex_lock(&root->fs_info->fs_mutex); |
166 | trans = btrfs_start_transaction(root, 1); | 168 | trans = btrfs_start_transaction(root, 1); |
@@ -169,8 +171,8 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
169 | goto out_unlock; | 171 | goto out_unlock; |
170 | } | 172 | } |
171 | btrfs_set_trans_block_group(trans, inode); | 173 | btrfs_set_trans_block_group(trans, inode); |
172 | inode->i_blocks += num_blocks << 3; | 174 | inode->i_blocks += num_bytes >> 9; |
173 | hint_block = 0; | 175 | hint_byte = 0; |
174 | 176 | ||
175 | if ((end_of_last_block & 4095) == 0) { | 177 | if ((end_of_last_block & 4095) == 0) { |
176 | printk("strange end of last %Lu %zu %Lu\n", start_pos, write_bytes, end_of_last_block); | 178 | printk("strange end of last %Lu %zu %Lu\n", start_pos, write_bytes, end_of_last_block); |
@@ -191,11 +193,10 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
191 | err = btrfs_drop_extents(trans, root, inode, | 193 | err = btrfs_drop_extents(trans, root, inode, |
192 | last_pos_in_file, | 194 | last_pos_in_file, |
193 | last_pos_in_file + hole_size, | 195 | last_pos_in_file + hole_size, |
194 | &hint_block); | 196 | &hint_byte); |
195 | if (err) | 197 | if (err) |
196 | goto failed; | 198 | goto failed; |
197 | 199 | ||
198 | hole_size >>= inode->i_blkbits; | ||
199 | err = btrfs_insert_file_extent(trans, root, | 200 | err = btrfs_insert_file_extent(trans, root, |
200 | inode->i_ino, | 201 | inode->i_ino, |
201 | last_pos_in_file, | 202 | last_pos_in_file, |
@@ -209,8 +210,10 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
209 | * either allocate an extent for the new bytes or setup the key | 210 | * either allocate an extent for the new bytes or setup the key |
210 | * to show we are doing inline data in the extent | 211 | * to show we are doing inline data in the extent |
211 | */ | 212 | */ |
213 | inline_size = end_pos - start_pos; | ||
212 | if (isize >= PAGE_CACHE_SIZE || pos + write_bytes < inode->i_size || | 214 | if (isize >= PAGE_CACHE_SIZE || pos + write_bytes < inode->i_size || |
213 | pos + write_bytes - start_pos > BTRFS_MAX_INLINE_DATA_SIZE(root)) { | 215 | inline_size >= BTRFS_MAX_INLINE_DATA_SIZE(root) || |
216 | inline_size >= PAGE_CACHE_SIZE) { | ||
214 | u64 last_end; | 217 | u64 last_end; |
215 | for (i = 0; i < num_pages; i++) { | 218 | for (i = 0; i < num_pages; i++) { |
216 | struct page *p = pages[i]; | 219 | struct page *p = pages[i]; |
@@ -224,10 +227,9 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
224 | } else { | 227 | } else { |
225 | struct page *p = pages[0]; | 228 | struct page *p = pages[0]; |
226 | /* step one, delete the existing extents in this range */ | 229 | /* step one, delete the existing extents in this range */ |
227 | /* FIXME blocksize != pagesize */ | ||
228 | err = btrfs_drop_extents(trans, root, inode, start_pos, | 230 | err = btrfs_drop_extents(trans, root, inode, start_pos, |
229 | (pos + write_bytes + root->sectorsize -1) & | 231 | (pos + write_bytes + root->sectorsize -1) & |
230 | ~((u64)root->sectorsize - 1), &hint_block); | 232 | ~((u64)root->sectorsize - 1), &hint_byte); |
231 | if (err) | 233 | if (err) |
232 | goto failed; | 234 | goto failed; |
233 | 235 | ||
@@ -283,7 +285,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) | |||
283 | */ | 285 | */ |
284 | int btrfs_drop_extents(struct btrfs_trans_handle *trans, | 286 | int btrfs_drop_extents(struct btrfs_trans_handle *trans, |
285 | struct btrfs_root *root, struct inode *inode, | 287 | struct btrfs_root *root, struct inode *inode, |
286 | u64 start, u64 end, u64 *hint_block) | 288 | u64 start, u64 end, u64 *hint_byte) |
287 | { | 289 | { |
288 | int ret; | 290 | int ret; |
289 | struct btrfs_key key; | 291 | struct btrfs_key key; |
@@ -346,8 +348,7 @@ next_slot: | |||
346 | found_type = btrfs_file_extent_type(leaf, extent); | 348 | found_type = btrfs_file_extent_type(leaf, extent); |
347 | if (found_type == BTRFS_FILE_EXTENT_REG) { | 349 | if (found_type == BTRFS_FILE_EXTENT_REG) { |
348 | extent_end = key.offset + | 350 | extent_end = key.offset + |
349 | (btrfs_file_extent_num_blocks(leaf, extent) << | 351 | btrfs_file_extent_num_bytes(leaf, extent); |
350 | inode->i_blkbits); | ||
351 | found_extent = 1; | 352 | found_extent = 1; |
352 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | 353 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { |
353 | struct btrfs_item *item; | 354 | struct btrfs_item *item; |
@@ -386,17 +387,17 @@ next_slot: | |||
386 | 387 | ||
387 | if (end < extent_end && end >= key.offset) { | 388 | if (end < extent_end && end >= key.offset) { |
388 | if (found_extent) { | 389 | if (found_extent) { |
389 | u64 disk_blocknr = | 390 | u64 disk_bytenr = |
390 | btrfs_file_extent_disk_blocknr(leaf,extent); | 391 | btrfs_file_extent_disk_bytenr(leaf, extent); |
391 | u64 disk_num_blocks = | 392 | u64 disk_num_bytes = |
392 | btrfs_file_extent_disk_num_blocks(leaf, | 393 | btrfs_file_extent_disk_num_bytes(leaf, |
393 | extent); | 394 | extent); |
394 | read_extent_buffer(leaf, &old, | 395 | read_extent_buffer(leaf, &old, |
395 | (unsigned long)extent, | 396 | (unsigned long)extent, |
396 | sizeof(old)); | 397 | sizeof(old)); |
397 | if (disk_blocknr != 0) { | 398 | if (disk_bytenr != 0) { |
398 | ret = btrfs_inc_extent_ref(trans, root, | 399 | ret = btrfs_inc_extent_ref(trans, root, |
399 | disk_blocknr, disk_num_blocks); | 400 | disk_bytenr, disk_num_bytes); |
400 | BUG_ON(ret); | 401 | BUG_ON(ret); |
401 | } | 402 | } |
402 | } | 403 | } |
@@ -410,21 +411,19 @@ next_slot: | |||
410 | keep = 1; | 411 | keep = 1; |
411 | WARN_ON(start & (root->sectorsize - 1)); | 412 | WARN_ON(start & (root->sectorsize - 1)); |
412 | if (found_extent) { | 413 | if (found_extent) { |
413 | new_num = (start - key.offset) >> | 414 | new_num = start - key.offset; |
414 | inode->i_blkbits; | 415 | old_num = btrfs_file_extent_num_bytes(leaf, |
415 | old_num = btrfs_file_extent_num_blocks(leaf, | 416 | extent); |
416 | extent); | 417 | *hint_byte = |
417 | *hint_block = | 418 | btrfs_file_extent_disk_bytenr(leaf, |
418 | btrfs_file_extent_disk_blocknr(leaf, | 419 | extent); |
419 | extent); | 420 | if (btrfs_file_extent_disk_bytenr(leaf, |
420 | if (btrfs_file_extent_disk_blocknr(leaf, | 421 | extent)) { |
421 | extent)) { | ||
422 | inode->i_blocks -= | 422 | inode->i_blocks -= |
423 | (old_num - new_num) << 3; | 423 | (old_num - new_num) >> 9; |
424 | } | 424 | } |
425 | btrfs_set_file_extent_num_blocks(leaf, | 425 | btrfs_set_file_extent_num_bytes(leaf, extent, |
426 | extent, | 426 | new_num); |
427 | new_num); | ||
428 | btrfs_mark_buffer_dirty(leaf); | 427 | btrfs_mark_buffer_dirty(leaf); |
429 | } else { | 428 | } else { |
430 | WARN_ON(1); | 429 | WARN_ON(1); |
@@ -432,33 +431,32 @@ next_slot: | |||
432 | } | 431 | } |
433 | /* delete the entire extent */ | 432 | /* delete the entire extent */ |
434 | if (!keep) { | 433 | if (!keep) { |
435 | u64 disk_blocknr = 0; | 434 | u64 disk_bytenr = 0; |
436 | u64 disk_num_blocks = 0; | 435 | u64 disk_num_bytes = 0; |
437 | u64 extent_num_blocks = 0; | 436 | u64 extent_num_bytes = 0; |
438 | if (found_extent) { | 437 | if (found_extent) { |
439 | disk_blocknr = | 438 | disk_bytenr = |
440 | btrfs_file_extent_disk_blocknr(leaf, | 439 | btrfs_file_extent_disk_bytenr(leaf, |
441 | extent); | 440 | extent); |
442 | disk_num_blocks = | 441 | disk_num_bytes = |
443 | btrfs_file_extent_disk_num_blocks(leaf, | 442 | btrfs_file_extent_disk_num_bytes(leaf, |
444 | extent); | ||
445 | extent_num_blocks = | ||
446 | btrfs_file_extent_num_blocks(leaf, | ||
447 | extent); | ||
448 | *hint_block = | ||
449 | btrfs_file_extent_disk_blocknr(leaf, | ||
450 | extent); | 443 | extent); |
444 | extent_num_bytes = | ||
445 | btrfs_file_extent_num_bytes(leaf, extent); | ||
446 | *hint_byte = | ||
447 | btrfs_file_extent_disk_bytenr(leaf, | ||
448 | extent); | ||
451 | } | 449 | } |
452 | ret = btrfs_del_item(trans, root, path); | 450 | ret = btrfs_del_item(trans, root, path); |
453 | /* TODO update progress marker and return */ | 451 | /* TODO update progress marker and return */ |
454 | BUG_ON(ret); | 452 | BUG_ON(ret); |
455 | btrfs_release_path(root, path); | 453 | btrfs_release_path(root, path); |
456 | extent = NULL; | 454 | extent = NULL; |
457 | if (found_extent && disk_blocknr != 0) { | 455 | if (found_extent && disk_bytenr != 0) { |
458 | inode->i_blocks -= extent_num_blocks << 3; | 456 | inode->i_blocks -= extent_num_bytes >> 9; |
459 | ret = btrfs_free_extent(trans, root, | 457 | ret = btrfs_free_extent(trans, root, |
460 | disk_blocknr, | 458 | disk_bytenr, |
461 | disk_num_blocks, 0); | 459 | disk_num_bytes, 0); |
462 | } | 460 | } |
463 | 461 | ||
464 | BUG_ON(ret); | 462 | BUG_ON(ret); |
@@ -491,20 +489,19 @@ next_slot: | |||
491 | (unsigned long)extent, sizeof(old)); | 489 | (unsigned long)extent, sizeof(old)); |
492 | 490 | ||
493 | btrfs_set_file_extent_offset(leaf, extent, | 491 | btrfs_set_file_extent_offset(leaf, extent, |
494 | le64_to_cpu(old.offset) + | 492 | le64_to_cpu(old.offset) + end - key.offset); |
495 | ((end - key.offset) >> inode->i_blkbits)); | 493 | WARN_ON(le64_to_cpu(old.num_bytes) < |
496 | WARN_ON(le64_to_cpu(old.num_blocks) < | 494 | (extent_end - end)); |
497 | (extent_end - end) >> inode->i_blkbits); | 495 | btrfs_set_file_extent_num_bytes(leaf, extent, |
498 | btrfs_set_file_extent_num_blocks(leaf, extent, | 496 | extent_end - end); |
499 | (extent_end - end) >> inode->i_blkbits); | ||
500 | |||
501 | btrfs_set_file_extent_type(leaf, extent, | 497 | btrfs_set_file_extent_type(leaf, extent, |
502 | BTRFS_FILE_EXTENT_REG); | 498 | BTRFS_FILE_EXTENT_REG); |
499 | |||
503 | btrfs_mark_buffer_dirty(path->nodes[0]); | 500 | btrfs_mark_buffer_dirty(path->nodes[0]); |
504 | if (le64_to_cpu(old.disk_blocknr) != 0) { | 501 | if (le64_to_cpu(old.disk_bytenr) != 0) { |
505 | inode->i_blocks += | 502 | inode->i_blocks += |
506 | btrfs_file_extent_num_blocks(leaf, | 503 | btrfs_file_extent_num_bytes(leaf, |
507 | extent) << 3; | 504 | extent) >> 9; |
508 | } | 505 | } |
509 | ret = 0; | 506 | ret = 0; |
510 | goto out; | 507 | goto out; |
@@ -531,12 +528,9 @@ static int prepare_pages(struct btrfs_root *root, | |||
531 | unsigned long index = pos >> PAGE_CACHE_SHIFT; | 528 | unsigned long index = pos >> PAGE_CACHE_SHIFT; |
532 | struct inode *inode = file->f_path.dentry->d_inode; | 529 | struct inode *inode = file->f_path.dentry->d_inode; |
533 | int err = 0; | 530 | int err = 0; |
534 | u64 num_blocks; | ||
535 | u64 start_pos; | 531 | u64 start_pos; |
536 | 532 | ||
537 | start_pos = pos & ~((u64)root->sectorsize - 1); | 533 | start_pos = pos & ~((u64)root->sectorsize - 1); |
538 | num_blocks = (write_bytes + pos - start_pos + root->sectorsize - 1) >> | ||
539 | inode->i_blkbits; | ||
540 | 534 | ||
541 | memset(pages, 0, num_pages * sizeof(struct page *)); | 535 | memset(pages, 0, num_pages * sizeof(struct page *)); |
542 | 536 | ||