diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-08-27 16:49:44 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-08-27 16:49:44 -0400 |
commit | b888db2bd7b67f190b32934e6a86181f262ac3ec (patch) | |
tree | 7eb4472c65b6a634db6be689eedca09f09a40cd5 /fs/btrfs/inode.c | |
parent | a52d9a8033c454cd9b4697cfafb467509fc1693f (diff) |
Btrfs: Add delayed allocation to the extent based page tree code
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 141 |
1 files changed, 79 insertions, 62 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index fd4cb65fcf1f..dc181089aa74 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -70,6 +70,40 @@ static unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = { | |||
70 | [S_IFLNK >> S_SHIFT] = BTRFS_FT_SYMLINK, | 70 | [S_IFLNK >> S_SHIFT] = BTRFS_FT_SYMLINK, |
71 | }; | 71 | }; |
72 | 72 | ||
73 | static int run_delalloc_range(struct inode *inode, u64 start, u64 end) | ||
74 | { | ||
75 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
76 | struct btrfs_trans_handle *trans; | ||
77 | struct btrfs_key ins; | ||
78 | u64 alloc_hint = 0; | ||
79 | u64 num_blocks; | ||
80 | int ret; | ||
81 | u64 blocksize = 1 << inode->i_blkbits; | ||
82 | |||
83 | mutex_lock(&root->fs_info->fs_mutex); | ||
84 | trans = btrfs_start_transaction(root, 1); | ||
85 | btrfs_set_trans_block_group(trans, inode); | ||
86 | BUG_ON(!trans); | ||
87 | num_blocks = (end - start + blocksize) & ~(blocksize - 1); | ||
88 | ret = btrfs_drop_extents(trans, root, inode, | ||
89 | start, start + num_blocks, &alloc_hint); | ||
90 | num_blocks = num_blocks >> inode->i_blkbits; | ||
91 | ret = btrfs_alloc_extent(trans, root, inode->i_ino, num_blocks, 0, | ||
92 | alloc_hint, (u64)-1, &ins, 1); | ||
93 | if (ret) { | ||
94 | WARN_ON(1); | ||
95 | goto out; | ||
96 | } | ||
97 | ret = btrfs_insert_file_extent(trans, root, inode->i_ino, | ||
98 | start, ins.objectid, ins.offset, | ||
99 | ins.offset); | ||
100 | out: | ||
101 | btrfs_end_transaction(trans, root); | ||
102 | mutex_unlock(&root->fs_info->fs_mutex); | ||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | |||
73 | void btrfs_read_locked_inode(struct inode *inode) | 107 | void btrfs_read_locked_inode(struct inode *inode) |
74 | { | 108 | { |
75 | struct btrfs_path *path; | 109 | struct btrfs_path *path; |
@@ -121,8 +155,7 @@ void btrfs_read_locked_inode(struct inode *inode) | |||
121 | switch (inode->i_mode & S_IFMT) { | 155 | switch (inode->i_mode & S_IFMT) { |
122 | case S_IFREG: | 156 | case S_IFREG: |
123 | inode->i_mapping->a_ops = &btrfs_aops; | 157 | inode->i_mapping->a_ops = &btrfs_aops; |
124 | extent_map_tree_init(&BTRFS_I(inode)->extent_tree, | 158 | BTRFS_I(inode)->extent_tree.fill_delalloc = run_delalloc_range; |
125 | inode->i_mapping, GFP_NOFS); | ||
126 | inode->i_fop = &btrfs_file_operations; | 159 | inode->i_fop = &btrfs_file_operations; |
127 | inode->i_op = &btrfs_file_inode_operations; | 160 | inode->i_op = &btrfs_file_inode_operations; |
128 | break; | 161 | break; |
@@ -450,11 +483,17 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
450 | BUG_ON(ret); | 483 | BUG_ON(ret); |
451 | } | 484 | } |
452 | if (item_end < inode->i_size) { | 485 | if (item_end < inode->i_size) { |
453 | if (found_type) { | 486 | if (found_type == BTRFS_DIR_ITEM_KEY) { |
454 | btrfs_set_key_type(&key, found_type - 1); | 487 | found_type = BTRFS_INODE_ITEM_KEY; |
455 | continue; | 488 | } else if (found_type == BTRFS_EXTENT_ITEM_KEY) { |
489 | found_type = BTRFS_CSUM_ITEM_KEY; | ||
490 | } else if (found_type) { | ||
491 | found_type--; | ||
492 | } else { | ||
493 | break; | ||
456 | } | 494 | } |
457 | break; | 495 | btrfs_set_key_type(&key, found_type - 1); |
496 | continue; | ||
458 | } | 497 | } |
459 | if (btrfs_disk_key_offset(found_key) >= inode->i_size) | 498 | if (btrfs_disk_key_offset(found_key) >= inode->i_size) |
460 | del_item = 1; | 499 | del_item = 1; |
@@ -514,47 +553,34 @@ error: | |||
514 | return ret; | 553 | return ret; |
515 | } | 554 | } |
516 | 555 | ||
517 | static int btrfs_cow_one_page(struct btrfs_trans_handle *trans, | 556 | static int btrfs_cow_one_page(struct inode *inode, struct page *page, |
518 | struct inode *inode, struct page *page, | ||
519 | size_t zero_start) | 557 | size_t zero_start) |
520 | { | 558 | { |
521 | char *kaddr; | 559 | char *kaddr; |
522 | int ret = 0; | 560 | int ret = 0; |
523 | struct btrfs_root *root = BTRFS_I(inode)->root; | 561 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; |
524 | u64 alloc_hint = 0; | ||
525 | u64 page_start = page->index << PAGE_CACHE_SHIFT; | 562 | u64 page_start = page->index << PAGE_CACHE_SHIFT; |
526 | struct btrfs_key ins; | 563 | u64 page_end = page_start + PAGE_CACHE_SIZE - 1; |
527 | 564 | ||
528 | if (!PagePrivate(page)) { | 565 | if (!PagePrivate(page)) { |
529 | SetPagePrivate(page); | 566 | SetPagePrivate(page); |
530 | set_page_private(page, 1); | 567 | set_page_private(page, 1); |
568 | WARN_ON(!page->mapping->a_ops->invalidatepage); | ||
531 | page_cache_get(page); | 569 | page_cache_get(page); |
532 | } | 570 | } |
533 | 571 | ||
534 | btrfs_set_trans_block_group(trans, inode); | 572 | lock_extent(em_tree, page_start, page_end, GFP_NOFS); |
535 | 573 | set_extent_delalloc(&BTRFS_I(inode)->extent_tree, page_start, | |
536 | ret = btrfs_drop_extents(trans, root, inode, | 574 | page_end, GFP_NOFS); |
537 | page_start, page_start + PAGE_CACHE_SIZE, | ||
538 | &alloc_hint); | ||
539 | if (ret) | ||
540 | goto out; | ||
541 | ret = btrfs_alloc_extent(trans, root, inode->i_ino, 1, 0, | ||
542 | alloc_hint, (u64)-1, &ins, 1); | ||
543 | if (ret) | ||
544 | goto out; | ||
545 | ret = btrfs_insert_file_extent(trans, root, inode->i_ino, | ||
546 | page_start, ins.objectid, 1, 1); | ||
547 | if (ret) | ||
548 | goto out; | ||
549 | SetPageChecked(page); | ||
550 | kaddr = kmap(page); | ||
551 | if (zero_start != PAGE_CACHE_SIZE) { | 575 | if (zero_start != PAGE_CACHE_SIZE) { |
576 | kaddr = kmap(page); | ||
552 | memset(kaddr + zero_start, 0, PAGE_CACHE_SIZE - zero_start); | 577 | memset(kaddr + zero_start, 0, PAGE_CACHE_SIZE - zero_start); |
553 | flush_dcache_page(page); | 578 | flush_dcache_page(page); |
579 | kunmap(page); | ||
554 | } | 580 | } |
555 | kunmap(page); | 581 | set_page_dirty(page); |
582 | unlock_extent(em_tree, page_start, page_end, GFP_NOFS); | ||
556 | 583 | ||
557 | out: | ||
558 | return ret; | 584 | return ret; |
559 | } | 585 | } |
560 | 586 | ||
@@ -565,8 +591,6 @@ out: | |||
565 | static int btrfs_truncate_page(struct address_space *mapping, loff_t from) | 591 | static int btrfs_truncate_page(struct address_space *mapping, loff_t from) |
566 | { | 592 | { |
567 | struct inode *inode = mapping->host; | 593 | struct inode *inode = mapping->host; |
568 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
569 | struct btrfs_trans_handle *trans; | ||
570 | unsigned blocksize = 1 << inode->i_blkbits; | 594 | unsigned blocksize = 1 << inode->i_blkbits; |
571 | pgoff_t index = from >> PAGE_CACHE_SHIFT; | 595 | pgoff_t index = from >> PAGE_CACHE_SHIFT; |
572 | unsigned offset = from & (PAGE_CACHE_SIZE-1); | 596 | unsigned offset = from & (PAGE_CACHE_SIZE-1); |
@@ -591,21 +615,7 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from) | |||
591 | } | 615 | } |
592 | page_start = page->index << PAGE_CACHE_SHIFT; | 616 | page_start = page->index << PAGE_CACHE_SHIFT; |
593 | 617 | ||
594 | mutex_lock(&root->fs_info->fs_mutex); | 618 | ret = btrfs_cow_one_page(inode, page, offset); |
595 | trans = btrfs_start_transaction(root, 1); | ||
596 | ret = btrfs_cow_one_page(trans, inode, page, offset); | ||
597 | if (!ret) { | ||
598 | char *kaddr = kmap(page); | ||
599 | ret = btrfs_csum_file_block(trans, root, inode->i_ino, | ||
600 | page_start, kaddr, PAGE_CACHE_SIZE); | ||
601 | kunmap(page); | ||
602 | } | ||
603 | set_extent_dirty(&BTRFS_I(inode)->extent_tree, | ||
604 | page_start, page_start + PAGE_CACHE_SIZE - 1, | ||
605 | GFP_NOFS); | ||
606 | set_page_dirty(page); | ||
607 | btrfs_end_transaction(trans, root); | ||
608 | mutex_unlock(&root->fs_info->fs_mutex); | ||
609 | 619 | ||
610 | unlock_page(page); | 620 | unlock_page(page); |
611 | page_cache_release(page); | 621 | page_cache_release(page); |
@@ -757,6 +767,8 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p) | |||
757 | struct btrfs_iget_args *args = p; | 767 | struct btrfs_iget_args *args = p; |
758 | inode->i_ino = args->ino; | 768 | inode->i_ino = args->ino; |
759 | BTRFS_I(inode)->root = args->root; | 769 | BTRFS_I(inode)->root = args->root; |
770 | extent_map_tree_init(&BTRFS_I(inode)->extent_tree, | ||
771 | inode->i_mapping, GFP_NOFS); | ||
760 | return 0; | 772 | return 0; |
761 | } | 773 | } |
762 | 774 | ||
@@ -968,7 +980,10 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
968 | if (!inode) | 980 | if (!inode) |
969 | return ERR_PTR(-ENOMEM); | 981 | return ERR_PTR(-ENOMEM); |
970 | 982 | ||
983 | extent_map_tree_init(&BTRFS_I(inode)->extent_tree, | ||
984 | inode->i_mapping, GFP_NOFS); | ||
971 | BTRFS_I(inode)->root = root; | 985 | BTRFS_I(inode)->root = root; |
986 | |||
972 | if (mode & S_IFDIR) | 987 | if (mode & S_IFDIR) |
973 | owner = 0; | 988 | owner = 0; |
974 | else | 989 | else |
@@ -1128,6 +1143,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, | |||
1128 | inode->i_op = &btrfs_file_inode_operations; | 1143 | inode->i_op = &btrfs_file_inode_operations; |
1129 | extent_map_tree_init(&BTRFS_I(inode)->extent_tree, | 1144 | extent_map_tree_init(&BTRFS_I(inode)->extent_tree, |
1130 | inode->i_mapping, GFP_NOFS); | 1145 | inode->i_mapping, GFP_NOFS); |
1146 | BTRFS_I(inode)->extent_tree.fill_delalloc = run_delalloc_range; | ||
1131 | } | 1147 | } |
1132 | dir->i_sb->s_dirt = 1; | 1148 | dir->i_sb->s_dirt = 1; |
1133 | btrfs_update_inode_block_group(trans, inode); | 1149 | btrfs_update_inode_block_group(trans, inode); |
@@ -1344,9 +1360,11 @@ again: | |||
1344 | extent_end = extent_start + | 1360 | extent_end = extent_start + |
1345 | (btrfs_file_extent_num_blocks(item) << inode->i_blkbits); | 1361 | (btrfs_file_extent_num_blocks(item) << inode->i_blkbits); |
1346 | err = 0; | 1362 | err = 0; |
1347 | if (start < extent_start || start > extent_end) { | 1363 | if (start < extent_start || start >= extent_end) { |
1348 | em->start = start; | 1364 | em->start = start; |
1349 | if (start < extent_start) { | 1365 | if (start < extent_start) { |
1366 | if (end < extent_start) | ||
1367 | goto not_found; | ||
1350 | em->end = extent_end - 1; | 1368 | em->end = extent_end - 1; |
1351 | } else { | 1369 | } else { |
1352 | em->end = end; | 1370 | em->end = end; |
@@ -1375,9 +1393,11 @@ again: | |||
1375 | size = btrfs_file_extent_inline_len(leaf->items + | 1393 | size = btrfs_file_extent_inline_len(leaf->items + |
1376 | path->slots[0]); | 1394 | path->slots[0]); |
1377 | extent_end = extent_start + size; | 1395 | extent_end = extent_start + size; |
1378 | if (start < extent_start || start > extent_end) { | 1396 | if (start < extent_start || start >= extent_end) { |
1379 | em->start = start; | 1397 | em->start = start; |
1380 | if (start < extent_start) { | 1398 | if (start < extent_start) { |
1399 | if (end < extent_start) | ||
1400 | goto not_found; | ||
1381 | em->end = extent_end - 1; | 1401 | em->end = extent_end - 1; |
1382 | } else { | 1402 | } else { |
1383 | em->end = end; | 1403 | em->end = end; |
@@ -1412,8 +1432,7 @@ not_found_em: | |||
1412 | insert: | 1432 | insert: |
1413 | btrfs_release_path(root, path); | 1433 | btrfs_release_path(root, path); |
1414 | if (em->start > start || em->end < start) { | 1434 | if (em->start > start || em->end < start) { |
1415 | printk("bad extent! %Lu %Lu start %Lu end %Lu\n", em->start, em->end, start, end); | 1435 | printk("bad extent! em: [%Lu %Lu] passed [%Lu %Lu]\n", em->start, em->end, start, end); |
1416 | WARN_ON(1); | ||
1417 | err = -EIO; | 1436 | err = -EIO; |
1418 | goto out; | 1437 | goto out; |
1419 | } | 1438 | } |
@@ -1648,6 +1667,13 @@ int btrfs_readpage(struct file *file, struct page *page) | |||
1648 | static int btrfs_writepage(struct page *page, struct writeback_control *wbc) | 1667 | static int btrfs_writepage(struct page *page, struct writeback_control *wbc) |
1649 | { | 1668 | { |
1650 | struct extent_map_tree *tree; | 1669 | struct extent_map_tree *tree; |
1670 | |||
1671 | |||
1672 | if (current->flags & PF_MEMALLOC) { | ||
1673 | redirty_page_for_writepage(wbc, page); | ||
1674 | unlock_page(page); | ||
1675 | return 0; | ||
1676 | } | ||
1651 | tree = &BTRFS_I(page->mapping->host)->extent_tree; | 1677 | tree = &BTRFS_I(page->mapping->host)->extent_tree; |
1652 | return extent_write_full_page(tree, page, btrfs_get_extent, wbc); | 1678 | return extent_write_full_page(tree, page, btrfs_get_extent, wbc); |
1653 | } | 1679 | } |
@@ -1698,8 +1724,6 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset) | |||
1698 | int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page) | 1724 | int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page) |
1699 | { | 1725 | { |
1700 | struct inode *inode = vma->vm_file->f_path.dentry->d_inode; | 1726 | struct inode *inode = vma->vm_file->f_path.dentry->d_inode; |
1701 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
1702 | struct btrfs_trans_handle *trans; | ||
1703 | unsigned long end; | 1727 | unsigned long end; |
1704 | loff_t size; | 1728 | loff_t size; |
1705 | int ret = -EINVAL; | 1729 | int ret = -EINVAL; |
@@ -1722,15 +1746,7 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page) | |||
1722 | else | 1746 | else |
1723 | end = PAGE_CACHE_SIZE; | 1747 | end = PAGE_CACHE_SIZE; |
1724 | 1748 | ||
1725 | mutex_lock(&root->fs_info->fs_mutex); | 1749 | ret = btrfs_cow_one_page(inode, page, end); |
1726 | trans = btrfs_start_transaction(root, 1); | ||
1727 | ret = btrfs_cow_one_page(trans, inode, page, end); | ||
1728 | btrfs_end_transaction(trans, root); | ||
1729 | mutex_unlock(&root->fs_info->fs_mutex); | ||
1730 | set_extent_dirty(&BTRFS_I(inode)->extent_tree, | ||
1731 | page_start, page_start + PAGE_CACHE_SIZE - 1, | ||
1732 | GFP_NOFS); | ||
1733 | set_page_dirty(page); | ||
1734 | 1750 | ||
1735 | out_unlock: | 1751 | out_unlock: |
1736 | unlock_page(page); | 1752 | unlock_page(page); |
@@ -2264,6 +2280,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, | |||
2264 | inode->i_op = &btrfs_file_inode_operations; | 2280 | inode->i_op = &btrfs_file_inode_operations; |
2265 | extent_map_tree_init(&BTRFS_I(inode)->extent_tree, | 2281 | extent_map_tree_init(&BTRFS_I(inode)->extent_tree, |
2266 | inode->i_mapping, GFP_NOFS); | 2282 | inode->i_mapping, GFP_NOFS); |
2283 | BTRFS_I(inode)->extent_tree.fill_delalloc = run_delalloc_range; | ||
2267 | } | 2284 | } |
2268 | dir->i_sb->s_dirt = 1; | 2285 | dir->i_sb->s_dirt = 1; |
2269 | btrfs_update_inode_block_group(trans, inode); | 2286 | btrfs_update_inode_block_group(trans, inode); |