aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/qgroup.c
diff options
context:
space:
mode:
authorWang Shilong <wangsl-fnst@cn.fujitsu.com>2013-04-07 06:50:16 -0400
committerJosef Bacik <jbacik@fusionio.com>2013-05-06 15:54:38 -0400
commitf2f6ed3d54648ec19dcdeec30f66843cf7a38487 (patch)
treecc82afe22a835994252961f21e422258393a8974 /fs/btrfs/qgroup.c
parent7708f029dca5f1b9e9d6ea01ab10cd83e4c74ff2 (diff)
Btrfs: introduce a mutex lock for btrfs quota operations
The original code has one spin_lock 'qgroup_lock' to protect quota configurations in memory. If we want to add a BTRFS_QGROUP_INFO_KEY, it will be added to Btree firstly, and then update configurations in memory,however, a race condition may happen between these operations. For example: ->add_qgroup_info_item() ->add_qgroup_rb() For the above case, del_qgroup_info_item() may happen just before add_qgroup_rb(). What's worse, when we want to add a qgroup relation: ->add_qgroup_relation_item() ->add_qgroup_relations() We don't have any checks whether 'src' and 'dst' exist before add_qgroup_relation_item(), a race condition can also happen for the above case. To avoid race condition and have all the necessary checks, we introduce a mutex lock 'qgroup_ioctl_lock', and we make all the user change operations protected by the mutex lock. Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com> Reviewed-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs/btrfs/qgroup.c')
-rw-r--r--fs/btrfs/qgroup.c82
1 files changed, 57 insertions, 25 deletions
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 5be5a39dedc4..0a1f6861ae9a 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -791,6 +791,7 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans,
791 int ret = 0; 791 int ret = 0;
792 int slot; 792 int slot;
793 793
794 mutex_lock(&fs_info->qgroup_ioctl_lock);
794 spin_lock(&fs_info->qgroup_lock); 795 spin_lock(&fs_info->qgroup_lock);
795 if (fs_info->quota_root) { 796 if (fs_info->quota_root) {
796 fs_info->pending_quota_state = 1; 797 fs_info->pending_quota_state = 1;
@@ -900,6 +901,7 @@ out_free_root:
900 kfree(quota_root); 901 kfree(quota_root);
901 } 902 }
902out: 903out:
904 mutex_unlock(&fs_info->qgroup_ioctl_lock);
903 return ret; 905 return ret;
904} 906}
905 907
@@ -910,10 +912,11 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans,
910 struct btrfs_root *quota_root; 912 struct btrfs_root *quota_root;
911 int ret = 0; 913 int ret = 0;
912 914
915 mutex_lock(&fs_info->qgroup_ioctl_lock);
913 spin_lock(&fs_info->qgroup_lock); 916 spin_lock(&fs_info->qgroup_lock);
914 if (!fs_info->quota_root) { 917 if (!fs_info->quota_root) {
915 spin_unlock(&fs_info->qgroup_lock); 918 spin_unlock(&fs_info->qgroup_lock);
916 return 0; 919 goto out;
917 } 920 }
918 fs_info->quota_enabled = 0; 921 fs_info->quota_enabled = 0;
919 fs_info->pending_quota_state = 0; 922 fs_info->pending_quota_state = 0;
@@ -922,8 +925,10 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans,
922 btrfs_free_qgroup_config(fs_info); 925 btrfs_free_qgroup_config(fs_info);
923 spin_unlock(&fs_info->qgroup_lock); 926 spin_unlock(&fs_info->qgroup_lock);
924 927
925 if (!quota_root) 928 if (!quota_root) {
926 return -EINVAL; 929 ret = -EINVAL;
930 goto out;
931 }
927 932
928 ret = btrfs_clean_quota_tree(trans, quota_root); 933 ret = btrfs_clean_quota_tree(trans, quota_root);
929 if (ret) 934 if (ret)
@@ -944,6 +949,7 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans,
944 free_extent_buffer(quota_root->commit_root); 949 free_extent_buffer(quota_root->commit_root);
945 kfree(quota_root); 950 kfree(quota_root);
946out: 951out:
952 mutex_unlock(&fs_info->qgroup_ioctl_lock);
947 return ret; 953 return ret;
948} 954}
949 955
@@ -959,24 +965,28 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans,
959 struct btrfs_root *quota_root; 965 struct btrfs_root *quota_root;
960 int ret = 0; 966 int ret = 0;
961 967
968 mutex_lock(&fs_info->qgroup_ioctl_lock);
962 quota_root = fs_info->quota_root; 969 quota_root = fs_info->quota_root;
963 if (!quota_root) 970 if (!quota_root) {
964 return -EINVAL; 971 ret = -EINVAL;
972 goto out;
973 }
965 974
966 ret = add_qgroup_relation_item(trans, quota_root, src, dst); 975 ret = add_qgroup_relation_item(trans, quota_root, src, dst);
967 if (ret) 976 if (ret)
968 return ret; 977 goto out;
969 978
970 ret = add_qgroup_relation_item(trans, quota_root, dst, src); 979 ret = add_qgroup_relation_item(trans, quota_root, dst, src);
971 if (ret) { 980 if (ret) {
972 del_qgroup_relation_item(trans, quota_root, src, dst); 981 del_qgroup_relation_item(trans, quota_root, src, dst);
973 return ret; 982 goto out;
974 } 983 }
975 984
976 spin_lock(&fs_info->qgroup_lock); 985 spin_lock(&fs_info->qgroup_lock);
977 ret = add_relation_rb(quota_root->fs_info, src, dst); 986 ret = add_relation_rb(quota_root->fs_info, src, dst);
978 spin_unlock(&fs_info->qgroup_lock); 987 spin_unlock(&fs_info->qgroup_lock);
979 988out:
989 mutex_unlock(&fs_info->qgroup_ioctl_lock);
980 return ret; 990 return ret;
981} 991}
982 992
@@ -987,9 +997,12 @@ int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans,
987 int ret = 0; 997 int ret = 0;
988 int err; 998 int err;
989 999
1000 mutex_lock(&fs_info->qgroup_ioctl_lock);
990 quota_root = fs_info->quota_root; 1001 quota_root = fs_info->quota_root;
991 if (!quota_root) 1002 if (!quota_root) {
992 return -EINVAL; 1003 ret = -EINVAL;
1004 goto out;
1005 }
993 1006
994 ret = del_qgroup_relation_item(trans, quota_root, src, dst); 1007 ret = del_qgroup_relation_item(trans, quota_root, src, dst);
995 err = del_qgroup_relation_item(trans, quota_root, dst, src); 1008 err = del_qgroup_relation_item(trans, quota_root, dst, src);
@@ -1000,7 +1013,8 @@ int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans,
1000 del_relation_rb(fs_info, src, dst); 1013 del_relation_rb(fs_info, src, dst);
1001 1014
1002 spin_unlock(&fs_info->qgroup_lock); 1015 spin_unlock(&fs_info->qgroup_lock);
1003 1016out:
1017 mutex_unlock(&fs_info->qgroup_ioctl_lock);
1004 return ret; 1018 return ret;
1005} 1019}
1006 1020
@@ -1011,9 +1025,12 @@ int btrfs_create_qgroup(struct btrfs_trans_handle *trans,
1011 struct btrfs_qgroup *qgroup; 1025 struct btrfs_qgroup *qgroup;
1012 int ret = 0; 1026 int ret = 0;
1013 1027
1028 mutex_lock(&fs_info->qgroup_ioctl_lock);
1014 quota_root = fs_info->quota_root; 1029 quota_root = fs_info->quota_root;
1015 if (!quota_root) 1030 if (!quota_root) {
1016 return -EINVAL; 1031 ret = -EINVAL;
1032 goto out;
1033 }
1017 1034
1018 ret = add_qgroup_item(trans, quota_root, qgroupid); 1035 ret = add_qgroup_item(trans, quota_root, qgroupid);
1019 1036
@@ -1023,7 +1040,8 @@ int btrfs_create_qgroup(struct btrfs_trans_handle *trans,
1023 1040
1024 if (IS_ERR(qgroup)) 1041 if (IS_ERR(qgroup))
1025 ret = PTR_ERR(qgroup); 1042 ret = PTR_ERR(qgroup);
1026 1043out:
1044 mutex_unlock(&fs_info->qgroup_ioctl_lock);
1027 return ret; 1045 return ret;
1028} 1046}
1029 1047
@@ -1034,9 +1052,12 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans,
1034 struct btrfs_qgroup *qgroup; 1052 struct btrfs_qgroup *qgroup;
1035 int ret = 0; 1053 int ret = 0;
1036 1054
1055 mutex_lock(&fs_info->qgroup_ioctl_lock);
1037 quota_root = fs_info->quota_root; 1056 quota_root = fs_info->quota_root;
1038 if (!quota_root) 1057 if (!quota_root) {
1039 return -EINVAL; 1058 ret = -EINVAL;
1059 goto out;
1060 }
1040 1061
1041 /* check if there are no relations to this qgroup */ 1062 /* check if there are no relations to this qgroup */
1042 spin_lock(&fs_info->qgroup_lock); 1063 spin_lock(&fs_info->qgroup_lock);
@@ -1044,7 +1065,8 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans,
1044 if (qgroup) { 1065 if (qgroup) {
1045 if (!list_empty(&qgroup->groups) || !list_empty(&qgroup->members)) { 1066 if (!list_empty(&qgroup->groups) || !list_empty(&qgroup->members)) {
1046 spin_unlock(&fs_info->qgroup_lock); 1067 spin_unlock(&fs_info->qgroup_lock);
1047 return -EBUSY; 1068 ret = -EBUSY;
1069 goto out;
1048 } 1070 }
1049 } 1071 }
1050 spin_unlock(&fs_info->qgroup_lock); 1072 spin_unlock(&fs_info->qgroup_lock);
@@ -1054,7 +1076,8 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans,
1054 spin_lock(&fs_info->qgroup_lock); 1076 spin_lock(&fs_info->qgroup_lock);
1055 del_qgroup_rb(quota_root->fs_info, qgroupid); 1077 del_qgroup_rb(quota_root->fs_info, qgroupid);
1056 spin_unlock(&fs_info->qgroup_lock); 1078 spin_unlock(&fs_info->qgroup_lock);
1057 1079out:
1080 mutex_unlock(&fs_info->qgroup_ioctl_lock);
1058 return ret; 1081 return ret;
1059} 1082}
1060 1083
@@ -1062,12 +1085,16 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans,
1062 struct btrfs_fs_info *fs_info, u64 qgroupid, 1085 struct btrfs_fs_info *fs_info, u64 qgroupid,
1063 struct btrfs_qgroup_limit *limit) 1086 struct btrfs_qgroup_limit *limit)
1064{ 1087{
1065 struct btrfs_root *quota_root = fs_info->quota_root; 1088 struct btrfs_root *quota_root;
1066 struct btrfs_qgroup *qgroup; 1089 struct btrfs_qgroup *qgroup;
1067 int ret = 0; 1090 int ret = 0;
1068 1091
1069 if (!quota_root) 1092 mutex_lock(&fs_info->qgroup_ioctl_lock);
1070 return -EINVAL; 1093 quota_root = fs_info->quota_root;
1094 if (!quota_root) {
1095 ret = -EINVAL;
1096 goto out;
1097 }
1071 1098
1072 ret = update_qgroup_limit_item(trans, quota_root, qgroupid, 1099 ret = update_qgroup_limit_item(trans, quota_root, qgroupid,
1073 limit->flags, limit->max_rfer, 1100 limit->flags, limit->max_rfer,
@@ -1094,7 +1121,8 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans,
1094 1121
1095unlock: 1122unlock:
1096 spin_unlock(&fs_info->qgroup_lock); 1123 spin_unlock(&fs_info->qgroup_lock);
1097 1124out:
1125 mutex_unlock(&fs_info->qgroup_ioctl_lock);
1098 return ret; 1126 return ret;
1099} 1127}
1100 1128
@@ -1392,11 +1420,14 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
1392 struct btrfs_qgroup *dstgroup; 1420 struct btrfs_qgroup *dstgroup;
1393 u32 level_size = 0; 1421 u32 level_size = 0;
1394 1422
1423 mutex_lock(&fs_info->qgroup_ioctl_lock);
1395 if (!fs_info->quota_enabled) 1424 if (!fs_info->quota_enabled)
1396 return 0; 1425 goto out;
1397 1426
1398 if (!quota_root) 1427 if (!quota_root) {
1399 return -EINVAL; 1428 ret = -EINVAL;
1429 goto out;
1430 }
1400 1431
1401 /* 1432 /*
1402 * create a tracking group for the subvol itself 1433 * create a tracking group for the subvol itself
@@ -1523,6 +1554,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
1523unlock: 1554unlock:
1524 spin_unlock(&fs_info->qgroup_lock); 1555 spin_unlock(&fs_info->qgroup_lock);
1525out: 1556out:
1557 mutex_unlock(&fs_info->qgroup_ioctl_lock);
1526 return ret; 1558 return ret;
1527} 1559}
1528 1560