diff options
-rw-r--r-- | fs/btrfs/ctree.h | 2 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 58 | ||||
-rw-r--r-- | fs/btrfs/super.c | 146 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 84 | ||||
-rw-r--r-- | fs/btrfs/volumes.h | 3 |
5 files changed, 286 insertions, 7 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 0cb322cc4fc0..0995f4f68d7a 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -2158,6 +2158,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, | |||
2158 | int btrfs_remove_block_group(struct btrfs_trans_handle *trans, | 2158 | int btrfs_remove_block_group(struct btrfs_trans_handle *trans, |
2159 | struct btrfs_root *root, u64 group_start); | 2159 | struct btrfs_root *root, u64 group_start); |
2160 | u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags); | 2160 | u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags); |
2161 | u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data); | ||
2161 | void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *ionde); | 2162 | void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *ionde); |
2162 | void btrfs_clear_space_info_full(struct btrfs_fs_info *info); | 2163 | void btrfs_clear_space_info_full(struct btrfs_fs_info *info); |
2163 | int btrfs_check_data_free_space(struct inode *inode, u64 bytes); | 2164 | int btrfs_check_data_free_space(struct inode *inode, u64 bytes); |
@@ -2201,6 +2202,7 @@ int btrfs_set_block_group_ro(struct btrfs_root *root, | |||
2201 | int btrfs_set_block_group_rw(struct btrfs_root *root, | 2202 | int btrfs_set_block_group_rw(struct btrfs_root *root, |
2202 | struct btrfs_block_group_cache *cache); | 2203 | struct btrfs_block_group_cache *cache); |
2203 | void btrfs_put_block_group_cache(struct btrfs_fs_info *info); | 2204 | void btrfs_put_block_group_cache(struct btrfs_fs_info *info); |
2205 | u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo); | ||
2204 | /* ctree.c */ | 2206 | /* ctree.c */ |
2205 | int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, | 2207 | int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, |
2206 | int level, int *slot); | 2208 | int level, int *slot); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 1e1c9a177626..04bfc3a2bd9f 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -3090,7 +3090,7 @@ static u64 get_alloc_profile(struct btrfs_root *root, u64 flags) | |||
3090 | return btrfs_reduce_alloc_profile(root, flags); | 3090 | return btrfs_reduce_alloc_profile(root, flags); |
3091 | } | 3091 | } |
3092 | 3092 | ||
3093 | static u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data) | 3093 | u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data) |
3094 | { | 3094 | { |
3095 | u64 flags; | 3095 | u64 flags; |
3096 | 3096 | ||
@@ -8019,6 +8019,62 @@ out: | |||
8019 | return ret; | 8019 | return ret; |
8020 | } | 8020 | } |
8021 | 8021 | ||
8022 | /* | ||
8023 | * helper to account the unused space of all the readonly block group in the | ||
8024 | * list. takes mirrors into account. | ||
8025 | */ | ||
8026 | static u64 __btrfs_get_ro_block_group_free_space(struct list_head *groups_list) | ||
8027 | { | ||
8028 | struct btrfs_block_group_cache *block_group; | ||
8029 | u64 free_bytes = 0; | ||
8030 | int factor; | ||
8031 | |||
8032 | list_for_each_entry(block_group, groups_list, list) { | ||
8033 | spin_lock(&block_group->lock); | ||
8034 | |||
8035 | if (!block_group->ro) { | ||
8036 | spin_unlock(&block_group->lock); | ||
8037 | continue; | ||
8038 | } | ||
8039 | |||
8040 | if (block_group->flags & (BTRFS_BLOCK_GROUP_RAID1 | | ||
8041 | BTRFS_BLOCK_GROUP_RAID10 | | ||
8042 | BTRFS_BLOCK_GROUP_DUP)) | ||
8043 | factor = 2; | ||
8044 | else | ||
8045 | factor = 1; | ||
8046 | |||
8047 | free_bytes += (block_group->key.offset - | ||
8048 | btrfs_block_group_used(&block_group->item)) * | ||
8049 | factor; | ||
8050 | |||
8051 | spin_unlock(&block_group->lock); | ||
8052 | } | ||
8053 | |||
8054 | return free_bytes; | ||
8055 | } | ||
8056 | |||
8057 | /* | ||
8058 | * helper to account the unused space of all the readonly block group in the | ||
8059 | * space_info. takes mirrors into account. | ||
8060 | */ | ||
8061 | u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo) | ||
8062 | { | ||
8063 | int i; | ||
8064 | u64 free_bytes = 0; | ||
8065 | |||
8066 | spin_lock(&sinfo->lock); | ||
8067 | |||
8068 | for(i = 0; i < BTRFS_NR_RAID_TYPES; i++) | ||
8069 | if (!list_empty(&sinfo->block_groups[i])) | ||
8070 | free_bytes += __btrfs_get_ro_block_group_free_space( | ||
8071 | &sinfo->block_groups[i]); | ||
8072 | |||
8073 | spin_unlock(&sinfo->lock); | ||
8074 | |||
8075 | return free_bytes; | ||
8076 | } | ||
8077 | |||
8022 | int btrfs_set_block_group_rw(struct btrfs_root *root, | 8078 | int btrfs_set_block_group_rw(struct btrfs_root *root, |
8023 | struct btrfs_block_group_cache *cache) | 8079 | struct btrfs_block_group_cache *cache) |
8024 | { | 8080 | { |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index caa5bcc62f16..2963376e77f4 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -777,6 +777,127 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) | |||
777 | return 0; | 777 | return 0; |
778 | } | 778 | } |
779 | 779 | ||
780 | /* | ||
781 | * The helper to calc the free space on the devices that can be used to store | ||
782 | * file data. | ||
783 | */ | ||
784 | static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes) | ||
785 | { | ||
786 | struct btrfs_fs_info *fs_info = root->fs_info; | ||
787 | struct btrfs_device_info *devices_info; | ||
788 | struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; | ||
789 | struct btrfs_device *device; | ||
790 | u64 skip_space; | ||
791 | u64 type; | ||
792 | u64 avail_space; | ||
793 | u64 used_space; | ||
794 | u64 min_stripe_size; | ||
795 | int min_stripes = 1; | ||
796 | int i = 0, nr_devices; | ||
797 | int ret; | ||
798 | |||
799 | nr_devices = fs_info->fs_devices->rw_devices; | ||
800 | BUG_ON(!nr_devices); | ||
801 | |||
802 | devices_info = kmalloc(sizeof(*devices_info) * nr_devices, | ||
803 | GFP_NOFS); | ||
804 | if (!devices_info) | ||
805 | return -ENOMEM; | ||
806 | |||
807 | /* calc min stripe number for data space alloction */ | ||
808 | type = btrfs_get_alloc_profile(root, 1); | ||
809 | if (type & BTRFS_BLOCK_GROUP_RAID0) | ||
810 | min_stripes = 2; | ||
811 | else if (type & BTRFS_BLOCK_GROUP_RAID1) | ||
812 | min_stripes = 2; | ||
813 | else if (type & BTRFS_BLOCK_GROUP_RAID10) | ||
814 | min_stripes = 4; | ||
815 | |||
816 | if (type & BTRFS_BLOCK_GROUP_DUP) | ||
817 | min_stripe_size = 2 * BTRFS_STRIPE_LEN; | ||
818 | else | ||
819 | min_stripe_size = BTRFS_STRIPE_LEN; | ||
820 | |||
821 | list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) { | ||
822 | if (!device->in_fs_metadata) | ||
823 | continue; | ||
824 | |||
825 | avail_space = device->total_bytes - device->bytes_used; | ||
826 | |||
827 | /* align with stripe_len */ | ||
828 | do_div(avail_space, BTRFS_STRIPE_LEN); | ||
829 | avail_space *= BTRFS_STRIPE_LEN; | ||
830 | |||
831 | /* | ||
832 | * In order to avoid overwritting the superblock on the drive, | ||
833 | * btrfs starts at an offset of at least 1MB when doing chunk | ||
834 | * allocation. | ||
835 | */ | ||
836 | skip_space = 1024 * 1024; | ||
837 | |||
838 | /* user can set the offset in fs_info->alloc_start. */ | ||
839 | if (fs_info->alloc_start + BTRFS_STRIPE_LEN <= | ||
840 | device->total_bytes) | ||
841 | skip_space = max(fs_info->alloc_start, skip_space); | ||
842 | |||
843 | /* | ||
844 | * btrfs can not use the free space in [0, skip_space - 1], | ||
845 | * we must subtract it from the total. In order to implement | ||
846 | * it, we account the used space in this range first. | ||
847 | */ | ||
848 | ret = btrfs_account_dev_extents_size(device, 0, skip_space - 1, | ||
849 | &used_space); | ||
850 | if (ret) { | ||
851 | kfree(devices_info); | ||
852 | return ret; | ||
853 | } | ||
854 | |||
855 | /* calc the free space in [0, skip_space - 1] */ | ||
856 | skip_space -= used_space; | ||
857 | |||
858 | /* | ||
859 | * we can use the free space in [0, skip_space - 1], subtract | ||
860 | * it from the total. | ||
861 | */ | ||
862 | if (avail_space && avail_space >= skip_space) | ||
863 | avail_space -= skip_space; | ||
864 | else | ||
865 | avail_space = 0; | ||
866 | |||
867 | if (avail_space < min_stripe_size) | ||
868 | continue; | ||
869 | |||
870 | devices_info[i].dev = device; | ||
871 | devices_info[i].max_avail = avail_space; | ||
872 | |||
873 | i++; | ||
874 | } | ||
875 | |||
876 | nr_devices = i; | ||
877 | |||
878 | btrfs_descending_sort_devices(devices_info, nr_devices); | ||
879 | |||
880 | i = nr_devices - 1; | ||
881 | avail_space = 0; | ||
882 | while (nr_devices >= min_stripes) { | ||
883 | if (devices_info[i].max_avail >= min_stripe_size) { | ||
884 | int j; | ||
885 | u64 alloc_size; | ||
886 | |||
887 | avail_space += devices_info[i].max_avail * min_stripes; | ||
888 | alloc_size = devices_info[i].max_avail; | ||
889 | for (j = i + 1 - min_stripes; j <= i; j++) | ||
890 | devices_info[j].max_avail -= alloc_size; | ||
891 | } | ||
892 | i--; | ||
893 | nr_devices--; | ||
894 | } | ||
895 | |||
896 | kfree(devices_info); | ||
897 | *free_bytes = avail_space; | ||
898 | return 0; | ||
899 | } | ||
900 | |||
780 | static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 901 | static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) |
781 | { | 902 | { |
782 | struct btrfs_root *root = btrfs_sb(dentry->d_sb); | 903 | struct btrfs_root *root = btrfs_sb(dentry->d_sb); |
@@ -784,16 +905,21 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
784 | struct list_head *head = &root->fs_info->space_info; | 905 | struct list_head *head = &root->fs_info->space_info; |
785 | struct btrfs_space_info *found; | 906 | struct btrfs_space_info *found; |
786 | u64 total_used = 0; | 907 | u64 total_used = 0; |
787 | u64 total_used_data = 0; | 908 | u64 total_free_data = 0; |
788 | int bits = dentry->d_sb->s_blocksize_bits; | 909 | int bits = dentry->d_sb->s_blocksize_bits; |
789 | __be32 *fsid = (__be32 *)root->fs_info->fsid; | 910 | __be32 *fsid = (__be32 *)root->fs_info->fsid; |
911 | int ret; | ||
790 | 912 | ||
913 | /* holding chunk_muext to avoid allocating new chunks */ | ||
914 | mutex_lock(&root->fs_info->chunk_mutex); | ||
791 | rcu_read_lock(); | 915 | rcu_read_lock(); |
792 | list_for_each_entry_rcu(found, head, list) { | 916 | list_for_each_entry_rcu(found, head, list) { |
793 | if (found->flags & BTRFS_BLOCK_GROUP_DATA) | 917 | if (found->flags & BTRFS_BLOCK_GROUP_DATA) { |
794 | total_used_data += found->disk_used; | 918 | total_free_data += found->disk_total - found->disk_used; |
795 | else | 919 | total_free_data -= |
796 | total_used_data += found->disk_total; | 920 | btrfs_account_ro_block_groups_free_space(found); |
921 | } | ||
922 | |||
797 | total_used += found->disk_used; | 923 | total_used += found->disk_used; |
798 | } | 924 | } |
799 | rcu_read_unlock(); | 925 | rcu_read_unlock(); |
@@ -801,9 +927,17 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
801 | buf->f_namelen = BTRFS_NAME_LEN; | 927 | buf->f_namelen = BTRFS_NAME_LEN; |
802 | buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits; | 928 | buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits; |
803 | buf->f_bfree = buf->f_blocks - (total_used >> bits); | 929 | buf->f_bfree = buf->f_blocks - (total_used >> bits); |
804 | buf->f_bavail = buf->f_blocks - (total_used_data >> bits); | ||
805 | buf->f_bsize = dentry->d_sb->s_blocksize; | 930 | buf->f_bsize = dentry->d_sb->s_blocksize; |
806 | buf->f_type = BTRFS_SUPER_MAGIC; | 931 | buf->f_type = BTRFS_SUPER_MAGIC; |
932 | buf->f_bavail = total_free_data; | ||
933 | ret = btrfs_calc_avail_data_space(root, &total_free_data); | ||
934 | if (ret) { | ||
935 | mutex_unlock(&root->fs_info->chunk_mutex); | ||
936 | return ret; | ||
937 | } | ||
938 | buf->f_bavail += total_free_data; | ||
939 | buf->f_bavail = buf->f_bavail >> bits; | ||
940 | mutex_unlock(&root->fs_info->chunk_mutex); | ||
807 | 941 | ||
808 | /* We treat it as constant endianness (it doesn't matter _which_) | 942 | /* We treat it as constant endianness (it doesn't matter _which_) |
809 | because we want the fsid to come out the same whether mounted | 943 | because we want the fsid to come out the same whether mounted |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index c22784b989b7..0c7f478cf645 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -728,6 +728,90 @@ error: | |||
728 | return ret; | 728 | return ret; |
729 | } | 729 | } |
730 | 730 | ||
731 | /* helper to account the used device space in the range */ | ||
732 | int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, | ||
733 | u64 end, u64 *length) | ||
734 | { | ||
735 | struct btrfs_key key; | ||
736 | struct btrfs_root *root = device->dev_root; | ||
737 | struct btrfs_dev_extent *dev_extent; | ||
738 | struct btrfs_path *path; | ||
739 | u64 extent_end; | ||
740 | int ret; | ||
741 | int slot; | ||
742 | struct extent_buffer *l; | ||
743 | |||
744 | *length = 0; | ||
745 | |||
746 | if (start >= device->total_bytes) | ||
747 | return 0; | ||
748 | |||
749 | path = btrfs_alloc_path(); | ||
750 | if (!path) | ||
751 | return -ENOMEM; | ||
752 | path->reada = 2; | ||
753 | |||
754 | key.objectid = device->devid; | ||
755 | key.offset = start; | ||
756 | key.type = BTRFS_DEV_EXTENT_KEY; | ||
757 | |||
758 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | ||
759 | if (ret < 0) | ||
760 | goto out; | ||
761 | if (ret > 0) { | ||
762 | ret = btrfs_previous_item(root, path, key.objectid, key.type); | ||
763 | if (ret < 0) | ||
764 | goto out; | ||
765 | } | ||
766 | |||
767 | while (1) { | ||
768 | l = path->nodes[0]; | ||
769 | slot = path->slots[0]; | ||
770 | if (slot >= btrfs_header_nritems(l)) { | ||
771 | ret = btrfs_next_leaf(root, path); | ||
772 | if (ret == 0) | ||
773 | continue; | ||
774 | if (ret < 0) | ||
775 | goto out; | ||
776 | |||
777 | break; | ||
778 | } | ||
779 | btrfs_item_key_to_cpu(l, &key, slot); | ||
780 | |||
781 | if (key.objectid < device->devid) | ||
782 | goto next; | ||
783 | |||
784 | if (key.objectid > device->devid) | ||
785 | break; | ||
786 | |||
787 | if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY) | ||
788 | goto next; | ||
789 | |||
790 | dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent); | ||
791 | extent_end = key.offset + btrfs_dev_extent_length(l, | ||
792 | dev_extent); | ||
793 | if (key.offset <= start && extent_end > end) { | ||
794 | *length = end - start + 1; | ||
795 | break; | ||
796 | } else if (key.offset <= start && extent_end > start) | ||
797 | *length += extent_end - start; | ||
798 | else if (key.offset > start && extent_end <= end) | ||
799 | *length += extent_end - key.offset; | ||
800 | else if (key.offset > start && key.offset <= end) { | ||
801 | *length += end - key.offset + 1; | ||
802 | break; | ||
803 | } else if (key.offset > end) | ||
804 | break; | ||
805 | |||
806 | next: | ||
807 | path->slots[0]++; | ||
808 | } | ||
809 | ret = 0; | ||
810 | out: | ||
811 | btrfs_free_path(path); | ||
812 | return ret; | ||
813 | } | ||
814 | |||
731 | /* | 815 | /* |
732 | * find_free_dev_extent - find free space in the specified device | 816 | * find_free_dev_extent - find free space in the specified device |
733 | * @trans: transaction handler | 817 | * @trans: transaction handler |
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index a5cfedf393f9..7af6144a7954 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h | |||
@@ -161,6 +161,9 @@ static inline void btrfs_descending_sort_devices( | |||
161 | btrfs_cmp_device_free_bytes, NULL); | 161 | btrfs_cmp_device_free_bytes, NULL); |
162 | } | 162 | } |
163 | 163 | ||
164 | int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, | ||
165 | u64 end, u64 *length); | ||
166 | |||
164 | #define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \ | 167 | #define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \ |
165 | (sizeof(struct btrfs_bio_stripe) * (n))) | 168 | (sizeof(struct btrfs_bio_stripe) * (n))) |
166 | 169 | ||