diff options
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r-- | fs/btrfs/super.c | 76 |
1 files changed, 57 insertions, 19 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index eaa48f09d1c4..0f79490123cf 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -351,6 +351,35 @@ static int btrfs_free_inode(struct btrfs_trans_handle *trans, | |||
351 | return ret; | 351 | return ret; |
352 | } | 352 | } |
353 | 353 | ||
354 | static void reada_truncate(struct btrfs_root *root, struct btrfs_path *path, | ||
355 | u64 objectid) | ||
356 | { | ||
357 | struct btrfs_node *node; | ||
358 | int i; | ||
359 | int nritems; | ||
360 | u64 item_objectid; | ||
361 | u64 blocknr; | ||
362 | int slot; | ||
363 | int ret; | ||
364 | |||
365 | if (!path->nodes[1]) | ||
366 | return; | ||
367 | node = btrfs_buffer_node(path->nodes[1]); | ||
368 | slot = path->slots[1]; | ||
369 | if (slot == 0) | ||
370 | return; | ||
371 | nritems = btrfs_header_nritems(&node->header); | ||
372 | for (i = slot - 1; i >= 0; i--) { | ||
373 | item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key); | ||
374 | if (item_objectid != objectid) | ||
375 | break; | ||
376 | blocknr = btrfs_node_blockptr(node, i); | ||
377 | ret = readahead_tree_block(root, blocknr); | ||
378 | if (ret) | ||
379 | break; | ||
380 | } | ||
381 | } | ||
382 | |||
354 | static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | 383 | static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, |
355 | struct btrfs_root *root, | 384 | struct btrfs_root *root, |
356 | struct inode *inode) | 385 | struct inode *inode) |
@@ -386,6 +415,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
386 | BUG_ON(path->slots[0] == 0); | 415 | BUG_ON(path->slots[0] == 0); |
387 | path->slots[0]--; | 416 | path->slots[0]--; |
388 | } | 417 | } |
418 | reada_truncate(root, path, inode->i_ino); | ||
389 | leaf = btrfs_buffer_leaf(path->nodes[0]); | 419 | leaf = btrfs_buffer_leaf(path->nodes[0]); |
390 | found_key = &leaf->items[path->slots[0]].key; | 420 | found_key = &leaf->items[path->slots[0]].key; |
391 | if (btrfs_disk_key_objectid(found_key) != inode->i_ino) | 421 | if (btrfs_disk_key_objectid(found_key) != inode->i_ino) |
@@ -587,28 +617,30 @@ printk("adding new root for inode %lu root %p (found %p)\n", inode->i_ino, sub_r | |||
587 | return d_splice_alias(inode, dentry); | 617 | return d_splice_alias(inode, dentry); |
588 | } | 618 | } |
589 | 619 | ||
590 | static void reada_leaves(struct btrfs_root *root, struct btrfs_path *path) | 620 | static void reada_leaves(struct btrfs_root *root, struct btrfs_path *path, |
621 | u64 objectid) | ||
591 | { | 622 | { |
592 | struct btrfs_node *node; | 623 | struct btrfs_node *node; |
593 | int i; | 624 | int i; |
594 | int nritems; | 625 | u32 nritems; |
595 | u64 objectid; | ||
596 | u64 item_objectid; | 626 | u64 item_objectid; |
597 | u64 blocknr; | 627 | u64 blocknr; |
598 | int slot; | 628 | int slot; |
629 | int ret; | ||
599 | 630 | ||
600 | if (!path->nodes[1]) | 631 | if (!path->nodes[1]) |
601 | return; | 632 | return; |
602 | node = btrfs_buffer_node(path->nodes[1]); | 633 | node = btrfs_buffer_node(path->nodes[1]); |
603 | slot = path->slots[1]; | 634 | slot = path->slots[1]; |
604 | objectid = btrfs_disk_key_objectid(&node->ptrs[slot].key); | ||
605 | nritems = btrfs_header_nritems(&node->header); | 635 | nritems = btrfs_header_nritems(&node->header); |
606 | for (i = slot; i < nritems; i++) { | 636 | for (i = slot + 1; i < nritems; i++) { |
607 | item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key); | 637 | item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key); |
608 | if (item_objectid != objectid) | 638 | if (item_objectid != objectid) |
609 | break; | 639 | break; |
610 | blocknr = btrfs_node_blockptr(node, i); | 640 | blocknr = btrfs_node_blockptr(node, i); |
611 | readahead_tree_block(root, blocknr); | 641 | ret = readahead_tree_block(root, blocknr); |
642 | if (ret) | ||
643 | break; | ||
612 | } | 644 | } |
613 | } | 645 | } |
614 | 646 | ||
@@ -646,21 +678,20 @@ static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
646 | if (ret < 0) | 678 | if (ret < 0) |
647 | goto err; | 679 | goto err; |
648 | advance = 0; | 680 | advance = 0; |
649 | reada_leaves(root, path); | 681 | reada_leaves(root, path, inode->i_ino); |
650 | while(1) { | 682 | while(1) { |
651 | leaf = btrfs_buffer_leaf(path->nodes[0]); | 683 | leaf = btrfs_buffer_leaf(path->nodes[0]); |
652 | nritems = btrfs_header_nritems(&leaf->header); | 684 | nritems = btrfs_header_nritems(&leaf->header); |
653 | slot = path->slots[0]; | 685 | slot = path->slots[0]; |
654 | if (advance || slot >= nritems) { | 686 | if (advance || slot >= nritems) { |
655 | if (slot >= nritems -1) { | 687 | if (slot >= nritems -1) { |
688 | reada_leaves(root, path, inode->i_ino); | ||
656 | ret = btrfs_next_leaf(root, path); | 689 | ret = btrfs_next_leaf(root, path); |
657 | if (ret) | 690 | if (ret) |
658 | break; | 691 | break; |
659 | leaf = btrfs_buffer_leaf(path->nodes[0]); | 692 | leaf = btrfs_buffer_leaf(path->nodes[0]); |
660 | nritems = btrfs_header_nritems(&leaf->header); | 693 | nritems = btrfs_header_nritems(&leaf->header); |
661 | slot = path->slots[0]; | 694 | slot = path->slots[0]; |
662 | if (path->slots[1] == 0) | ||
663 | reada_leaves(root, path); | ||
664 | } else { | 695 | } else { |
665 | slot++; | 696 | slot++; |
666 | path->slots[0]++; | 697 | path->slots[0]++; |
@@ -805,13 +836,18 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
805 | struct btrfs_inode_item inode_item; | 836 | struct btrfs_inode_item inode_item; |
806 | struct btrfs_key *location; | 837 | struct btrfs_key *location; |
807 | int ret; | 838 | int ret; |
839 | int owner; | ||
808 | 840 | ||
809 | inode = new_inode(root->fs_info->sb); | 841 | inode = new_inode(root->fs_info->sb); |
810 | if (!inode) | 842 | if (!inode) |
811 | return ERR_PTR(-ENOMEM); | 843 | return ERR_PTR(-ENOMEM); |
812 | 844 | ||
813 | BTRFS_I(inode)->root = root; | 845 | BTRFS_I(inode)->root = root; |
814 | group = btrfs_find_block_group(root, group, 0, 0); | 846 | if (mode & S_IFDIR) |
847 | owner = 0; | ||
848 | else | ||
849 | owner = 1; | ||
850 | group = btrfs_find_block_group(root, group, 0, 0, owner); | ||
815 | BTRFS_I(inode)->block_group = group; | 851 | BTRFS_I(inode)->block_group = group; |
816 | 852 | ||
817 | inode->i_uid = current->fsuid; | 853 | inode->i_uid = current->fsuid; |
@@ -1562,7 +1598,7 @@ failed: | |||
1562 | static int drop_extents(struct btrfs_trans_handle *trans, | 1598 | static int drop_extents(struct btrfs_trans_handle *trans, |
1563 | struct btrfs_root *root, | 1599 | struct btrfs_root *root, |
1564 | struct inode *inode, | 1600 | struct inode *inode, |
1565 | u64 start, u64 end) | 1601 | u64 start, u64 end, u64 *hint_block) |
1566 | { | 1602 | { |
1567 | int ret; | 1603 | int ret; |
1568 | struct btrfs_key key; | 1604 | struct btrfs_key key; |
@@ -1659,17 +1695,14 @@ static int drop_extents(struct btrfs_trans_handle *trans, | |||
1659 | new_num = (start - key.offset) >> | 1695 | new_num = (start - key.offset) >> |
1660 | inode->i_blkbits; | 1696 | inode->i_blkbits; |
1661 | old_num = btrfs_file_extent_num_blocks(extent); | 1697 | old_num = btrfs_file_extent_num_blocks(extent); |
1698 | *hint_block = | ||
1699 | btrfs_file_extent_disk_blocknr(extent); | ||
1662 | inode->i_blocks -= (old_num - new_num) << 3; | 1700 | inode->i_blocks -= (old_num - new_num) << 3; |
1663 | btrfs_set_file_extent_num_blocks(extent, | 1701 | btrfs_set_file_extent_num_blocks(extent, |
1664 | new_num); | 1702 | new_num); |
1665 | mark_buffer_dirty(path->nodes[0]); | 1703 | mark_buffer_dirty(path->nodes[0]); |
1666 | } else { | 1704 | } else { |
1667 | WARN_ON(1); | 1705 | WARN_ON(1); |
1668 | /* | ||
1669 | ret = btrfs_truncate_item(trans, root, path, | ||
1670 | start - key.offset); | ||
1671 | BUG_ON(ret); | ||
1672 | */ | ||
1673 | } | 1706 | } |
1674 | } | 1707 | } |
1675 | if (!keep) { | 1708 | if (!keep) { |
@@ -1683,6 +1716,8 @@ static int drop_extents(struct btrfs_trans_handle *trans, | |||
1683 | btrfs_file_extent_disk_num_blocks(extent); | 1716 | btrfs_file_extent_disk_num_blocks(extent); |
1684 | extent_num_blocks = | 1717 | extent_num_blocks = |
1685 | btrfs_file_extent_num_blocks(extent); | 1718 | btrfs_file_extent_num_blocks(extent); |
1719 | *hint_block = | ||
1720 | btrfs_file_extent_disk_blocknr(extent); | ||
1686 | } | 1721 | } |
1687 | ret = btrfs_del_item(trans, root, path); | 1722 | ret = btrfs_del_item(trans, root, path); |
1688 | BUG_ON(ret); | 1723 | BUG_ON(ret); |
@@ -1831,6 +1866,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1831 | u64 start_pos; | 1866 | u64 start_pos; |
1832 | u64 num_blocks; | 1867 | u64 num_blocks; |
1833 | u64 alloc_extent_start; | 1868 | u64 alloc_extent_start; |
1869 | u64 hint_block; | ||
1834 | struct btrfs_trans_handle *trans; | 1870 | struct btrfs_trans_handle *trans; |
1835 | struct btrfs_key ins; | 1871 | struct btrfs_key ins; |
1836 | pinned[0] = NULL; | 1872 | pinned[0] = NULL; |
@@ -1871,6 +1907,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1871 | } | 1907 | } |
1872 | if (first_index != last_index && | 1908 | if (first_index != last_index && |
1873 | (last_index << PAGE_CACHE_SHIFT) < inode->i_size && | 1909 | (last_index << PAGE_CACHE_SHIFT) < inode->i_size && |
1910 | pos + count < inode->i_size && | ||
1874 | (count & (PAGE_CACHE_SIZE - 1))) { | 1911 | (count & (PAGE_CACHE_SIZE - 1))) { |
1875 | pinned[1] = grab_cache_page(inode->i_mapping, last_index); | 1912 | pinned[1] = grab_cache_page(inode->i_mapping, last_index); |
1876 | if (!PageUptodate(pinned[1])) { | 1913 | if (!PageUptodate(pinned[1])) { |
@@ -1892,18 +1929,20 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1892 | btrfs_set_trans_block_group(trans, inode); | 1929 | btrfs_set_trans_block_group(trans, inode); |
1893 | /* FIXME blocksize != 4096 */ | 1930 | /* FIXME blocksize != 4096 */ |
1894 | inode->i_blocks += num_blocks << 3; | 1931 | inode->i_blocks += num_blocks << 3; |
1932 | hint_block = 0; | ||
1895 | if (start_pos < inode->i_size) { | 1933 | if (start_pos < inode->i_size) { |
1896 | /* FIXME blocksize != pagesize */ | 1934 | /* FIXME blocksize != pagesize */ |
1897 | ret = drop_extents(trans, root, inode, | 1935 | ret = drop_extents(trans, root, inode, |
1898 | start_pos, | 1936 | start_pos, |
1899 | (pos + count + root->blocksize -1) & | 1937 | (pos + count + root->blocksize -1) & |
1900 | ~((u64)root->blocksize - 1)); | 1938 | ~((u64)root->blocksize - 1), &hint_block); |
1901 | BUG_ON(ret); | 1939 | BUG_ON(ret); |
1902 | } | 1940 | } |
1903 | if (inode->i_size >= PAGE_CACHE_SIZE || pos + count < inode->i_size || | 1941 | if (inode->i_size >= PAGE_CACHE_SIZE || pos + count < inode->i_size || |
1904 | pos + count - start_pos > BTRFS_MAX_INLINE_DATA_SIZE(root)) { | 1942 | pos + count - start_pos > BTRFS_MAX_INLINE_DATA_SIZE(root)) { |
1905 | ret = btrfs_alloc_extent(trans, root, inode->i_ino, | 1943 | ret = btrfs_alloc_extent(trans, root, inode->i_ino, |
1906 | num_blocks, 1, (u64)-1, &ins, 1); | 1944 | num_blocks, hint_block, (u64)-1, |
1945 | &ins, 1); | ||
1907 | BUG_ON(ret); | 1946 | BUG_ON(ret); |
1908 | ret = btrfs_insert_file_extent(trans, root, inode->i_ino, | 1947 | ret = btrfs_insert_file_extent(trans, root, inode->i_ino, |
1909 | start_pos, ins.objectid, ins.offset); | 1948 | start_pos, ins.objectid, ins.offset); |
@@ -2455,7 +2494,6 @@ static int btrfs_get_sb(struct file_system_type *fs_type, | |||
2455 | btrfs_fill_super, mnt); | 2494 | btrfs_fill_super, mnt); |
2456 | } | 2495 | } |
2457 | 2496 | ||
2458 | |||
2459 | static int btrfs_getattr(struct vfsmount *mnt, | 2497 | static int btrfs_getattr(struct vfsmount *mnt, |
2460 | struct dentry *dentry, struct kstat *stat) | 2498 | struct dentry *dentry, struct kstat *stat) |
2461 | { | 2499 | { |