1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include <linux/btrfs_tree.h>
8 #include <linux/loop.h>
9 #include <linux/magic.h>
13 #include <sys/ioctl.h>
14 #include <sys/sysmacros.h>
17 #include "alloc-util.h"
18 #include "blockdev-util.h"
19 #include "btrfs-util.h"
20 #include "chattr-util.h"
27 #include "path-util.h"
29 #include "smack-util.h"
30 #include "sparse-endian.h"
31 #include "stat-util.h"
32 #include "string-util.h"
33 #include "time-util.h"
35 /* WARNING: Be careful with file system ioctls! When we get an fd, we
36 * need to make sure it either refers to only a regular file or
37 * directory, or that it is located on btrfs, before invoking any
38 * btrfs ioctls. The ioctl numbers are reused by some device drivers
39 * (such as DRM), and hence might have bad effects when invoked on
40 * device nodes (that reference drivers) rather than fds to normal
41 * files or directories. */
43 static int validate_subvolume_name(const char *name
) {
45 if (!filename_is_valid(name
))
48 if (strlen(name
) > BTRFS_SUBVOL_NAME_MAX
)
54 static int extract_subvolume_name(const char *path
, const char **subvolume
) {
63 r
= validate_subvolume_name(fn
);
71 int btrfs_is_subvol_fd(int fd
) {
76 /* On btrfs subvolumes always have the inode 256 */
78 if (fstat(fd
, &st
) < 0)
81 if (!btrfs_might_be_subvol(&st
))
84 return fd_is_fs_type(fd
, BTRFS_SUPER_MAGIC
);
87 int btrfs_is_subvol(const char *path
) {
88 _cleanup_close_
int fd
= -EBADF
;
92 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
96 return btrfs_is_subvol_fd(fd
);
99 int btrfs_subvol_make_fd(int fd
, const char *subvolume
) {
100 struct btrfs_ioctl_vol_args args
= {};
101 _cleanup_close_
int real_fd
= -EBADF
;
106 r
= validate_subvolume_name(subvolume
);
110 /* If an O_PATH fd was specified, let's convert here to a proper one, as btrfs ioctl's can't deal
112 fd
= fd_reopen_condition(fd
, O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
, O_PATH
|O_DIRECTORY
, &real_fd
);
116 strncpy(args
.name
, subvolume
, sizeof(args
.name
)-1);
118 return RET_NERRNO(ioctl(fd
, BTRFS_IOC_SUBVOL_CREATE
, &args
));
121 int btrfs_subvol_make(const char *path
) {
122 _cleanup_close_
int fd
= -EBADF
;
123 const char *subvolume
;
128 r
= extract_subvolume_name(path
, &subvolume
);
132 fd
= open_parent(path
, O_CLOEXEC
, 0);
136 return btrfs_subvol_make_fd(fd
, subvolume
);
139 int btrfs_subvol_make_fallback(const char *path
, mode_t mode
) {
140 mode_t old
, combined
;
145 /* Let's work like mkdir(), i.e. take the specified mode, and mask it with the current umask. */
147 combined
= old
| ~mode
;
148 if (combined
!= ~mode
)
150 r
= btrfs_subvol_make(path
);
154 return 1; /* subvol worked */
158 if (mkdir(path
, mode
) < 0)
161 return 0; /* plain directory */
164 int btrfs_subvol_set_read_only_fd(int fd
, bool b
) {
165 uint64_t flags
, nflags
;
170 if (fstat(fd
, &st
) < 0)
173 if (!btrfs_might_be_subvol(&st
))
176 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
179 nflags
= UPDATE_FLAG(flags
, BTRFS_SUBVOL_RDONLY
, b
);
183 return RET_NERRNO(ioctl(fd
, BTRFS_IOC_SUBVOL_SETFLAGS
, &nflags
));
186 int btrfs_subvol_set_read_only(const char *path
, bool b
) {
187 _cleanup_close_
int fd
= -EBADF
;
189 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
193 return btrfs_subvol_set_read_only_fd(fd
, b
);
196 int btrfs_subvol_get_read_only_fd(int fd
) {
202 if (fstat(fd
, &st
) < 0)
205 if (!btrfs_might_be_subvol(&st
))
208 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
211 return !!(flags
& BTRFS_SUBVOL_RDONLY
);
214 int btrfs_reflink(int infd
, int outfd
) {
220 /* Make sure we invoke the ioctl on a regular file, so that no device driver accidentally gets it. */
222 r
= fd_verify_regular(outfd
);
226 return RET_NERRNO(ioctl(outfd
, BTRFS_IOC_CLONE
, infd
));
229 int btrfs_clone_range(int infd
, uint64_t in_offset
, int outfd
, uint64_t out_offset
, uint64_t sz
) {
230 struct btrfs_ioctl_clone_range_args args
= {
232 .src_offset
= in_offset
,
234 .dest_offset
= out_offset
,
241 r
= fd_verify_regular(outfd
);
245 return RET_NERRNO(ioctl(outfd
, BTRFS_IOC_CLONE_RANGE
, &args
));
248 int btrfs_get_block_device_fd(int fd
, dev_t
*dev
) {
249 struct btrfs_ioctl_fs_info_args fsi
= {};
250 _cleanup_close_
int regfd
= -EBADF
;
257 fd
= fd_reopen_condition(fd
, O_RDONLY
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
, O_PATH
, ®fd
);
261 r
= fd_is_fs_type(fd
, BTRFS_SUPER_MAGIC
);
267 if (ioctl(fd
, BTRFS_IOC_FS_INFO
, &fsi
) < 0)
270 /* We won't do this for btrfs RAID */
271 if (fsi
.num_devices
!= 1) {
276 for (id
= 1; id
<= fsi
.max_id
; id
++) {
277 struct btrfs_ioctl_dev_info_args di
= {
282 if (ioctl(fd
, BTRFS_IOC_DEV_INFO
, &di
) < 0) {
289 /* For the root fs — when no initrd is involved — btrfs returns /dev/root on any kernels from
290 * the past few years. That sucks, as we have no API to determine the actual root then. let's
291 * return an recognizable error for this case, so that the caller can maybe print a nice
292 * message about this.
294 * https://bugzilla.kernel.org/show_bug.cgi?id=89721 */
295 if (path_equal((char*) di
.path
, "/dev/root"))
298 if (stat((char*) di
.path
, &st
) < 0)
301 if (!S_ISBLK(st
.st_mode
))
304 if (major(st
.st_rdev
) == 0)
314 int btrfs_get_block_device(const char *path
, dev_t
*dev
) {
315 _cleanup_close_
int fd
= -EBADF
;
320 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
324 return btrfs_get_block_device_fd(fd
, dev
);
327 int btrfs_subvol_get_id_fd(int fd
, uint64_t *ret
) {
328 struct btrfs_ioctl_ino_lookup_args args
= {
329 .objectid
= BTRFS_FIRST_FREE_OBJECTID
336 r
= fd_is_fs_type(fd
, BTRFS_SUPER_MAGIC
);
342 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
) < 0)
349 int btrfs_subvol_get_id(int fd
, const char *subvol
, uint64_t *ret
) {
350 _cleanup_close_
int subvol_fd
= -EBADF
;
355 subvol_fd
= openat(fd
, subvol
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
359 return btrfs_subvol_get_id_fd(subvol_fd
, ret
);
362 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args
*args
) {
365 /* the objectid, type, offset together make up the btrfs key,
366 * which is considered a single 136byte integer when
367 * comparing. This call increases the counter by one, dealing
368 * with the overflow between the overflows */
370 if (args
->key
.min_offset
< UINT64_MAX
) {
371 args
->key
.min_offset
++;
375 if (args
->key
.min_type
< UINT8_MAX
) {
376 args
->key
.min_type
++;
377 args
->key
.min_offset
= 0;
381 if (args
->key
.min_objectid
< UINT64_MAX
) {
382 args
->key
.min_objectid
++;
383 args
->key
.min_offset
= 0;
384 args
->key
.min_type
= 0;
391 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args
*args
, const struct btrfs_ioctl_search_header
*h
) {
395 args
->key
.min_objectid
= h
->objectid
;
396 args
->key
.min_type
= h
->type
;
397 args
->key
.min_offset
= h
->offset
;
400 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
*args
) {
405 /* Compare min and max */
407 r
= CMP(args
->key
.min_objectid
, args
->key
.max_objectid
);
411 r
= CMP(args
->key
.min_type
, args
->key
.max_type
);
415 return CMP(args
->key
.min_offset
, args
->key
.max_offset
);
418 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
420 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
421 (i) < (args).key.nr_items; \
423 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
425 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
426 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
428 int btrfs_subvol_get_info_fd(int fd
, uint64_t subvol_id
, BtrfsSubvolInfo
*ret
) {
429 struct btrfs_ioctl_search_args args
= {
430 /* Tree of tree roots */
431 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
433 /* Look precisely for the subvolume items */
434 .key
.min_type
= BTRFS_ROOT_ITEM_KEY
,
435 .key
.max_type
= BTRFS_ROOT_ITEM_KEY
,
438 .key
.max_offset
= UINT64_MAX
,
440 /* No restrictions on the other components */
441 .key
.min_transid
= 0,
442 .key
.max_transid
= UINT64_MAX
,
451 if (subvol_id
== 0) {
452 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
456 r
= fd_is_fs_type(fd
, BTRFS_SUPER_MAGIC
);
463 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
465 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
466 const struct btrfs_ioctl_search_header
*sh
;
469 args
.key
.nr_items
= 256;
470 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
473 if (args
.key
.nr_items
<= 0)
476 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
478 const struct btrfs_root_item
*ri
;
480 /* Make sure we start the next search at least from this entry */
481 btrfs_ioctl_search_args_set(&args
, sh
);
483 if (sh
->objectid
!= subvol_id
)
485 if (sh
->type
!= BTRFS_ROOT_ITEM_KEY
)
488 /* Older versions of the struct lacked the otime setting */
489 if (sh
->len
< offsetof(struct btrfs_root_item
, otime
) + sizeof(struct btrfs_timespec
))
492 ri
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
494 ret
->otime
= (usec_t
) le64toh(ri
->otime
.sec
) * USEC_PER_SEC
+
495 (usec_t
) le32toh(ri
->otime
.nsec
) / NSEC_PER_USEC
;
497 ret
->subvol_id
= subvol_id
;
498 ret
->read_only
= le64toh(ri
->flags
) & BTRFS_ROOT_SUBVOL_RDONLY
;
500 assert_cc(sizeof(ri
->uuid
) == sizeof(ret
->uuid
));
501 memcpy(&ret
->uuid
, ri
->uuid
, sizeof(ret
->uuid
));
502 memcpy(&ret
->parent_uuid
, ri
->parent_uuid
, sizeof(ret
->parent_uuid
));
508 /* Increase search key by one, to read the next item, if we can. */
509 if (!btrfs_ioctl_search_args_inc(&args
))
514 return found
? 0 : -ENODATA
;
517 int btrfs_qgroup_get_quota_fd(int fd
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
519 struct btrfs_ioctl_search_args args
= {
520 /* Tree of quota items */
521 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
523 /* The object ID is always 0 */
524 .key
.min_objectid
= 0,
525 .key
.max_objectid
= 0,
527 /* Look precisely for the quota items */
528 .key
.min_type
= BTRFS_QGROUP_STATUS_KEY
,
529 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
531 /* No restrictions on the other components */
532 .key
.min_transid
= 0,
533 .key
.max_transid
= UINT64_MAX
,
536 bool found_info
= false, found_limit
= false;
543 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
547 r
= fd_is_fs_type(fd
, BTRFS_SUPER_MAGIC
);
554 args
.key
.min_offset
= args
.key
.max_offset
= qgroupid
;
556 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
557 const struct btrfs_ioctl_search_header
*sh
;
560 args
.key
.nr_items
= 256;
561 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
562 if (errno
== ENOENT
) /* quota tree is missing: quota disabled */
568 if (args
.key
.nr_items
<= 0)
571 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
573 /* Make sure we start the next search at least from this entry */
574 btrfs_ioctl_search_args_set(&args
, sh
);
576 if (sh
->objectid
!= 0)
578 if (sh
->offset
!= qgroupid
)
581 if (sh
->type
== BTRFS_QGROUP_INFO_KEY
) {
582 const struct btrfs_qgroup_info_item
*qii
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
584 ret
->referenced
= le64toh(qii
->rfer
);
585 ret
->exclusive
= le64toh(qii
->excl
);
589 } else if (sh
->type
== BTRFS_QGROUP_LIMIT_KEY
) {
590 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
592 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_RFER
)
593 ret
->referenced_max
= le64toh(qli
->max_rfer
);
595 ret
->referenced_max
= UINT64_MAX
;
597 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_EXCL
)
598 ret
->exclusive_max
= le64toh(qli
->max_excl
);
600 ret
->exclusive_max
= UINT64_MAX
;
605 if (found_info
&& found_limit
)
609 /* Increase search key by one, to read the next item, if we can. */
610 if (!btrfs_ioctl_search_args_inc(&args
))
615 if (!found_limit
&& !found_info
)
619 ret
->referenced
= UINT64_MAX
;
620 ret
->exclusive
= UINT64_MAX
;
624 ret
->referenced_max
= UINT64_MAX
;
625 ret
->exclusive_max
= UINT64_MAX
;
631 int btrfs_qgroup_get_quota(const char *path
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
632 _cleanup_close_
int fd
= -EBADF
;
634 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
638 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
641 int btrfs_subvol_find_subtree_qgroup(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
642 uint64_t level
, lowest
= UINT64_MAX
, lowest_qgroupid
= 0;
643 _cleanup_free_
uint64_t *qgroups
= NULL
;
649 /* This finds the "subtree" qgroup for a specific
650 * subvolume. This only works for subvolumes that have been
651 * prepared with btrfs_subvol_auto_qgroup_fd() with
652 * insert_intermediary_qgroup=true (or equivalent). For others
653 * it will return the leaf qgroup instead. The two cases may
654 * be distinguished via the return value, which is 1 in case
655 * an appropriate "subtree" qgroup was found, and 0
658 if (subvol_id
== 0) {
659 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
664 r
= btrfs_qgroupid_split(subvol_id
, &level
, NULL
);
667 if (level
!= 0) /* Input must be a leaf qgroup */
670 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
674 for (int i
= 0; i
< n
; i
++) {
677 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, &id
);
684 if (lowest
== UINT64_MAX
|| level
< lowest
) {
685 lowest_qgroupid
= qgroups
[i
];
690 if (lowest
== UINT64_MAX
) {
691 /* No suitable higher-level qgroup found, let's return
692 * the leaf qgroup instead, and indicate that with the
699 *ret
= lowest_qgroupid
;
703 int btrfs_subvol_get_subtree_quota_fd(int fd
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
710 /* This determines the quota data of the qgroup with the
711 * lowest level, that shares the id part with the specified
712 * subvolume. This is useful for determining the quota data
713 * for entire subvolume subtrees, as long as the subtrees have
714 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
717 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
721 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
724 int btrfs_subvol_get_subtree_quota(const char *path
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
725 _cleanup_close_
int fd
= -EBADF
;
727 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
731 return btrfs_subvol_get_subtree_quota_fd(fd
, subvol_id
, ret
);
734 int btrfs_defrag_fd(int fd
) {
739 r
= fd_verify_regular(fd
);
743 return RET_NERRNO(ioctl(fd
, BTRFS_IOC_DEFRAG
, NULL
));
746 int btrfs_defrag(const char *p
) {
747 _cleanup_close_
int fd
= -EBADF
;
749 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
753 return btrfs_defrag_fd(fd
);
756 int btrfs_quota_enable_fd(int fd
, bool b
) {
757 struct btrfs_ioctl_quota_ctl_args args
= {
758 .cmd
= b
? BTRFS_QUOTA_CTL_ENABLE
: BTRFS_QUOTA_CTL_DISABLE
,
764 r
= fd_is_fs_type(fd
, BTRFS_SUPER_MAGIC
);
770 return RET_NERRNO(ioctl(fd
, BTRFS_IOC_QUOTA_CTL
, &args
));
773 int btrfs_quota_enable(const char *path
, bool b
) {
774 _cleanup_close_
int fd
= -EBADF
;
776 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
780 return btrfs_quota_enable_fd(fd
, b
);
783 int btrfs_qgroup_set_limit_fd(int fd
, uint64_t qgroupid
, uint64_t referenced_max
) {
785 struct btrfs_ioctl_qgroup_limit_args args
= {
786 .lim
.max_rfer
= referenced_max
,
787 .lim
.flags
= BTRFS_QGROUP_LIMIT_MAX_RFER
,
794 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
798 r
= fd_is_fs_type(fd
, BTRFS_SUPER_MAGIC
);
805 args
.qgroupid
= qgroupid
;
807 for (unsigned c
= 0;; c
++) {
808 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &args
) < 0) {
810 if (errno
== EBUSY
&& c
< 10) {
811 (void) btrfs_quota_scan_wait(fd
);
824 int btrfs_qgroup_set_limit(const char *path
, uint64_t qgroupid
, uint64_t referenced_max
) {
825 _cleanup_close_
int fd
= -EBADF
;
827 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
831 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
834 int btrfs_subvol_set_subtree_quota_limit_fd(int fd
, uint64_t subvol_id
, uint64_t referenced_max
) {
840 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
844 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
847 int btrfs_subvol_set_subtree_quota_limit(const char *path
, uint64_t subvol_id
, uint64_t referenced_max
) {
848 _cleanup_close_
int fd
= -EBADF
;
850 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
854 return btrfs_subvol_set_subtree_quota_limit_fd(fd
, subvol_id
, referenced_max
);
857 int btrfs_qgroupid_make(uint64_t level
, uint64_t id
, uint64_t *ret
) {
860 if (level
>= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT
)))
863 if (id
>= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
))
866 *ret
= (level
<< BTRFS_QGROUP_LEVEL_SHIFT
) | id
;
870 int btrfs_qgroupid_split(uint64_t qgroupid
, uint64_t *level
, uint64_t *id
) {
874 *level
= qgroupid
>> BTRFS_QGROUP_LEVEL_SHIFT
;
877 *id
= qgroupid
& ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
) - 1);
882 static int qgroup_create_or_destroy(int fd
, bool b
, uint64_t qgroupid
) {
884 struct btrfs_ioctl_qgroup_create_args args
= {
886 .qgroupid
= qgroupid
,
890 r
= fd_is_fs_type(fd
, BTRFS_SUPER_MAGIC
);
896 for (unsigned c
= 0;; c
++) {
897 if (ioctl(fd
, BTRFS_IOC_QGROUP_CREATE
, &args
) < 0) {
899 /* On old kernels if quota is not enabled, we get EINVAL. On newer kernels we get
900 * ENOTCONN. Let's always convert this to ENOTCONN to make this recognizable
901 * everywhere the same way. */
903 if (IN_SET(errno
, EINVAL
, ENOTCONN
))
906 if (errno
== EBUSY
&& c
< 10) {
907 (void) btrfs_quota_scan_wait(fd
);
920 int btrfs_qgroup_create(int fd
, uint64_t qgroupid
) {
921 return qgroup_create_or_destroy(fd
, true, qgroupid
);
924 int btrfs_qgroup_destroy(int fd
, uint64_t qgroupid
) {
925 return qgroup_create_or_destroy(fd
, false, qgroupid
);
928 int btrfs_qgroup_destroy_recursive(int fd
, uint64_t qgroupid
) {
929 _cleanup_free_
uint64_t *qgroups
= NULL
;
933 /* Destroys the specified qgroup, but unassigns it from all
934 * its parents first. Also, it recursively destroys all
935 * qgroups it is assigned to that have the same id part of the
936 * qgroupid as the specified group. */
938 r
= btrfs_qgroupid_split(qgroupid
, NULL
, &subvol_id
);
942 n
= btrfs_qgroup_find_parents(fd
, qgroupid
, &qgroups
);
946 for (int i
= 0; i
< n
; i
++) {
949 r
= btrfs_qgroupid_split(qgroups
[i
], NULL
, &id
);
953 r
= btrfs_qgroup_unassign(fd
, qgroupid
, qgroups
[i
]);
960 /* The parent qgroupid shares the same id part with
961 * us? If so, destroy it too. */
963 (void) btrfs_qgroup_destroy_recursive(fd
, qgroups
[i
]);
966 return btrfs_qgroup_destroy(fd
, qgroupid
);
969 int btrfs_quota_scan_start(int fd
) {
970 struct btrfs_ioctl_quota_rescan_args args
= {};
974 return RET_NERRNO(ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN
, &args
));
977 int btrfs_quota_scan_wait(int fd
) {
980 return RET_NERRNO(ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_WAIT
));
983 int btrfs_quota_scan_ongoing(int fd
) {
984 struct btrfs_ioctl_quota_rescan_args args
= {};
988 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_STATUS
, &args
) < 0)
994 static int qgroup_assign_or_unassign(int fd
, bool b
, uint64_t child
, uint64_t parent
) {
995 struct btrfs_ioctl_qgroup_assign_args args
= {
1002 r
= fd_is_fs_type(fd
, BTRFS_SUPER_MAGIC
);
1008 for (unsigned c
= 0;; c
++) {
1009 r
= ioctl(fd
, BTRFS_IOC_QGROUP_ASSIGN
, &args
);
1011 if (errno
== EBUSY
&& c
< 10) {
1012 (void) btrfs_quota_scan_wait(fd
);
1022 /* If the return value is > 0, we need to request a rescan */
1024 (void) btrfs_quota_scan_start(fd
);
1029 int btrfs_qgroup_assign(int fd
, uint64_t child
, uint64_t parent
) {
1030 return qgroup_assign_or_unassign(fd
, true, child
, parent
);
1033 int btrfs_qgroup_unassign(int fd
, uint64_t child
, uint64_t parent
) {
1034 return qgroup_assign_or_unassign(fd
, false, child
, parent
);
1037 static int subvol_remove_children(int fd
, const char *subvolume
, uint64_t subvol_id
, BtrfsRemoveFlags flags
) {
1038 struct btrfs_ioctl_search_args args
= {
1039 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1041 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1042 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1044 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1045 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1047 .key
.min_transid
= 0,
1048 .key
.max_transid
= UINT64_MAX
,
1051 struct btrfs_ioctl_vol_args vol_args
= {};
1052 _cleanup_close_
int subvol_fd
= -EBADF
;
1054 bool made_writable
= false;
1060 if (fstat(fd
, &st
) < 0)
1063 if (!S_ISDIR(st
.st_mode
))
1066 subvol_fd
= openat(fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1070 /* Let's check if this is actually a subvolume. Note that this is mostly redundant, as BTRFS_IOC_SNAP_DESTROY
1071 * would fail anyway if it is not. However, it's a good thing to check this ahead of time so that we can return
1072 * ENOTTY unconditionally in this case. This is different from the ioctl() which will return EPERM/EACCES if we
1073 * don't have the privileges to remove subvolumes, regardless if the specified directory is actually a
1074 * subvolume or not. In order to make it easy for callers to cover the "this is not a btrfs subvolume" case
1075 * let's prefer ENOTTY over EPERM/EACCES though. */
1076 r
= btrfs_is_subvol_fd(subvol_fd
);
1079 if (r
== 0) /* Not a btrfs subvolume */
1082 if (subvol_id
== 0) {
1083 r
= btrfs_subvol_get_id_fd(subvol_fd
, &subvol_id
);
1088 /* First, try to remove the subvolume. If it happens to be
1089 * already empty, this will just work. */
1090 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1091 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) >= 0) {
1092 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1095 if (!(flags
& BTRFS_REMOVE_RECURSIVE
) || errno
!= ENOTEMPTY
)
1098 /* OK, the subvolume is not empty, let's look for child
1099 * subvolumes, and remove them, first */
1101 args
.key
.min_offset
= args
.key
.max_offset
= subvol_id
;
1103 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1104 const struct btrfs_ioctl_search_header
*sh
;
1107 args
.key
.nr_items
= 256;
1108 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1111 if (args
.key
.nr_items
<= 0)
1114 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1115 _cleanup_free_
char *p
= NULL
;
1116 const struct btrfs_root_ref
*ref
;
1118 btrfs_ioctl_search_args_set(&args
, sh
);
1120 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1122 if (sh
->offset
!= subvol_id
)
1125 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1127 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1131 struct btrfs_ioctl_ino_lookup_args ino_args
= {
1132 .treeid
= subvol_id
,
1133 .objectid
= htole64(ref
->dirid
),
1136 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1139 if (!made_writable
) {
1140 r
= btrfs_subvol_set_read_only_fd(subvol_fd
, false);
1144 made_writable
= true;
1147 if (isempty(ino_args
.name
))
1148 /* Subvolume is in the top-level
1149 * directory of the subvolume. */
1150 r
= subvol_remove_children(subvol_fd
, p
, sh
->objectid
, flags
);
1152 _cleanup_close_
int child_fd
= -EBADF
;
1154 /* Subvolume is somewhere further down,
1155 * hence we need to open the
1156 * containing directory first */
1158 child_fd
= openat(subvol_fd
, ino_args
.name
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1162 r
= subvol_remove_children(child_fd
, p
, sh
->objectid
, flags
);
1168 /* Increase search key by one, to read the next item, if we can. */
1169 if (!btrfs_ioctl_search_args_inc(&args
))
1173 /* OK, the child subvolumes should all be gone now, let's try
1174 * again to remove the subvolume */
1175 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) < 0)
1178 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
);
1182 int btrfs_subvol_remove(const char *path
, BtrfsRemoveFlags flags
) {
1183 _cleanup_close_
int fd
= -EBADF
;
1184 const char *subvolume
;
1189 r
= extract_subvolume_name(path
, &subvolume
);
1193 fd
= open_parent(path
, O_CLOEXEC
, 0);
1197 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1200 int btrfs_subvol_remove_fd(int fd
, const char *subvolume
, BtrfsRemoveFlags flags
) {
1201 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1204 int btrfs_qgroup_copy_limits(int fd
, uint64_t old_qgroupid
, uint64_t new_qgroupid
) {
1206 struct btrfs_ioctl_search_args args
= {
1207 /* Tree of quota items */
1208 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1210 /* The object ID is always 0 */
1211 .key
.min_objectid
= 0,
1212 .key
.max_objectid
= 0,
1214 /* Look precisely for the quota items */
1215 .key
.min_type
= BTRFS_QGROUP_LIMIT_KEY
,
1216 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
1218 /* For our qgroup */
1219 .key
.min_offset
= old_qgroupid
,
1220 .key
.max_offset
= old_qgroupid
,
1222 /* No restrictions on the other components */
1223 .key
.min_transid
= 0,
1224 .key
.max_transid
= UINT64_MAX
,
1229 r
= fd_is_fs_type(fd
, BTRFS_SUPER_MAGIC
);
1235 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1236 const struct btrfs_ioctl_search_header
*sh
;
1239 args
.key
.nr_items
= 256;
1240 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1241 if (errno
== ENOENT
) /* quota tree missing: quota is not enabled, hence nothing to copy */
1247 if (args
.key
.nr_items
<= 0)
1250 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1251 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1252 struct btrfs_ioctl_qgroup_limit_args qargs
;
1255 /* Make sure we start the next search at least from this entry */
1256 btrfs_ioctl_search_args_set(&args
, sh
);
1258 if (sh
->objectid
!= 0)
1260 if (sh
->type
!= BTRFS_QGROUP_LIMIT_KEY
)
1262 if (sh
->offset
!= old_qgroupid
)
1265 /* We found the entry, now copy things over. */
1267 qargs
= (struct btrfs_ioctl_qgroup_limit_args
) {
1268 .qgroupid
= new_qgroupid
,
1270 .lim
.max_rfer
= le64toh(qli
->max_rfer
),
1271 .lim
.max_excl
= le64toh(qli
->max_excl
),
1272 .lim
.rsv_rfer
= le64toh(qli
->rsv_rfer
),
1273 .lim
.rsv_excl
= le64toh(qli
->rsv_excl
),
1275 .lim
.flags
= le64toh(qli
->flags
) & (BTRFS_QGROUP_LIMIT_MAX_RFER
|
1276 BTRFS_QGROUP_LIMIT_MAX_EXCL
|
1277 BTRFS_QGROUP_LIMIT_RSV_RFER
|
1278 BTRFS_QGROUP_LIMIT_RSV_EXCL
),
1282 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &qargs
) < 0) {
1283 if (errno
== EBUSY
&& c
< 10) {
1284 (void) btrfs_quota_scan_wait(fd
);
1296 /* Increase search key by one, to read the next item, if we can. */
1297 if (!btrfs_ioctl_search_args_inc(&args
))
1304 static int copy_quota_hierarchy(int fd
, uint64_t old_subvol_id
, uint64_t new_subvol_id
) {
1305 _cleanup_free_
uint64_t *old_qgroups
= NULL
, *old_parent_qgroups
= NULL
;
1306 bool copy_from_parent
= false, insert_intermediary_qgroup
= false;
1307 int n_old_qgroups
, n_old_parent_qgroups
, r
;
1308 uint64_t old_parent_id
;
1312 /* Copies a reduced form of quota information from the old to
1313 * the new subvolume. */
1315 n_old_qgroups
= btrfs_qgroup_find_parents(fd
, old_subvol_id
, &old_qgroups
);
1316 if (n_old_qgroups
<= 0) /* Nothing to copy */
1317 return n_old_qgroups
;
1319 r
= btrfs_subvol_get_parent(fd
, old_subvol_id
, &old_parent_id
);
1321 /* We have no parent, hence nothing to copy. */
1322 n_old_parent_qgroups
= 0;
1326 n_old_parent_qgroups
= btrfs_qgroup_find_parents(fd
, old_parent_id
, &old_parent_qgroups
);
1327 if (n_old_parent_qgroups
< 0)
1328 return n_old_parent_qgroups
;
1331 for (int i
= 0; i
< n_old_qgroups
; i
++) {
1334 r
= btrfs_qgroupid_split(old_qgroups
[i
], NULL
, &id
);
1338 if (id
== old_subvol_id
) {
1339 /* The old subvolume was member of a qgroup
1340 * that had the same id, but a different level
1341 * as it self. Let's set up something similar
1342 * in the destination. */
1343 insert_intermediary_qgroup
= true;
1347 for (int j
= 0; j
< n_old_parent_qgroups
; j
++)
1348 if (old_parent_qgroups
[j
] == old_qgroups
[i
])
1349 /* The old subvolume shared a common
1350 * parent qgroup with its parent
1351 * subvolume. Let's set up something
1352 * similar in the destination. */
1353 copy_from_parent
= true;
1356 if (!insert_intermediary_qgroup
&& !copy_from_parent
)
1359 return btrfs_subvol_auto_qgroup_fd(fd
, new_subvol_id
, insert_intermediary_qgroup
);
1362 static int copy_subtree_quota_limits(int fd
, uint64_t old_subvol
, uint64_t new_subvol
) {
1363 uint64_t old_subtree_qgroup
, new_subtree_qgroup
;
1367 /* First copy the leaf limits */
1368 r
= btrfs_qgroup_copy_limits(fd
, old_subvol
, new_subvol
);
1373 /* Then, try to copy the subtree limits, if there are any. */
1374 r
= btrfs_subvol_find_subtree_qgroup(fd
, old_subvol
, &old_subtree_qgroup
);
1380 r
= btrfs_subvol_find_subtree_qgroup(fd
, new_subvol
, &new_subtree_qgroup
);
1386 r
= btrfs_qgroup_copy_limits(fd
, old_subtree_qgroup
, new_subtree_qgroup
);
1393 static int subvol_snapshot_children(
1396 const char *subvolume
,
1397 uint64_t old_subvol_id
,
1398 BtrfsSnapshotFlags flags
) {
1400 struct btrfs_ioctl_search_args args
= {
1401 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1403 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1404 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1406 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1407 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1409 .key
.min_transid
= 0,
1410 .key
.max_transid
= UINT64_MAX
,
1413 struct btrfs_ioctl_vol_args_v2 vol_args
= {
1414 .flags
= flags
& BTRFS_SNAPSHOT_READ_ONLY
? BTRFS_SUBVOL_RDONLY
: 0,
1417 _cleanup_close_
int subvolume_fd
= -EBADF
;
1418 uint64_t new_subvol_id
;
1421 assert(old_fd
>= 0);
1422 assert(new_fd
>= 0);
1425 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1427 if (ioctl(new_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &vol_args
) < 0)
1430 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
) &&
1431 !(flags
& BTRFS_SNAPSHOT_QUOTA
))
1434 if (old_subvol_id
== 0) {
1435 r
= btrfs_subvol_get_id_fd(old_fd
, &old_subvol_id
);
1440 r
= btrfs_subvol_get_id(new_fd
, vol_args
.name
, &new_subvol_id
);
1444 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1445 (void) copy_quota_hierarchy(new_fd
, old_subvol_id
, new_subvol_id
);
1447 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
)) {
1449 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1450 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1455 args
.key
.min_offset
= args
.key
.max_offset
= old_subvol_id
;
1457 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1458 const struct btrfs_ioctl_search_header
*sh
;
1461 args
.key
.nr_items
= 256;
1462 if (ioctl(old_fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1465 if (args
.key
.nr_items
<= 0)
1468 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1469 _cleanup_free_
char *p
= NULL
, *c
= NULL
, *np
= NULL
;
1470 const struct btrfs_root_ref
*ref
;
1471 _cleanup_close_
int old_child_fd
= -EBADF
, new_child_fd
= -EBADF
;
1473 btrfs_ioctl_search_args_set(&args
, sh
);
1475 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1478 /* Avoid finding the source subvolume a second
1480 if (sh
->offset
!= old_subvol_id
)
1483 /* Avoid running into loops if the new
1484 * subvolume is below the old one. */
1485 if (sh
->objectid
== new_subvol_id
)
1488 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1489 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1493 struct btrfs_ioctl_ino_lookup_args ino_args
= {
1494 .treeid
= old_subvol_id
,
1495 .objectid
= htole64(ref
->dirid
),
1498 if (ioctl(old_fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1501 c
= path_join(ino_args
.name
, p
);
1505 old_child_fd
= openat(old_fd
, c
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1506 if (old_child_fd
< 0)
1509 np
= path_join(subvolume
, ino_args
.name
);
1513 new_child_fd
= openat(new_fd
, np
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1514 if (new_child_fd
< 0)
1517 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1518 /* If the snapshot is read-only we
1519 * need to mark it writable
1520 * temporarily, to put the subsnapshot
1523 if (subvolume_fd
< 0) {
1524 subvolume_fd
= openat(new_fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1525 if (subvolume_fd
< 0)
1529 r
= btrfs_subvol_set_read_only_fd(subvolume_fd
, false);
1534 /* When btrfs clones the subvolumes, child
1535 * subvolumes appear as empty directories. Remove
1536 * them, so that we can create a new snapshot
1538 if (unlinkat(new_child_fd
, p
, AT_REMOVEDIR
) < 0) {
1541 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
)
1542 (void) btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1547 r
= subvol_snapshot_children(old_child_fd
, new_child_fd
, p
, sh
->objectid
, flags
& ~BTRFS_SNAPSHOT_FALLBACK_COPY
);
1549 /* Restore the readonly flag */
1550 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1553 k
= btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1554 if (r
>= 0 && k
< 0)
1562 /* Increase search key by one, to read the next item, if we can. */
1563 if (!btrfs_ioctl_search_args_inc(&args
))
1567 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1568 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1573 int btrfs_subvol_snapshot_fd_full(
1575 const char *new_path
,
1576 BtrfsSnapshotFlags flags
,
1577 copy_progress_path_t progress_path
,
1578 copy_progress_bytes_t progress_bytes
,
1581 _cleanup_close_
int new_fd
= -EBADF
;
1582 const char *subvolume
;
1585 assert(old_fd
>= 0);
1588 r
= btrfs_is_subvol_fd(old_fd
);
1592 bool plain_directory
= false;
1594 /* If the source isn't a proper subvolume, fail unless fallback is requested */
1595 if (!(flags
& BTRFS_SNAPSHOT_FALLBACK_COPY
))
1598 r
= btrfs_subvol_make(new_path
);
1599 if (ERRNO_IS_NOT_SUPPORTED(r
) && (flags
& BTRFS_SNAPSHOT_FALLBACK_DIRECTORY
)) {
1600 /* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */
1601 if (mkdir(new_path
, 0755) < 0)
1604 plain_directory
= true;
1608 r
= copy_directory_fd_full(
1615 (FLAGS_SET(flags
, BTRFS_SNAPSHOT_SIGINT
) ? COPY_SIGINT
: 0)|
1616 (FLAGS_SET(flags
, BTRFS_SNAPSHOT_SIGTERM
) ? COPY_SIGTERM
: 0),
1623 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1625 if (plain_directory
) {
1626 /* Plain directories have no recursive read-only flag, but something pretty close to
1627 * it: the IMMUTABLE bit. Let's use this here, if this is requested. */
1629 if (flags
& BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE
)
1630 (void) chattr_path(new_path
, FS_IMMUTABLE_FL
, FS_IMMUTABLE_FL
, NULL
);
1632 r
= btrfs_subvol_set_read_only(new_path
, true);
1641 (void) rm_rf(new_path
, REMOVE_ROOT
|REMOVE_PHYSICAL
|REMOVE_SUBVOLUME
);
1645 r
= extract_subvolume_name(new_path
, &subvolume
);
1649 new_fd
= open_parent(new_path
, O_CLOEXEC
, 0);
1653 return subvol_snapshot_children(old_fd
, new_fd
, subvolume
, 0, flags
);
1656 int btrfs_subvol_snapshot_full(
1657 const char *old_path
,
1658 const char *new_path
,
1659 BtrfsSnapshotFlags flags
,
1660 copy_progress_path_t progress_path
,
1661 copy_progress_bytes_t progress_bytes
,
1664 _cleanup_close_
int old_fd
= -EBADF
;
1669 old_fd
= open(old_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1673 return btrfs_subvol_snapshot_fd_full(old_fd
, new_path
, flags
, progress_path
, progress_bytes
, userdata
);
1676 int btrfs_qgroup_find_parents(int fd
, uint64_t qgroupid
, uint64_t **ret
) {
1678 struct btrfs_ioctl_search_args args
= {
1679 /* Tree of quota items */
1680 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1682 /* Look precisely for the quota relation items */
1683 .key
.min_type
= BTRFS_QGROUP_RELATION_KEY
,
1684 .key
.max_type
= BTRFS_QGROUP_RELATION_KEY
,
1686 /* No restrictions on the other components */
1687 .key
.min_offset
= 0,
1688 .key
.max_offset
= UINT64_MAX
,
1690 .key
.min_transid
= 0,
1691 .key
.max_transid
= UINT64_MAX
,
1694 _cleanup_free_
uint64_t *items
= NULL
;
1701 if (qgroupid
== 0) {
1702 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
1706 r
= fd_is_fs_type(fd
, BTRFS_SUPER_MAGIC
);
1713 args
.key
.min_objectid
= args
.key
.max_objectid
= qgroupid
;
1715 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1716 const struct btrfs_ioctl_search_header
*sh
;
1719 args
.key
.nr_items
= 256;
1720 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1721 if (errno
== ENOENT
) /* quota tree missing: quota is disabled */
1727 if (args
.key
.nr_items
<= 0)
1730 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1732 /* Make sure we start the next search at least from this entry */
1733 btrfs_ioctl_search_args_set(&args
, sh
);
1735 if (sh
->type
!= BTRFS_QGROUP_RELATION_KEY
)
1737 if (sh
->offset
< sh
->objectid
)
1739 if (sh
->objectid
!= qgroupid
)
1742 if (!GREEDY_REALLOC(items
, n_items
+1))
1745 items
[n_items
++] = sh
->offset
;
1748 /* Increase search key by one, to read the next item, if we can. */
1749 if (!btrfs_ioctl_search_args_inc(&args
))
1758 *ret
= TAKE_PTR(items
);
1760 return (int) n_items
;
1763 int btrfs_subvol_auto_qgroup_fd(int fd
, uint64_t subvol_id
, bool insert_intermediary_qgroup
) {
1764 _cleanup_free_
uint64_t *qgroups
= NULL
;
1765 _cleanup_close_
int real_fd
= -EBADF
;
1766 uint64_t parent_subvol
;
1767 bool changed
= false;
1773 * Sets up the specified subvolume's qgroup automatically in
1776 * If insert_intermediary_qgroup is false, the subvolume's
1777 * leaf qgroup will be assigned to the same parent qgroups as
1778 * the subvolume's parent subvolume.
1780 * If insert_intermediary_qgroup is true a new intermediary
1781 * higher-level qgroup is created, with a higher level number,
1782 * but reusing the id of the subvolume. The level number is
1783 * picked as one smaller than the lowest level qgroup the
1784 * parent subvolume is a member of. If the parent subvolume's
1785 * leaf qgroup is assigned to no higher-level qgroup a new
1786 * qgroup of level 255 is created instead. Either way, the new
1787 * qgroup is then assigned to the parent's higher-level
1788 * qgroup, and the subvolume itself is assigned to it.
1790 * If the subvolume is already assigned to a higher level
1791 * qgroup, no operation is executed.
1793 * Effectively this means: regardless if
1794 * insert_intermediary_qgroup is true or not, after this
1795 * function is invoked the subvolume will be accounted within
1796 * the same qgroups as the parent. However, if it is true, it
1797 * will also get its own higher-level qgroup, which may in
1798 * turn be used by subvolumes created beneath this subvolume
1801 * This hence defines a simple default qgroup setup for
1802 * subvolumes, as long as this function is invoked on each
1803 * created subvolume: each subvolume is always accounting
1804 * together with its immediate parents. Optionally, if
1805 * insert_intermediary_qgroup is true, it will also get a
1806 * qgroup that then includes all its own child subvolumes.
1809 /* Turn this into a proper fd, if it is currently O_PATH */
1810 fd
= fd_reopen_condition(fd
, O_RDONLY
|O_CLOEXEC
, O_PATH
, &real_fd
);
1814 if (subvol_id
== 0) {
1815 r
= btrfs_is_subvol_fd(fd
);
1821 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1826 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
1829 if (n
> 0) /* already parent qgroups set up, let's bail */
1832 qgroups
= mfree(qgroups
);
1834 r
= btrfs_subvol_get_parent(fd
, subvol_id
, &parent_subvol
);
1836 /* No parent, hence no qgroup memberships */
1841 n
= btrfs_qgroup_find_parents(fd
, parent_subvol
, &qgroups
);
1846 if (insert_intermediary_qgroup
) {
1847 uint64_t lowest
= 256, new_qgroupid
;
1848 bool created
= false;
1850 /* Determine the lowest qgroup that the parent
1851 * subvolume is assigned to. */
1853 for (int i
= 0; i
< n
; i
++) {
1856 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, NULL
);
1864 if (lowest
<= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1867 r
= btrfs_qgroupid_make(lowest
- 1, subvol_id
, &new_qgroupid
);
1871 /* Create the new intermediary group, unless it already exists */
1872 r
= btrfs_qgroup_create(fd
, new_qgroupid
);
1873 if (r
< 0 && r
!= -EEXIST
)
1876 changed
= created
= true;
1878 for (int i
= 0; i
< n
; i
++) {
1879 r
= btrfs_qgroup_assign(fd
, new_qgroupid
, qgroups
[i
]);
1880 if (r
< 0 && r
!= -EEXIST
) {
1882 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1890 r
= btrfs_qgroup_assign(fd
, subvol_id
, new_qgroupid
);
1891 if (r
< 0 && r
!= -EEXIST
) {
1893 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1902 /* Assign our subvolume to all the same qgroups as the parent */
1904 for (i
= 0; i
< n
; i
++) {
1905 r
= btrfs_qgroup_assign(fd
, subvol_id
, qgroups
[i
]);
1906 if (r
< 0 && r
!= -EEXIST
)
1916 int btrfs_subvol_auto_qgroup(const char *path
, uint64_t subvol_id
, bool create_intermediary_qgroup
) {
1917 _cleanup_close_
int fd
= -EBADF
;
1919 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1923 return btrfs_subvol_auto_qgroup_fd(fd
, subvol_id
, create_intermediary_qgroup
);
1926 int btrfs_subvol_get_parent(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
1928 struct btrfs_ioctl_search_args args
= {
1929 /* Tree of tree roots */
1930 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1932 /* Look precisely for the subvolume items */
1933 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1934 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1936 /* No restrictions on the other components */
1937 .key
.min_offset
= 0,
1938 .key
.max_offset
= UINT64_MAX
,
1940 .key
.min_transid
= 0,
1941 .key
.max_transid
= UINT64_MAX
,
1948 if (subvol_id
== 0) {
1949 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1953 r
= fd_is_fs_type(fd
, BTRFS_SUPER_MAGIC
);
1960 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
1962 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1963 const struct btrfs_ioctl_search_header
*sh
;
1966 args
.key
.nr_items
= 256;
1967 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1968 return negative_errno();
1970 if (args
.key
.nr_items
<= 0)
1973 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1975 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1977 if (sh
->objectid
!= subvol_id
)