diff options
Diffstat (limited to 'fs/btrfs/qgroup.c')
-rw-r--r-- | fs/btrfs/qgroup.c | 840 |
1 files changed, 671 insertions, 169 deletions
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index b44124dd2370..9d49c586995a 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c | |||
@@ -31,13 +31,13 @@ | |||
31 | #include "locking.h" | 31 | #include "locking.h" |
32 | #include "ulist.h" | 32 | #include "ulist.h" |
33 | #include "backref.h" | 33 | #include "backref.h" |
34 | #include "extent_io.h" | ||
34 | 35 | ||
35 | /* TODO XXX FIXME | 36 | /* TODO XXX FIXME |
36 | * - subvol delete -> delete when ref goes to 0? delete limits also? | 37 | * - subvol delete -> delete when ref goes to 0? delete limits also? |
37 | * - reorganize keys | 38 | * - reorganize keys |
38 | * - compressed | 39 | * - compressed |
39 | * - sync | 40 | * - sync |
40 | * - rescan | ||
41 | * - copy also limits on subvol creation | 41 | * - copy also limits on subvol creation |
42 | * - limit | 42 | * - limit |
43 | * - caches fuer ulists | 43 | * - caches fuer ulists |
@@ -98,7 +98,15 @@ struct btrfs_qgroup_list { | |||
98 | struct btrfs_qgroup *member; | 98 | struct btrfs_qgroup *member; |
99 | }; | 99 | }; |
100 | 100 | ||
101 | /* must be called with qgroup_lock held */ | 101 | struct qgroup_rescan { |
102 | struct btrfs_work work; | ||
103 | struct btrfs_fs_info *fs_info; | ||
104 | }; | ||
105 | |||
106 | static void qgroup_rescan_start(struct btrfs_fs_info *fs_info, | ||
107 | struct qgroup_rescan *qscan); | ||
108 | |||
109 | /* must be called with qgroup_ioctl_lock held */ | ||
102 | static struct btrfs_qgroup *find_qgroup_rb(struct btrfs_fs_info *fs_info, | 110 | static struct btrfs_qgroup *find_qgroup_rb(struct btrfs_fs_info *fs_info, |
103 | u64 qgroupid) | 111 | u64 qgroupid) |
104 | { | 112 | { |
@@ -298,7 +306,20 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info) | |||
298 | } | 306 | } |
299 | fs_info->qgroup_flags = btrfs_qgroup_status_flags(l, | 307 | fs_info->qgroup_flags = btrfs_qgroup_status_flags(l, |
300 | ptr); | 308 | ptr); |
301 | /* FIXME read scan element */ | 309 | fs_info->qgroup_rescan_progress.objectid = |
310 | btrfs_qgroup_status_rescan(l, ptr); | ||
311 | if (fs_info->qgroup_flags & | ||
312 | BTRFS_QGROUP_STATUS_FLAG_RESCAN) { | ||
313 | struct qgroup_rescan *qscan = | ||
314 | kmalloc(sizeof(*qscan), GFP_NOFS); | ||
315 | if (!qscan) { | ||
316 | ret = -ENOMEM; | ||
317 | goto out; | ||
318 | } | ||
319 | fs_info->qgroup_rescan_progress.type = 0; | ||
320 | fs_info->qgroup_rescan_progress.offset = 0; | ||
321 | qgroup_rescan_start(fs_info, qscan); | ||
322 | } | ||
302 | goto next1; | 323 | goto next1; |
303 | } | 324 | } |
304 | 325 | ||
@@ -420,8 +441,6 @@ void btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info) | |||
420 | qgroup = rb_entry(n, struct btrfs_qgroup, node); | 441 | qgroup = rb_entry(n, struct btrfs_qgroup, node); |
421 | rb_erase(n, &fs_info->qgroup_tree); | 442 | rb_erase(n, &fs_info->qgroup_tree); |
422 | 443 | ||
423 | WARN_ON(!list_empty(&qgroup->dirty)); | ||
424 | |||
425 | while (!list_empty(&qgroup->groups)) { | 444 | while (!list_empty(&qgroup->groups)) { |
426 | list = list_first_entry(&qgroup->groups, | 445 | list = list_first_entry(&qgroup->groups, |
427 | struct btrfs_qgroup_list, | 446 | struct btrfs_qgroup_list, |
@@ -721,7 +740,8 @@ static int update_qgroup_status_item(struct btrfs_trans_handle *trans, | |||
721 | ptr = btrfs_item_ptr(l, slot, struct btrfs_qgroup_status_item); | 740 | ptr = btrfs_item_ptr(l, slot, struct btrfs_qgroup_status_item); |
722 | btrfs_set_qgroup_status_flags(l, ptr, fs_info->qgroup_flags); | 741 | btrfs_set_qgroup_status_flags(l, ptr, fs_info->qgroup_flags); |
723 | btrfs_set_qgroup_status_generation(l, ptr, trans->transid); | 742 | btrfs_set_qgroup_status_generation(l, ptr, trans->transid); |
724 | /* XXX scan */ | 743 | btrfs_set_qgroup_status_rescan(l, ptr, |
744 | fs_info->qgroup_rescan_progress.objectid); | ||
725 | 745 | ||
726 | btrfs_mark_buffer_dirty(l); | 746 | btrfs_mark_buffer_dirty(l); |
727 | 747 | ||
@@ -783,19 +803,21 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans, | |||
783 | struct btrfs_fs_info *fs_info) | 803 | struct btrfs_fs_info *fs_info) |
784 | { | 804 | { |
785 | struct btrfs_root *quota_root; | 805 | struct btrfs_root *quota_root; |
806 | struct btrfs_root *tree_root = fs_info->tree_root; | ||
786 | struct btrfs_path *path = NULL; | 807 | struct btrfs_path *path = NULL; |
787 | struct btrfs_qgroup_status_item *ptr; | 808 | struct btrfs_qgroup_status_item *ptr; |
788 | struct extent_buffer *leaf; | 809 | struct extent_buffer *leaf; |
789 | struct btrfs_key key; | 810 | struct btrfs_key key; |
811 | struct btrfs_key found_key; | ||
812 | struct btrfs_qgroup *qgroup = NULL; | ||
790 | int ret = 0; | 813 | int ret = 0; |
814 | int slot; | ||
791 | 815 | ||
792 | spin_lock(&fs_info->qgroup_lock); | 816 | mutex_lock(&fs_info->qgroup_ioctl_lock); |
793 | if (fs_info->quota_root) { | 817 | if (fs_info->quota_root) { |
794 | fs_info->pending_quota_state = 1; | 818 | fs_info->pending_quota_state = 1; |
795 | spin_unlock(&fs_info->qgroup_lock); | ||
796 | goto out; | 819 | goto out; |
797 | } | 820 | } |
798 | spin_unlock(&fs_info->qgroup_lock); | ||
799 | 821 | ||
800 | /* | 822 | /* |
801 | * initially create the quota tree | 823 | * initially create the quota tree |
@@ -830,10 +852,57 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans, | |||
830 | fs_info->qgroup_flags = BTRFS_QGROUP_STATUS_FLAG_ON | | 852 | fs_info->qgroup_flags = BTRFS_QGROUP_STATUS_FLAG_ON | |
831 | BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; | 853 | BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; |
832 | btrfs_set_qgroup_status_flags(leaf, ptr, fs_info->qgroup_flags); | 854 | btrfs_set_qgroup_status_flags(leaf, ptr, fs_info->qgroup_flags); |
833 | btrfs_set_qgroup_status_scan(leaf, ptr, 0); | 855 | btrfs_set_qgroup_status_rescan(leaf, ptr, 0); |
834 | 856 | ||
835 | btrfs_mark_buffer_dirty(leaf); | 857 | btrfs_mark_buffer_dirty(leaf); |
836 | 858 | ||
859 | key.objectid = 0; | ||
860 | key.type = BTRFS_ROOT_REF_KEY; | ||
861 | key.offset = 0; | ||
862 | |||
863 | btrfs_release_path(path); | ||
864 | ret = btrfs_search_slot_for_read(tree_root, &key, path, 1, 0); | ||
865 | if (ret > 0) | ||
866 | goto out_add_root; | ||
867 | if (ret < 0) | ||
868 | goto out_free_path; | ||
869 | |||
870 | |||
871 | while (1) { | ||
872 | slot = path->slots[0]; | ||
873 | leaf = path->nodes[0]; | ||
874 | btrfs_item_key_to_cpu(leaf, &found_key, slot); | ||
875 | |||
876 | if (found_key.type == BTRFS_ROOT_REF_KEY) { | ||
877 | ret = add_qgroup_item(trans, quota_root, | ||
878 | found_key.offset); | ||
879 | if (ret) | ||
880 | goto out_free_path; | ||
881 | |||
882 | qgroup = add_qgroup_rb(fs_info, found_key.offset); | ||
883 | if (IS_ERR(qgroup)) { | ||
884 | ret = PTR_ERR(qgroup); | ||
885 | goto out_free_path; | ||
886 | } | ||
887 | } | ||
888 | ret = btrfs_next_item(tree_root, path); | ||
889 | if (ret < 0) | ||
890 | goto out_free_path; | ||
891 | if (ret) | ||
892 | break; | ||
893 | } | ||
894 | |||
895 | out_add_root: | ||
896 | btrfs_release_path(path); | ||
897 | ret = add_qgroup_item(trans, quota_root, BTRFS_FS_TREE_OBJECTID); | ||
898 | if (ret) | ||
899 | goto out_free_path; | ||
900 | |||
901 | qgroup = add_qgroup_rb(fs_info, BTRFS_FS_TREE_OBJECTID); | ||
902 | if (IS_ERR(qgroup)) { | ||
903 | ret = PTR_ERR(qgroup); | ||
904 | goto out_free_path; | ||
905 | } | ||
837 | spin_lock(&fs_info->qgroup_lock); | 906 | spin_lock(&fs_info->qgroup_lock); |
838 | fs_info->quota_root = quota_root; | 907 | fs_info->quota_root = quota_root; |
839 | fs_info->pending_quota_state = 1; | 908 | fs_info->pending_quota_state = 1; |
@@ -847,6 +916,7 @@ out_free_root: | |||
847 | kfree(quota_root); | 916 | kfree(quota_root); |
848 | } | 917 | } |
849 | out: | 918 | out: |
919 | mutex_unlock(&fs_info->qgroup_ioctl_lock); | ||
850 | return ret; | 920 | return ret; |
851 | } | 921 | } |
852 | 922 | ||
@@ -857,11 +927,10 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans, | |||
857 | struct btrfs_root *quota_root; | 927 | struct btrfs_root *quota_root; |
858 | int ret = 0; | 928 | int ret = 0; |
859 | 929 | ||
930 | mutex_lock(&fs_info->qgroup_ioctl_lock); | ||
931 | if (!fs_info->quota_root) | ||
932 | goto out; | ||
860 | spin_lock(&fs_info->qgroup_lock); | 933 | spin_lock(&fs_info->qgroup_lock); |
861 | if (!fs_info->quota_root) { | ||
862 | spin_unlock(&fs_info->qgroup_lock); | ||
863 | return 0; | ||
864 | } | ||
865 | fs_info->quota_enabled = 0; | 934 | fs_info->quota_enabled = 0; |
866 | fs_info->pending_quota_state = 0; | 935 | fs_info->pending_quota_state = 0; |
867 | quota_root = fs_info->quota_root; | 936 | quota_root = fs_info->quota_root; |
@@ -869,8 +938,10 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans, | |||
869 | btrfs_free_qgroup_config(fs_info); | 938 | btrfs_free_qgroup_config(fs_info); |
870 | spin_unlock(&fs_info->qgroup_lock); | 939 | spin_unlock(&fs_info->qgroup_lock); |
871 | 940 | ||
872 | if (!quota_root) | 941 | if (!quota_root) { |
873 | return -EINVAL; | 942 | ret = -EINVAL; |
943 | goto out; | ||
944 | } | ||
874 | 945 | ||
875 | ret = btrfs_clean_quota_tree(trans, quota_root); | 946 | ret = btrfs_clean_quota_tree(trans, quota_root); |
876 | if (ret) | 947 | if (ret) |
@@ -891,39 +962,62 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans, | |||
891 | free_extent_buffer(quota_root->commit_root); | 962 | free_extent_buffer(quota_root->commit_root); |
892 | kfree(quota_root); | 963 | kfree(quota_root); |
893 | out: | 964 | out: |
965 | mutex_unlock(&fs_info->qgroup_ioctl_lock); | ||
894 | return ret; | 966 | return ret; |
895 | } | 967 | } |
896 | 968 | ||
897 | int btrfs_quota_rescan(struct btrfs_fs_info *fs_info) | 969 | static void qgroup_dirty(struct btrfs_fs_info *fs_info, |
970 | struct btrfs_qgroup *qgroup) | ||
898 | { | 971 | { |
899 | /* FIXME */ | 972 | if (list_empty(&qgroup->dirty)) |
900 | return 0; | 973 | list_add(&qgroup->dirty, &fs_info->dirty_qgroups); |
901 | } | 974 | } |
902 | 975 | ||
903 | int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, | 976 | int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, |
904 | struct btrfs_fs_info *fs_info, u64 src, u64 dst) | 977 | struct btrfs_fs_info *fs_info, u64 src, u64 dst) |
905 | { | 978 | { |
906 | struct btrfs_root *quota_root; | 979 | struct btrfs_root *quota_root; |
980 | struct btrfs_qgroup *parent; | ||
981 | struct btrfs_qgroup *member; | ||
982 | struct btrfs_qgroup_list *list; | ||
907 | int ret = 0; | 983 | int ret = 0; |
908 | 984 | ||
985 | mutex_lock(&fs_info->qgroup_ioctl_lock); | ||
909 | quota_root = fs_info->quota_root; | 986 | quota_root = fs_info->quota_root; |
910 | if (!quota_root) | 987 | if (!quota_root) { |
911 | return -EINVAL; | 988 | ret = -EINVAL; |
989 | goto out; | ||
990 | } | ||
991 | member = find_qgroup_rb(fs_info, src); | ||
992 | parent = find_qgroup_rb(fs_info, dst); | ||
993 | if (!member || !parent) { | ||
994 | ret = -EINVAL; | ||
995 | goto out; | ||
996 | } | ||
997 | |||
998 | /* check if such qgroup relation exist firstly */ | ||
999 | list_for_each_entry(list, &member->groups, next_group) { | ||
1000 | if (list->group == parent) { | ||
1001 | ret = -EEXIST; | ||
1002 | goto out; | ||
1003 | } | ||
1004 | } | ||
912 | 1005 | ||
913 | ret = add_qgroup_relation_item(trans, quota_root, src, dst); | 1006 | ret = add_qgroup_relation_item(trans, quota_root, src, dst); |
914 | if (ret) | 1007 | if (ret) |
915 | return ret; | 1008 | goto out; |
916 | 1009 | ||
917 | ret = add_qgroup_relation_item(trans, quota_root, dst, src); | 1010 | ret = add_qgroup_relation_item(trans, quota_root, dst, src); |
918 | if (ret) { | 1011 | if (ret) { |
919 | del_qgroup_relation_item(trans, quota_root, src, dst); | 1012 | del_qgroup_relation_item(trans, quota_root, src, dst); |
920 | return ret; | 1013 | goto out; |
921 | } | 1014 | } |
922 | 1015 | ||
923 | spin_lock(&fs_info->qgroup_lock); | 1016 | spin_lock(&fs_info->qgroup_lock); |
924 | ret = add_relation_rb(quota_root->fs_info, src, dst); | 1017 | ret = add_relation_rb(quota_root->fs_info, src, dst); |
925 | spin_unlock(&fs_info->qgroup_lock); | 1018 | spin_unlock(&fs_info->qgroup_lock); |
926 | 1019 | out: | |
1020 | mutex_unlock(&fs_info->qgroup_ioctl_lock); | ||
927 | return ret; | 1021 | return ret; |
928 | } | 1022 | } |
929 | 1023 | ||
@@ -931,13 +1025,34 @@ int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, | |||
931 | struct btrfs_fs_info *fs_info, u64 src, u64 dst) | 1025 | struct btrfs_fs_info *fs_info, u64 src, u64 dst) |
932 | { | 1026 | { |
933 | struct btrfs_root *quota_root; | 1027 | struct btrfs_root *quota_root; |
1028 | struct btrfs_qgroup *parent; | ||
1029 | struct btrfs_qgroup *member; | ||
1030 | struct btrfs_qgroup_list *list; | ||
934 | int ret = 0; | 1031 | int ret = 0; |
935 | int err; | 1032 | int err; |
936 | 1033 | ||
1034 | mutex_lock(&fs_info->qgroup_ioctl_lock); | ||
937 | quota_root = fs_info->quota_root; | 1035 | quota_root = fs_info->quota_root; |
938 | if (!quota_root) | 1036 | if (!quota_root) { |
939 | return -EINVAL; | 1037 | ret = -EINVAL; |
1038 | goto out; | ||
1039 | } | ||
940 | 1040 | ||
1041 | member = find_qgroup_rb(fs_info, src); | ||
1042 | parent = find_qgroup_rb(fs_info, dst); | ||
1043 | if (!member || !parent) { | ||
1044 | ret = -EINVAL; | ||
1045 | goto out; | ||
1046 | } | ||
1047 | |||
1048 | /* check if such qgroup relation exist firstly */ | ||
1049 | list_for_each_entry(list, &member->groups, next_group) { | ||
1050 | if (list->group == parent) | ||
1051 | goto exist; | ||
1052 | } | ||
1053 | ret = -ENOENT; | ||
1054 | goto out; | ||
1055 | exist: | ||
941 | ret = del_qgroup_relation_item(trans, quota_root, src, dst); | 1056 | ret = del_qgroup_relation_item(trans, quota_root, src, dst); |
942 | err = del_qgroup_relation_item(trans, quota_root, dst, src); | 1057 | err = del_qgroup_relation_item(trans, quota_root, dst, src); |
943 | if (err && !ret) | 1058 | if (err && !ret) |
@@ -945,9 +1060,9 @@ int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, | |||
945 | 1060 | ||
946 | spin_lock(&fs_info->qgroup_lock); | 1061 | spin_lock(&fs_info->qgroup_lock); |
947 | del_relation_rb(fs_info, src, dst); | 1062 | del_relation_rb(fs_info, src, dst); |
948 | |||
949 | spin_unlock(&fs_info->qgroup_lock); | 1063 | spin_unlock(&fs_info->qgroup_lock); |
950 | 1064 | out: | |
1065 | mutex_unlock(&fs_info->qgroup_ioctl_lock); | ||
951 | return ret; | 1066 | return ret; |
952 | } | 1067 | } |
953 | 1068 | ||
@@ -958,11 +1073,21 @@ int btrfs_create_qgroup(struct btrfs_trans_handle *trans, | |||
958 | struct btrfs_qgroup *qgroup; | 1073 | struct btrfs_qgroup *qgroup; |
959 | int ret = 0; | 1074 | int ret = 0; |
960 | 1075 | ||
1076 | mutex_lock(&fs_info->qgroup_ioctl_lock); | ||
961 | quota_root = fs_info->quota_root; | 1077 | quota_root = fs_info->quota_root; |
962 | if (!quota_root) | 1078 | if (!quota_root) { |
963 | return -EINVAL; | 1079 | ret = -EINVAL; |
1080 | goto out; | ||
1081 | } | ||
1082 | qgroup = find_qgroup_rb(fs_info, qgroupid); | ||
1083 | if (qgroup) { | ||
1084 | ret = -EEXIST; | ||
1085 | goto out; | ||
1086 | } | ||
964 | 1087 | ||
965 | ret = add_qgroup_item(trans, quota_root, qgroupid); | 1088 | ret = add_qgroup_item(trans, quota_root, qgroupid); |
1089 | if (ret) | ||
1090 | goto out; | ||
966 | 1091 | ||
967 | spin_lock(&fs_info->qgroup_lock); | 1092 | spin_lock(&fs_info->qgroup_lock); |
968 | qgroup = add_qgroup_rb(fs_info, qgroupid); | 1093 | qgroup = add_qgroup_rb(fs_info, qgroupid); |
@@ -970,7 +1095,8 @@ int btrfs_create_qgroup(struct btrfs_trans_handle *trans, | |||
970 | 1095 | ||
971 | if (IS_ERR(qgroup)) | 1096 | if (IS_ERR(qgroup)) |
972 | ret = PTR_ERR(qgroup); | 1097 | ret = PTR_ERR(qgroup); |
973 | 1098 | out: | |
1099 | mutex_unlock(&fs_info->qgroup_ioctl_lock); | ||
974 | return ret; | 1100 | return ret; |
975 | } | 1101 | } |
976 | 1102 | ||
@@ -981,27 +1107,32 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, | |||
981 | struct btrfs_qgroup *qgroup; | 1107 | struct btrfs_qgroup *qgroup; |
982 | int ret = 0; | 1108 | int ret = 0; |
983 | 1109 | ||
1110 | mutex_lock(&fs_info->qgroup_ioctl_lock); | ||
984 | quota_root = fs_info->quota_root; | 1111 | quota_root = fs_info->quota_root; |
985 | if (!quota_root) | 1112 | if (!quota_root) { |
986 | return -EINVAL; | 1113 | ret = -EINVAL; |
1114 | goto out; | ||
1115 | } | ||
987 | 1116 | ||
988 | /* check if there are no relations to this qgroup */ | ||
989 | spin_lock(&fs_info->qgroup_lock); | ||
990 | qgroup = find_qgroup_rb(fs_info, qgroupid); | 1117 | qgroup = find_qgroup_rb(fs_info, qgroupid); |
991 | if (qgroup) { | 1118 | if (!qgroup) { |
992 | if (!list_empty(&qgroup->groups) || !list_empty(&qgroup->members)) { | 1119 | ret = -ENOENT; |
993 | spin_unlock(&fs_info->qgroup_lock); | 1120 | goto out; |
994 | return -EBUSY; | 1121 | } else { |
1122 | /* check if there are no relations to this qgroup */ | ||
1123 | if (!list_empty(&qgroup->groups) || | ||
1124 | !list_empty(&qgroup->members)) { | ||
1125 | ret = -EBUSY; | ||
1126 | goto out; | ||
995 | } | 1127 | } |
996 | } | 1128 | } |
997 | spin_unlock(&fs_info->qgroup_lock); | ||
998 | |||
999 | ret = del_qgroup_item(trans, quota_root, qgroupid); | 1129 | ret = del_qgroup_item(trans, quota_root, qgroupid); |
1000 | 1130 | ||
1001 | spin_lock(&fs_info->qgroup_lock); | 1131 | spin_lock(&fs_info->qgroup_lock); |
1002 | del_qgroup_rb(quota_root->fs_info, qgroupid); | 1132 | del_qgroup_rb(quota_root->fs_info, qgroupid); |
1003 | spin_unlock(&fs_info->qgroup_lock); | 1133 | spin_unlock(&fs_info->qgroup_lock); |
1004 | 1134 | out: | |
1135 | mutex_unlock(&fs_info->qgroup_ioctl_lock); | ||
1005 | return ret; | 1136 | return ret; |
1006 | } | 1137 | } |
1007 | 1138 | ||
@@ -1009,13 +1140,22 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, | |||
1009 | struct btrfs_fs_info *fs_info, u64 qgroupid, | 1140 | struct btrfs_fs_info *fs_info, u64 qgroupid, |
1010 | struct btrfs_qgroup_limit *limit) | 1141 | struct btrfs_qgroup_limit *limit) |
1011 | { | 1142 | { |
1012 | struct btrfs_root *quota_root = fs_info->quota_root; | 1143 | struct btrfs_root *quota_root; |
1013 | struct btrfs_qgroup *qgroup; | 1144 | struct btrfs_qgroup *qgroup; |
1014 | int ret = 0; | 1145 | int ret = 0; |
1015 | 1146 | ||
1016 | if (!quota_root) | 1147 | mutex_lock(&fs_info->qgroup_ioctl_lock); |
1017 | return -EINVAL; | 1148 | quota_root = fs_info->quota_root; |
1149 | if (!quota_root) { | ||
1150 | ret = -EINVAL; | ||
1151 | goto out; | ||
1152 | } | ||
1018 | 1153 | ||
1154 | qgroup = find_qgroup_rb(fs_info, qgroupid); | ||
1155 | if (!qgroup) { | ||
1156 | ret = -ENOENT; | ||
1157 | goto out; | ||
1158 | } | ||
1019 | ret = update_qgroup_limit_item(trans, quota_root, qgroupid, | 1159 | ret = update_qgroup_limit_item(trans, quota_root, qgroupid, |
1020 | limit->flags, limit->max_rfer, | 1160 | limit->flags, limit->max_rfer, |
1021 | limit->max_excl, limit->rsv_rfer, | 1161 | limit->max_excl, limit->rsv_rfer, |
@@ -1027,31 +1167,17 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, | |||
1027 | } | 1167 | } |
1028 | 1168 | ||
1029 | spin_lock(&fs_info->qgroup_lock); | 1169 | spin_lock(&fs_info->qgroup_lock); |
1030 | |||
1031 | qgroup = find_qgroup_rb(fs_info, qgroupid); | ||
1032 | if (!qgroup) { | ||
1033 | ret = -ENOENT; | ||
1034 | goto unlock; | ||
1035 | } | ||
1036 | qgroup->lim_flags = limit->flags; | 1170 | qgroup->lim_flags = limit->flags; |
1037 | qgroup->max_rfer = limit->max_rfer; | 1171 | qgroup->max_rfer = limit->max_rfer; |
1038 | qgroup->max_excl = limit->max_excl; | 1172 | qgroup->max_excl = limit->max_excl; |
1039 | qgroup->rsv_rfer = limit->rsv_rfer; | 1173 | qgroup->rsv_rfer = limit->rsv_rfer; |
1040 | qgroup->rsv_excl = limit->rsv_excl; | 1174 | qgroup->rsv_excl = limit->rsv_excl; |
1041 | |||
1042 | unlock: | ||
1043 | spin_unlock(&fs_info->qgroup_lock); | 1175 | spin_unlock(&fs_info->qgroup_lock); |
1044 | 1176 | out: | |
1177 | mutex_unlock(&fs_info->qgroup_ioctl_lock); | ||
1045 | return ret; | 1178 | return ret; |
1046 | } | 1179 | } |
1047 | 1180 | ||
1048 | static void qgroup_dirty(struct btrfs_fs_info *fs_info, | ||
1049 | struct btrfs_qgroup *qgroup) | ||
1050 | { | ||
1051 | if (list_empty(&qgroup->dirty)) | ||
1052 | list_add(&qgroup->dirty, &fs_info->dirty_qgroups); | ||
1053 | } | ||
1054 | |||
1055 | /* | 1181 | /* |
1056 | * btrfs_qgroup_record_ref is called when the ref is added or deleted. it puts | 1182 | * btrfs_qgroup_record_ref is called when the ref is added or deleted. it puts |
1057 | * the modification into a list that's later used by btrfs_end_transaction to | 1183 | * the modification into a list that's later used by btrfs_end_transaction to |
@@ -1075,6 +1201,144 @@ int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans, | |||
1075 | return 0; | 1201 | return 0; |
1076 | } | 1202 | } |
1077 | 1203 | ||
1204 | static int qgroup_account_ref_step1(struct btrfs_fs_info *fs_info, | ||
1205 | struct ulist *roots, struct ulist *tmp, | ||
1206 | u64 seq) | ||
1207 | { | ||
1208 | struct ulist_node *unode; | ||
1209 | struct ulist_iterator uiter; | ||
1210 | struct ulist_node *tmp_unode; | ||
1211 | struct ulist_iterator tmp_uiter; | ||
1212 | struct btrfs_qgroup *qg; | ||
1213 | int ret; | ||
1214 | |||
1215 | ULIST_ITER_INIT(&uiter); | ||
1216 | while ((unode = ulist_next(roots, &uiter))) { | ||
1217 | qg = find_qgroup_rb(fs_info, unode->val); | ||
1218 | if (!qg) | ||
1219 | continue; | ||
1220 | |||
1221 | ulist_reinit(tmp); | ||
1222 | /* XXX id not needed */ | ||
1223 | ret = ulist_add(tmp, qg->qgroupid, | ||
1224 | (u64)(uintptr_t)qg, GFP_ATOMIC); | ||
1225 | if (ret < 0) | ||
1226 | return ret; | ||
1227 | ULIST_ITER_INIT(&tmp_uiter); | ||
1228 | while ((tmp_unode = ulist_next(tmp, &tmp_uiter))) { | ||
1229 | struct btrfs_qgroup_list *glist; | ||
1230 | |||
1231 | qg = (struct btrfs_qgroup *)(uintptr_t)tmp_unode->aux; | ||
1232 | if (qg->refcnt < seq) | ||
1233 | qg->refcnt = seq + 1; | ||
1234 | else | ||
1235 | ++qg->refcnt; | ||
1236 | |||
1237 | list_for_each_entry(glist, &qg->groups, next_group) { | ||
1238 | ret = ulist_add(tmp, glist->group->qgroupid, | ||
1239 | (u64)(uintptr_t)glist->group, | ||
1240 | GFP_ATOMIC); | ||
1241 | if (ret < 0) | ||
1242 | return ret; | ||
1243 | } | ||
1244 | } | ||
1245 | } | ||
1246 | |||
1247 | return 0; | ||
1248 | } | ||
1249 | |||
1250 | static int qgroup_account_ref_step2(struct btrfs_fs_info *fs_info, | ||
1251 | struct ulist *roots, struct ulist *tmp, | ||
1252 | u64 seq, int sgn, u64 num_bytes, | ||
1253 | struct btrfs_qgroup *qgroup) | ||
1254 | { | ||
1255 | struct ulist_node *unode; | ||
1256 | struct ulist_iterator uiter; | ||
1257 | struct btrfs_qgroup *qg; | ||
1258 | struct btrfs_qgroup_list *glist; | ||
1259 | int ret; | ||
1260 | |||
1261 | ulist_reinit(tmp); | ||
1262 | ret = ulist_add(tmp, qgroup->qgroupid, (uintptr_t)qgroup, GFP_ATOMIC); | ||
1263 | if (ret < 0) | ||
1264 | return ret; | ||
1265 | |||
1266 | ULIST_ITER_INIT(&uiter); | ||
1267 | while ((unode = ulist_next(tmp, &uiter))) { | ||
1268 | qg = (struct btrfs_qgroup *)(uintptr_t)unode->aux; | ||
1269 | if (qg->refcnt < seq) { | ||
1270 | /* not visited by step 1 */ | ||
1271 | qg->rfer += sgn * num_bytes; | ||
1272 | qg->rfer_cmpr += sgn * num_bytes; | ||
1273 | if (roots->nnodes == 0) { | ||
1274 | qg->excl += sgn * num_bytes; | ||
1275 | qg->excl_cmpr += sgn * num_bytes; | ||
1276 | } | ||
1277 | qgroup_dirty(fs_info, qg); | ||
1278 | } | ||
1279 | WARN_ON(qg->tag >= seq); | ||
1280 | qg->tag = seq; | ||
1281 | |||
1282 | list_for_each_entry(glist, &qg->groups, next_group) { | ||
1283 | ret = ulist_add(tmp, glist->group->qgroupid, | ||
1284 | (uintptr_t)glist->group, GFP_ATOMIC); | ||
1285 | if (ret < 0) | ||
1286 | return ret; | ||
1287 | } | ||
1288 | } | ||
1289 | |||
1290 | return 0; | ||
1291 | } | ||
1292 | |||
1293 | static int qgroup_account_ref_step3(struct btrfs_fs_info *fs_info, | ||
1294 | struct ulist *roots, struct ulist *tmp, | ||
1295 | u64 seq, int sgn, u64 num_bytes) | ||
1296 | { | ||
1297 | struct ulist_node *unode; | ||
1298 | struct ulist_iterator uiter; | ||
1299 | struct btrfs_qgroup *qg; | ||
1300 | struct ulist_node *tmp_unode; | ||
1301 | struct ulist_iterator tmp_uiter; | ||
1302 | int ret; | ||
1303 | |||
1304 | ULIST_ITER_INIT(&uiter); | ||
1305 | while ((unode = ulist_next(roots, &uiter))) { | ||
1306 | qg = find_qgroup_rb(fs_info, unode->val); | ||
1307 | if (!qg) | ||
1308 | continue; | ||
1309 | |||
1310 | ulist_reinit(tmp); | ||
1311 | ret = ulist_add(tmp, qg->qgroupid, (uintptr_t)qg, GFP_ATOMIC); | ||
1312 | if (ret < 0) | ||
1313 | return ret; | ||
1314 | |||
1315 | ULIST_ITER_INIT(&tmp_uiter); | ||
1316 | while ((tmp_unode = ulist_next(tmp, &tmp_uiter))) { | ||
1317 | struct btrfs_qgroup_list *glist; | ||
1318 | |||
1319 | qg = (struct btrfs_qgroup *)(uintptr_t)tmp_unode->aux; | ||
1320 | if (qg->tag == seq) | ||
1321 | continue; | ||
1322 | |||
1323 | if (qg->refcnt - seq == roots->nnodes) { | ||
1324 | qg->excl -= sgn * num_bytes; | ||
1325 | qg->excl_cmpr -= sgn * num_bytes; | ||
1326 | qgroup_dirty(fs_info, qg); | ||
1327 | } | ||
1328 | |||
1329 | list_for_each_entry(glist, &qg->groups, next_group) { | ||
1330 | ret = ulist_add(tmp, glist->group->qgroupid, | ||
1331 | (uintptr_t)glist->group, | ||
1332 | GFP_ATOMIC); | ||
1333 | if (ret < 0) | ||
1334 | return ret; | ||
1335 | } | ||
1336 | } | ||
1337 | } | ||
1338 | |||
1339 | return 0; | ||
1340 | } | ||
1341 | |||
1078 | /* | 1342 | /* |
1079 | * btrfs_qgroup_account_ref is called for every ref that is added to or deleted | 1343 | * btrfs_qgroup_account_ref is called for every ref that is added to or deleted |
1080 | * from the fs. First, all roots referencing the extent are searched, and | 1344 | * from the fs. First, all roots referencing the extent are searched, and |
@@ -1090,10 +1354,8 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans, | |||
1090 | struct btrfs_root *quota_root; | 1354 | struct btrfs_root *quota_root; |
1091 | u64 ref_root; | 1355 | u64 ref_root; |
1092 | struct btrfs_qgroup *qgroup; | 1356 | struct btrfs_qgroup *qgroup; |
1093 | struct ulist_node *unode; | ||
1094 | struct ulist *roots = NULL; | 1357 | struct ulist *roots = NULL; |
1095 | struct ulist *tmp = NULL; | 1358 | struct ulist *tmp = NULL; |
1096 | struct ulist_iterator uiter; | ||
1097 | u64 seq; | 1359 | u64 seq; |
1098 | int ret = 0; | 1360 | int ret = 0; |
1099 | int sgn; | 1361 | int sgn; |
@@ -1132,9 +1394,11 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans, | |||
1132 | case BTRFS_ADD_DELAYED_REF: | 1394 | case BTRFS_ADD_DELAYED_REF: |
1133 | case BTRFS_ADD_DELAYED_EXTENT: | 1395 | case BTRFS_ADD_DELAYED_EXTENT: |
1134 | sgn = 1; | 1396 | sgn = 1; |
1397 | seq = btrfs_tree_mod_seq_prev(node->seq); | ||
1135 | break; | 1398 | break; |
1136 | case BTRFS_DROP_DELAYED_REF: | 1399 | case BTRFS_DROP_DELAYED_REF: |
1137 | sgn = -1; | 1400 | sgn = -1; |
1401 | seq = node->seq; | ||
1138 | break; | 1402 | break; |
1139 | case BTRFS_UPDATE_DELAYED_HEAD: | 1403 | case BTRFS_UPDATE_DELAYED_HEAD: |
1140 | return 0; | 1404 | return 0; |
@@ -1142,20 +1406,37 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans, | |||
1142 | BUG(); | 1406 | BUG(); |
1143 | } | 1407 | } |
1144 | 1408 | ||
1409 | mutex_lock(&fs_info->qgroup_rescan_lock); | ||
1410 | if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { | ||
1411 | if (fs_info->qgroup_rescan_progress.objectid <= node->bytenr) { | ||
1412 | mutex_unlock(&fs_info->qgroup_rescan_lock); | ||
1413 | return 0; | ||
1414 | } | ||
1415 | } | ||
1416 | mutex_unlock(&fs_info->qgroup_rescan_lock); | ||
1417 | |||
1145 | /* | 1418 | /* |
1146 | * the delayed ref sequence number we pass depends on the direction of | 1419 | * the delayed ref sequence number we pass depends on the direction of |
1147 | * the operation. for add operations, we pass (node->seq - 1) to skip | 1420 | * the operation. for add operations, we pass |
1421 | * tree_mod_log_prev_seq(node->seq) to skip | ||
1148 | * the delayed ref's current sequence number, because we need the state | 1422 | * the delayed ref's current sequence number, because we need the state |
1149 | * of the tree before the add operation. for delete operations, we pass | 1423 | * of the tree before the add operation. for delete operations, we pass |
1150 | * (node->seq) to include the delayed ref's current sequence number, | 1424 | * (node->seq) to include the delayed ref's current sequence number, |
1151 | * because we need the state of the tree after the delete operation. | 1425 | * because we need the state of the tree after the delete operation. |
1152 | */ | 1426 | */ |
1153 | ret = btrfs_find_all_roots(trans, fs_info, node->bytenr, | 1427 | ret = btrfs_find_all_roots(trans, fs_info, node->bytenr, seq, &roots); |
1154 | sgn > 0 ? node->seq - 1 : node->seq, &roots); | ||
1155 | if (ret < 0) | 1428 | if (ret < 0) |
1156 | return ret; | 1429 | return ret; |
1157 | 1430 | ||
1431 | mutex_lock(&fs_info->qgroup_rescan_lock); | ||
1158 | spin_lock(&fs_info->qgroup_lock); | 1432 | spin_lock(&fs_info->qgroup_lock); |
1433 | if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { | ||
1434 | if (fs_info->qgroup_rescan_progress.objectid <= node->bytenr) { | ||
1435 | ret = 0; | ||
1436 | goto unlock; | ||
1437 | } | ||
1438 | } | ||
1439 | |||
1159 | quota_root = fs_info->quota_root; | 1440 | quota_root = fs_info->quota_root; |
1160 | if (!quota_root) | 1441 | if (!quota_root) |
1161 | goto unlock; | 1442 | goto unlock; |
@@ -1175,106 +1456,29 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans, | |||
1175 | seq = fs_info->qgroup_seq; | 1456 | seq = fs_info->qgroup_seq; |
1176 | fs_info->qgroup_seq += roots->nnodes + 1; /* max refcnt */ | 1457 | fs_info->qgroup_seq += roots->nnodes + 1; /* max refcnt */ |
1177 | 1458 | ||
1178 | ULIST_ITER_INIT(&uiter); | 1459 | ret = qgroup_account_ref_step1(fs_info, roots, tmp, seq); |
1179 | while ((unode = ulist_next(roots, &uiter))) { | 1460 | if (ret) |
1180 | struct ulist_node *tmp_unode; | 1461 | goto unlock; |
1181 | struct ulist_iterator tmp_uiter; | ||
1182 | struct btrfs_qgroup *qg; | ||
1183 | |||
1184 | qg = find_qgroup_rb(fs_info, unode->val); | ||
1185 | if (!qg) | ||
1186 | continue; | ||
1187 | |||
1188 | ulist_reinit(tmp); | ||
1189 | /* XXX id not needed */ | ||
1190 | ulist_add(tmp, qg->qgroupid, (u64)(uintptr_t)qg, GFP_ATOMIC); | ||
1191 | ULIST_ITER_INIT(&tmp_uiter); | ||
1192 | while ((tmp_unode = ulist_next(tmp, &tmp_uiter))) { | ||
1193 | struct btrfs_qgroup_list *glist; | ||
1194 | |||
1195 | qg = (struct btrfs_qgroup *)(uintptr_t)tmp_unode->aux; | ||
1196 | if (qg->refcnt < seq) | ||
1197 | qg->refcnt = seq + 1; | ||
1198 | else | ||
1199 | ++qg->refcnt; | ||
1200 | |||
1201 | list_for_each_entry(glist, &qg->groups, next_group) { | ||
1202 | ulist_add(tmp, glist->group->qgroupid, | ||
1203 | (u64)(uintptr_t)glist->group, | ||
1204 | GFP_ATOMIC); | ||
1205 | } | ||
1206 | } | ||
1207 | } | ||
1208 | 1462 | ||
1209 | /* | 1463 | /* |
1210 | * step 2: walk from the new root | 1464 | * step 2: walk from the new root |
1211 | */ | 1465 | */ |
1212 | ulist_reinit(tmp); | 1466 | ret = qgroup_account_ref_step2(fs_info, roots, tmp, seq, sgn, |
1213 | ulist_add(tmp, qgroup->qgroupid, (uintptr_t)qgroup, GFP_ATOMIC); | 1467 | node->num_bytes, qgroup); |
1214 | ULIST_ITER_INIT(&uiter); | 1468 | if (ret) |
1215 | while ((unode = ulist_next(tmp, &uiter))) { | 1469 | goto unlock; |
1216 | struct btrfs_qgroup *qg; | ||
1217 | struct btrfs_qgroup_list *glist; | ||
1218 | |||
1219 | qg = (struct btrfs_qgroup *)(uintptr_t)unode->aux; | ||
1220 | if (qg->refcnt < seq) { | ||
1221 | /* not visited by step 1 */ | ||
1222 | qg->rfer += sgn * node->num_bytes; | ||
1223 | qg->rfer_cmpr += sgn * node->num_bytes; | ||
1224 | if (roots->nnodes == 0) { | ||
1225 | qg->excl += sgn * node->num_bytes; | ||
1226 | qg->excl_cmpr += sgn * node->num_bytes; | ||
1227 | } | ||
1228 | qgroup_dirty(fs_info, qg); | ||
1229 | } | ||
1230 | WARN_ON(qg->tag >= seq); | ||
1231 | qg->tag = seq; | ||
1232 | |||
1233 | list_for_each_entry(glist, &qg->groups, next_group) { | ||
1234 | ulist_add(tmp, glist->group->qgroupid, | ||
1235 | (uintptr_t)glist->group, GFP_ATOMIC); | ||
1236 | } | ||
1237 | } | ||
1238 | 1470 | ||
1239 | /* | 1471 | /* |
1240 | * step 3: walk again from old refs | 1472 | * step 3: walk again from old refs |
1241 | */ | 1473 | */ |
1242 | ULIST_ITER_INIT(&uiter); | 1474 | ret = qgroup_account_ref_step3(fs_info, roots, tmp, seq, sgn, |
1243 | while ((unode = ulist_next(roots, &uiter))) { | 1475 | node->num_bytes); |
1244 | struct btrfs_qgroup *qg; | 1476 | if (ret) |
1245 | struct ulist_node *tmp_unode; | 1477 | goto unlock; |
1246 | struct ulist_iterator tmp_uiter; | ||
1247 | |||
1248 | qg = find_qgroup_rb(fs_info, unode->val); | ||
1249 | if (!qg) | ||
1250 | continue; | ||
1251 | |||
1252 | ulist_reinit(tmp); | ||
1253 | ulist_add(tmp, qg->qgroupid, (uintptr_t)qg, GFP_ATOMIC); | ||
1254 | ULIST_ITER_INIT(&tmp_uiter); | ||
1255 | while ((tmp_unode = ulist_next(tmp, &tmp_uiter))) { | ||
1256 | struct btrfs_qgroup_list *glist; | ||
1257 | |||
1258 | qg = (struct btrfs_qgroup *)(uintptr_t)tmp_unode->aux; | ||
1259 | if (qg->tag == seq) | ||
1260 | continue; | ||
1261 | |||
1262 | if (qg->refcnt - seq == roots->nnodes) { | ||
1263 | qg->excl -= sgn * node->num_bytes; | ||
1264 | qg->excl_cmpr -= sgn * node->num_bytes; | ||
1265 | qgroup_dirty(fs_info, qg); | ||
1266 | } | ||
1267 | 1478 | ||
1268 | list_for_each_entry(glist, &qg->groups, next_group) { | ||
1269 | ulist_add(tmp, glist->group->qgroupid, | ||
1270 | (uintptr_t)glist->group, | ||
1271 | GFP_ATOMIC); | ||
1272 | } | ||
1273 | } | ||
1274 | } | ||
1275 | ret = 0; | ||
1276 | unlock: | 1479 | unlock: |
1277 | spin_unlock(&fs_info->qgroup_lock); | 1480 | spin_unlock(&fs_info->qgroup_lock); |
1481 | mutex_unlock(&fs_info->qgroup_rescan_lock); | ||
1278 | ulist_free(roots); | 1482 | ulist_free(roots); |
1279 | ulist_free(tmp); | 1483 | ulist_free(tmp); |
1280 | 1484 | ||
@@ -1289,10 +1493,14 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans, | |||
1289 | { | 1493 | { |
1290 | struct btrfs_root *quota_root = fs_info->quota_root; | 1494 | struct btrfs_root *quota_root = fs_info->quota_root; |
1291 | int ret = 0; | 1495 | int ret = 0; |
1496 | int start_rescan_worker = 0; | ||
1292 | 1497 | ||
1293 | if (!quota_root) | 1498 | if (!quota_root) |
1294 | goto out; | 1499 | goto out; |
1295 | 1500 | ||
1501 | if (!fs_info->quota_enabled && fs_info->pending_quota_state) | ||
1502 | start_rescan_worker = 1; | ||
1503 | |||
1296 | fs_info->quota_enabled = fs_info->pending_quota_state; | 1504 | fs_info->quota_enabled = fs_info->pending_quota_state; |
1297 | 1505 | ||
1298 | spin_lock(&fs_info->qgroup_lock); | 1506 | spin_lock(&fs_info->qgroup_lock); |
@@ -1318,6 +1526,13 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans, | |||
1318 | if (ret) | 1526 | if (ret) |
1319 | fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; | 1527 | fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; |
1320 | 1528 | ||
1529 | if (!ret && start_rescan_worker) { | ||
1530 | ret = btrfs_qgroup_rescan(fs_info); | ||
1531 | if (ret) | ||
1532 | pr_err("btrfs: start rescan quota failed: %d\n", ret); | ||
1533 | ret = 0; | ||
1534 | } | ||
1535 | |||
1321 | out: | 1536 | out: |
1322 | 1537 | ||
1323 | return ret; | 1538 | return ret; |
@@ -1338,12 +1553,30 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, | |||
1338 | struct btrfs_qgroup *srcgroup; | 1553 | struct btrfs_qgroup *srcgroup; |
1339 | struct btrfs_qgroup *dstgroup; | 1554 | struct btrfs_qgroup *dstgroup; |
1340 | u32 level_size = 0; | 1555 | u32 level_size = 0; |
1556 | u64 nums; | ||
1341 | 1557 | ||
1558 | mutex_lock(&fs_info->qgroup_ioctl_lock); | ||
1342 | if (!fs_info->quota_enabled) | 1559 | if (!fs_info->quota_enabled) |
1343 | return 0; | 1560 | goto out; |
1344 | 1561 | ||
1345 | if (!quota_root) | 1562 | if (!quota_root) { |
1346 | return -EINVAL; | 1563 | ret = -EINVAL; |
1564 | goto out; | ||
1565 | } | ||
1566 | |||
1567 | if (inherit) { | ||
1568 | i_qgroups = (u64 *)(inherit + 1); | ||
1569 | nums = inherit->num_qgroups + 2 * inherit->num_ref_copies + | ||
1570 | 2 * inherit->num_excl_copies; | ||
1571 | for (i = 0; i < nums; ++i) { | ||
1572 | srcgroup = find_qgroup_rb(fs_info, *i_qgroups); | ||
1573 | if (!srcgroup) { | ||
1574 | ret = -EINVAL; | ||
1575 | goto out; | ||
1576 | } | ||
1577 | ++i_qgroups; | ||
1578 | } | ||
1579 | } | ||
1347 | 1580 | ||
1348 | /* | 1581 | /* |
1349 | * create a tracking group for the subvol itself | 1582 | * create a tracking group for the subvol itself |
@@ -1470,6 +1703,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, | |||
1470 | unlock: | 1703 | unlock: |
1471 | spin_unlock(&fs_info->qgroup_lock); | 1704 | spin_unlock(&fs_info->qgroup_lock); |
1472 | out: | 1705 | out: |
1706 | mutex_unlock(&fs_info->qgroup_ioctl_lock); | ||
1473 | return ret; | 1707 | return ret; |
1474 | } | 1708 | } |
1475 | 1709 | ||
@@ -1514,7 +1748,10 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes) | |||
1514 | ret = -ENOMEM; | 1748 | ret = -ENOMEM; |
1515 | goto out; | 1749 | goto out; |
1516 | } | 1750 | } |
1517 | ulist_add(ulist, qgroup->qgroupid, (uintptr_t)qgroup, GFP_ATOMIC); | 1751 | ret = ulist_add(ulist, qgroup->qgroupid, |
1752 | (uintptr_t)qgroup, GFP_ATOMIC); | ||
1753 | if (ret < 0) | ||
1754 | goto out; | ||
1518 | ULIST_ITER_INIT(&uiter); | 1755 | ULIST_ITER_INIT(&uiter); |
1519 | while ((unode = ulist_next(ulist, &uiter))) { | 1756 | while ((unode = ulist_next(ulist, &uiter))) { |
1520 | struct btrfs_qgroup *qg; | 1757 | struct btrfs_qgroup *qg; |
@@ -1523,25 +1760,27 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes) | |||
1523 | qg = (struct btrfs_qgroup *)(uintptr_t)unode->aux; | 1760 | qg = (struct btrfs_qgroup *)(uintptr_t)unode->aux; |
1524 | 1761 | ||
1525 | if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) && | 1762 | if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) && |
1526 | qg->reserved + qg->rfer + num_bytes > | 1763 | qg->reserved + (s64)qg->rfer + num_bytes > |
1527 | qg->max_rfer) { | 1764 | qg->max_rfer) { |
1528 | ret = -EDQUOT; | 1765 | ret = -EDQUOT; |
1529 | goto out; | 1766 | goto out; |
1530 | } | 1767 | } |
1531 | 1768 | ||
1532 | if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) && | 1769 | if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) && |
1533 | qg->reserved + qg->excl + num_bytes > | 1770 | qg->reserved + (s64)qg->excl + num_bytes > |
1534 | qg->max_excl) { | 1771 | qg->max_excl) { |
1535 | ret = -EDQUOT; | 1772 | ret = -EDQUOT; |
1536 | goto out; | 1773 | goto out; |
1537 | } | 1774 | } |
1538 | 1775 | ||
1539 | list_for_each_entry(glist, &qg->groups, next_group) { | 1776 | list_for_each_entry(glist, &qg->groups, next_group) { |
1540 | ulist_add(ulist, glist->group->qgroupid, | 1777 | ret = ulist_add(ulist, glist->group->qgroupid, |
1541 | (uintptr_t)glist->group, GFP_ATOMIC); | 1778 | (uintptr_t)glist->group, GFP_ATOMIC); |
1779 | if (ret < 0) | ||
1780 | goto out; | ||
1542 | } | 1781 | } |
1543 | } | 1782 | } |
1544 | 1783 | ret = 0; | |
1545 | /* | 1784 | /* |
1546 | * no limits exceeded, now record the reservation into all qgroups | 1785 | * no limits exceeded, now record the reservation into all qgroups |
1547 | */ | 1786 | */ |
@@ -1570,6 +1809,7 @@ void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes) | |||
1570 | struct ulist_node *unode; | 1809 | struct ulist_node *unode; |
1571 | struct ulist_iterator uiter; | 1810 | struct ulist_iterator uiter; |
1572 | u64 ref_root = root->root_key.objectid; | 1811 | u64 ref_root = root->root_key.objectid; |
1812 | int ret = 0; | ||
1573 | 1813 | ||
1574 | if (!is_fstree(ref_root)) | 1814 | if (!is_fstree(ref_root)) |
1575 | return; | 1815 | return; |
@@ -1592,7 +1832,10 @@ void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes) | |||
1592 | btrfs_std_error(fs_info, -ENOMEM); | 1832 | btrfs_std_error(fs_info, -ENOMEM); |
1593 | goto out; | 1833 | goto out; |
1594 | } | 1834 | } |
1595 | ulist_add(ulist, qgroup->qgroupid, (uintptr_t)qgroup, GFP_ATOMIC); | 1835 | ret = ulist_add(ulist, qgroup->qgroupid, |
1836 | (uintptr_t)qgroup, GFP_ATOMIC); | ||
1837 | if (ret < 0) | ||
1838 | goto out; | ||
1596 | ULIST_ITER_INIT(&uiter); | 1839 | ULIST_ITER_INIT(&uiter); |
1597 | while ((unode = ulist_next(ulist, &uiter))) { | 1840 | while ((unode = ulist_next(ulist, &uiter))) { |
1598 | struct btrfs_qgroup *qg; | 1841 | struct btrfs_qgroup *qg; |
@@ -1603,8 +1846,10 @@ void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes) | |||
1603 | qg->reserved -= num_bytes; | 1846 | qg->reserved -= num_bytes; |
1604 | 1847 | ||
1605 | list_for_each_entry(glist, &qg->groups, next_group) { | 1848 | list_for_each_entry(glist, &qg->groups, next_group) { |
1606 | ulist_add(ulist, glist->group->qgroupid, | 1849 | ret = ulist_add(ulist, glist->group->qgroupid, |
1607 | (uintptr_t)glist->group, GFP_ATOMIC); | 1850 | (uintptr_t)glist->group, GFP_ATOMIC); |
1851 | if (ret < 0) | ||
1852 | goto out; | ||
1608 | } | 1853 | } |
1609 | } | 1854 | } |
1610 | 1855 | ||
@@ -1617,8 +1862,265 @@ void assert_qgroups_uptodate(struct btrfs_trans_handle *trans) | |||
1617 | { | 1862 | { |
1618 | if (list_empty(&trans->qgroup_ref_list) && !trans->delayed_ref_elem.seq) | 1863 | if (list_empty(&trans->qgroup_ref_list) && !trans->delayed_ref_elem.seq) |
1619 | return; | 1864 | return; |
1620 | printk(KERN_ERR "btrfs: qgroups not uptodate in trans handle %p: list is%s empty, seq is %llu\n", | 1865 | pr_err("btrfs: qgroups not uptodate in trans handle %p: list is%s empty, seq is %#x.%x\n", |
1621 | trans, list_empty(&trans->qgroup_ref_list) ? "" : " not", | 1866 | trans, list_empty(&trans->qgroup_ref_list) ? "" : " not", |
1622 | trans->delayed_ref_elem.seq); | 1867 | (u32)(trans->delayed_ref_elem.seq >> 32), |
1868 | (u32)trans->delayed_ref_elem.seq); | ||
1623 | BUG(); | 1869 | BUG(); |
1624 | } | 1870 | } |
1871 | |||
1872 | /* | ||
1873 | * returns < 0 on error, 0 when more leafs are to be scanned. | ||
1874 | * returns 1 when done, 2 when done and FLAG_INCONSISTENT was cleared. | ||
1875 | */ | ||
1876 | static int | ||
1877 | qgroup_rescan_leaf(struct qgroup_rescan *qscan, struct btrfs_path *path, | ||
1878 | struct btrfs_trans_handle *trans, struct ulist *tmp, | ||
1879 | struct extent_buffer *scratch_leaf) | ||
1880 | { | ||
1881 | struct btrfs_key found; | ||
1882 | struct btrfs_fs_info *fs_info = qscan->fs_info; | ||
1883 | struct ulist *roots = NULL; | ||
1884 | struct ulist_node *unode; | ||
1885 | struct ulist_iterator uiter; | ||
1886 | struct seq_list tree_mod_seq_elem = {}; | ||
1887 | u64 seq; | ||
1888 | int slot; | ||
1889 | int ret; | ||
1890 | |||
1891 | path->leave_spinning = 1; | ||
1892 | mutex_lock(&fs_info->qgroup_rescan_lock); | ||
1893 | ret = btrfs_search_slot_for_read(fs_info->extent_root, | ||
1894 | &fs_info->qgroup_rescan_progress, | ||
1895 | path, 1, 0); | ||
1896 | |||
1897 | pr_debug("current progress key (%llu %u %llu), search_slot ret %d\n", | ||
1898 | (unsigned long long)fs_info->qgroup_rescan_progress.objectid, | ||
1899 | fs_info->qgroup_rescan_progress.type, | ||
1900 | (unsigned long long)fs_info->qgroup_rescan_progress.offset, | ||
1901 | ret); | ||
1902 | |||
1903 | if (ret) { | ||
1904 | /* | ||
1905 | * The rescan is about to end, we will not be scanning any | ||
1906 | * further blocks. We cannot unset the RESCAN flag here, because | ||
1907 | * we want to commit the transaction if everything went well. | ||
1908 | * To make the live accounting work in this phase, we set our | ||
1909 | * scan progress pointer such that every real extent objectid | ||
1910 | * will be smaller. | ||
1911 | */ | ||
1912 | fs_info->qgroup_rescan_progress.objectid = (u64)-1; | ||
1913 | btrfs_release_path(path); | ||
1914 | mutex_unlock(&fs_info->qgroup_rescan_lock); | ||
1915 | return ret; | ||
1916 | } | ||
1917 | |||
1918 | btrfs_item_key_to_cpu(path->nodes[0], &found, | ||
1919 | btrfs_header_nritems(path->nodes[0]) - 1); | ||
1920 | fs_info->qgroup_rescan_progress.objectid = found.objectid + 1; | ||
1921 | |||
1922 | btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem); | ||
1923 | memcpy(scratch_leaf, path->nodes[0], sizeof(*scratch_leaf)); | ||
1924 | slot = path->slots[0]; | ||
1925 | btrfs_release_path(path); | ||
1926 | mutex_unlock(&fs_info->qgroup_rescan_lock); | ||
1927 | |||
1928 | for (; slot < btrfs_header_nritems(scratch_leaf); ++slot) { | ||
1929 | btrfs_item_key_to_cpu(scratch_leaf, &found, slot); | ||
1930 | if (found.type != BTRFS_EXTENT_ITEM_KEY) | ||
1931 | continue; | ||
1932 | ret = btrfs_find_all_roots(trans, fs_info, found.objectid, | ||
1933 | tree_mod_seq_elem.seq, &roots); | ||
1934 | if (ret < 0) | ||
1935 | goto out; | ||
1936 | spin_lock(&fs_info->qgroup_lock); | ||
1937 | seq = fs_info->qgroup_seq; | ||
1938 | fs_info->qgroup_seq += roots->nnodes + 1; /* max refcnt */ | ||
1939 | |||
1940 | ret = qgroup_account_ref_step1(fs_info, roots, tmp, seq); | ||
1941 | if (ret) { | ||
1942 | spin_unlock(&fs_info->qgroup_lock); | ||
1943 | ulist_free(roots); | ||
1944 | goto out; | ||
1945 | } | ||
1946 | |||
1947 | /* | ||
1948 | * step2 of btrfs_qgroup_account_ref works from a single root, | ||
1949 | * we're doing all at once here. | ||
1950 | */ | ||
1951 | ulist_reinit(tmp); | ||
1952 | ULIST_ITER_INIT(&uiter); | ||
1953 | while ((unode = ulist_next(roots, &uiter))) { | ||
1954 | struct btrfs_qgroup *qg; | ||
1955 | |||
1956 | qg = find_qgroup_rb(fs_info, unode->val); | ||
1957 | if (!qg) | ||
1958 | continue; | ||
1959 | |||
1960 | ret = ulist_add(tmp, qg->qgroupid, (uintptr_t)qg, | ||
1961 | GFP_ATOMIC); | ||
1962 | if (ret < 0) { | ||
1963 | spin_unlock(&fs_info->qgroup_lock); | ||
1964 | ulist_free(roots); | ||
1965 | goto out; | ||
1966 | } | ||
1967 | } | ||
1968 | |||
1969 | /* this loop is similar to step 2 of btrfs_qgroup_account_ref */ | ||
1970 | ULIST_ITER_INIT(&uiter); | ||
1971 | while ((unode = ulist_next(tmp, &uiter))) { | ||
1972 | struct btrfs_qgroup *qg; | ||
1973 | struct btrfs_qgroup_list *glist; | ||
1974 | |||
1975 | qg = (struct btrfs_qgroup *)(uintptr_t) unode->aux; | ||
1976 | qg->rfer += found.offset; | ||
1977 | qg->rfer_cmpr += found.offset; | ||
1978 | WARN_ON(qg->tag >= seq); | ||
1979 | if (qg->refcnt - seq == roots->nnodes) { | ||
1980 | qg->excl += found.offset; | ||
1981 | qg->excl_cmpr += found.offset; | ||
1982 | } | ||
1983 | qgroup_dirty(fs_info, qg); | ||
1984 | |||
1985 | list_for_each_entry(glist, &qg->groups, next_group) { | ||
1986 | ret = ulist_add(tmp, glist->group->qgroupid, | ||
1987 | (uintptr_t)glist->group, | ||
1988 | GFP_ATOMIC); | ||
1989 | if (ret < 0) { | ||
1990 | spin_unlock(&fs_info->qgroup_lock); | ||
1991 | ulist_free(roots); | ||
1992 | goto out; | ||
1993 | } | ||
1994 | } | ||
1995 | } | ||
1996 | |||
1997 | spin_unlock(&fs_info->qgroup_lock); | ||
1998 | ulist_free(roots); | ||
1999 | ret = 0; | ||
2000 | } | ||
2001 | |||
2002 | out: | ||
2003 | btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem); | ||
2004 | |||
2005 | return ret; | ||
2006 | } | ||
2007 | |||
2008 | static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) | ||
2009 | { | ||
2010 | struct qgroup_rescan *qscan = container_of(work, struct qgroup_rescan, | ||
2011 | work); | ||
2012 | struct btrfs_path *path; | ||
2013 | struct btrfs_trans_handle *trans = NULL; | ||
2014 | struct btrfs_fs_info *fs_info = qscan->fs_info; | ||
2015 | struct ulist *tmp = NULL; | ||
2016 | struct extent_buffer *scratch_leaf = NULL; | ||
2017 | int err = -ENOMEM; | ||
2018 | |||
2019 | path = btrfs_alloc_path(); | ||
2020 | if (!path) | ||
2021 | goto out; | ||
2022 | tmp = ulist_alloc(GFP_NOFS); | ||
2023 | if (!tmp) | ||
2024 | goto out; | ||
2025 | scratch_leaf = kmalloc(sizeof(*scratch_leaf), GFP_NOFS); | ||
2026 | if (!scratch_leaf) | ||
2027 | goto out; | ||
2028 | |||
2029 | err = 0; | ||
2030 | while (!err) { | ||
2031 | trans = btrfs_start_transaction(fs_info->fs_root, 0); | ||
2032 | if (IS_ERR(trans)) { | ||
2033 | err = PTR_ERR(trans); | ||
2034 | break; | ||
2035 | } | ||
2036 | if (!fs_info->quota_enabled) { | ||
2037 | err = -EINTR; | ||
2038 | } else { | ||
2039 | err = qgroup_rescan_leaf(qscan, path, trans, | ||
2040 | tmp, scratch_leaf); | ||
2041 | } | ||
2042 | if (err > 0) | ||
2043 | btrfs_commit_transaction(trans, fs_info->fs_root); | ||
2044 | else | ||
2045 | btrfs_end_transaction(trans, fs_info->fs_root); | ||
2046 | } | ||
2047 | |||
2048 | out: | ||
2049 | kfree(scratch_leaf); | ||
2050 | ulist_free(tmp); | ||
2051 | btrfs_free_path(path); | ||
2052 | kfree(qscan); | ||
2053 | |||
2054 | mutex_lock(&fs_info->qgroup_rescan_lock); | ||
2055 | fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; | ||
2056 | |||
2057 | if (err == 2 && | ||
2058 | fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT) { | ||
2059 | fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; | ||
2060 | } else if (err < 0) { | ||
2061 | fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; | ||
2062 | } | ||
2063 | mutex_unlock(&fs_info->qgroup_rescan_lock); | ||
2064 | |||
2065 | if (err >= 0) { | ||
2066 | pr_info("btrfs: qgroup scan completed%s\n", | ||
2067 | err == 2 ? " (inconsistency flag cleared)" : ""); | ||
2068 | } else { | ||
2069 | pr_err("btrfs: qgroup scan failed with %d\n", err); | ||
2070 | } | ||
2071 | } | ||
2072 | |||
2073 | static void | ||
2074 | qgroup_rescan_start(struct btrfs_fs_info *fs_info, struct qgroup_rescan *qscan) | ||
2075 | { | ||
2076 | memset(&qscan->work, 0, sizeof(qscan->work)); | ||
2077 | qscan->work.func = btrfs_qgroup_rescan_worker; | ||
2078 | qscan->fs_info = fs_info; | ||
2079 | |||
2080 | pr_info("btrfs: qgroup scan started\n"); | ||
2081 | btrfs_queue_worker(&fs_info->qgroup_rescan_workers, &qscan->work); | ||
2082 | } | ||
2083 | |||
2084 | int | ||
2085 | btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info) | ||
2086 | { | ||
2087 | int ret = 0; | ||
2088 | struct rb_node *n; | ||
2089 | struct btrfs_qgroup *qgroup; | ||
2090 | struct qgroup_rescan *qscan = kmalloc(sizeof(*qscan), GFP_NOFS); | ||
2091 | |||
2092 | if (!qscan) | ||
2093 | return -ENOMEM; | ||
2094 | |||
2095 | mutex_lock(&fs_info->qgroup_rescan_lock); | ||
2096 | spin_lock(&fs_info->qgroup_lock); | ||
2097 | if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) | ||
2098 | ret = -EINPROGRESS; | ||
2099 | else if (!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_ON)) | ||
2100 | ret = -EINVAL; | ||
2101 | if (ret) { | ||
2102 | spin_unlock(&fs_info->qgroup_lock); | ||
2103 | mutex_unlock(&fs_info->qgroup_rescan_lock); | ||
2104 | kfree(qscan); | ||
2105 | return ret; | ||
2106 | } | ||
2107 | |||
2108 | fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_RESCAN; | ||
2109 | memset(&fs_info->qgroup_rescan_progress, 0, | ||
2110 | sizeof(fs_info->qgroup_rescan_progress)); | ||
2111 | |||
2112 | /* clear all current qgroup tracking information */ | ||
2113 | for (n = rb_first(&fs_info->qgroup_tree); n; n = rb_next(n)) { | ||
2114 | qgroup = rb_entry(n, struct btrfs_qgroup, node); | ||
2115 | qgroup->rfer = 0; | ||
2116 | qgroup->rfer_cmpr = 0; | ||
2117 | qgroup->excl = 0; | ||
2118 | qgroup->excl_cmpr = 0; | ||
2119 | } | ||
2120 | spin_unlock(&fs_info->qgroup_lock); | ||
2121 | mutex_unlock(&fs_info->qgroup_rescan_lock); | ||
2122 | |||
2123 | qgroup_rescan_start(fs_info, qscan); | ||
2124 | |||
2125 | return 0; | ||
2126 | } | ||