aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Fasheh <mfasheh@suse.de>2016-03-30 20:57:48 -0400
committerDavid Sterba <dsterba@suse.com>2016-04-04 10:29:22 -0400
commit918c2ee103cf9956f1c61d3f848dbb49fd2d104a (patch)
treebe9e58da9801a1210acc6f4fec901eb1797acc17
parent0305bc279317a6ba261a663cc32721d78e6544cf (diff)
btrfs: handle non-fatal errors in btrfs_qgroup_inherit()
create_pending_snapshot() will go readonly on _any_ error return from btrfs_qgroup_inherit(). If qgroups are enabled, a user can crash their fs by just making a snapshot and asking it to inherit from an invalid qgroup. For example: $ btrfs sub snap -i 1/10 /btrfs/ /btrfs/foo Will cause a transaction abort. Fix this by only throwing errors in btrfs_qgroup_inherit() when we know going readonly is acceptable. The following xfstests test case reproduces this bug: seq=`basename $0` seqres=$RESULT_DIR/$seq echo "QA output created by $seq" here=`pwd` tmp=/tmp/$$ status=1 # failure is the default! trap "_cleanup; exit \$status" 0 1 2 3 15 _cleanup() { cd / rm -f $tmp.* } # get standard environment, filters and checks . ./common/rc . ./common/filter # remove previous $seqres.full before test rm -f $seqres.full # real QA test starts here _supported_fs btrfs _supported_os Linux _require_scratch rm -f $seqres.full _scratch_mkfs _scratch_mount _run_btrfs_util_prog quota enable $SCRATCH_MNT # The qgroup '1/10' does not exist and should be silently ignored _run_btrfs_util_prog subvolume snapshot -i 1/10 $SCRATCH_MNT $SCRATCH_MNT/snap1 _scratch_unmount echo "Silence is golden" status=0 exit Signed-off-by: Mark Fasheh <mfasheh@suse.de> Reviewed-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/qgroup.c54
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 */
1848int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, 1850int 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
2030unlock: 2040unlock: