aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/qgroup.c
diff options
context:
space:
mode:
authorWang Shilong <wangsl-fnst@cn.fujitsu.com>2013-04-17 10:49:51 -0400
committerJosef Bacik <jbacik@fusionio.com>2013-05-06 15:54:59 -0400
commit534e6623b7bc03ddcf6c98b9398ff512d5135fe5 (patch)
tree1f699427735afa1fa7ceb77863697703e434459f /fs/btrfs/qgroup.c
parent3c97185c65858d23bc02492fbd27733f1f11ea83 (diff)
Btrfs: add all ioctl checks before user change for quota operations
Since all the quota configurations are loaded in memory, and we can have ioctl checks before operating in the disk. It is safe to do such things because qgroup_ioctl_lock is held outside. Without these extra checks firstly, it should be ok to do user change for quota operations. For example: if we want to add an existed qgroup, we will do: ->add_qgroup_item() ->add_qgroup_rb() add_qgroup_item() will return -EEXIST to us, however, qgroups are all in memory, why not check them in memory firstly. Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs/btrfs/qgroup.c')
-rw-r--r--fs/btrfs/qgroup.c46
1 files changed, 41 insertions, 5 deletions
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index f9fb52e52bb6..f175471da882 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -956,6 +956,7 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans,
956 struct btrfs_root *quota_root; 956 struct btrfs_root *quota_root;
957 struct btrfs_qgroup *parent; 957 struct btrfs_qgroup *parent;
958 struct btrfs_qgroup *member; 958 struct btrfs_qgroup *member;
959 struct btrfs_qgroup_list *list;
959 int ret = 0; 960 int ret = 0;
960 961
961 mutex_lock(&fs_info->qgroup_ioctl_lock); 962 mutex_lock(&fs_info->qgroup_ioctl_lock);
@@ -971,6 +972,14 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans,
971 goto out; 972 goto out;
972 } 973 }
973 974
975 /* check if such qgroup relation exist firstly */
976 list_for_each_entry(list, &member->groups, next_group) {
977 if (list->group == parent) {
978 ret = -EEXIST;
979 goto out;
980 }
981 }
982
974 ret = add_qgroup_relation_item(trans, quota_root, src, dst); 983 ret = add_qgroup_relation_item(trans, quota_root, src, dst);
975 if (ret) 984 if (ret)
976 goto out; 985 goto out;
@@ -993,6 +1002,9 @@ int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans,
993 struct btrfs_fs_info *fs_info, u64 src, u64 dst) 1002 struct btrfs_fs_info *fs_info, u64 src, u64 dst)
994{ 1003{
995 struct btrfs_root *quota_root; 1004 struct btrfs_root *quota_root;
1005 struct btrfs_qgroup *parent;
1006 struct btrfs_qgroup *member;
1007 struct btrfs_qgroup_list *list;
996 int ret = 0; 1008 int ret = 0;
997 int err; 1009 int err;
998 1010
@@ -1003,6 +1015,21 @@ int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans,
1003 goto out; 1015 goto out;
1004 } 1016 }
1005 1017
1018 member = find_qgroup_rb(fs_info, src);
1019 parent = find_qgroup_rb(fs_info, dst);
1020 if (!member || !parent) {
1021 ret = -EINVAL;
1022 goto out;
1023 }
1024
1025 /* check if such qgroup relation exist firstly */
1026 list_for_each_entry(list, &member->groups, next_group) {
1027 if (list->group == parent)
1028 goto exist;
1029 }
1030 ret = -ENOENT;
1031 goto out;
1032exist:
1006 ret = del_qgroup_relation_item(trans, quota_root, src, dst); 1033 ret = del_qgroup_relation_item(trans, quota_root, src, dst);
1007 err = del_qgroup_relation_item(trans, quota_root, dst, src); 1034 err = del_qgroup_relation_item(trans, quota_root, dst, src);
1008 if (err && !ret) 1035 if (err && !ret)
@@ -1010,7 +1037,6 @@ int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans,
1010 1037
1011 spin_lock(&fs_info->qgroup_lock); 1038 spin_lock(&fs_info->qgroup_lock);
1012 del_relation_rb(fs_info, src, dst); 1039 del_relation_rb(fs_info, src, dst);
1013
1014 spin_unlock(&fs_info->qgroup_lock); 1040 spin_unlock(&fs_info->qgroup_lock);
1015out: 1041out:
1016 mutex_unlock(&fs_info->qgroup_ioctl_lock); 1042 mutex_unlock(&fs_info->qgroup_ioctl_lock);
@@ -1030,8 +1056,15 @@ int btrfs_create_qgroup(struct btrfs_trans_handle *trans,
1030 ret = -EINVAL; 1056 ret = -EINVAL;
1031 goto out; 1057 goto out;
1032 } 1058 }
1059 qgroup = find_qgroup_rb(fs_info, qgroupid);
1060 if (qgroup) {
1061 ret = -EEXIST;
1062 goto out;
1063 }
1033 1064
1034 ret = add_qgroup_item(trans, quota_root, qgroupid); 1065 ret = add_qgroup_item(trans, quota_root, qgroupid);
1066 if (ret)
1067 goto out;
1035 1068
1036 spin_lock(&fs_info->qgroup_lock); 1069 spin_lock(&fs_info->qgroup_lock);
1037 qgroup = add_qgroup_rb(fs_info, qgroupid); 1070 qgroup = add_qgroup_rb(fs_info, qgroupid);
@@ -1058,15 +1091,18 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans,
1058 goto out; 1091 goto out;
1059 } 1092 }
1060 1093
1061 /* check if there are no relations to this qgroup */
1062 qgroup = find_qgroup_rb(fs_info, qgroupid); 1094 qgroup = find_qgroup_rb(fs_info, qgroupid);
1063 if (qgroup) { 1095 if (!qgroup) {
1064 if (!list_empty(&qgroup->groups) || !list_empty(&qgroup->members)) { 1096 ret = -ENOENT;
1097 goto out;
1098 } else {
1099 /* check if there are no relations to this qgroup */
1100 if (!list_empty(&qgroup->groups) ||
1101 !list_empty(&qgroup->members)) {
1065 ret = -EBUSY; 1102 ret = -EBUSY;
1066 goto out; 1103 goto out;
1067 } 1104 }
1068 } 1105 }
1069
1070 ret = del_qgroup_item(trans, quota_root, qgroupid); 1106 ret = del_qgroup_item(trans, quota_root, qgroupid);
1071 1107
1072 spin_lock(&fs_info->qgroup_lock); 1108 spin_lock(&fs_info->qgroup_lock);