diff options
author | Yan Zheng <zheng.yan@oracle.com> | 2008-10-30 14:25:28 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-10-30 14:25:28 -0400 |
commit | d899e05215178fed903ad0e7fc1cb4d8e0cc0a88 (patch) | |
tree | 2969e3558f5c50ec0f9ac4201099c0d5d1d6e2c2 /fs/btrfs/inode.c | |
parent | 80ff385665b7fca29fefe358a60ab0d09f9b8e87 (diff) |
Btrfs: Add fallocate support v2
This patch updates btrfs-progs for fallocate support.
fallocate is a little different in Btrfs because we need to tell the
COW system that a given preallocated extent doesn't need to be
cow'd as long as there are no snapshots of it. This leverages the
-o nodatacow checks.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 323 |
1 files changed, 252 insertions, 71 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 3e6f0568fdb4..789c376157f9 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/version.h> | 37 | #include <linux/version.h> |
38 | #include <linux/xattr.h> | 38 | #include <linux/xattr.h> |
39 | #include <linux/posix_acl.h> | 39 | #include <linux/posix_acl.h> |
40 | #include <linux/falloc.h> | ||
40 | #include "ctree.h" | 41 | #include "ctree.h" |
41 | #include "disk-io.h" | 42 | #include "disk-io.h" |
42 | #include "transaction.h" | 43 | #include "transaction.h" |
@@ -587,7 +588,7 @@ free_pages_out: | |||
587 | * blocks on disk | 588 | * blocks on disk |
588 | */ | 589 | */ |
589 | static int run_delalloc_nocow(struct inode *inode, struct page *locked_page, | 590 | static int run_delalloc_nocow(struct inode *inode, struct page *locked_page, |
590 | u64 start, u64 end, int *page_started) | 591 | u64 start, u64 end, int *page_started, int force) |
591 | { | 592 | { |
592 | struct btrfs_root *root = BTRFS_I(inode)->root; | 593 | struct btrfs_root *root = BTRFS_I(inode)->root; |
593 | struct btrfs_trans_handle *trans; | 594 | struct btrfs_trans_handle *trans; |
@@ -602,6 +603,7 @@ static int run_delalloc_nocow(struct inode *inode, struct page *locked_page, | |||
602 | u64 num_bytes; | 603 | u64 num_bytes; |
603 | int extent_type; | 604 | int extent_type; |
604 | int ret; | 605 | int ret; |
606 | int type; | ||
605 | int nocow; | 607 | int nocow; |
606 | int check_prev = 1; | 608 | int check_prev = 1; |
607 | 609 | ||
@@ -654,7 +656,8 @@ next_slot: | |||
654 | struct btrfs_file_extent_item); | 656 | struct btrfs_file_extent_item); |
655 | extent_type = btrfs_file_extent_type(leaf, fi); | 657 | extent_type = btrfs_file_extent_type(leaf, fi); |
656 | 658 | ||
657 | if (extent_type == BTRFS_FILE_EXTENT_REG) { | 659 | if (extent_type == BTRFS_FILE_EXTENT_REG || |
660 | extent_type == BTRFS_FILE_EXTENT_PREALLOC) { | ||
658 | struct btrfs_block_group_cache *block_group; | 661 | struct btrfs_block_group_cache *block_group; |
659 | disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); | 662 | disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); |
660 | extent_end = found_key.offset + | 663 | extent_end = found_key.offset + |
@@ -669,6 +672,8 @@ next_slot: | |||
669 | goto out_check; | 672 | goto out_check; |
670 | if (disk_bytenr == 0) | 673 | if (disk_bytenr == 0) |
671 | goto out_check; | 674 | goto out_check; |
675 | if (extent_type == BTRFS_FILE_EXTENT_REG && !force) | ||
676 | goto out_check; | ||
672 | if (btrfs_cross_ref_exist(trans, root, disk_bytenr)) | 677 | if (btrfs_cross_ref_exist(trans, root, disk_bytenr)) |
673 | goto out_check; | 678 | goto out_check; |
674 | block_group = btrfs_lookup_block_group(root->fs_info, | 679 | block_group = btrfs_lookup_block_group(root->fs_info, |
@@ -709,10 +714,39 @@ out_check: | |||
709 | 714 | ||
710 | disk_bytenr += cur_offset - found_key.offset; | 715 | disk_bytenr += cur_offset - found_key.offset; |
711 | num_bytes = min(end + 1, extent_end) - cur_offset; | 716 | num_bytes = min(end + 1, extent_end) - cur_offset; |
717 | if (extent_type == BTRFS_FILE_EXTENT_PREALLOC) { | ||
718 | struct extent_map *em; | ||
719 | struct extent_map_tree *em_tree; | ||
720 | em_tree = &BTRFS_I(inode)->extent_tree; | ||
721 | em = alloc_extent_map(GFP_NOFS); | ||
722 | em->start = cur_offset; | ||
723 | em->len = num_bytes; | ||
724 | em->block_len = num_bytes; | ||
725 | em->block_start = disk_bytenr; | ||
726 | em->bdev = root->fs_info->fs_devices->latest_bdev; | ||
727 | set_bit(EXTENT_FLAG_PINNED, &em->flags); | ||
728 | while (1) { | ||
729 | spin_lock(&em_tree->lock); | ||
730 | ret = add_extent_mapping(em_tree, em); | ||
731 | spin_unlock(&em_tree->lock); | ||
732 | if (ret != -EEXIST) { | ||
733 | free_extent_map(em); | ||
734 | break; | ||
735 | } | ||
736 | btrfs_drop_extent_cache(inode, em->start, | ||
737 | em->start + em->len - 1, 0); | ||
738 | } | ||
739 | type = BTRFS_ORDERED_PREALLOC; | ||
740 | } else { | ||
741 | type = BTRFS_ORDERED_NOCOW; | ||
742 | } | ||
712 | 743 | ||
713 | ret = btrfs_add_ordered_extent(inode, cur_offset, disk_bytenr, | 744 | ret = btrfs_add_ordered_extent(inode, cur_offset, disk_bytenr, |
714 | num_bytes, num_bytes, | 745 | num_bytes, num_bytes, type); |
715 | BTRFS_ORDERED_NOCOW); | 746 | BUG_ON(ret); |
747 | extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree, | ||
748 | cur_offset, cur_offset + num_bytes - 1, | ||
749 | locked_page, 0, 0, 0); | ||
716 | cur_offset = extent_end; | 750 | cur_offset = extent_end; |
717 | if (cur_offset > end) | 751 | if (cur_offset > end) |
718 | break; | 752 | break; |
@@ -745,7 +779,10 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page, | |||
745 | if (btrfs_test_opt(root, NODATACOW) || | 779 | if (btrfs_test_opt(root, NODATACOW) || |
746 | btrfs_test_flag(inode, NODATACOW)) | 780 | btrfs_test_flag(inode, NODATACOW)) |
747 | ret = run_delalloc_nocow(inode, locked_page, start, end, | 781 | ret = run_delalloc_nocow(inode, locked_page, start, end, |
748 | page_started); | 782 | page_started, 0); |
783 | else if (btrfs_test_flag(inode, PREALLOC)) | ||
784 | ret = run_delalloc_nocow(inode, locked_page, start, end, | ||
785 | page_started, 1); | ||
749 | else | 786 | else |
750 | ret = cow_file_range(inode, locked_page, start, end, | 787 | ret = cow_file_range(inode, locked_page, start, end, |
751 | page_started); | 788 | page_started); |
@@ -1006,6 +1043,63 @@ int btrfs_writepage_start_hook(struct page *page, u64 start, u64 end) | |||
1006 | return -EAGAIN; | 1043 | return -EAGAIN; |
1007 | } | 1044 | } |
1008 | 1045 | ||
1046 | static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, | ||
1047 | struct inode *inode, u64 file_pos, | ||
1048 | u64 disk_bytenr, u64 disk_num_bytes, | ||
1049 | u64 num_bytes, u64 ram_bytes, | ||
1050 | u8 compression, u8 encryption, | ||
1051 | u16 other_encoding, int extent_type) | ||
1052 | { | ||
1053 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
1054 | struct btrfs_file_extent_item *fi; | ||
1055 | struct btrfs_path *path; | ||
1056 | struct extent_buffer *leaf; | ||
1057 | struct btrfs_key ins; | ||
1058 | u64 hint; | ||
1059 | int ret; | ||
1060 | |||
1061 | path = btrfs_alloc_path(); | ||
1062 | BUG_ON(!path); | ||
1063 | |||
1064 | ret = btrfs_drop_extents(trans, root, inode, file_pos, | ||
1065 | file_pos + num_bytes, file_pos, &hint); | ||
1066 | BUG_ON(ret); | ||
1067 | |||
1068 | ins.objectid = inode->i_ino; | ||
1069 | ins.offset = file_pos; | ||
1070 | ins.type = BTRFS_EXTENT_DATA_KEY; | ||
1071 | ret = btrfs_insert_empty_item(trans, root, path, &ins, sizeof(*fi)); | ||
1072 | BUG_ON(ret); | ||
1073 | leaf = path->nodes[0]; | ||
1074 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
1075 | struct btrfs_file_extent_item); | ||
1076 | btrfs_set_file_extent_generation(leaf, fi, trans->transid); | ||
1077 | btrfs_set_file_extent_type(leaf, fi, extent_type); | ||
1078 | btrfs_set_file_extent_disk_bytenr(leaf, fi, disk_bytenr); | ||
1079 | btrfs_set_file_extent_disk_num_bytes(leaf, fi, disk_num_bytes); | ||
1080 | btrfs_set_file_extent_offset(leaf, fi, 0); | ||
1081 | btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes); | ||
1082 | btrfs_set_file_extent_ram_bytes(leaf, fi, ram_bytes); | ||
1083 | btrfs_set_file_extent_compression(leaf, fi, compression); | ||
1084 | btrfs_set_file_extent_encryption(leaf, fi, encryption); | ||
1085 | btrfs_set_file_extent_other_encoding(leaf, fi, other_encoding); | ||
1086 | btrfs_mark_buffer_dirty(leaf); | ||
1087 | |||
1088 | inode_add_bytes(inode, num_bytes); | ||
1089 | btrfs_drop_extent_cache(inode, file_pos, file_pos + num_bytes - 1, 0); | ||
1090 | |||
1091 | ins.objectid = disk_bytenr; | ||
1092 | ins.offset = disk_num_bytes; | ||
1093 | ins.type = BTRFS_EXTENT_ITEM_KEY; | ||
1094 | ret = btrfs_alloc_reserved_extent(trans, root, leaf->start, | ||
1095 | root->root_key.objectid, | ||
1096 | trans->transid, inode->i_ino, &ins); | ||
1097 | BUG_ON(ret); | ||
1098 | |||
1099 | btrfs_free_path(path); | ||
1100 | return 0; | ||
1101 | } | ||
1102 | |||
1009 | /* as ordered data IO finishes, this gets called so we can finish | 1103 | /* as ordered data IO finishes, this gets called so we can finish |
1010 | * an ordered extent if the range of bytes in the file it covers are | 1104 | * an ordered extent if the range of bytes in the file it covers are |
1011 | * fully written. | 1105 | * fully written. |
@@ -1016,12 +1110,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
1016 | struct btrfs_trans_handle *trans; | 1110 | struct btrfs_trans_handle *trans; |
1017 | struct btrfs_ordered_extent *ordered_extent; | 1111 | struct btrfs_ordered_extent *ordered_extent; |
1018 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | 1112 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; |
1019 | struct btrfs_file_extent_item *extent_item; | 1113 | int compressed = 0; |
1020 | struct btrfs_path *path = NULL; | ||
1021 | struct extent_buffer *leaf; | ||
1022 | u64 alloc_hint = 0; | ||
1023 | struct list_head list; | ||
1024 | struct btrfs_key ins; | ||
1025 | int ret; | 1114 | int ret; |
1026 | 1115 | ||
1027 | ret = btrfs_dec_test_ordered_pending(inode, start, end - start + 1); | 1116 | ret = btrfs_dec_test_ordered_pending(inode, start, end - start + 1); |
@@ -1035,67 +1124,30 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
1035 | if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) | 1124 | if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) |
1036 | goto nocow; | 1125 | goto nocow; |
1037 | 1126 | ||
1038 | path = btrfs_alloc_path(); | ||
1039 | BUG_ON(!path); | ||
1040 | |||
1041 | lock_extent(io_tree, ordered_extent->file_offset, | 1127 | lock_extent(io_tree, ordered_extent->file_offset, |
1042 | ordered_extent->file_offset + ordered_extent->len - 1, | 1128 | ordered_extent->file_offset + ordered_extent->len - 1, |
1043 | GFP_NOFS); | 1129 | GFP_NOFS); |
1044 | 1130 | ||
1045 | INIT_LIST_HEAD(&list); | ||
1046 | |||
1047 | ret = btrfs_drop_extents(trans, root, inode, | ||
1048 | ordered_extent->file_offset, | ||
1049 | ordered_extent->file_offset + | ||
1050 | ordered_extent->len, | ||
1051 | ordered_extent->file_offset, &alloc_hint); | ||
1052 | BUG_ON(ret); | ||
1053 | |||
1054 | ins.objectid = inode->i_ino; | ||
1055 | ins.offset = ordered_extent->file_offset; | ||
1056 | ins.type = BTRFS_EXTENT_DATA_KEY; | ||
1057 | ret = btrfs_insert_empty_item(trans, root, path, &ins, | ||
1058 | sizeof(*extent_item)); | ||
1059 | BUG_ON(ret); | ||
1060 | leaf = path->nodes[0]; | ||
1061 | extent_item = btrfs_item_ptr(leaf, path->slots[0], | ||
1062 | struct btrfs_file_extent_item); | ||
1063 | btrfs_set_file_extent_generation(leaf, extent_item, trans->transid); | ||
1064 | btrfs_set_file_extent_type(leaf, extent_item, BTRFS_FILE_EXTENT_REG); | ||
1065 | btrfs_set_file_extent_disk_bytenr(leaf, extent_item, | ||
1066 | ordered_extent->start); | ||
1067 | btrfs_set_file_extent_disk_num_bytes(leaf, extent_item, | ||
1068 | ordered_extent->disk_len); | ||
1069 | btrfs_set_file_extent_offset(leaf, extent_item, 0); | ||
1070 | |||
1071 | if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags)) | 1131 | if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags)) |
1072 | btrfs_set_file_extent_compression(leaf, extent_item, 1); | 1132 | compressed = 1; |
1073 | else | 1133 | if (test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) { |
1074 | btrfs_set_file_extent_compression(leaf, extent_item, 0); | 1134 | BUG_ON(compressed); |
1075 | btrfs_set_file_extent_encryption(leaf, extent_item, 0); | 1135 | ret = btrfs_mark_extent_written(trans, root, inode, |
1076 | btrfs_set_file_extent_other_encoding(leaf, extent_item, 0); | 1136 | ordered_extent->file_offset, |
1077 | 1137 | ordered_extent->file_offset + | |
1078 | /* ram bytes = extent_num_bytes for now */ | 1138 | ordered_extent->len); |
1079 | btrfs_set_file_extent_num_bytes(leaf, extent_item, | 1139 | BUG_ON(ret); |
1080 | ordered_extent->len); | 1140 | } else { |
1081 | btrfs_set_file_extent_ram_bytes(leaf, extent_item, | 1141 | ret = insert_reserved_file_extent(trans, inode, |
1082 | ordered_extent->len); | 1142 | ordered_extent->file_offset, |
1083 | btrfs_mark_buffer_dirty(leaf); | 1143 | ordered_extent->start, |
1084 | 1144 | ordered_extent->disk_len, | |
1085 | btrfs_drop_extent_cache(inode, ordered_extent->file_offset, | 1145 | ordered_extent->len, |
1086 | ordered_extent->file_offset + | 1146 | ordered_extent->len, |
1087 | ordered_extent->len - 1, 0); | 1147 | compressed, 0, 0, |
1088 | 1148 | BTRFS_FILE_EXTENT_REG); | |
1089 | ins.objectid = ordered_extent->start; | 1149 | BUG_ON(ret); |
1090 | ins.offset = ordered_extent->disk_len; | 1150 | } |
1091 | ins.type = BTRFS_EXTENT_ITEM_KEY; | ||
1092 | ret = btrfs_alloc_reserved_extent(trans, root, leaf->start, | ||
1093 | root->root_key.objectid, | ||
1094 | trans->transid, inode->i_ino, &ins); | ||
1095 | BUG_ON(ret); | ||
1096 | btrfs_release_path(root, path); | ||
1097 | |||
1098 | inode_add_bytes(inode, ordered_extent->len); | ||
1099 | unlock_extent(io_tree, ordered_extent->file_offset, | 1151 | unlock_extent(io_tree, ordered_extent->file_offset, |
1100 | ordered_extent->file_offset + ordered_extent->len - 1, | 1152 | ordered_extent->file_offset + ordered_extent->len - 1, |
1101 | GFP_NOFS); | 1153 | GFP_NOFS); |
@@ -1115,8 +1167,6 @@ nocow: | |||
1115 | btrfs_put_ordered_extent(ordered_extent); | 1167 | btrfs_put_ordered_extent(ordered_extent); |
1116 | 1168 | ||
1117 | btrfs_end_transaction(trans, root); | 1169 | btrfs_end_transaction(trans, root); |
1118 | if (path) | ||
1119 | btrfs_free_path(path); | ||
1120 | return 0; | 1170 | return 0; |
1121 | } | 1171 | } |
1122 | 1172 | ||
@@ -3488,7 +3538,8 @@ again: | |||
3488 | found_type = btrfs_file_extent_type(leaf, item); | 3538 | found_type = btrfs_file_extent_type(leaf, item); |
3489 | extent_start = found_key.offset; | 3539 | extent_start = found_key.offset; |
3490 | compressed = btrfs_file_extent_compression(leaf, item); | 3540 | compressed = btrfs_file_extent_compression(leaf, item); |
3491 | if (found_type == BTRFS_FILE_EXTENT_REG) { | 3541 | if (found_type == BTRFS_FILE_EXTENT_REG || |
3542 | found_type == BTRFS_FILE_EXTENT_PREALLOC) { | ||
3492 | extent_end = extent_start + | 3543 | extent_end = extent_start + |
3493 | btrfs_file_extent_num_bytes(leaf, item); | 3544 | btrfs_file_extent_num_bytes(leaf, item); |
3494 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | 3545 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { |
@@ -3521,7 +3572,8 @@ again: | |||
3521 | goto not_found_em; | 3572 | goto not_found_em; |
3522 | } | 3573 | } |
3523 | 3574 | ||
3524 | if (found_type == BTRFS_FILE_EXTENT_REG) { | 3575 | if (found_type == BTRFS_FILE_EXTENT_REG || |
3576 | found_type == BTRFS_FILE_EXTENT_PREALLOC) { | ||
3525 | em->start = extent_start; | 3577 | em->start = extent_start; |
3526 | em->len = extent_end - extent_start; | 3578 | em->len = extent_end - extent_start; |
3527 | bytenr = btrfs_file_extent_disk_bytenr(leaf, item); | 3579 | bytenr = btrfs_file_extent_disk_bytenr(leaf, item); |
@@ -3538,6 +3590,8 @@ again: | |||
3538 | bytenr += btrfs_file_extent_offset(leaf, item); | 3590 | bytenr += btrfs_file_extent_offset(leaf, item); |
3539 | em->block_start = bytenr; | 3591 | em->block_start = bytenr; |
3540 | em->block_len = em->len; | 3592 | em->block_len = em->len; |
3593 | if (found_type == BTRFS_FILE_EXTENT_PREALLOC) | ||
3594 | set_bit(EXTENT_FLAG_PREALLOC, &em->flags); | ||
3541 | } | 3595 | } |
3542 | goto insert; | 3596 | goto insert; |
3543 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | 3597 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { |
@@ -3969,6 +4023,7 @@ int btrfs_create_subvol_root(struct btrfs_root *new_root, struct dentry *dentry, | |||
3969 | if (error) | 4023 | if (error) |
3970 | return error; | 4024 | return error; |
3971 | 4025 | ||
4026 | atomic_inc(&inode->i_count); | ||
3972 | d_instantiate(dentry, inode); | 4027 | d_instantiate(dentry, inode); |
3973 | return 0; | 4028 | return 0; |
3974 | } | 4029 | } |
@@ -4318,6 +4373,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, | |||
4318 | inode->i_op = &btrfs_symlink_inode_operations; | 4373 | inode->i_op = &btrfs_symlink_inode_operations; |
4319 | inode->i_mapping->a_ops = &btrfs_symlink_aops; | 4374 | inode->i_mapping->a_ops = &btrfs_symlink_aops; |
4320 | inode->i_mapping->backing_dev_info = &root->fs_info->bdi; | 4375 | inode->i_mapping->backing_dev_info = &root->fs_info->bdi; |
4376 | inode_set_bytes(inode, name_len); | ||
4321 | btrfs_i_size_write(inode, name_len - 1); | 4377 | btrfs_i_size_write(inode, name_len - 1); |
4322 | err = btrfs_update_inode(trans, root, inode); | 4378 | err = btrfs_update_inode(trans, root, inode); |
4323 | if (err) | 4379 | if (err) |
@@ -4335,6 +4391,130 @@ out_fail: | |||
4335 | return err; | 4391 | return err; |
4336 | } | 4392 | } |
4337 | 4393 | ||
4394 | static int prealloc_file_range(struct inode *inode, u64 start, u64 end, | ||
4395 | u64 alloc_hint, int mode) | ||
4396 | { | ||
4397 | struct btrfs_trans_handle *trans; | ||
4398 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
4399 | struct btrfs_key ins; | ||
4400 | u64 alloc_size; | ||
4401 | u64 cur_offset = start; | ||
4402 | u64 num_bytes = end - start; | ||
4403 | int ret = 0; | ||
4404 | |||
4405 | trans = btrfs_join_transaction(root, 1); | ||
4406 | BUG_ON(!trans); | ||
4407 | btrfs_set_trans_block_group(trans, inode); | ||
4408 | |||
4409 | while (num_bytes > 0) { | ||
4410 | alloc_size = min(num_bytes, root->fs_info->max_extent); | ||
4411 | ret = btrfs_reserve_extent(trans, root, alloc_size, | ||
4412 | root->sectorsize, 0, alloc_hint, | ||
4413 | (u64)-1, &ins, 1); | ||
4414 | if (ret) { | ||
4415 | WARN_ON(1); | ||
4416 | goto out; | ||
4417 | } | ||
4418 | ret = insert_reserved_file_extent(trans, inode, | ||
4419 | cur_offset, ins.objectid, | ||
4420 | ins.offset, ins.offset, | ||
4421 | ins.offset, 0, 0, 0, | ||
4422 | BTRFS_FILE_EXTENT_PREALLOC); | ||
4423 | BUG_ON(ret); | ||
4424 | num_bytes -= ins.offset; | ||
4425 | cur_offset += ins.offset; | ||
4426 | alloc_hint = ins.objectid + ins.offset; | ||
4427 | } | ||
4428 | out: | ||
4429 | if (cur_offset > start) { | ||
4430 | inode->i_ctime = CURRENT_TIME; | ||
4431 | btrfs_set_flag(inode, PREALLOC); | ||
4432 | if (!(mode & FALLOC_FL_KEEP_SIZE) && | ||
4433 | cur_offset > i_size_read(inode)) | ||
4434 | btrfs_i_size_write(inode, cur_offset); | ||
4435 | ret = btrfs_update_inode(trans, root, inode); | ||
4436 | BUG_ON(ret); | ||
4437 | } | ||
4438 | |||
4439 | btrfs_end_transaction(trans, root); | ||
4440 | return ret; | ||
4441 | } | ||
4442 | |||
4443 | static long btrfs_fallocate(struct inode *inode, int mode, | ||
4444 | loff_t offset, loff_t len) | ||
4445 | { | ||
4446 | u64 cur_offset; | ||
4447 | u64 last_byte; | ||
4448 | u64 alloc_start; | ||
4449 | u64 alloc_end; | ||
4450 | u64 alloc_hint = 0; | ||
4451 | u64 mask = BTRFS_I(inode)->root->sectorsize - 1; | ||
4452 | struct extent_map *em; | ||
4453 | int ret; | ||
4454 | |||
4455 | alloc_start = offset & ~mask; | ||
4456 | alloc_end = (offset + len + mask) & ~mask; | ||
4457 | |||
4458 | mutex_lock(&inode->i_mutex); | ||
4459 | if (alloc_start > inode->i_size) { | ||
4460 | ret = btrfs_cont_expand(inode, alloc_start); | ||
4461 | if (ret) | ||
4462 | goto out; | ||
4463 | } | ||
4464 | |||
4465 | while (1) { | ||
4466 | struct btrfs_ordered_extent *ordered; | ||
4467 | lock_extent(&BTRFS_I(inode)->io_tree, alloc_start, | ||
4468 | alloc_end - 1, GFP_NOFS); | ||
4469 | ordered = btrfs_lookup_first_ordered_extent(inode, | ||
4470 | alloc_end - 1); | ||
4471 | if (ordered && | ||
4472 | ordered->file_offset + ordered->len > alloc_start && | ||
4473 | ordered->file_offset < alloc_end) { | ||
4474 | btrfs_put_ordered_extent(ordered); | ||
4475 | unlock_extent(&BTRFS_I(inode)->io_tree, | ||
4476 | alloc_start, alloc_end - 1, GFP_NOFS); | ||
4477 | btrfs_wait_ordered_range(inode, alloc_start, | ||
4478 | alloc_end - alloc_start); | ||
4479 | } else { | ||
4480 | if (ordered) | ||
4481 | btrfs_put_ordered_extent(ordered); | ||
4482 | break; | ||
4483 | } | ||
4484 | } | ||
4485 | |||
4486 | cur_offset = alloc_start; | ||
4487 | while (1) { | ||
4488 | em = btrfs_get_extent(inode, NULL, 0, cur_offset, | ||
4489 | alloc_end - cur_offset, 0); | ||
4490 | BUG_ON(IS_ERR(em) || !em); | ||
4491 | last_byte = min(extent_map_end(em), alloc_end); | ||
4492 | last_byte = (last_byte + mask) & ~mask; | ||
4493 | if (em->block_start == EXTENT_MAP_HOLE) { | ||
4494 | ret = prealloc_file_range(inode, cur_offset, | ||
4495 | last_byte, alloc_hint, mode); | ||
4496 | if (ret < 0) { | ||
4497 | free_extent_map(em); | ||
4498 | break; | ||
4499 | } | ||
4500 | } | ||
4501 | if (em->block_start <= EXTENT_MAP_LAST_BYTE) | ||
4502 | alloc_hint = em->block_start; | ||
4503 | free_extent_map(em); | ||
4504 | |||
4505 | cur_offset = last_byte; | ||
4506 | if (cur_offset >= alloc_end) { | ||
4507 | ret = 0; | ||
4508 | break; | ||
4509 | } | ||
4510 | } | ||
4511 | unlock_extent(&BTRFS_I(inode)->io_tree, alloc_start, alloc_end - 1, | ||
4512 | GFP_NOFS); | ||
4513 | out: | ||
4514 | mutex_unlock(&inode->i_mutex); | ||
4515 | return ret; | ||
4516 | } | ||
4517 | |||
4338 | static int btrfs_set_page_dirty(struct page *page) | 4518 | static int btrfs_set_page_dirty(struct page *page) |
4339 | { | 4519 | { |
4340 | return __set_page_dirty_nobuffers(page); | 4520 | return __set_page_dirty_nobuffers(page); |
@@ -4421,6 +4601,7 @@ static struct inode_operations btrfs_file_inode_operations = { | |||
4421 | .listxattr = btrfs_listxattr, | 4601 | .listxattr = btrfs_listxattr, |
4422 | .removexattr = btrfs_removexattr, | 4602 | .removexattr = btrfs_removexattr, |
4423 | .permission = btrfs_permission, | 4603 | .permission = btrfs_permission, |
4604 | .fallocate = btrfs_fallocate, | ||
4424 | }; | 4605 | }; |
4425 | static struct inode_operations btrfs_special_inode_operations = { | 4606 | static struct inode_operations btrfs_special_inode_operations = { |
4426 | .getattr = btrfs_getattr, | 4607 | .getattr = btrfs_getattr, |