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)
581 if (args
.key
.nr_items
<= 0)
584 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
586 /* Make sure we start the next search at least from this entry */
587 btrfs_ioctl_search_args_set(&args
, sh
);
589 if (sh
->objectid
!= 0)
591 if (sh
->offset
!= qgroupid
)
594 if (sh
->type
== BTRFS_QGROUP_INFO_KEY
) {
595 const struct btrfs_qgroup_info_item
*qii
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
597 ret
->referenced
= le64toh(qii
->rfer
);
598 ret
->exclusive
= le64toh(qii
->excl
);
602 } else if (sh
->type
== BTRFS_QGROUP_LIMIT_KEY
) {
603 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
605 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_RFER
)
606 ret
->referenced_max
= le64toh(qli
->max_rfer
);
608 ret
->referenced_max
= (uint64_t) -1;
610 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_EXCL
)
611 ret
->exclusive_max
= le64toh(qli
->max_excl
);
613 ret
->exclusive_max
= (uint64_t) -1;
618 if (found_info
&& found_limit
)
622 /* Increase search key by one, to read the next item, if we can. */
623 if (!btrfs_ioctl_search_args_inc(&args
))
628 if (!found_limit
&& !found_info
)
632 ret
->referenced
= (uint64_t) -1;
633 ret
->exclusive
= (uint64_t) -1;
637 ret
->referenced_max
= (uint64_t) -1;
638 ret
->exclusive_max
= (uint64_t) -1;
644 int btrfs_qgroup_get_quota(const char *path
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
645 _cleanup_close_
int fd
= -1;
647 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
651 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
654 int btrfs_subvol_find_subtree_qgroup(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
655 uint64_t level
, lowest
= (uint64_t) -1, lowest_qgroupid
= 0;
656 _cleanup_free_
uint64_t *qgroups
= NULL
;
662 /* This finds the "subtree" qgroup for a specific
663 * subvolume. This only works for subvolumes that have been
664 * prepared with btrfs_subvol_auto_qgroup_fd() with
665 * insert_intermediary_qgroup=true (or equivalent). For others
666 * it will return the leaf qgroup instead. The two cases may
667 * be distuingished via the return value, which is 1 in case
668 * an appropriate "subtree" qgroup was found, and 0
671 if (subvol_id
== 0) {
672 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
677 r
= btrfs_qgroupid_split(subvol_id
, &level
, NULL
);
680 if (level
!= 0) /* Input must be a leaf qgroup */
683 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
687 for (i
= 0; i
< n
; i
++) {
690 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, &id
);
697 if (lowest
== (uint64_t) -1 || level
< lowest
) {
698 lowest_qgroupid
= qgroups
[i
];
703 if (lowest
== (uint64_t) -1) {
704 /* No suitable higher-level qgroup found, let's return
705 * the leaf qgroup instead, and indicate that with the
712 *ret
= lowest_qgroupid
;
716 int btrfs_subvol_get_subtree_quota_fd(int fd
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
723 /* This determines the quota data of the qgroup with the
724 * lowest level, that shares the id part with the specified
725 * subvolume. This is useful for determining the quota data
726 * for entire subvolume subtrees, as long as the subtrees have
727 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
730 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
734 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
737 int btrfs_subvol_get_subtree_quota(const char *path
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
738 _cleanup_close_
int fd
= -1;
740 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
744 return btrfs_subvol_get_subtree_quota_fd(fd
, subvol_id
, ret
);
747 int btrfs_defrag_fd(int fd
) {
752 if (fstat(fd
, &st
) < 0)
755 if (!S_ISREG(st
.st_mode
))
758 if (ioctl(fd
, BTRFS_IOC_DEFRAG
, NULL
) < 0)
764 int btrfs_defrag(const char *p
) {
765 _cleanup_close_
int fd
= -1;
767 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
771 return btrfs_defrag_fd(fd
);
774 int btrfs_quota_enable_fd(int fd
, bool b
) {
775 struct btrfs_ioctl_quota_ctl_args args
= {
776 .cmd
= b
? BTRFS_QUOTA_CTL_ENABLE
: BTRFS_QUOTA_CTL_DISABLE
,
782 r
= btrfs_is_filesystem(fd
);
788 if (ioctl(fd
, BTRFS_IOC_QUOTA_CTL
, &args
) < 0)
794 int btrfs_quota_enable(const char *path
, bool b
) {
795 _cleanup_close_
int fd
= -1;
797 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
801 return btrfs_quota_enable_fd(fd
, b
);
804 int btrfs_qgroup_set_limit_fd(int fd
, uint64_t qgroupid
, uint64_t referenced_max
) {
806 struct btrfs_ioctl_qgroup_limit_args args
= {
807 .lim
.max_rfer
= referenced_max
,
808 .lim
.flags
= BTRFS_QGROUP_LIMIT_MAX_RFER
,
816 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
820 r
= btrfs_is_filesystem(fd
);
827 args
.qgroupid
= qgroupid
;
830 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &args
) < 0) {
832 if (errno
== EBUSY
&& c
< 10) {
833 (void) btrfs_quota_scan_wait(fd
);
846 int btrfs_qgroup_set_limit(const char *path
, uint64_t qgroupid
, uint64_t referenced_max
) {
847 _cleanup_close_
int fd
= -1;
849 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
853 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
856 int btrfs_subvol_set_subtree_quota_limit_fd(int fd
, uint64_t subvol_id
, uint64_t referenced_max
) {
862 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
866 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
869 int btrfs_subvol_set_subtree_quota_limit(const char *path
, uint64_t subvol_id
, uint64_t referenced_max
) {
870 _cleanup_close_
int fd
= -1;
872 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
876 return btrfs_subvol_set_subtree_quota_limit_fd(fd
, subvol_id
, referenced_max
);
879 int btrfs_resize_loopback_fd(int fd
, uint64_t new_size
, bool grow_only
) {
880 struct btrfs_ioctl_vol_args args
= {};
881 _cleanup_free_
char *p
= NULL
, *loop
= NULL
, *backing
= NULL
;
882 _cleanup_close_
int loop_fd
= -1, backing_fd
= -1;
887 /* btrfs cannot handle file systems < 16M, hence use this as minimum */
888 if (new_size
< 16*1024*1024)
889 new_size
= 16*1024*1024;
891 r
= btrfs_get_block_device_fd(fd
, &dev
);
897 if (asprintf(&p
, "/sys/dev/block/%u:%u/loop/backing_file", major(dev
), minor(dev
)) < 0)
899 r
= read_one_line_file(p
, &backing
);
904 if (isempty(backing
) || !path_is_absolute(backing
))
907 backing_fd
= open(backing
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
911 if (fstat(backing_fd
, &st
) < 0)
913 if (!S_ISREG(st
.st_mode
))
916 if (new_size
== (uint64_t) st
.st_size
)
919 if (grow_only
&& new_size
< (uint64_t) st
.st_size
)
922 if (asprintf(&loop
, "/dev/block/%u:%u", major(dev
), minor(dev
)) < 0)
924 loop_fd
= open(loop
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
928 if (snprintf(args
.name
, sizeof(args
.name
), "%" PRIu64
, new_size
) >= (int) sizeof(args
.name
))
931 if (new_size
< (uint64_t) st
.st_size
) {
932 /* Decrease size: first decrease btrfs size, then shorten loopback */
933 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
937 if (ftruncate(backing_fd
, new_size
) < 0)
940 if (ioctl(loop_fd
, LOOP_SET_CAPACITY
, 0) < 0)
943 if (new_size
> (uint64_t) st
.st_size
) {
944 /* Increase size: first enlarge loopback, then increase btrfs size */
945 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
949 /* Make sure the free disk space is correctly updated for both file systems */
951 (void) fsync(backing_fd
);
956 int btrfs_resize_loopback(const char *p
, uint64_t new_size
, bool grow_only
) {
957 _cleanup_close_
int fd
= -1;
959 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
963 return btrfs_resize_loopback_fd(fd
, new_size
, grow_only
);
966 int btrfs_qgroupid_make(uint64_t level
, uint64_t id
, uint64_t *ret
) {
969 if (level
>= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT
)))
972 if (id
>= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
))
975 *ret
= (level
<< BTRFS_QGROUP_LEVEL_SHIFT
) | id
;
979 int btrfs_qgroupid_split(uint64_t qgroupid
, uint64_t *level
, uint64_t *id
) {
983 *level
= qgroupid
>> BTRFS_QGROUP_LEVEL_SHIFT
;
986 *id
= qgroupid
& ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
) - 1);
991 static int qgroup_create_or_destroy(int fd
, bool b
, uint64_t qgroupid
) {
993 struct btrfs_ioctl_qgroup_create_args args
= {
995 .qgroupid
= qgroupid
,
1000 r
= btrfs_is_filesystem(fd
);
1007 if (ioctl(fd
, BTRFS_IOC_QGROUP_CREATE
, &args
) < 0) {
1009 if (errno
== EBUSY
&& c
< 10) {
1010 (void) btrfs_quota_scan_wait(fd
);
1023 int btrfs_qgroup_create(int fd
, uint64_t qgroupid
) {
1024 return qgroup_create_or_destroy(fd
, true, qgroupid
);
1027 int btrfs_qgroup_destroy(int fd
, uint64_t qgroupid
) {
1028 return qgroup_create_or_destroy(fd
, false, qgroupid
);
1031 int btrfs_qgroup_destroy_recursive(int fd
, uint64_t qgroupid
) {
1032 _cleanup_free_
uint64_t *qgroups
= NULL
;
1036 /* Destroys the specified qgroup, but unassigns it from all
1037 * its parents first. Also, it recursively destroys all
1038 * qgroups it is assgined to that have the same id part of the
1039 * qgroupid as the specified group. */
1041 r
= btrfs_qgroupid_split(qgroupid
, NULL
, &subvol_id
);
1045 n
= btrfs_qgroup_find_parents(fd
, qgroupid
, &qgroups
);
1049 for (i
= 0; i
< n
; i
++) {
1052 r
= btrfs_qgroupid_split(qgroups
[i
], NULL
, &id
);
1056 r
= btrfs_qgroup_unassign(fd
, qgroupid
, qgroups
[i
]);
1060 if (id
!= subvol_id
)
1063 /* The parent qgroupid shares the same id part with
1064 * us? If so, destroy it too. */
1066 (void) btrfs_qgroup_destroy_recursive(fd
, qgroups
[i
]);
1069 return btrfs_qgroup_destroy(fd
, qgroupid
);
1072 int btrfs_quota_scan_start(int fd
) {
1073 struct btrfs_ioctl_quota_rescan_args args
= {};
1077 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN
, &args
) < 0)
1083 int btrfs_quota_scan_wait(int fd
) {
1086 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_WAIT
) < 0)
1092 int btrfs_quota_scan_ongoing(int fd
) {
1093 struct btrfs_ioctl_quota_rescan_args args
= {};
1097 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_STATUS
, &args
) < 0)
1100 return !!args
.flags
;
1103 static int qgroup_assign_or_unassign(int fd
, bool b
, uint64_t child
, uint64_t parent
) {
1104 struct btrfs_ioctl_qgroup_assign_args args
= {
1112 r
= btrfs_is_filesystem(fd
);
1119 r
= ioctl(fd
, BTRFS_IOC_QGROUP_ASSIGN
, &args
);
1121 if (errno
== EBUSY
&& c
< 10) {
1122 (void) btrfs_quota_scan_wait(fd
);
1132 /* If the return value is > 0, we need to request a rescan */
1134 (void) btrfs_quota_scan_start(fd
);
1139 int btrfs_qgroup_assign(int fd
, uint64_t child
, uint64_t parent
) {
1140 return qgroup_assign_or_unassign(fd
, true, child
, parent
);
1143 int btrfs_qgroup_unassign(int fd
, uint64_t child
, uint64_t parent
) {
1144 return qgroup_assign_or_unassign(fd
, false, child
, parent
);
1147 static int subvol_remove_children(int fd
, const char *subvolume
, uint64_t subvol_id
, BtrfsRemoveFlags flags
) {
1148 struct btrfs_ioctl_search_args args
= {
1149 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1151 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1152 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1154 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1155 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1157 .key
.min_transid
= 0,
1158 .key
.max_transid
= (uint64_t) -1,
1161 struct btrfs_ioctl_vol_args vol_args
= {};
1162 _cleanup_close_
int subvol_fd
= -1;
1164 bool made_writable
= false;
1170 if (fstat(fd
, &st
) < 0)
1173 if (!S_ISDIR(st
.st_mode
))
1176 subvol_fd
= openat(fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1180 if (subvol_id
== 0) {
1181 r
= btrfs_subvol_get_id_fd(subvol_fd
, &subvol_id
);
1186 /* First, try to remove the subvolume. If it happens to be
1187 * already empty, this will just work. */
1188 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1189 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) >= 0) {
1190 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1193 if (!(flags
& BTRFS_REMOVE_RECURSIVE
) || errno
!= ENOTEMPTY
)
1196 /* OK, the subvolume is not empty, let's look for child
1197 * subvolumes, and remove them, first */
1199 args
.key
.min_offset
= args
.key
.max_offset
= subvol_id
;
1201 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1202 const struct btrfs_ioctl_search_header
*sh
;
1205 args
.key
.nr_items
= 256;
1206 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1209 if (args
.key
.nr_items
<= 0)
1212 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1213 _cleanup_free_
char *p
= NULL
;
1214 const struct btrfs_root_ref
*ref
;
1215 struct btrfs_ioctl_ino_lookup_args ino_args
;
1217 btrfs_ioctl_search_args_set(&args
, sh
);
1219 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1221 if (sh
->offset
!= subvol_id
)
1224 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1226 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1231 ino_args
.treeid
= subvol_id
;
1232 ino_args
.objectid
= htole64(ref
->dirid
);
1234 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1237 if (!made_writable
) {
1238 r
= btrfs_subvol_set_read_only_fd(subvol_fd
, false);
1242 made_writable
= true;
1245 if (isempty(ino_args
.name
))
1246 /* Subvolume is in the top-level
1247 * directory of the subvolume. */
1248 r
= subvol_remove_children(subvol_fd
, p
, sh
->objectid
, flags
);
1250 _cleanup_close_
int child_fd
= -1;
1252 /* Subvolume is somewhere further down,
1253 * hence we need to open the
1254 * containing directory first */
1256 child_fd
= openat(subvol_fd
, ino_args
.name
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1260 r
= subvol_remove_children(child_fd
, p
, sh
->objectid
, flags
);
1266 /* Increase search key by one, to read the next item, if we can. */
1267 if (!btrfs_ioctl_search_args_inc(&args
))
1271 /* OK, the child subvolumes should all be gone now, let's try
1272 * again to remove the subvolume */
1273 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) < 0)
1276 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
);
1280 int btrfs_subvol_remove(const char *path
, BtrfsRemoveFlags flags
) {
1281 _cleanup_close_
int fd
= -1;
1282 const char *subvolume
;
1287 r
= extract_subvolume_name(path
, &subvolume
);
1291 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1295 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1298 int btrfs_subvol_remove_fd(int fd
, const char *subvolume
, BtrfsRemoveFlags flags
) {
1299 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1302 int btrfs_qgroup_copy_limits(int fd
, uint64_t old_qgroupid
, uint64_t new_qgroupid
) {
1304 struct btrfs_ioctl_search_args args
= {
1305 /* Tree of quota items */
1306 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1308 /* The object ID is always 0 */
1309 .key
.min_objectid
= 0,
1310 .key
.max_objectid
= 0,
1312 /* Look precisely for the quota items */
1313 .key
.min_type
= BTRFS_QGROUP_LIMIT_KEY
,
1314 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
1316 /* For our qgroup */
1317 .key
.min_offset
= old_qgroupid
,
1318 .key
.max_offset
= old_qgroupid
,
1320 /* No restrictions on the other components */
1321 .key
.min_transid
= 0,
1322 .key
.max_transid
= (uint64_t) -1,
1327 r
= btrfs_is_filesystem(fd
);
1333 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1334 const struct btrfs_ioctl_search_header
*sh
;
1337 args
.key
.nr_items
= 256;
1338 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1341 if (args
.key
.nr_items
<= 0)
1344 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1345 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1346 struct btrfs_ioctl_qgroup_limit_args qargs
;
1349 /* Make sure we start the next search at least from this entry */
1350 btrfs_ioctl_search_args_set(&args
, sh
);
1352 if (sh
->objectid
!= 0)
1354 if (sh
->type
!= BTRFS_QGROUP_LIMIT_KEY
)
1356 if (sh
->offset
!= old_qgroupid
)
1359 /* We found the entry, now copy things over. */
1361 qargs
= (struct btrfs_ioctl_qgroup_limit_args
) {
1362 .qgroupid
= new_qgroupid
,
1364 .lim
.max_rfer
= le64toh(qli
->max_rfer
),
1365 .lim
.max_excl
= le64toh(qli
->max_excl
),
1366 .lim
.rsv_rfer
= le64toh(qli
->rsv_rfer
),
1367 .lim
.rsv_excl
= le64toh(qli
->rsv_excl
),
1369 .lim
.flags
= le64toh(qli
->flags
) & (BTRFS_QGROUP_LIMIT_MAX_RFER
|
1370 BTRFS_QGROUP_LIMIT_MAX_EXCL
|
1371 BTRFS_QGROUP_LIMIT_RSV_RFER
|
1372 BTRFS_QGROUP_LIMIT_RSV_EXCL
),
1376 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &qargs
) < 0) {
1377 if (errno
== EBUSY
&& c
< 10) {
1378 (void) btrfs_quota_scan_wait(fd
);
1390 /* Increase search key by one, to read the next item, if we can. */
1391 if (!btrfs_ioctl_search_args_inc(&args
))
1398 static int copy_quota_hierarchy(int fd
, uint64_t old_subvol_id
, uint64_t new_subvol_id
) {
1399 _cleanup_free_
uint64_t *old_qgroups
= NULL
, *old_parent_qgroups
= NULL
;
1400 bool copy_from_parent
= false, insert_intermediary_qgroup
= false;
1401 int n_old_qgroups
, n_old_parent_qgroups
, r
, i
;
1402 uint64_t old_parent_id
;
1406 /* Copies a reduced form of quota information from the old to
1407 * the new subvolume. */
1409 n_old_qgroups
= btrfs_qgroup_find_parents(fd
, old_subvol_id
, &old_qgroups
);
1410 if (n_old_qgroups
<= 0) /* Nothing to copy */
1411 return n_old_qgroups
;
1413 r
= btrfs_subvol_get_parent(fd
, old_subvol_id
, &old_parent_id
);
1417 n_old_parent_qgroups
= btrfs_qgroup_find_parents(fd
, old_parent_id
, &old_parent_qgroups
);
1418 if (n_old_parent_qgroups
< 0)
1419 return n_old_parent_qgroups
;
1421 for (i
= 0; i
< n_old_qgroups
; i
++) {
1425 r
= btrfs_qgroupid_split(old_qgroups
[i
], NULL
, &id
);
1429 if (id
== old_subvol_id
) {
1430 /* The old subvolume was member of a qgroup
1431 * that had the same id, but a different level
1432 * as it self. Let's set up something similar
1433 * in the destination. */
1434 insert_intermediary_qgroup
= true;
1438 for (j
= 0; j
< n_old_parent_qgroups
; j
++)
1439 if (old_parent_qgroups
[j
] == old_qgroups
[i
]) {
1440 /* The old subvolume shared a common
1441 * parent qgroup with its parent
1442 * subvolume. Let's set up something
1443 * similar in the destination. */
1444 copy_from_parent
= true;
1448 if (!insert_intermediary_qgroup
&& !copy_from_parent
)
1451 return btrfs_subvol_auto_qgroup_fd(fd
, new_subvol_id
, insert_intermediary_qgroup
);
1454 static int copy_subtree_quota_limits(int fd
, uint64_t old_subvol
, uint64_t new_subvol
) {
1455 uint64_t old_subtree_qgroup
, new_subtree_qgroup
;
1459 /* First copy the leaf limits */
1460 r
= btrfs_qgroup_copy_limits(fd
, old_subvol
, new_subvol
);
1465 /* Then, try to copy the subtree limits, if there are any. */
1466 r
= btrfs_subvol_find_subtree_qgroup(fd
, old_subvol
, &old_subtree_qgroup
);
1472 r
= btrfs_subvol_find_subtree_qgroup(fd
, new_subvol
, &new_subtree_qgroup
);
1478 r
= btrfs_qgroup_copy_limits(fd
, old_subtree_qgroup
, new_subtree_qgroup
);
1485 static int subvol_snapshot_children(int old_fd
, int new_fd
, const char *subvolume
, uint64_t old_subvol_id
, BtrfsSnapshotFlags flags
) {
1487 struct btrfs_ioctl_search_args args
= {
1488 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1490 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1491 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1493 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1494 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1496 .key
.min_transid
= 0,
1497 .key
.max_transid
= (uint64_t) -1,
1500 struct btrfs_ioctl_vol_args_v2 vol_args
= {
1501 .flags
= flags
& BTRFS_SNAPSHOT_READ_ONLY
? BTRFS_SUBVOL_RDONLY
: 0,
1504 _cleanup_close_
int subvolume_fd
= -1;
1505 uint64_t new_subvol_id
;
1508 assert(old_fd
>= 0);
1509 assert(new_fd
>= 0);
1512 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1514 if (ioctl(new_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &vol_args
) < 0)
1517 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
) &&
1518 !(flags
& BTRFS_SNAPSHOT_QUOTA
))
1521 if (old_subvol_id
== 0) {
1522 r
= btrfs_subvol_get_id_fd(old_fd
, &old_subvol_id
);
1527 r
= btrfs_subvol_get_id(new_fd
, vol_args
.name
, &new_subvol_id
);
1531 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1532 (void) copy_quota_hierarchy(new_fd
, old_subvol_id
, new_subvol_id
);
1534 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
)) {
1536 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1537 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1542 args
.key
.min_offset
= args
.key
.max_offset
= old_subvol_id
;
1544 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1545 const struct btrfs_ioctl_search_header
*sh
;
1548 args
.key
.nr_items
= 256;
1549 if (ioctl(old_fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1552 if (args
.key
.nr_items
<= 0)
1555 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1556 _cleanup_free_
char *p
= NULL
, *c
= NULL
, *np
= NULL
;
1557 struct btrfs_ioctl_ino_lookup_args ino_args
;
1558 const struct btrfs_root_ref
*ref
;
1559 _cleanup_close_
int old_child_fd
= -1, new_child_fd
= -1;
1561 btrfs_ioctl_search_args_set(&args
, sh
);
1563 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1566 /* Avoid finding the source subvolume a second
1568 if (sh
->offset
!= old_subvol_id
)
1571 /* Avoid running into loops if the new
1572 * subvolume is below the old one. */
1573 if (sh
->objectid
== new_subvol_id
)
1576 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1577 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1582 ino_args
.treeid
= old_subvol_id
;
1583 ino_args
.objectid
= htole64(ref
->dirid
);
1585 if (ioctl(old_fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1588 /* The kernel returns an empty name if the
1589 * subvolume is in the top-level directory,
1590 * and otherwise appends a slash, so that we
1591 * can just concatenate easily here, without
1592 * adding a slash. */
1593 c
= strappend(ino_args
.name
, p
);
1597 old_child_fd
= openat(old_fd
, c
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1598 if (old_child_fd
< 0)
1601 np
= strjoin(subvolume
, "/", ino_args
.name
, NULL
);
1605 new_child_fd
= openat(new_fd
, np
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1606 if (new_child_fd
< 0)
1609 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1610 /* If the snapshot is read-only we
1611 * need to mark it writable
1612 * temporarily, to put the subsnapshot
1615 if (subvolume_fd
< 0) {
1616 subvolume_fd
= openat(new_fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1617 if (subvolume_fd
< 0)
1621 r
= btrfs_subvol_set_read_only_fd(subvolume_fd
, false);
1626 /* When btrfs clones the subvolumes, child
1627 * subvolumes appear as empty directories. Remove
1628 * them, so that we can create a new snapshot
1630 if (unlinkat(new_child_fd
, p
, AT_REMOVEDIR
) < 0) {
1633 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
)
1634 (void) btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1639 r
= subvol_snapshot_children(old_child_fd
, new_child_fd
, p
, sh
->objectid
, flags
& ~BTRFS_SNAPSHOT_FALLBACK_COPY
);
1641 /* Restore the readonly flag */
1642 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1645 k
= btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1646 if (r
>= 0 && k
< 0)
1654 /* Increase search key by one, to read the next item, if we can. */
1655 if (!btrfs_ioctl_search_args_inc(&args
))
1659 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1660 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1665 int btrfs_subvol_snapshot_fd(int old_fd
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1666 _cleanup_close_
int new_fd
= -1;
1667 const char *subvolume
;
1670 assert(old_fd
>= 0);
1673 r
= btrfs_is_subvol(old_fd
);
1677 if (!(flags
& BTRFS_SNAPSHOT_FALLBACK_COPY
))
1680 r
= btrfs_subvol_make(new_path
);
1684 r
= copy_directory_fd(old_fd
, new_path
, true);
1686 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1690 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1691 r
= btrfs_subvol_set_read_only(new_path
, true);
1693 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1701 r
= extract_subvolume_name(new_path
, &subvolume
);
1705 new_fd
= open_parent(new_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1709 return subvol_snapshot_children(old_fd
, new_fd
, subvolume
, 0, flags
);
1712 int btrfs_subvol_snapshot(const char *old_path
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1713 _cleanup_close_
int old_fd
= -1;
1718 old_fd
= open(old_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1722 return btrfs_subvol_snapshot_fd(old_fd
, new_path
, flags
);
1725 int btrfs_qgroup_find_parents(int fd
, uint64_t qgroupid
, uint64_t **ret
) {
1727 struct btrfs_ioctl_search_args args
= {
1728 /* Tree of quota items */
1729 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1731 /* Look precisely for the quota relation items */
1732 .key
.min_type
= BTRFS_QGROUP_RELATION_KEY
,
1733 .key
.max_type
= BTRFS_QGROUP_RELATION_KEY
,
1735 /* No restrictions on the other components */
1736 .key
.min_offset
= 0,
1737 .key
.max_offset
= (uint64_t) -1,
1739 .key
.min_transid
= 0,
1740 .key
.max_transid
= (uint64_t) -1,
1743 _cleanup_free_
uint64_t *items
= NULL
;
1744 size_t n_items
= 0, n_allocated
= 0;
1750 if (qgroupid
== 0) {
1751 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
1755 r
= btrfs_is_filesystem(fd
);
1762 args
.key
.min_objectid
= args
.key
.max_objectid
= qgroupid
;
1764 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1765 const struct btrfs_ioctl_search_header
*sh
;
1768 args
.key
.nr_items
= 256;
1769 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1772 if (args
.key
.nr_items
<= 0)
1775 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1777 /* Make sure we start the next search at least from this entry */
1778 btrfs_ioctl_search_args_set(&args
, sh
);
1780 if (sh
->type
!= BTRFS_QGROUP_RELATION_KEY
)
1782 if (sh
->offset
< sh
->objectid
)
1784 if (sh
->objectid
!= qgroupid
)
1787 if (!GREEDY_REALLOC(items
, n_allocated
, n_items
+1))
1790 items
[n_items
++] = sh
->offset
;
1793 /* Increase search key by one, to read the next item, if we can. */
1794 if (!btrfs_ioctl_search_args_inc(&args
))
1806 return (int) n_items
;
1809 int btrfs_subvol_auto_qgroup_fd(int fd
, uint64_t subvol_id
, bool insert_intermediary_qgroup
) {
1810 _cleanup_free_
uint64_t *qgroups
= NULL
;
1811 uint64_t parent_subvol
;
1812 bool changed
= false;
1818 * Sets up the specified subvolume's qgroup automatically in
1821 * If insert_intermediary_qgroup is false, the subvolume's
1822 * leaf qgroup will be assigned to the same parent qgroups as
1823 * the subvolume's parent subvolume.
1825 * If insert_intermediary_qgroup is true a new intermediary
1826 * higher-level qgroup is created, with a higher level number,
1827 * but reusing the id of the subvolume. The level number is
1828 * picked as one smaller than the lowest level qgroup the
1829 * parent subvolume is a member of. If the parent subvolume's
1830 * leaf qgroup is assigned to no higher-level qgroup a new
1831 * qgroup of level 255 is created instead. Either way, the new
1832 * qgroup is then assigned to the parent's higher-level
1833 * qgroup, and the subvolume itself is assigned to it.
1835 * If the subvolume is already assigned to a higher level
1836 * qgroup, no operation is executed.
1838 * Effectively this means: regardless if
1839 * insert_intermediary_qgroup is true or not, after this
1840 * function is invoked the subvolume will be accounted within
1841 * the same qgroups as the parent. However, if it is true, it
1842 * will also get its own higher-level qgroup, which may in
1843 * turn be used by subvolumes created beneath this subvolume
1846 * This hence defines a simple default qgroup setup for
1847 * subvolumes, as long as this function is invoked on each
1848 * created subvolume: each subvolume is always accounting
1849 * together with its immediate parents. Optionally, if
1850 * insert_intermediary_qgroup is true, it will also get a
1851 * qgroup that then includes all its own child subvolumes.
1854 if (subvol_id
== 0) {
1855 r
= btrfs_is_subvol(fd
);
1861 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1866 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
1869 if (n
> 0) /* already parent qgroups set up, let's bail */
1872 r
= btrfs_subvol_get_parent(fd
, subvol_id
, &parent_subvol
);
1876 qgroups
= mfree(qgroups
);
1877 n
= btrfs_qgroup_find_parents(fd
, parent_subvol
, &qgroups
);
1881 if (insert_intermediary_qgroup
) {
1882 uint64_t lowest
= 256, new_qgroupid
;
1883 bool created
= false;
1886 /* Determine the lowest qgroup that the parent
1887 * subvolume is assigned to. */
1889 for (i
= 0; i
< n
; i
++) {
1892 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, NULL
);
1900 if (lowest
<= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1903 r
= btrfs_qgroupid_make(lowest
- 1, subvol_id
, &new_qgroupid
);
1907 /* Create the new intermediary group, unless it already exists */
1908 r
= btrfs_qgroup_create(fd
, new_qgroupid
);
1909 if (r
< 0 && r
!= -EEXIST
)
1912 changed
= created
= true;
1914 for (i
= 0; i
< n
; i
++) {
1915 r
= btrfs_qgroup_assign(fd
, new_qgroupid
, qgroups
[i
]);
1916 if (r
< 0 && r
!= -EEXIST
) {
1918 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1926 r
= btrfs_qgroup_assign(fd
, subvol_id
, new_qgroupid
);
1927 if (r
< 0 && r
!= -EEXIST
) {
1929 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1938 /* Assign our subvolume to all the same qgroups as the parent */
1940 for (i
= 0; i
< n
; i
++) {
1941 r
= btrfs_qgroup_assign(fd
, subvol_id
, qgroups
[i
]);
1942 if (r
< 0 && r
!= -EEXIST
)
1952 int btrfs_subvol_auto_qgroup(const char *path
, uint64_t subvol_id
, bool create_intermediary_qgroup
) {
1953 _cleanup_close_
int fd
= -1;
1955 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1959 return btrfs_subvol_auto_qgroup_fd(fd
, subvol_id
, create_intermediary_qgroup
);
1962 int btrfs_subvol_get_parent(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
1964 struct btrfs_ioctl_search_args args
= {
1965 /* Tree of tree roots */
1966 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1968 /* Look precisely for the subvolume items */
1969 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1970 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1972 /* No restrictions on the other components */
1973 .key
.min_offset
= 0,
1974 .key
.max_offset
= (uint64_t) -1,
1976 .key
.min_transid
= 0,
1977 .key
.max_transid
= (uint64_t) -1,
1984 if (subvol_id
== 0) {
1985 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1989 r
= btrfs_is_filesystem(fd
);
1996 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
1998 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1999 const struct btrfs_ioctl_search_header
*sh
;
2002 args
.key
.nr_items
= 256;
2003 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
2006 if (args
.key
.nr_items
<= 0)
2009 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
2011 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
2013 if (sh
->objectid
!= subvol_id
)