1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #ifdef HAVE_LINUX_BTRFS_H
26 #include <linux/btrfs.h>
29 #include "alloc-util.h"
30 #include "btrfs-ctree.h"
31 #include "btrfs-util.h"
37 #include "path-util.h"
38 #include "selinux-util.h"
39 #include "smack-util.h"
40 #include "stat-util.h"
41 #include "string-util.h"
44 /* WARNING: Be careful with file system ioctls! When we get an fd, we
45 * need to make sure it either refers to only a regular file or
46 * directory, or that it is located on btrfs, before invoking any
47 * btrfs ioctls. The ioctl numbers are reused by some device drivers
48 * (such as DRM), and hence might have bad effects when invoked on
49 * device nodes (that reference drivers) rather than fds to normal
50 * files or directories. */
52 static int validate_subvolume_name(const char *name
) {
54 if (!filename_is_valid(name
))
57 if (strlen(name
) > BTRFS_SUBVOL_NAME_MAX
)
63 static int open_parent(const char *path
, int flags
) {
64 _cleanup_free_
char *parent
= NULL
;
69 parent
= dirname_malloc(path
);
73 fd
= open(parent
, flags
);
80 static int extract_subvolume_name(const char *path
, const char **subvolume
) {
89 r
= validate_subvolume_name(fn
);
97 int btrfs_is_filesystem(int fd
) {
102 if (fstatfs(fd
, &sfs
) < 0)
105 return F_TYPE_EQUAL(sfs
.f_type
, BTRFS_SUPER_MAGIC
);
108 int btrfs_is_subvol_fd(int fd
) {
113 /* On btrfs subvolumes always have the inode 256 */
115 if (fstat(fd
, &st
) < 0)
118 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
121 return btrfs_is_filesystem(fd
);
124 int btrfs_is_subvol(const char *path
) {
125 _cleanup_close_
int fd
= -1;
129 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
133 return btrfs_is_subvol_fd(fd
);
136 int btrfs_subvol_make(const char *path
) {
137 struct btrfs_ioctl_vol_args args
= {};
138 _cleanup_close_
int fd
= -1;
139 const char *subvolume
;
144 r
= extract_subvolume_name(path
, &subvolume
);
148 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
152 strncpy(args
.name
, subvolume
, sizeof(args
.name
)-1);
154 if (ioctl(fd
, BTRFS_IOC_SUBVOL_CREATE
, &args
) < 0)
160 int btrfs_subvol_make_label(const char *path
) {
165 r
= mac_selinux_create_file_prepare(path
, S_IFDIR
);
169 r
= btrfs_subvol_make(path
);
170 mac_selinux_create_file_clear();
175 return mac_smack_fix(path
, false, false);
178 int btrfs_subvol_set_read_only_fd(int fd
, bool b
) {
179 uint64_t flags
, nflags
;
184 if (fstat(fd
, &st
) < 0)
187 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
190 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
194 nflags
= flags
| BTRFS_SUBVOL_RDONLY
;
196 nflags
= flags
& ~BTRFS_SUBVOL_RDONLY
;
201 if (ioctl(fd
, BTRFS_IOC_SUBVOL_SETFLAGS
, &nflags
) < 0)
207 int btrfs_subvol_set_read_only(const char *path
, bool b
) {
208 _cleanup_close_
int fd
= -1;
210 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
214 return btrfs_subvol_set_read_only_fd(fd
, b
);
217 int btrfs_subvol_get_read_only_fd(int fd
) {
223 if (fstat(fd
, &st
) < 0)
226 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
229 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
232 return !!(flags
& BTRFS_SUBVOL_RDONLY
);
235 int btrfs_reflink(int infd
, int outfd
) {
242 /* Make sure we invoke the ioctl on a regular file, so that no
243 * device driver accidentally gets it. */
245 if (fstat(outfd
, &st
) < 0)
248 if (!S_ISREG(st
.st_mode
))
251 r
= ioctl(outfd
, BTRFS_IOC_CLONE
, infd
);
258 int btrfs_clone_range(int infd
, uint64_t in_offset
, int outfd
, uint64_t out_offset
, uint64_t sz
) {
259 struct btrfs_ioctl_clone_range_args args
= {
261 .src_offset
= in_offset
,
263 .dest_offset
= out_offset
,
272 if (fstat(outfd
, &st
) < 0)
275 if (!S_ISREG(st
.st_mode
))
278 r
= ioctl(outfd
, BTRFS_IOC_CLONE_RANGE
, &args
);
285 int btrfs_get_block_device_fd(int fd
, dev_t
*dev
) {
286 struct btrfs_ioctl_fs_info_args fsi
= {};
293 r
= btrfs_is_filesystem(fd
);
299 if (ioctl(fd
, BTRFS_IOC_FS_INFO
, &fsi
) < 0)
302 /* We won't do this for btrfs RAID */
303 if (fsi
.num_devices
!= 1)
306 for (id
= 1; id
<= fsi
.max_id
; id
++) {
307 struct btrfs_ioctl_dev_info_args di
= {
312 if (ioctl(fd
, BTRFS_IOC_DEV_INFO
, &di
) < 0) {
319 if (stat((char*) di
.path
, &st
) < 0)
322 if (!S_ISBLK(st
.st_mode
))
325 if (major(st
.st_rdev
) == 0)
335 int btrfs_get_block_device(const char *path
, dev_t
*dev
) {
336 _cleanup_close_
int fd
= -1;
341 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
345 return btrfs_get_block_device_fd(fd
, dev
);
348 int btrfs_subvol_get_id_fd(int fd
, uint64_t *ret
) {
349 struct btrfs_ioctl_ino_lookup_args args
= {
350 .objectid
= BTRFS_FIRST_FREE_OBJECTID
357 r
= btrfs_is_filesystem(fd
);
363 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
) < 0)
370 int btrfs_subvol_get_id(int fd
, const char *subvol
, uint64_t *ret
) {
371 _cleanup_close_
int subvol_fd
= -1;
376 subvol_fd
= openat(fd
, subvol
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
380 return btrfs_subvol_get_id_fd(subvol_fd
, ret
);
383 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args
*args
) {
386 /* the objectid, type, offset together make up the btrfs key,
387 * which is considered a single 136byte integer when
388 * comparing. This call increases the counter by one, dealing
389 * with the overflow between the overflows */
391 if (args
->key
.min_offset
< (uint64_t) -1) {
392 args
->key
.min_offset
++;
396 if (args
->key
.min_type
< (uint8_t) -1) {
397 args
->key
.min_type
++;
398 args
->key
.min_offset
= 0;
402 if (args
->key
.min_objectid
< (uint64_t) -1) {
403 args
->key
.min_objectid
++;
404 args
->key
.min_offset
= 0;
405 args
->key
.min_type
= 0;
412 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args
*args
, const struct btrfs_ioctl_search_header
*h
) {
416 args
->key
.min_objectid
= h
->objectid
;
417 args
->key
.min_type
= h
->type
;
418 args
->key
.min_offset
= h
->offset
;
421 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
*args
) {
424 /* Compare min and max */
426 if (args
->key
.min_objectid
< args
->key
.max_objectid
)
428 if (args
->key
.min_objectid
> args
->key
.max_objectid
)
431 if (args
->key
.min_type
< args
->key
.max_type
)
433 if (args
->key
.min_type
> args
->key
.max_type
)
436 if (args
->key
.min_offset
< args
->key
.max_offset
)
438 if (args
->key
.min_offset
> args
->key
.max_offset
)
444 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
446 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
447 (i) < (args).key.nr_items; \
449 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
451 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
452 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
454 int btrfs_subvol_get_info_fd(int fd
, uint64_t subvol_id
, BtrfsSubvolInfo
*ret
) {
455 struct btrfs_ioctl_search_args args
= {
456 /* Tree of tree roots */
457 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
459 /* Look precisely for the subvolume items */
460 .key
.min_type
= BTRFS_ROOT_ITEM_KEY
,
461 .key
.max_type
= BTRFS_ROOT_ITEM_KEY
,
464 .key
.max_offset
= (uint64_t) -1,
466 /* No restrictions on the other components */
467 .key
.min_transid
= 0,
468 .key
.max_transid
= (uint64_t) -1,
477 if (subvol_id
== 0) {
478 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
482 r
= btrfs_is_filesystem(fd
);
489 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
491 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
492 const struct btrfs_ioctl_search_header
*sh
;
495 args
.key
.nr_items
= 256;
496 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
499 if (args
.key
.nr_items
<= 0)
502 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
504 const struct btrfs_root_item
*ri
;
506 /* Make sure we start the next search at least from this entry */
507 btrfs_ioctl_search_args_set(&args
, sh
);
509 if (sh
->objectid
!= subvol_id
)
511 if (sh
->type
!= BTRFS_ROOT_ITEM_KEY
)
514 /* Older versions of the struct lacked the otime setting */
515 if (sh
->len
< offsetof(struct btrfs_root_item
, otime
) + sizeof(struct btrfs_timespec
))
518 ri
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
520 ret
->otime
= (usec_t
) le64toh(ri
->otime
.sec
) * USEC_PER_SEC
+
521 (usec_t
) le32toh(ri
->otime
.nsec
) / NSEC_PER_USEC
;
523 ret
->subvol_id
= subvol_id
;
524 ret
->read_only
= !!(le64toh(ri
->flags
) & BTRFS_ROOT_SUBVOL_RDONLY
);
526 assert_cc(sizeof(ri
->uuid
) == sizeof(ret
->uuid
));
527 memcpy(&ret
->uuid
, ri
->uuid
, sizeof(ret
->uuid
));
528 memcpy(&ret
->parent_uuid
, ri
->parent_uuid
, sizeof(ret
->parent_uuid
));
534 /* Increase search key by one, to read the next item, if we can. */
535 if (!btrfs_ioctl_search_args_inc(&args
))
546 int btrfs_qgroup_get_quota_fd(int fd
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
548 struct btrfs_ioctl_search_args args
= {
549 /* Tree of quota items */
550 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
552 /* The object ID is always 0 */
553 .key
.min_objectid
= 0,
554 .key
.max_objectid
= 0,
556 /* Look precisely for the quota items */
557 .key
.min_type
= BTRFS_QGROUP_STATUS_KEY
,
558 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
560 /* No restrictions on the other components */
561 .key
.min_transid
= 0,
562 .key
.max_transid
= (uint64_t) -1,
565 bool found_info
= false, found_limit
= false;
572 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
576 r
= btrfs_is_filesystem(fd
);
583 args
.key
.min_offset
= args
.key
.max_offset
= qgroupid
;
585 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
586 const struct btrfs_ioctl_search_header
*sh
;
589 args
.key
.nr_items
= 256;
590 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
591 if (errno
== ENOENT
) /* quota tree is missing: quota disabled */
597 if (args
.key
.nr_items
<= 0)
600 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
602 /* Make sure we start the next search at least from this entry */
603 btrfs_ioctl_search_args_set(&args
, sh
);
605 if (sh
->objectid
!= 0)
607 if (sh
->offset
!= qgroupid
)
610 if (sh
->type
== BTRFS_QGROUP_INFO_KEY
) {
611 const struct btrfs_qgroup_info_item
*qii
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
613 ret
->referenced
= le64toh(qii
->rfer
);
614 ret
->exclusive
= le64toh(qii
->excl
);
618 } else if (sh
->type
== BTRFS_QGROUP_LIMIT_KEY
) {
619 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
621 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_RFER
)
622 ret
->referenced_max
= le64toh(qli
->max_rfer
);
624 ret
->referenced_max
= (uint64_t) -1;
626 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_EXCL
)
627 ret
->exclusive_max
= le64toh(qli
->max_excl
);
629 ret
->exclusive_max
= (uint64_t) -1;
634 if (found_info
&& found_limit
)
638 /* Increase search key by one, to read the next item, if we can. */
639 if (!btrfs_ioctl_search_args_inc(&args
))
644 if (!found_limit
&& !found_info
)
648 ret
->referenced
= (uint64_t) -1;
649 ret
->exclusive
= (uint64_t) -1;
653 ret
->referenced_max
= (uint64_t) -1;
654 ret
->exclusive_max
= (uint64_t) -1;
660 int btrfs_qgroup_get_quota(const char *path
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
661 _cleanup_close_
int fd
= -1;
663 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
667 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
670 int btrfs_subvol_find_subtree_qgroup(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
671 uint64_t level
, lowest
= (uint64_t) -1, lowest_qgroupid
= 0;
672 _cleanup_free_
uint64_t *qgroups
= NULL
;
678 /* This finds the "subtree" qgroup for a specific
679 * subvolume. This only works for subvolumes that have been
680 * prepared with btrfs_subvol_auto_qgroup_fd() with
681 * insert_intermediary_qgroup=true (or equivalent). For others
682 * it will return the leaf qgroup instead. The two cases may
683 * be distuingished via the return value, which is 1 in case
684 * an appropriate "subtree" qgroup was found, and 0
687 if (subvol_id
== 0) {
688 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
693 r
= btrfs_qgroupid_split(subvol_id
, &level
, NULL
);
696 if (level
!= 0) /* Input must be a leaf qgroup */
699 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
703 for (i
= 0; i
< n
; i
++) {
706 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, &id
);
713 if (lowest
== (uint64_t) -1 || level
< lowest
) {
714 lowest_qgroupid
= qgroups
[i
];
719 if (lowest
== (uint64_t) -1) {
720 /* No suitable higher-level qgroup found, let's return
721 * the leaf qgroup instead, and indicate that with the
728 *ret
= lowest_qgroupid
;
732 int btrfs_subvol_get_subtree_quota_fd(int fd
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
739 /* This determines the quota data of the qgroup with the
740 * lowest level, that shares the id part with the specified
741 * subvolume. This is useful for determining the quota data
742 * for entire subvolume subtrees, as long as the subtrees have
743 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
746 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
750 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
753 int btrfs_subvol_get_subtree_quota(const char *path
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
754 _cleanup_close_
int fd
= -1;
756 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
760 return btrfs_subvol_get_subtree_quota_fd(fd
, subvol_id
, ret
);
763 int btrfs_defrag_fd(int fd
) {
768 if (fstat(fd
, &st
) < 0)
771 if (!S_ISREG(st
.st_mode
))
774 if (ioctl(fd
, BTRFS_IOC_DEFRAG
, NULL
) < 0)
780 int btrfs_defrag(const char *p
) {
781 _cleanup_close_
int fd
= -1;
783 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
787 return btrfs_defrag_fd(fd
);
790 int btrfs_quota_enable_fd(int fd
, bool b
) {
791 struct btrfs_ioctl_quota_ctl_args args
= {
792 .cmd
= b
? BTRFS_QUOTA_CTL_ENABLE
: BTRFS_QUOTA_CTL_DISABLE
,
798 r
= btrfs_is_filesystem(fd
);
804 if (ioctl(fd
, BTRFS_IOC_QUOTA_CTL
, &args
) < 0)
810 int btrfs_quota_enable(const char *path
, bool b
) {
811 _cleanup_close_
int fd
= -1;
813 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
817 return btrfs_quota_enable_fd(fd
, b
);
820 int btrfs_qgroup_set_limit_fd(int fd
, uint64_t qgroupid
, uint64_t referenced_max
) {
822 struct btrfs_ioctl_qgroup_limit_args args
= {
823 .lim
.max_rfer
= referenced_max
,
824 .lim
.flags
= BTRFS_QGROUP_LIMIT_MAX_RFER
,
832 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
836 r
= btrfs_is_filesystem(fd
);
843 args
.qgroupid
= qgroupid
;
846 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &args
) < 0) {
848 if (errno
== EBUSY
&& c
< 10) {
849 (void) btrfs_quota_scan_wait(fd
);
862 int btrfs_qgroup_set_limit(const char *path
, uint64_t qgroupid
, uint64_t referenced_max
) {
863 _cleanup_close_
int fd
= -1;
865 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
869 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
872 int btrfs_subvol_set_subtree_quota_limit_fd(int fd
, uint64_t subvol_id
, uint64_t referenced_max
) {
878 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
882 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
885 int btrfs_subvol_set_subtree_quota_limit(const char *path
, uint64_t subvol_id
, uint64_t referenced_max
) {
886 _cleanup_close_
int fd
= -1;
888 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
892 return btrfs_subvol_set_subtree_quota_limit_fd(fd
, subvol_id
, referenced_max
);
895 int btrfs_resize_loopback_fd(int fd
, uint64_t new_size
, bool grow_only
) {
896 struct btrfs_ioctl_vol_args args
= {};
897 _cleanup_free_
char *p
= NULL
, *loop
= NULL
, *backing
= NULL
;
898 _cleanup_close_
int loop_fd
= -1, backing_fd
= -1;
903 /* btrfs cannot handle file systems < 16M, hence use this as minimum */
904 if (new_size
< 16*1024*1024)
905 new_size
= 16*1024*1024;
907 r
= btrfs_get_block_device_fd(fd
, &dev
);
913 if (asprintf(&p
, "/sys/dev/block/%u:%u/loop/backing_file", major(dev
), minor(dev
)) < 0)
915 r
= read_one_line_file(p
, &backing
);
920 if (isempty(backing
) || !path_is_absolute(backing
))
923 backing_fd
= open(backing
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
927 if (fstat(backing_fd
, &st
) < 0)
929 if (!S_ISREG(st
.st_mode
))
932 if (new_size
== (uint64_t) st
.st_size
)
935 if (grow_only
&& new_size
< (uint64_t) st
.st_size
)
938 if (asprintf(&loop
, "/dev/block/%u:%u", major(dev
), minor(dev
)) < 0)
940 loop_fd
= open(loop
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
944 if (snprintf(args
.name
, sizeof(args
.name
), "%" PRIu64
, new_size
) >= (int) sizeof(args
.name
))
947 if (new_size
< (uint64_t) st
.st_size
) {
948 /* Decrease size: first decrease btrfs size, then shorten loopback */
949 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
953 if (ftruncate(backing_fd
, new_size
) < 0)
956 if (ioctl(loop_fd
, LOOP_SET_CAPACITY
, 0) < 0)
959 if (new_size
> (uint64_t) st
.st_size
) {
960 /* Increase size: first enlarge loopback, then increase btrfs size */
961 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
965 /* Make sure the free disk space is correctly updated for both file systems */
967 (void) fsync(backing_fd
);
972 int btrfs_resize_loopback(const char *p
, uint64_t new_size
, bool grow_only
) {
973 _cleanup_close_
int fd
= -1;
975 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
979 return btrfs_resize_loopback_fd(fd
, new_size
, grow_only
);
982 int btrfs_qgroupid_make(uint64_t level
, uint64_t id
, uint64_t *ret
) {
985 if (level
>= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT
)))
988 if (id
>= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
))
991 *ret
= (level
<< BTRFS_QGROUP_LEVEL_SHIFT
) | id
;
995 int btrfs_qgroupid_split(uint64_t qgroupid
, uint64_t *level
, uint64_t *id
) {
999 *level
= qgroupid
>> BTRFS_QGROUP_LEVEL_SHIFT
;
1002 *id
= qgroupid
& ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
) - 1);
1007 static int qgroup_create_or_destroy(int fd
, bool b
, uint64_t qgroupid
) {
1009 struct btrfs_ioctl_qgroup_create_args args
= {
1011 .qgroupid
= qgroupid
,
1016 r
= btrfs_is_filesystem(fd
);
1023 if (ioctl(fd
, BTRFS_IOC_QGROUP_CREATE
, &args
) < 0) {
1025 /* If quota is not enabled, we get EINVAL. Turn this into a recognizable error */
1026 if (errno
== EINVAL
)
1027 return -ENOPROTOOPT
;
1029 if (errno
== EBUSY
&& c
< 10) {
1030 (void) btrfs_quota_scan_wait(fd
);
1043 int btrfs_qgroup_create(int fd
, uint64_t qgroupid
) {
1044 return qgroup_create_or_destroy(fd
, true, qgroupid
);
1047 int btrfs_qgroup_destroy(int fd
, uint64_t qgroupid
) {
1048 return qgroup_create_or_destroy(fd
, false, qgroupid
);
1051 int btrfs_qgroup_destroy_recursive(int fd
, uint64_t qgroupid
) {
1052 _cleanup_free_
uint64_t *qgroups
= NULL
;
1056 /* Destroys the specified qgroup, but unassigns it from all
1057 * its parents first. Also, it recursively destroys all
1058 * qgroups it is assgined to that have the same id part of the
1059 * qgroupid as the specified group. */
1061 r
= btrfs_qgroupid_split(qgroupid
, NULL
, &subvol_id
);
1065 n
= btrfs_qgroup_find_parents(fd
, qgroupid
, &qgroups
);
1069 for (i
= 0; i
< n
; i
++) {
1072 r
= btrfs_qgroupid_split(qgroups
[i
], NULL
, &id
);
1076 r
= btrfs_qgroup_unassign(fd
, qgroupid
, qgroups
[i
]);
1080 if (id
!= subvol_id
)
1083 /* The parent qgroupid shares the same id part with
1084 * us? If so, destroy it too. */
1086 (void) btrfs_qgroup_destroy_recursive(fd
, qgroups
[i
]);
1089 return btrfs_qgroup_destroy(fd
, qgroupid
);
1092 int btrfs_quota_scan_start(int fd
) {
1093 struct btrfs_ioctl_quota_rescan_args args
= {};
1097 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN
, &args
) < 0)
1103 int btrfs_quota_scan_wait(int fd
) {
1106 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_WAIT
) < 0)
1112 int btrfs_quota_scan_ongoing(int fd
) {
1113 struct btrfs_ioctl_quota_rescan_args args
= {};
1117 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_STATUS
, &args
) < 0)
1120 return !!args
.flags
;
1123 static int qgroup_assign_or_unassign(int fd
, bool b
, uint64_t child
, uint64_t parent
) {
1124 struct btrfs_ioctl_qgroup_assign_args args
= {
1132 r
= btrfs_is_filesystem(fd
);
1139 r
= ioctl(fd
, BTRFS_IOC_QGROUP_ASSIGN
, &args
);
1141 if (errno
== EBUSY
&& c
< 10) {
1142 (void) btrfs_quota_scan_wait(fd
);
1152 /* If the return value is > 0, we need to request a rescan */
1154 (void) btrfs_quota_scan_start(fd
);
1159 int btrfs_qgroup_assign(int fd
, uint64_t child
, uint64_t parent
) {
1160 return qgroup_assign_or_unassign(fd
, true, child
, parent
);
1163 int btrfs_qgroup_unassign(int fd
, uint64_t child
, uint64_t parent
) {
1164 return qgroup_assign_or_unassign(fd
, false, child
, parent
);
1167 static int subvol_remove_children(int fd
, const char *subvolume
, uint64_t subvol_id
, BtrfsRemoveFlags flags
) {
1168 struct btrfs_ioctl_search_args args
= {
1169 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1171 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1172 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1174 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1175 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1177 .key
.min_transid
= 0,
1178 .key
.max_transid
= (uint64_t) -1,
1181 struct btrfs_ioctl_vol_args vol_args
= {};
1182 _cleanup_close_
int subvol_fd
= -1;
1184 bool made_writable
= false;
1190 if (fstat(fd
, &st
) < 0)
1193 if (!S_ISDIR(st
.st_mode
))
1196 subvol_fd
= openat(fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1200 if (subvol_id
== 0) {
1201 r
= btrfs_subvol_get_id_fd(subvol_fd
, &subvol_id
);
1206 /* First, try to remove the subvolume. If it happens to be
1207 * already empty, this will just work. */
1208 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1209 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) >= 0) {
1210 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1213 if (!(flags
& BTRFS_REMOVE_RECURSIVE
) || errno
!= ENOTEMPTY
)
1216 /* OK, the subvolume is not empty, let's look for child
1217 * subvolumes, and remove them, first */
1219 args
.key
.min_offset
= args
.key
.max_offset
= subvol_id
;
1221 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1222 const struct btrfs_ioctl_search_header
*sh
;
1225 args
.key
.nr_items
= 256;
1226 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1229 if (args
.key
.nr_items
<= 0)
1232 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1233 _cleanup_free_
char *p
= NULL
;
1234 const struct btrfs_root_ref
*ref
;
1235 struct btrfs_ioctl_ino_lookup_args ino_args
;
1237 btrfs_ioctl_search_args_set(&args
, sh
);
1239 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1241 if (sh
->offset
!= subvol_id
)
1244 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1246 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1251 ino_args
.treeid
= subvol_id
;
1252 ino_args
.objectid
= htole64(ref
->dirid
);
1254 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1257 if (!made_writable
) {
1258 r
= btrfs_subvol_set_read_only_fd(subvol_fd
, false);
1262 made_writable
= true;
1265 if (isempty(ino_args
.name
))
1266 /* Subvolume is in the top-level
1267 * directory of the subvolume. */
1268 r
= subvol_remove_children(subvol_fd
, p
, sh
->objectid
, flags
);
1270 _cleanup_close_
int child_fd
= -1;
1272 /* Subvolume is somewhere further down,
1273 * hence we need to open the
1274 * containing directory first */
1276 child_fd
= openat(subvol_fd
, ino_args
.name
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1280 r
= subvol_remove_children(child_fd
, p
, sh
->objectid
, flags
);
1286 /* Increase search key by one, to read the next item, if we can. */
1287 if (!btrfs_ioctl_search_args_inc(&args
))
1291 /* OK, the child subvolumes should all be gone now, let's try
1292 * again to remove the subvolume */
1293 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) < 0)
1296 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
);
1300 int btrfs_subvol_remove(const char *path
, BtrfsRemoveFlags flags
) {
1301 _cleanup_close_
int fd
= -1;
1302 const char *subvolume
;
1307 r
= extract_subvolume_name(path
, &subvolume
);
1311 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1315 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1318 int btrfs_subvol_remove_fd(int fd
, const char *subvolume
, BtrfsRemoveFlags flags
) {
1319 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1322 int btrfs_qgroup_copy_limits(int fd
, uint64_t old_qgroupid
, uint64_t new_qgroupid
) {
1324 struct btrfs_ioctl_search_args args
= {
1325 /* Tree of quota items */
1326 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1328 /* The object ID is always 0 */
1329 .key
.min_objectid
= 0,
1330 .key
.max_objectid
= 0,
1332 /* Look precisely for the quota items */
1333 .key
.min_type
= BTRFS_QGROUP_LIMIT_KEY
,
1334 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
1336 /* For our qgroup */
1337 .key
.min_offset
= old_qgroupid
,
1338 .key
.max_offset
= old_qgroupid
,
1340 /* No restrictions on the other components */
1341 .key
.min_transid
= 0,
1342 .key
.max_transid
= (uint64_t) -1,
1347 r
= btrfs_is_filesystem(fd
);
1353 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1354 const struct btrfs_ioctl_search_header
*sh
;
1357 args
.key
.nr_items
= 256;
1358 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1359 if (errno
== ENOENT
) /* quota tree missing: quota is not enabled, hence nothing to copy */
1365 if (args
.key
.nr_items
<= 0)
1368 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1369 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1370 struct btrfs_ioctl_qgroup_limit_args qargs
;
1373 /* Make sure we start the next search at least from this entry */
1374 btrfs_ioctl_search_args_set(&args
, sh
);
1376 if (sh
->objectid
!= 0)
1378 if (sh
->type
!= BTRFS_QGROUP_LIMIT_KEY
)
1380 if (sh
->offset
!= old_qgroupid
)
1383 /* We found the entry, now copy things over. */
1385 qargs
= (struct btrfs_ioctl_qgroup_limit_args
) {
1386 .qgroupid
= new_qgroupid
,
1388 .lim
.max_rfer
= le64toh(qli
->max_rfer
),
1389 .lim
.max_excl
= le64toh(qli
->max_excl
),
1390 .lim
.rsv_rfer
= le64toh(qli
->rsv_rfer
),
1391 .lim
.rsv_excl
= le64toh(qli
->rsv_excl
),
1393 .lim
.flags
= le64toh(qli
->flags
) & (BTRFS_QGROUP_LIMIT_MAX_RFER
|
1394 BTRFS_QGROUP_LIMIT_MAX_EXCL
|
1395 BTRFS_QGROUP_LIMIT_RSV_RFER
|
1396 BTRFS_QGROUP_LIMIT_RSV_EXCL
),
1400 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &qargs
) < 0) {
1401 if (errno
== EBUSY
&& c
< 10) {
1402 (void) btrfs_quota_scan_wait(fd
);
1414 /* Increase search key by one, to read the next item, if we can. */
1415 if (!btrfs_ioctl_search_args_inc(&args
))
1422 static int copy_quota_hierarchy(int fd
, uint64_t old_subvol_id
, uint64_t new_subvol_id
) {
1423 _cleanup_free_
uint64_t *old_qgroups
= NULL
, *old_parent_qgroups
= NULL
;
1424 bool copy_from_parent
= false, insert_intermediary_qgroup
= false;
1425 int n_old_qgroups
, n_old_parent_qgroups
, r
, i
;
1426 uint64_t old_parent_id
;
1430 /* Copies a reduced form of quota information from the old to
1431 * the new subvolume. */
1433 n_old_qgroups
= btrfs_qgroup_find_parents(fd
, old_subvol_id
, &old_qgroups
);
1434 if (n_old_qgroups
<= 0) /* Nothing to copy */
1435 return n_old_qgroups
;
1437 r
= btrfs_subvol_get_parent(fd
, old_subvol_id
, &old_parent_id
);
1439 /* We have no parent, hence nothing to copy. */
1440 n_old_parent_qgroups
= 0;
1444 n_old_parent_qgroups
= btrfs_qgroup_find_parents(fd
, old_parent_id
, &old_parent_qgroups
);
1445 if (n_old_parent_qgroups
< 0)
1446 return n_old_parent_qgroups
;
1449 for (i
= 0; i
< n_old_qgroups
; i
++) {
1453 r
= btrfs_qgroupid_split(old_qgroups
[i
], NULL
, &id
);
1457 if (id
== old_subvol_id
) {
1458 /* The old subvolume was member of a qgroup
1459 * that had the same id, but a different level
1460 * as it self. Let's set up something similar
1461 * in the destination. */
1462 insert_intermediary_qgroup
= true;
1466 for (j
= 0; j
< n_old_parent_qgroups
; j
++)
1467 if (old_parent_qgroups
[j
] == old_qgroups
[i
]) {
1468 /* The old subvolume shared a common
1469 * parent qgroup with its parent
1470 * subvolume. Let's set up something
1471 * similar in the destination. */
1472 copy_from_parent
= true;
1476 if (!insert_intermediary_qgroup
&& !copy_from_parent
)
1479 return btrfs_subvol_auto_qgroup_fd(fd
, new_subvol_id
, insert_intermediary_qgroup
);
1482 static int copy_subtree_quota_limits(int fd
, uint64_t old_subvol
, uint64_t new_subvol
) {
1483 uint64_t old_subtree_qgroup
, new_subtree_qgroup
;
1487 /* First copy the leaf limits */
1488 r
= btrfs_qgroup_copy_limits(fd
, old_subvol
, new_subvol
);
1493 /* Then, try to copy the subtree limits, if there are any. */
1494 r
= btrfs_subvol_find_subtree_qgroup(fd
, old_subvol
, &old_subtree_qgroup
);
1500 r
= btrfs_subvol_find_subtree_qgroup(fd
, new_subvol
, &new_subtree_qgroup
);
1506 r
= btrfs_qgroup_copy_limits(fd
, old_subtree_qgroup
, new_subtree_qgroup
);
1513 static int subvol_snapshot_children(int old_fd
, int new_fd
, const char *subvolume
, uint64_t old_subvol_id
, BtrfsSnapshotFlags flags
) {
1515 struct btrfs_ioctl_search_args args
= {
1516 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1518 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1519 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1521 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1522 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1524 .key
.min_transid
= 0,
1525 .key
.max_transid
= (uint64_t) -1,
1528 struct btrfs_ioctl_vol_args_v2 vol_args
= {
1529 .flags
= flags
& BTRFS_SNAPSHOT_READ_ONLY
? BTRFS_SUBVOL_RDONLY
: 0,
1532 _cleanup_close_
int subvolume_fd
= -1;
1533 uint64_t new_subvol_id
;
1536 assert(old_fd
>= 0);
1537 assert(new_fd
>= 0);
1540 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1542 if (ioctl(new_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &vol_args
) < 0)
1545 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
) &&
1546 !(flags
& BTRFS_SNAPSHOT_QUOTA
))
1549 if (old_subvol_id
== 0) {
1550 r
= btrfs_subvol_get_id_fd(old_fd
, &old_subvol_id
);
1555 r
= btrfs_subvol_get_id(new_fd
, vol_args
.name
, &new_subvol_id
);
1559 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1560 (void) copy_quota_hierarchy(new_fd
, old_subvol_id
, new_subvol_id
);
1562 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
)) {
1564 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1565 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1570 args
.key
.min_offset
= args
.key
.max_offset
= old_subvol_id
;
1572 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1573 const struct btrfs_ioctl_search_header
*sh
;
1576 args
.key
.nr_items
= 256;
1577 if (ioctl(old_fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1580 if (args
.key
.nr_items
<= 0)
1583 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1584 _cleanup_free_
char *p
= NULL
, *c
= NULL
, *np
= NULL
;
1585 struct btrfs_ioctl_ino_lookup_args ino_args
;
1586 const struct btrfs_root_ref
*ref
;
1587 _cleanup_close_
int old_child_fd
= -1, new_child_fd
= -1;
1589 btrfs_ioctl_search_args_set(&args
, sh
);
1591 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1594 /* Avoid finding the source subvolume a second
1596 if (sh
->offset
!= old_subvol_id
)
1599 /* Avoid running into loops if the new
1600 * subvolume is below the old one. */
1601 if (sh
->objectid
== new_subvol_id
)
1604 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1605 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1610 ino_args
.treeid
= old_subvol_id
;
1611 ino_args
.objectid
= htole64(ref
->dirid
);
1613 if (ioctl(old_fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1616 /* The kernel returns an empty name if the
1617 * subvolume is in the top-level directory,
1618 * and otherwise appends a slash, so that we
1619 * can just concatenate easily here, without
1620 * adding a slash. */
1621 c
= strappend(ino_args
.name
, p
);
1625 old_child_fd
= openat(old_fd
, c
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1626 if (old_child_fd
< 0)
1629 np
= strjoin(subvolume
, "/", ino_args
.name
, NULL
);
1633 new_child_fd
= openat(new_fd
, np
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1634 if (new_child_fd
< 0)
1637 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1638 /* If the snapshot is read-only we
1639 * need to mark it writable
1640 * temporarily, to put the subsnapshot
1643 if (subvolume_fd
< 0) {
1644 subvolume_fd
= openat(new_fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1645 if (subvolume_fd
< 0)
1649 r
= btrfs_subvol_set_read_only_fd(subvolume_fd
, false);
1654 /* When btrfs clones the subvolumes, child
1655 * subvolumes appear as empty directories. Remove
1656 * them, so that we can create a new snapshot
1658 if (unlinkat(new_child_fd
, p
, AT_REMOVEDIR
) < 0) {
1661 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
)
1662 (void) btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1667 r
= subvol_snapshot_children(old_child_fd
, new_child_fd
, p
, sh
->objectid
, flags
& ~BTRFS_SNAPSHOT_FALLBACK_COPY
);
1669 /* Restore the readonly flag */
1670 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1673 k
= btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1674 if (r
>= 0 && k
< 0)
1682 /* Increase search key by one, to read the next item, if we can. */
1683 if (!btrfs_ioctl_search_args_inc(&args
))
1687 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1688 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1693 int btrfs_subvol_snapshot_fd(int old_fd
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1694 _cleanup_close_
int new_fd
= -1;
1695 const char *subvolume
;
1698 assert(old_fd
>= 0);
1701 r
= btrfs_is_subvol_fd(old_fd
);
1705 if (!(flags
& BTRFS_SNAPSHOT_FALLBACK_COPY
))
1708 r
= btrfs_subvol_make(new_path
);
1712 r
= copy_directory_fd(old_fd
, new_path
, true);
1714 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1718 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1719 r
= btrfs_subvol_set_read_only(new_path
, true);
1721 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1729 r
= extract_subvolume_name(new_path
, &subvolume
);
1733 new_fd
= open_parent(new_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1737 return subvol_snapshot_children(old_fd
, new_fd
, subvolume
, 0, flags
);
1740 int btrfs_subvol_snapshot(const char *old_path
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1741 _cleanup_close_
int old_fd
= -1;
1746 old_fd
= open(old_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1750 return btrfs_subvol_snapshot_fd(old_fd
, new_path
, flags
);
1753 int btrfs_qgroup_find_parents(int fd
, uint64_t qgroupid
, uint64_t **ret
) {
1755 struct btrfs_ioctl_search_args args
= {
1756 /* Tree of quota items */
1757 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1759 /* Look precisely for the quota relation items */
1760 .key
.min_type
= BTRFS_QGROUP_RELATION_KEY
,
1761 .key
.max_type
= BTRFS_QGROUP_RELATION_KEY
,
1763 /* No restrictions on the other components */
1764 .key
.min_offset
= 0,
1765 .key
.max_offset
= (uint64_t) -1,
1767 .key
.min_transid
= 0,
1768 .key
.max_transid
= (uint64_t) -1,
1771 _cleanup_free_
uint64_t *items
= NULL
;
1772 size_t n_items
= 0, n_allocated
= 0;
1778 if (qgroupid
== 0) {
1779 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
1783 r
= btrfs_is_filesystem(fd
);
1790 args
.key
.min_objectid
= args
.key
.max_objectid
= qgroupid
;
1792 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1793 const struct btrfs_ioctl_search_header
*sh
;
1796 args
.key
.nr_items
= 256;
1797 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1798 if (errno
== ENOENT
) /* quota tree missing: quota is disabled */
1804 if (args
.key
.nr_items
<= 0)
1807 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1809 /* Make sure we start the next search at least from this entry */
1810 btrfs_ioctl_search_args_set(&args
, sh
);
1812 if (sh
->type
!= BTRFS_QGROUP_RELATION_KEY
)
1814 if (sh
->offset
< sh
->objectid
)
1816 if (sh
->objectid
!= qgroupid
)
1819 if (!GREEDY_REALLOC(items
, n_allocated
, n_items
+1))
1822 items
[n_items
++] = sh
->offset
;
1825 /* Increase search key by one, to read the next item, if we can. */
1826 if (!btrfs_ioctl_search_args_inc(&args
))
1838 return (int) n_items
;
1841 int btrfs_subvol_auto_qgroup_fd(int fd
, uint64_t subvol_id
, bool insert_intermediary_qgroup
) {
1842 _cleanup_free_
uint64_t *qgroups
= NULL
;
1843 uint64_t parent_subvol
;
1844 bool changed
= false;
1850 * Sets up the specified subvolume's qgroup automatically in
1853 * If insert_intermediary_qgroup is false, the subvolume's
1854 * leaf qgroup will be assigned to the same parent qgroups as
1855 * the subvolume's parent subvolume.
1857 * If insert_intermediary_qgroup is true a new intermediary
1858 * higher-level qgroup is created, with a higher level number,
1859 * but reusing the id of the subvolume. The level number is
1860 * picked as one smaller than the lowest level qgroup the
1861 * parent subvolume is a member of. If the parent subvolume's
1862 * leaf qgroup is assigned to no higher-level qgroup a new
1863 * qgroup of level 255 is created instead. Either way, the new
1864 * qgroup is then assigned to the parent's higher-level
1865 * qgroup, and the subvolume itself is assigned to it.
1867 * If the subvolume is already assigned to a higher level
1868 * qgroup, no operation is executed.
1870 * Effectively this means: regardless if
1871 * insert_intermediary_qgroup is true or not, after this
1872 * function is invoked the subvolume will be accounted within
1873 * the same qgroups as the parent. However, if it is true, it
1874 * will also get its own higher-level qgroup, which may in
1875 * turn be used by subvolumes created beneath this subvolume
1878 * This hence defines a simple default qgroup setup for
1879 * subvolumes, as long as this function is invoked on each
1880 * created subvolume: each subvolume is always accounting
1881 * together with its immediate parents. Optionally, if
1882 * insert_intermediary_qgroup is true, it will also get a
1883 * qgroup that then includes all its own child subvolumes.
1886 if (subvol_id
== 0) {
1887 r
= btrfs_is_subvol_fd(fd
);
1893 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1898 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
1901 if (n
> 0) /* already parent qgroups set up, let's bail */
1904 qgroups
= mfree(qgroups
);
1906 r
= btrfs_subvol_get_parent(fd
, subvol_id
, &parent_subvol
);
1908 /* No parent, hence no qgroup memberships */
1913 n
= btrfs_qgroup_find_parents(fd
, parent_subvol
, &qgroups
);
1918 if (insert_intermediary_qgroup
) {
1919 uint64_t lowest
= 256, new_qgroupid
;
1920 bool created
= false;
1923 /* Determine the lowest qgroup that the parent
1924 * subvolume is assigned to. */
1926 for (i
= 0; i
< n
; i
++) {
1929 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, NULL
);
1937 if (lowest
<= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1940 r
= btrfs_qgroupid_make(lowest
- 1, subvol_id
, &new_qgroupid
);
1944 /* Create the new intermediary group, unless it already exists */
1945 r
= btrfs_qgroup_create(fd
, new_qgroupid
);
1946 if (r
< 0 && r
!= -EEXIST
)
1949 changed
= created
= true;
1951 for (i
= 0; i
< n
; i
++) {
1952 r
= btrfs_qgroup_assign(fd
, new_qgroupid
, qgroups
[i
]);
1953 if (r
< 0 && r
!= -EEXIST
) {
1955 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1963 r
= btrfs_qgroup_assign(fd
, subvol_id
, new_qgroupid
);
1964 if (r
< 0 && r
!= -EEXIST
) {
1966 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1975 /* Assign our subvolume to all the same qgroups as the parent */
1977 for (i
= 0; i
< n
; i
++) {
1978 r
= btrfs_qgroup_assign(fd
, subvol_id
, qgroups
[i
]);
1979 if (r
< 0 && r
!= -EEXIST
)
1989 int btrfs_subvol_auto_qgroup(const char *path
, uint64_t subvol_id
, bool create_intermediary_qgroup
) {
1990 _cleanup_close_
int fd
= -1;
1992 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1996 return btrfs_subvol_auto_qgroup_fd(fd
, subvol_id
, create_intermediary_qgroup
);
1999 int btrfs_subvol_get_parent(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
2001 struct btrfs_ioctl_search_args args
= {
2002 /* Tree of tree roots */
2003 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
2005 /* Look precisely for the subvolume items */
2006 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
2007 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
2009 /* No restrictions on the other components */
2010 .key
.min_offset
= 0,
2011 .key
.max_offset
= (uint64_t) -1,
2013 .key
.min_transid
= 0,
2014 .key
.max_transid
= (uint64_t) -1,
2021 if (subvol_id
== 0) {
2022 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
2026 r
= btrfs_is_filesystem(fd
);
2033 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
2035 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
2036 const struct btrfs_ioctl_search_header
*sh
;
2039 args
.key
.nr_items
= 256;
2040 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
2043 if (args
.key
.nr_items
<= 0)
2046 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
2048 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
2050 if (sh
->objectid
!= subvol_id
)