]> git.hungrycats.org Git - linux/commitdiff
btrfs: Don't allow subvolid >= (1 << BTRFS_QGROUP_LEVEL_SHIFT) to be created
authorQu Wenruo <quwenruo@cn.fujitsu.com>
Fri, 27 Feb 2015 08:24:23 +0000 (16:24 +0800)
committerZygo Blaxell <zblaxell@serenity.furryterror.org>
Fri, 17 Apr 2015 16:00:57 +0000 (12:00 -0400)
Btrfs will create qgroup on subvolume creation if quota is enabled, but
qgroup uses the high bits(currently 16 bits) as level, to build the
inheritance.

However it is fully possible a subvolume can be created with a
subvolumeid larger than 1 << BTRFS_QGROUP_LEVEL_SHIFT, so it will be
considered as level 1 and can't be assigned to other qgroup in level 1.

This patch will prevent such things so qgroup inheritance will not be
screwed up.
The downside is very clear, btrfs subvolume number limit will decrease
from (u64 max - 256(fisrt free objectid) - 256(last free objectid)) to
(u48 max -256(first free objectid)).
But we still have near u48(that's 15 digits in dec), so that should not
be a huge problem.

Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Reviewed-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: Chris Mason <clm@fb.com>
(cherry picked from commit e09fe2d2119800e6060f9b8ba71e072a0eb0fa4d)

fs/btrfs/ctree.h
fs/btrfs/ioctl.c

index 8be582c87d8e053d69d8a2b1ae005e5235c2d166..ee96d65e2465c4efe68e70563e31d12380fae8cc 100644 (file)
@@ -4121,7 +4121,8 @@ int btree_readahead_hook(struct btrfs_root *root, struct extent_buffer *eb,
 static inline int is_fstree(u64 rootid)
 {
        if (rootid == BTRFS_FS_TREE_OBJECTID ||
-           (s64)rootid >= (s64)BTRFS_FIRST_FREE_OBJECTID)
+           ((s64)rootid >= (s64)BTRFS_FIRST_FREE_OBJECTID &&
+             !btrfs_qgroup_level(rootid)))
                return 1;
        return 0;
 }
index 78702c1f067d1c92f2bf9841a6d409431ab0314c..3ec0028c98b7fcbcbad56cdfdbc635ca7e4d185a 100644 (file)
@@ -456,6 +456,13 @@ static noinline int create_subvol(struct inode *dir,
        if (ret)
                return ret;
 
+       /*
+        * Don't create subvolume whose level is not zero. Or qgroup will be
+        * screwed up since it assume subvolme qgroup's level to be 0.
+        */
+       if (btrfs_qgroup_level(objectid))
+               return -ENOSPC;
+
        btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);
        /*
         * The same as the snapshot creation, please see the comment