diff options
-rw-r--r-- | fs/btrfs/qgroup.c | 54 |
1 files changed, 32 insertions, 22 deletions
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 5279fdae7142..7173360eea7a 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c | |||
@@ -1842,8 +1842,10 @@ out: | |||
1842 | } | 1842 | } |
1843 | 1843 | ||
1844 | /* | 1844 | /* |
1845 | * copy the acounting information between qgroups. This is necessary when a | 1845 | * Copy the acounting information between qgroups. This is necessary |
1846 | * snapshot or a subvolume is created | 1846 | * when a snapshot or a subvolume is created. Throwing an error will |
1847 | * cause a transaction abort so we take extra care here to only error | ||
1848 | * when a readonly fs is a reasonable outcome. | ||
1847 | */ | 1849 | */ |
1848 | int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, | 1850 | int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, |
1849 | struct btrfs_fs_info *fs_info, u64 srcid, u64 objectid, | 1851 | struct btrfs_fs_info *fs_info, u64 srcid, u64 objectid, |
@@ -1873,15 +1875,15 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, | |||
1873 | 2 * inherit->num_excl_copies; | 1875 | 2 * inherit->num_excl_copies; |
1874 | for (i = 0; i < nums; ++i) { | 1876 | for (i = 0; i < nums; ++i) { |
1875 | srcgroup = find_qgroup_rb(fs_info, *i_qgroups); | 1877 | srcgroup = find_qgroup_rb(fs_info, *i_qgroups); |
1876 | if (!srcgroup) { | ||
1877 | ret = -EINVAL; | ||
1878 | goto out; | ||
1879 | } | ||
1880 | 1878 | ||
1881 | if ((srcgroup->qgroupid >> 48) <= (objectid >> 48)) { | 1879 | /* |
1882 | ret = -EINVAL; | 1880 | * Zero out invalid groups so we can ignore |
1883 | goto out; | 1881 | * them later. |
1884 | } | 1882 | */ |
1883 | if (!srcgroup || | ||
1884 | ((srcgroup->qgroupid >> 48) <= (objectid >> 48))) | ||
1885 | *i_qgroups = 0ULL; | ||
1886 | |||
1885 | ++i_qgroups; | 1887 | ++i_qgroups; |
1886 | } | 1888 | } |
1887 | } | 1889 | } |
@@ -1916,17 +1918,19 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, | |||
1916 | */ | 1918 | */ |
1917 | if (inherit) { | 1919 | if (inherit) { |
1918 | i_qgroups = (u64 *)(inherit + 1); | 1920 | i_qgroups = (u64 *)(inherit + 1); |
1919 | for (i = 0; i < inherit->num_qgroups; ++i) { | 1921 | for (i = 0; i < inherit->num_qgroups; ++i, ++i_qgroups) { |
1922 | if (*i_qgroups == 0) | ||
1923 | continue; | ||
1920 | ret = add_qgroup_relation_item(trans, quota_root, | 1924 | ret = add_qgroup_relation_item(trans, quota_root, |
1921 | objectid, *i_qgroups); | 1925 | objectid, *i_qgroups); |
1922 | if (ret) | 1926 | if (ret && ret != -EEXIST) |
1923 | goto out; | 1927 | goto out; |
1924 | ret = add_qgroup_relation_item(trans, quota_root, | 1928 | ret = add_qgroup_relation_item(trans, quota_root, |
1925 | *i_qgroups, objectid); | 1929 | *i_qgroups, objectid); |
1926 | if (ret) | 1930 | if (ret && ret != -EEXIST) |
1927 | goto out; | 1931 | goto out; |
1928 | ++i_qgroups; | ||
1929 | } | 1932 | } |
1933 | ret = 0; | ||
1930 | } | 1934 | } |
1931 | 1935 | ||
1932 | 1936 | ||
@@ -1987,17 +1991,22 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, | |||
1987 | 1991 | ||
1988 | i_qgroups = (u64 *)(inherit + 1); | 1992 | i_qgroups = (u64 *)(inherit + 1); |
1989 | for (i = 0; i < inherit->num_qgroups; ++i) { | 1993 | for (i = 0; i < inherit->num_qgroups; ++i) { |
1990 | ret = add_relation_rb(quota_root->fs_info, objectid, | 1994 | if (*i_qgroups) { |
1991 | *i_qgroups); | 1995 | ret = add_relation_rb(quota_root->fs_info, objectid, |
1992 | if (ret) | 1996 | *i_qgroups); |
1993 | goto unlock; | 1997 | if (ret) |
1998 | goto unlock; | ||
1999 | } | ||
1994 | ++i_qgroups; | 2000 | ++i_qgroups; |
1995 | } | 2001 | } |
1996 | 2002 | ||
1997 | for (i = 0; i < inherit->num_ref_copies; ++i) { | 2003 | for (i = 0; i < inherit->num_ref_copies; ++i, i_qgroups += 2) { |
1998 | struct btrfs_qgroup *src; | 2004 | struct btrfs_qgroup *src; |
1999 | struct btrfs_qgroup *dst; | 2005 | struct btrfs_qgroup *dst; |
2000 | 2006 | ||
2007 | if (!i_qgroups[0] || !i_qgroups[1]) | ||
2008 | continue; | ||
2009 | |||
2001 | src = find_qgroup_rb(fs_info, i_qgroups[0]); | 2010 | src = find_qgroup_rb(fs_info, i_qgroups[0]); |
2002 | dst = find_qgroup_rb(fs_info, i_qgroups[1]); | 2011 | dst = find_qgroup_rb(fs_info, i_qgroups[1]); |
2003 | 2012 | ||
@@ -2008,12 +2017,14 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, | |||
2008 | 2017 | ||
2009 | dst->rfer = src->rfer - level_size; | 2018 | dst->rfer = src->rfer - level_size; |
2010 | dst->rfer_cmpr = src->rfer_cmpr - level_size; | 2019 | dst->rfer_cmpr = src->rfer_cmpr - level_size; |
2011 | i_qgroups += 2; | ||
2012 | } | 2020 | } |
2013 | for (i = 0; i < inherit->num_excl_copies; ++i) { | 2021 | for (i = 0; i < inherit->num_excl_copies; ++i, i_qgroups += 2) { |
2014 | struct btrfs_qgroup *src; | 2022 | struct btrfs_qgroup *src; |
2015 | struct btrfs_qgroup *dst; | 2023 | struct btrfs_qgroup *dst; |
2016 | 2024 | ||
2025 | if (!i_qgroups[0] || !i_qgroups[1]) | ||
2026 | continue; | ||
2027 | |||
2017 | src = find_qgroup_rb(fs_info, i_qgroups[0]); | 2028 | src = find_qgroup_rb(fs_info, i_qgroups[0]); |
2018 | dst = find_qgroup_rb(fs_info, i_qgroups[1]); | 2029 | dst = find_qgroup_rb(fs_info, i_qgroups[1]); |
2019 | 2030 | ||
@@ -2024,7 +2035,6 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, | |||
2024 | 2035 | ||
2025 | dst->excl = src->excl + level_size; | 2036 | dst->excl = src->excl + level_size; |
2026 | dst->excl_cmpr = src->excl_cmpr + level_size; | 2037 | dst->excl_cmpr = src->excl_cmpr + level_size; |
2027 | i_qgroups += 2; | ||
2028 | } | 2038 | } |
2029 | 2039 | ||
2030 | unlock: | 2040 | unlock: |