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(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_subvol_make(const char *path
) {
125 struct btrfs_ioctl_vol_args args
= {};
126 _cleanup_close_
int fd
= -1;
127 const char *subvolume
;
132 r
= extract_subvolume_name(path
, &subvolume
);
136 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
140 strncpy(args
.name
, subvolume
, sizeof(args
.name
)-1);
142 if (ioctl(fd
, BTRFS_IOC_SUBVOL_CREATE
, &args
) < 0)
148 int btrfs_subvol_make_label(const char *path
) {
153 r
= mac_selinux_create_file_prepare(path
, S_IFDIR
);
157 r
= btrfs_subvol_make(path
);
158 mac_selinux_create_file_clear();
163 return mac_smack_fix(path
, false, false);
166 int btrfs_subvol_set_read_only_fd(int fd
, bool b
) {
167 uint64_t flags
, nflags
;
172 if (fstat(fd
, &st
) < 0)
175 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
178 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
182 nflags
= flags
| BTRFS_SUBVOL_RDONLY
;
184 nflags
= flags
& ~BTRFS_SUBVOL_RDONLY
;
189 if (ioctl(fd
, BTRFS_IOC_SUBVOL_SETFLAGS
, &nflags
) < 0)
195 int btrfs_subvol_set_read_only(const char *path
, bool b
) {
196 _cleanup_close_
int fd
= -1;
198 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
202 return btrfs_subvol_set_read_only_fd(fd
, b
);
205 int btrfs_subvol_get_read_only_fd(int fd
) {
211 if (fstat(fd
, &st
) < 0)
214 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
217 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
220 return !!(flags
& BTRFS_SUBVOL_RDONLY
);
223 int btrfs_reflink(int infd
, int outfd
) {
230 /* Make sure we invoke the ioctl on a regular file, so that no
231 * device driver accidentally gets it. */
233 if (fstat(outfd
, &st
) < 0)
236 if (!S_ISREG(st
.st_mode
))
239 r
= ioctl(outfd
, BTRFS_IOC_CLONE
, infd
);
246 int btrfs_clone_range(int infd
, uint64_t in_offset
, int outfd
, uint64_t out_offset
, uint64_t sz
) {
247 struct btrfs_ioctl_clone_range_args args
= {
249 .src_offset
= in_offset
,
251 .dest_offset
= out_offset
,
260 if (fstat(outfd
, &st
) < 0)
263 if (!S_ISREG(st
.st_mode
))
266 r
= ioctl(outfd
, BTRFS_IOC_CLONE_RANGE
, &args
);
273 int btrfs_get_block_device_fd(int fd
, dev_t
*dev
) {
274 struct btrfs_ioctl_fs_info_args fsi
= {};
281 r
= btrfs_is_filesystem(fd
);
287 if (ioctl(fd
, BTRFS_IOC_FS_INFO
, &fsi
) < 0)
290 /* We won't do this for btrfs RAID */
291 if (fsi
.num_devices
!= 1)
294 for (id
= 1; id
<= fsi
.max_id
; id
++) {
295 struct btrfs_ioctl_dev_info_args di
= {
300 if (ioctl(fd
, BTRFS_IOC_DEV_INFO
, &di
) < 0) {
307 if (stat((char*) di
.path
, &st
) < 0)
310 if (!S_ISBLK(st
.st_mode
))
313 if (major(st
.st_rdev
) == 0)
323 int btrfs_get_block_device(const char *path
, dev_t
*dev
) {
324 _cleanup_close_
int fd
= -1;
329 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
333 return btrfs_get_block_device_fd(fd
, dev
);
336 int btrfs_subvol_get_id_fd(int fd
, uint64_t *ret
) {
337 struct btrfs_ioctl_ino_lookup_args args
= {
338 .objectid
= BTRFS_FIRST_FREE_OBJECTID
345 r
= btrfs_is_filesystem(fd
);
351 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
) < 0)
358 int btrfs_subvol_get_id(int fd
, const char *subvol
, uint64_t *ret
) {
359 _cleanup_close_
int subvol_fd
= -1;
364 subvol_fd
= openat(fd
, subvol
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
368 return btrfs_subvol_get_id_fd(subvol_fd
, ret
);
371 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args
*args
) {
374 /* the objectid, type, offset together make up the btrfs key,
375 * which is considered a single 136byte integer when
376 * comparing. This call increases the counter by one, dealing
377 * with the overflow between the overflows */
379 if (args
->key
.min_offset
< (uint64_t) -1) {
380 args
->key
.min_offset
++;
384 if (args
->key
.min_type
< (uint8_t) -1) {
385 args
->key
.min_type
++;
386 args
->key
.min_offset
= 0;
390 if (args
->key
.min_objectid
< (uint64_t) -1) {
391 args
->key
.min_objectid
++;
392 args
->key
.min_offset
= 0;
393 args
->key
.min_type
= 0;
400 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args
*args
, const struct btrfs_ioctl_search_header
*h
) {
404 args
->key
.min_objectid
= h
->objectid
;
405 args
->key
.min_type
= h
->type
;
406 args
->key
.min_offset
= h
->offset
;
409 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
*args
) {
412 /* Compare min and max */
414 if (args
->key
.min_objectid
< args
->key
.max_objectid
)
416 if (args
->key
.min_objectid
> args
->key
.max_objectid
)
419 if (args
->key
.min_type
< args
->key
.max_type
)
421 if (args
->key
.min_type
> args
->key
.max_type
)
424 if (args
->key
.min_offset
< args
->key
.max_offset
)
426 if (args
->key
.min_offset
> args
->key
.max_offset
)
432 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
434 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
435 (i) < (args).key.nr_items; \
437 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
439 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
440 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
442 int btrfs_subvol_get_info_fd(int fd
, uint64_t subvol_id
, BtrfsSubvolInfo
*ret
) {
443 struct btrfs_ioctl_search_args args
= {
444 /* Tree of tree roots */
445 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
447 /* Look precisely for the subvolume items */
448 .key
.min_type
= BTRFS_ROOT_ITEM_KEY
,
449 .key
.max_type
= BTRFS_ROOT_ITEM_KEY
,
452 .key
.max_offset
= (uint64_t) -1,
454 /* No restrictions on the other components */
455 .key
.min_transid
= 0,
456 .key
.max_transid
= (uint64_t) -1,
465 if (subvol_id
== 0) {
466 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
470 r
= btrfs_is_filesystem(fd
);
477 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
479 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
480 const struct btrfs_ioctl_search_header
*sh
;
483 args
.key
.nr_items
= 256;
484 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
487 if (args
.key
.nr_items
<= 0)
490 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
492 const struct btrfs_root_item
*ri
;
494 /* Make sure we start the next search at least from this entry */
495 btrfs_ioctl_search_args_set(&args
, sh
);
497 if (sh
->objectid
!= subvol_id
)
499 if (sh
->type
!= BTRFS_ROOT_ITEM_KEY
)
502 /* Older versions of the struct lacked the otime setting */
503 if (sh
->len
< offsetof(struct btrfs_root_item
, otime
) + sizeof(struct btrfs_timespec
))
506 ri
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
508 ret
->otime
= (usec_t
) le64toh(ri
->otime
.sec
) * USEC_PER_SEC
+
509 (usec_t
) le32toh(ri
->otime
.nsec
) / NSEC_PER_USEC
;
511 ret
->subvol_id
= subvol_id
;
512 ret
->read_only
= !!(le64toh(ri
->flags
) & BTRFS_ROOT_SUBVOL_RDONLY
);
514 assert_cc(sizeof(ri
->uuid
) == sizeof(ret
->uuid
));
515 memcpy(&ret
->uuid
, ri
->uuid
, sizeof(ret
->uuid
));
516 memcpy(&ret
->parent_uuid
, ri
->parent_uuid
, sizeof(ret
->parent_uuid
));
522 /* Increase search key by one, to read the next item, if we can. */
523 if (!btrfs_ioctl_search_args_inc(&args
))
534 int btrfs_qgroup_get_quota_fd(int fd
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
536 struct btrfs_ioctl_search_args args
= {
537 /* Tree of quota items */
538 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
540 /* The object ID is always 0 */
541 .key
.min_objectid
= 0,
542 .key
.max_objectid
= 0,
544 /* Look precisely for the quota items */
545 .key
.min_type
= BTRFS_QGROUP_STATUS_KEY
,
546 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
548 /* No restrictions on the other components */
549 .key
.min_transid
= 0,
550 .key
.max_transid
= (uint64_t) -1,
553 bool found_info
= false, found_limit
= false;
560 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
564 r
= btrfs_is_filesystem(fd
);
571 args
.key
.min_offset
= args
.key
.max_offset
= qgroupid
;
573 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
574 const struct btrfs_ioctl_search_header
*sh
;
577 args
.key
.nr_items
= 256;
578 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
579 if (errno
== ENOENT
) /* quota tree is missing: quota disabled */
585 if (args
.key
.nr_items
<= 0)
588 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
590 /* Make sure we start the next search at least from this entry */
591 btrfs_ioctl_search_args_set(&args
, sh
);
593 if (sh
->objectid
!= 0)
595 if (sh
->offset
!= qgroupid
)
598 if (sh
->type
== BTRFS_QGROUP_INFO_KEY
) {
599 const struct btrfs_qgroup_info_item
*qii
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
601 ret
->referenced
= le64toh(qii
->rfer
);
602 ret
->exclusive
= le64toh(qii
->excl
);
606 } else if (sh
->type
== BTRFS_QGROUP_LIMIT_KEY
) {
607 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
609 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_RFER
)
610 ret
->referenced_max
= le64toh(qli
->max_rfer
);
612 ret
->referenced_max
= (uint64_t) -1;
614 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_EXCL
)
615 ret
->exclusive_max
= le64toh(qli
->max_excl
);
617 ret
->exclusive_max
= (uint64_t) -1;
622 if (found_info
&& found_limit
)
626 /* Increase search key by one, to read the next item, if we can. */
627 if (!btrfs_ioctl_search_args_inc(&args
))
632 if (!found_limit
&& !found_info
)
636 ret
->referenced
= (uint64_t) -1;
637 ret
->exclusive
= (uint64_t) -1;
641 ret
->referenced_max
= (uint64_t) -1;
642 ret
->exclusive_max
= (uint64_t) -1;
648 int btrfs_qgroup_get_quota(const char *path
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
649 _cleanup_close_
int fd
= -1;
651 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
655 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
658 int btrfs_subvol_find_subtree_qgroup(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
659 uint64_t level
, lowest
= (uint64_t) -1, lowest_qgroupid
= 0;
660 _cleanup_free_
uint64_t *qgroups
= NULL
;
666 /* This finds the "subtree" qgroup for a specific
667 * subvolume. This only works for subvolumes that have been
668 * prepared with btrfs_subvol_auto_qgroup_fd() with
669 * insert_intermediary_qgroup=true (or equivalent). For others
670 * it will return the leaf qgroup instead. The two cases may
671 * be distuingished via the return value, which is 1 in case
672 * an appropriate "subtree" qgroup was found, and 0
675 if (subvol_id
== 0) {
676 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
681 r
= btrfs_qgroupid_split(subvol_id
, &level
, NULL
);
684 if (level
!= 0) /* Input must be a leaf qgroup */
687 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
691 for (i
= 0; i
< n
; i
++) {
694 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, &id
);
701 if (lowest
== (uint64_t) -1 || level
< lowest
) {
702 lowest_qgroupid
= qgroups
[i
];
707 if (lowest
== (uint64_t) -1) {
708 /* No suitable higher-level qgroup found, let's return
709 * the leaf qgroup instead, and indicate that with the
716 *ret
= lowest_qgroupid
;
720 int btrfs_subvol_get_subtree_quota_fd(int fd
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
727 /* This determines the quota data of the qgroup with the
728 * lowest level, that shares the id part with the specified
729 * subvolume. This is useful for determining the quota data
730 * for entire subvolume subtrees, as long as the subtrees have
731 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
734 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
738 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
741 int btrfs_subvol_get_subtree_quota(const char *path
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
742 _cleanup_close_
int fd
= -1;
744 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
748 return btrfs_subvol_get_subtree_quota_fd(fd
, subvol_id
, ret
);
751 int btrfs_defrag_fd(int fd
) {
756 if (fstat(fd
, &st
) < 0)
759 if (!S_ISREG(st
.st_mode
))
762 if (ioctl(fd
, BTRFS_IOC_DEFRAG
, NULL
) < 0)
768 int btrfs_defrag(const char *p
) {
769 _cleanup_close_
int fd
= -1;
771 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
775 return btrfs_defrag_fd(fd
);
778 int btrfs_quota_enable_fd(int fd
, bool b
) {
779 struct btrfs_ioctl_quota_ctl_args args
= {
780 .cmd
= b
? BTRFS_QUOTA_CTL_ENABLE
: BTRFS_QUOTA_CTL_DISABLE
,
786 r
= btrfs_is_filesystem(fd
);
792 if (ioctl(fd
, BTRFS_IOC_QUOTA_CTL
, &args
) < 0)
798 int btrfs_quota_enable(const char *path
, bool b
) {
799 _cleanup_close_
int fd
= -1;
801 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
805 return btrfs_quota_enable_fd(fd
, b
);
808 int btrfs_qgroup_set_limit_fd(int fd
, uint64_t qgroupid
, uint64_t referenced_max
) {
810 struct btrfs_ioctl_qgroup_limit_args args
= {
811 .lim
.max_rfer
= referenced_max
,
812 .lim
.flags
= BTRFS_QGROUP_LIMIT_MAX_RFER
,
820 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
824 r
= btrfs_is_filesystem(fd
);
831 args
.qgroupid
= qgroupid
;
834 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &args
) < 0) {
836 if (errno
== EBUSY
&& c
< 10) {
837 (void) btrfs_quota_scan_wait(fd
);
850 int btrfs_qgroup_set_limit(const char *path
, uint64_t qgroupid
, uint64_t referenced_max
) {
851 _cleanup_close_
int fd
= -1;
853 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
857 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
860 int btrfs_subvol_set_subtree_quota_limit_fd(int fd
, uint64_t subvol_id
, uint64_t referenced_max
) {
866 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
870 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
873 int btrfs_subvol_set_subtree_quota_limit(const char *path
, uint64_t subvol_id
, uint64_t referenced_max
) {
874 _cleanup_close_
int fd
= -1;
876 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
880 return btrfs_subvol_set_subtree_quota_limit_fd(fd
, subvol_id
, referenced_max
);
883 int btrfs_resize_loopback_fd(int fd
, uint64_t new_size
, bool grow_only
) {
884 struct btrfs_ioctl_vol_args args
= {};
885 _cleanup_free_
char *p
= NULL
, *loop
= NULL
, *backing
= NULL
;
886 _cleanup_close_
int loop_fd
= -1, backing_fd
= -1;
891 /* btrfs cannot handle file systems < 16M, hence use this as minimum */
892 if (new_size
< 16*1024*1024)
893 new_size
= 16*1024*1024;
895 r
= btrfs_get_block_device_fd(fd
, &dev
);
901 if (asprintf(&p
, "/sys/dev/block/%u:%u/loop/backing_file", major(dev
), minor(dev
)) < 0)
903 r
= read_one_line_file(p
, &backing
);
908 if (isempty(backing
) || !path_is_absolute(backing
))
911 backing_fd
= open(backing
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
915 if (fstat(backing_fd
, &st
) < 0)
917 if (!S_ISREG(st
.st_mode
))
920 if (new_size
== (uint64_t) st
.st_size
)
923 if (grow_only
&& new_size
< (uint64_t) st
.st_size
)
926 if (asprintf(&loop
, "/dev/block/%u:%u", major(dev
), minor(dev
)) < 0)
928 loop_fd
= open(loop
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
932 if (snprintf(args
.name
, sizeof(args
.name
), "%" PRIu64
, new_size
) >= (int) sizeof(args
.name
))
935 if (new_size
< (uint64_t) st
.st_size
) {
936 /* Decrease size: first decrease btrfs size, then shorten loopback */
937 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
941 if (ftruncate(backing_fd
, new_size
) < 0)
944 if (ioctl(loop_fd
, LOOP_SET_CAPACITY
, 0) < 0)
947 if (new_size
> (uint64_t) st
.st_size
) {
948 /* Increase size: first enlarge loopback, then increase btrfs size */
949 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
953 /* Make sure the free disk space is correctly updated for both file systems */
955 (void) fsync(backing_fd
);
960 int btrfs_resize_loopback(const char *p
, uint64_t new_size
, bool grow_only
) {
961 _cleanup_close_
int fd
= -1;
963 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
967 return btrfs_resize_loopback_fd(fd
, new_size
, grow_only
);
970 int btrfs_qgroupid_make(uint64_t level
, uint64_t id
, uint64_t *ret
) {
973 if (level
>= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT
)))
976 if (id
>= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
))
979 *ret
= (level
<< BTRFS_QGROUP_LEVEL_SHIFT
) | id
;
983 int btrfs_qgroupid_split(uint64_t qgroupid
, uint64_t *level
, uint64_t *id
) {
987 *level
= qgroupid
>> BTRFS_QGROUP_LEVEL_SHIFT
;
990 *id
= qgroupid
& ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
) - 1);
995 static int qgroup_create_or_destroy(int fd
, bool b
, uint64_t qgroupid
) {
997 struct btrfs_ioctl_qgroup_create_args args
= {
999 .qgroupid
= qgroupid
,
1004 r
= btrfs_is_filesystem(fd
);
1011 if (ioctl(fd
, BTRFS_IOC_QGROUP_CREATE
, &args
) < 0) {
1013 if (errno
== EBUSY
&& c
< 10) {
1014 (void) btrfs_quota_scan_wait(fd
);
1027 int btrfs_qgroup_create(int fd
, uint64_t qgroupid
) {
1028 return qgroup_create_or_destroy(fd
, true, qgroupid
);
1031 int btrfs_qgroup_destroy(int fd
, uint64_t qgroupid
) {
1032 return qgroup_create_or_destroy(fd
, false, qgroupid
);
1035 int btrfs_qgroup_destroy_recursive(int fd
, uint64_t qgroupid
) {
1036 _cleanup_free_
uint64_t *qgroups
= NULL
;
1040 /* Destroys the specified qgroup, but unassigns it from all
1041 * its parents first. Also, it recursively destroys all
1042 * qgroups it is assgined to that have the same id part of the
1043 * qgroupid as the specified group. */
1045 r
= btrfs_qgroupid_split(qgroupid
, NULL
, &subvol_id
);
1049 n
= btrfs_qgroup_find_parents(fd
, qgroupid
, &qgroups
);
1053 for (i
= 0; i
< n
; i
++) {
1056 r
= btrfs_qgroupid_split(qgroups
[i
], NULL
, &id
);
1060 r
= btrfs_qgroup_unassign(fd
, qgroupid
, qgroups
[i
]);
1064 if (id
!= subvol_id
)
1067 /* The parent qgroupid shares the same id part with
1068 * us? If so, destroy it too. */
1070 (void) btrfs_qgroup_destroy_recursive(fd
, qgroups
[i
]);
1073 return btrfs_qgroup_destroy(fd
, qgroupid
);
1076 int btrfs_quota_scan_start(int fd
) {
1077 struct btrfs_ioctl_quota_rescan_args args
= {};
1081 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN
, &args
) < 0)
1087 int btrfs_quota_scan_wait(int fd
) {
1090 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_WAIT
) < 0)
1096 int btrfs_quota_scan_ongoing(int fd
) {
1097 struct btrfs_ioctl_quota_rescan_args args
= {};
1101 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_STATUS
, &args
) < 0)
1104 return !!args
.flags
;
1107 static int qgroup_assign_or_unassign(int fd
, bool b
, uint64_t child
, uint64_t parent
) {
1108 struct btrfs_ioctl_qgroup_assign_args args
= {
1116 r
= btrfs_is_filesystem(fd
);
1123 r
= ioctl(fd
, BTRFS_IOC_QGROUP_ASSIGN
, &args
);
1125 if (errno
== EBUSY
&& c
< 10) {
1126 (void) btrfs_quota_scan_wait(fd
);
1136 /* If the return value is > 0, we need to request a rescan */
1138 (void) btrfs_quota_scan_start(fd
);
1143 int btrfs_qgroup_assign(int fd
, uint64_t child
, uint64_t parent
) {
1144 return qgroup_assign_or_unassign(fd
, true, child
, parent
);
1147 int btrfs_qgroup_unassign(int fd
, uint64_t child
, uint64_t parent
) {
1148 return qgroup_assign_or_unassign(fd
, false, child
, parent
);
1151 static int subvol_remove_children(int fd
, const char *subvolume
, uint64_t subvol_id
, BtrfsRemoveFlags flags
) {
1152 struct btrfs_ioctl_search_args args
= {
1153 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1155 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1156 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1158 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1159 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1161 .key
.min_transid
= 0,
1162 .key
.max_transid
= (uint64_t) -1,
1165 struct btrfs_ioctl_vol_args vol_args
= {};
1166 _cleanup_close_
int subvol_fd
= -1;
1168 bool made_writable
= false;
1174 if (fstat(fd
, &st
) < 0)
1177 if (!S_ISDIR(st
.st_mode
))
1180 subvol_fd
= openat(fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1184 if (subvol_id
== 0) {
1185 r
= btrfs_subvol_get_id_fd(subvol_fd
, &subvol_id
);
1190 /* First, try to remove the subvolume. If it happens to be
1191 * already empty, this will just work. */
1192 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1193 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) >= 0) {
1194 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1197 if (!(flags
& BTRFS_REMOVE_RECURSIVE
) || errno
!= ENOTEMPTY
)
1200 /* OK, the subvolume is not empty, let's look for child
1201 * subvolumes, and remove them, first */
1203 args
.key
.min_offset
= args
.key
.max_offset
= subvol_id
;
1205 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1206 const struct btrfs_ioctl_search_header
*sh
;
1209 args
.key
.nr_items
= 256;
1210 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1213 if (args
.key
.nr_items
<= 0)
1216 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1217 _cleanup_free_
char *p
= NULL
;
1218 const struct btrfs_root_ref
*ref
;
1219 struct btrfs_ioctl_ino_lookup_args ino_args
;
1221 btrfs_ioctl_search_args_set(&args
, sh
);
1223 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1225 if (sh
->offset
!= subvol_id
)
1228 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1230 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1235 ino_args
.treeid
= subvol_id
;
1236 ino_args
.objectid
= htole64(ref
->dirid
);
1238 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1241 if (!made_writable
) {
1242 r
= btrfs_subvol_set_read_only_fd(subvol_fd
, false);
1246 made_writable
= true;
1249 if (isempty(ino_args
.name
))
1250 /* Subvolume is in the top-level
1251 * directory of the subvolume. */
1252 r
= subvol_remove_children(subvol_fd
, p
, sh
->objectid
, flags
);
1254 _cleanup_close_
int child_fd
= -1;
1256 /* Subvolume is somewhere further down,
1257 * hence we need to open the
1258 * containing directory first */
1260 child_fd
= openat(subvol_fd
, ino_args
.name
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1264 r
= subvol_remove_children(child_fd
, p
, sh
->objectid
, flags
);
1270 /* Increase search key by one, to read the next item, if we can. */
1271 if (!btrfs_ioctl_search_args_inc(&args
))
1275 /* OK, the child subvolumes should all be gone now, let's try
1276 * again to remove the subvolume */
1277 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) < 0)
1280 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
);
1284 int btrfs_subvol_remove(const char *path
, BtrfsRemoveFlags flags
) {
1285 _cleanup_close_
int fd
= -1;
1286 const char *subvolume
;
1291 r
= extract_subvolume_name(path
, &subvolume
);
1295 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1299 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1302 int btrfs_subvol_remove_fd(int fd
, const char *subvolume
, BtrfsRemoveFlags flags
) {
1303 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1306 int btrfs_qgroup_copy_limits(int fd
, uint64_t old_qgroupid
, uint64_t new_qgroupid
) {
1308 struct btrfs_ioctl_search_args args
= {
1309 /* Tree of quota items */
1310 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1312 /* The object ID is always 0 */
1313 .key
.min_objectid
= 0,
1314 .key
.max_objectid
= 0,
1316 /* Look precisely for the quota items */
1317 .key
.min_type
= BTRFS_QGROUP_LIMIT_KEY
,
1318 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
1320 /* For our qgroup */
1321 .key
.min_offset
= old_qgroupid
,
1322 .key
.max_offset
= old_qgroupid
,
1324 /* No restrictions on the other components */
1325 .key
.min_transid
= 0,
1326 .key
.max_transid
= (uint64_t) -1,
1331 r
= btrfs_is_filesystem(fd
);
1337 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1338 const struct btrfs_ioctl_search_header
*sh
;
1341 args
.key
.nr_items
= 256;
1342 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1343 if (errno
== ENOENT
) /* quota tree missing: quota is not enabled, hence nothing to copy */
1349 if (args
.key
.nr_items
<= 0)
1352 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1353 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1354 struct btrfs_ioctl_qgroup_limit_args qargs
;
1357 /* Make sure we start the next search at least from this entry */
1358 btrfs_ioctl_search_args_set(&args
, sh
);
1360 if (sh
->objectid
!= 0)
1362 if (sh
->type
!= BTRFS_QGROUP_LIMIT_KEY
)
1364 if (sh
->offset
!= old_qgroupid
)
1367 /* We found the entry, now copy things over. */
1369 qargs
= (struct btrfs_ioctl_qgroup_limit_args
) {
1370 .qgroupid
= new_qgroupid
,
1372 .lim
.max_rfer
= le64toh(qli
->max_rfer
),
1373 .lim
.max_excl
= le64toh(qli
->max_excl
),
1374 .lim
.rsv_rfer
= le64toh(qli
->rsv_rfer
),
1375 .lim
.rsv_excl
= le64toh(qli
->rsv_excl
),
1377 .lim
.flags
= le64toh(qli
->flags
) & (BTRFS_QGROUP_LIMIT_MAX_RFER
|
1378 BTRFS_QGROUP_LIMIT_MAX_EXCL
|
1379 BTRFS_QGROUP_LIMIT_RSV_RFER
|
1380 BTRFS_QGROUP_LIMIT_RSV_EXCL
),
1384 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &qargs
) < 0) {
1385 if (errno
== EBUSY
&& c
< 10) {
1386 (void) btrfs_quota_scan_wait(fd
);
1398 /* Increase search key by one, to read the next item, if we can. */
1399 if (!btrfs_ioctl_search_args_inc(&args
))
1406 static int copy_quota_hierarchy(int fd
, uint64_t old_subvol_id
, uint64_t new_subvol_id
) {
1407 _cleanup_free_
uint64_t *old_qgroups
= NULL
, *old_parent_qgroups
= NULL
;
1408 bool copy_from_parent
= false, insert_intermediary_qgroup
= false;
1409 int n_old_qgroups
, n_old_parent_qgroups
, r
, i
;
1410 uint64_t old_parent_id
;
1414 /* Copies a reduced form of quota information from the old to
1415 * the new subvolume. */
1417 n_old_qgroups
= btrfs_qgroup_find_parents(fd
, old_subvol_id
, &old_qgroups
);
1418 if (n_old_qgroups
<= 0) /* Nothing to copy */
1419 return n_old_qgroups
;
1421 r
= btrfs_subvol_get_parent(fd
, old_subvol_id
, &old_parent_id
);
1425 n_old_parent_qgroups
= btrfs_qgroup_find_parents(fd
, old_parent_id
, &old_parent_qgroups
);
1426 if (n_old_parent_qgroups
< 0)
1427 return n_old_parent_qgroups
;
1429 for (i
= 0; i
< n_old_qgroups
; i
++) {
1433 r
= btrfs_qgroupid_split(old_qgroups
[i
], NULL
, &id
);
1437 if (id
== old_subvol_id
) {
1438 /* The old subvolume was member of a qgroup
1439 * that had the same id, but a different level
1440 * as it self. Let's set up something similar
1441 * in the destination. */
1442 insert_intermediary_qgroup
= true;
1446 for (j
= 0; j
< n_old_parent_qgroups
; j
++)
1447 if (old_parent_qgroups
[j
] == old_qgroups
[i
]) {
1448 /* The old subvolume shared a common
1449 * parent qgroup with its parent
1450 * subvolume. Let's set up something
1451 * similar in the destination. */
1452 copy_from_parent
= true;
1456 if (!insert_intermediary_qgroup
&& !copy_from_parent
)
1459 return btrfs_subvol_auto_qgroup_fd(fd
, new_subvol_id
, insert_intermediary_qgroup
);
1462 static int copy_subtree_quota_limits(int fd
, uint64_t old_subvol
, uint64_t new_subvol
) {
1463 uint64_t old_subtree_qgroup
, new_subtree_qgroup
;
1467 /* First copy the leaf limits */
1468 r
= btrfs_qgroup_copy_limits(fd
, old_subvol
, new_subvol
);
1473 /* Then, try to copy the subtree limits, if there are any. */
1474 r
= btrfs_subvol_find_subtree_qgroup(fd
, old_subvol
, &old_subtree_qgroup
);
1480 r
= btrfs_subvol_find_subtree_qgroup(fd
, new_subvol
, &new_subtree_qgroup
);
1486 r
= btrfs_qgroup_copy_limits(fd
, old_subtree_qgroup
, new_subtree_qgroup
);
1493 static int subvol_snapshot_children(int old_fd
, int new_fd
, const char *subvolume
, uint64_t old_subvol_id
, BtrfsSnapshotFlags flags
) {
1495 struct btrfs_ioctl_search_args args
= {
1496 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1498 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1499 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1501 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1502 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1504 .key
.min_transid
= 0,
1505 .key
.max_transid
= (uint64_t) -1,
1508 struct btrfs_ioctl_vol_args_v2 vol_args
= {
1509 .flags
= flags
& BTRFS_SNAPSHOT_READ_ONLY
? BTRFS_SUBVOL_RDONLY
: 0,
1512 _cleanup_close_
int subvolume_fd
= -1;
1513 uint64_t new_subvol_id
;
1516 assert(old_fd
>= 0);
1517 assert(new_fd
>= 0);
1520 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1522 if (ioctl(new_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &vol_args
) < 0)
1525 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
) &&
1526 !(flags
& BTRFS_SNAPSHOT_QUOTA
))
1529 if (old_subvol_id
== 0) {
1530 r
= btrfs_subvol_get_id_fd(old_fd
, &old_subvol_id
);
1535 r
= btrfs_subvol_get_id(new_fd
, vol_args
.name
, &new_subvol_id
);
1539 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1540 (void) copy_quota_hierarchy(new_fd
, old_subvol_id
, new_subvol_id
);
1542 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
)) {
1544 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1545 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1550 args
.key
.min_offset
= args
.key
.max_offset
= old_subvol_id
;
1552 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1553 const struct btrfs_ioctl_search_header
*sh
;
1556 args
.key
.nr_items
= 256;
1557 if (ioctl(old_fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1560 if (args
.key
.nr_items
<= 0)
1563 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1564 _cleanup_free_
char *p
= NULL
, *c
= NULL
, *np
= NULL
;
1565 struct btrfs_ioctl_ino_lookup_args ino_args
;
1566 const struct btrfs_root_ref
*ref
;
1567 _cleanup_close_
int old_child_fd
= -1, new_child_fd
= -1;
1569 btrfs_ioctl_search_args_set(&args
, sh
);
1571 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1574 /* Avoid finding the source subvolume a second
1576 if (sh
->offset
!= old_subvol_id
)
1579 /* Avoid running into loops if the new
1580 * subvolume is below the old one. */
1581 if (sh
->objectid
== new_subvol_id
)
1584 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1585 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1590 ino_args
.treeid
= old_subvol_id
;
1591 ino_args
.objectid
= htole64(ref
->dirid
);
1593 if (ioctl(old_fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1596 /* The kernel returns an empty name if the
1597 * subvolume is in the top-level directory,
1598 * and otherwise appends a slash, so that we
1599 * can just concatenate easily here, without
1600 * adding a slash. */
1601 c
= strappend(ino_args
.name
, p
);
1605 old_child_fd
= openat(old_fd
, c
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1606 if (old_child_fd
< 0)
1609 np
= strjoin(subvolume
, "/", ino_args
.name
, NULL
);
1613 new_child_fd
= openat(new_fd
, np
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1614 if (new_child_fd
< 0)
1617 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1618 /* If the snapshot is read-only we
1619 * need to mark it writable
1620 * temporarily, to put the subsnapshot
1623 if (subvolume_fd
< 0) {
1624 subvolume_fd
= openat(new_fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1625 if (subvolume_fd
< 0)
1629 r
= btrfs_subvol_set_read_only_fd(subvolume_fd
, false);
1634 /* When btrfs clones the subvolumes, child
1635 * subvolumes appear as empty directories. Remove
1636 * them, so that we can create a new snapshot
1638 if (unlinkat(new_child_fd
, p
, AT_REMOVEDIR
) < 0) {
1641 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
)
1642 (void) btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1647 r
= subvol_snapshot_children(old_child_fd
, new_child_fd
, p
, sh
->objectid
, flags
& ~BTRFS_SNAPSHOT_FALLBACK_COPY
);
1649 /* Restore the readonly flag */
1650 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1653 k
= btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1654 if (r
>= 0 && k
< 0)
1662 /* Increase search key by one, to read the next item, if we can. */
1663 if (!btrfs_ioctl_search_args_inc(&args
))
1667 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1668 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1673 int btrfs_subvol_snapshot_fd(int old_fd
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1674 _cleanup_close_
int new_fd
= -1;
1675 const char *subvolume
;
1678 assert(old_fd
>= 0);
1681 r
= btrfs_is_subvol(old_fd
);
1685 if (!(flags
& BTRFS_SNAPSHOT_FALLBACK_COPY
))
1688 r
= btrfs_subvol_make(new_path
);
1692 r
= copy_directory_fd(old_fd
, new_path
, true);
1694 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1698 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1699 r
= btrfs_subvol_set_read_only(new_path
, true);
1701 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1709 r
= extract_subvolume_name(new_path
, &subvolume
);
1713 new_fd
= open_parent(new_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1717 return subvol_snapshot_children(old_fd
, new_fd
, subvolume
, 0, flags
);
1720 int btrfs_subvol_snapshot(const char *old_path
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1721 _cleanup_close_
int old_fd
= -1;
1726 old_fd
= open(old_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1730 return btrfs_subvol_snapshot_fd(old_fd
, new_path
, flags
);
1733 int btrfs_qgroup_find_parents(int fd
, uint64_t qgroupid
, uint64_t **ret
) {
1735 struct btrfs_ioctl_search_args args
= {
1736 /* Tree of quota items */
1737 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1739 /* Look precisely for the quota relation items */
1740 .key
.min_type
= BTRFS_QGROUP_RELATION_KEY
,
1741 .key
.max_type
= BTRFS_QGROUP_RELATION_KEY
,
1743 /* No restrictions on the other components */
1744 .key
.min_offset
= 0,
1745 .key
.max_offset
= (uint64_t) -1,
1747 .key
.min_transid
= 0,
1748 .key
.max_transid
= (uint64_t) -1,
1751 _cleanup_free_
uint64_t *items
= NULL
;
1752 size_t n_items
= 0, n_allocated
= 0;
1758 if (qgroupid
== 0) {
1759 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
1763 r
= btrfs_is_filesystem(fd
);
1770 args
.key
.min_objectid
= args
.key
.max_objectid
= qgroupid
;
1772 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1773 const struct btrfs_ioctl_search_header
*sh
;
1776 args
.key
.nr_items
= 256;
1777 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1778 if (errno
== ENOENT
) /* quota tree missing: quota is disabled */
1784 if (args
.key
.nr_items
<= 0)
1787 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1789 /* Make sure we start the next search at least from this entry */
1790 btrfs_ioctl_search_args_set(&args
, sh
);
1792 if (sh
->type
!= BTRFS_QGROUP_RELATION_KEY
)
1794 if (sh
->offset
< sh
->objectid
)
1796 if (sh
->objectid
!= qgroupid
)
1799 if (!GREEDY_REALLOC(items
, n_allocated
, n_items
+1))
1802 items
[n_items
++] = sh
->offset
;
1805 /* Increase search key by one, to read the next item, if we can. */
1806 if (!btrfs_ioctl_search_args_inc(&args
))
1818 return (int) n_items
;
1821 int btrfs_subvol_auto_qgroup_fd(int fd
, uint64_t subvol_id
, bool insert_intermediary_qgroup
) {
1822 _cleanup_free_
uint64_t *qgroups
= NULL
;
1823 uint64_t parent_subvol
;
1824 bool changed
= false;
1830 * Sets up the specified subvolume's qgroup automatically in
1833 * If insert_intermediary_qgroup is false, the subvolume's
1834 * leaf qgroup will be assigned to the same parent qgroups as
1835 * the subvolume's parent subvolume.
1837 * If insert_intermediary_qgroup is true a new intermediary
1838 * higher-level qgroup is created, with a higher level number,
1839 * but reusing the id of the subvolume. The level number is
1840 * picked as one smaller than the lowest level qgroup the
1841 * parent subvolume is a member of. If the parent subvolume's
1842 * leaf qgroup is assigned to no higher-level qgroup a new
1843 * qgroup of level 255 is created instead. Either way, the new
1844 * qgroup is then assigned to the parent's higher-level
1845 * qgroup, and the subvolume itself is assigned to it.
1847 * If the subvolume is already assigned to a higher level
1848 * qgroup, no operation is executed.
1850 * Effectively this means: regardless if
1851 * insert_intermediary_qgroup is true or not, after this
1852 * function is invoked the subvolume will be accounted within
1853 * the same qgroups as the parent. However, if it is true, it
1854 * will also get its own higher-level qgroup, which may in
1855 * turn be used by subvolumes created beneath this subvolume
1858 * This hence defines a simple default qgroup setup for
1859 * subvolumes, as long as this function is invoked on each
1860 * created subvolume: each subvolume is always accounting
1861 * together with its immediate parents. Optionally, if
1862 * insert_intermediary_qgroup is true, it will also get a
1863 * qgroup that then includes all its own child subvolumes.
1866 if (subvol_id
== 0) {
1867 r
= btrfs_is_subvol(fd
);
1873 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1878 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
1881 if (n
> 0) /* already parent qgroups set up, let's bail */
1884 r
= btrfs_subvol_get_parent(fd
, subvol_id
, &parent_subvol
);
1888 qgroups
= mfree(qgroups
);
1889 n
= btrfs_qgroup_find_parents(fd
, parent_subvol
, &qgroups
);
1893 if (insert_intermediary_qgroup
) {
1894 uint64_t lowest
= 256, new_qgroupid
;
1895 bool created
= false;
1898 /* Determine the lowest qgroup that the parent
1899 * subvolume is assigned to. */
1901 for (i
= 0; i
< n
; i
++) {
1904 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, NULL
);
1912 if (lowest
<= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1915 r
= btrfs_qgroupid_make(lowest
- 1, subvol_id
, &new_qgroupid
);
1919 /* Create the new intermediary group, unless it already exists */
1920 r
= btrfs_qgroup_create(fd
, new_qgroupid
);
1921 if (r
< 0 && r
!= -EEXIST
)
1924 changed
= created
= true;
1926 for (i
= 0; i
< n
; i
++) {
1927 r
= btrfs_qgroup_assign(fd
, new_qgroupid
, qgroups
[i
]);
1928 if (r
< 0 && r
!= -EEXIST
) {
1930 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1938 r
= btrfs_qgroup_assign(fd
, subvol_id
, new_qgroupid
);
1939 if (r
< 0 && r
!= -EEXIST
) {
1941 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1950 /* Assign our subvolume to all the same qgroups as the parent */
1952 for (i
= 0; i
< n
; i
++) {
1953 r
= btrfs_qgroup_assign(fd
, subvol_id
, qgroups
[i
]);
1954 if (r
< 0 && r
!= -EEXIST
)
1964 int btrfs_subvol_auto_qgroup(const char *path
, uint64_t subvol_id
, bool create_intermediary_qgroup
) {
1965 _cleanup_close_
int fd
= -1;
1967 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1971 return btrfs_subvol_auto_qgroup_fd(fd
, subvol_id
, create_intermediary_qgroup
);
1974 int btrfs_subvol_get_parent(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
1976 struct btrfs_ioctl_search_args args
= {
1977 /* Tree of tree roots */
1978 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1980 /* Look precisely for the subvolume items */
1981 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1982 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1984 /* No restrictions on the other components */
1985 .key
.min_offset
= 0,
1986 .key
.max_offset
= (uint64_t) -1,
1988 .key
.min_transid
= 0,
1989 .key
.max_transid
= (uint64_t) -1,
1996 if (subvol_id
== 0) {
1997 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
2001 r
= btrfs_is_filesystem(fd
);
2008 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
2010 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
2011 const struct btrfs_ioctl_search_header
*sh
;
2014 args
.key
.nr_items
= 256;
2015 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
2018 if (args
.key
.nr_items
<= 0)
2021 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
2023 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
2025 if (sh
->objectid
!= subvol_id
)