1 /* SPDX-License-Identifier: LGPL-2.1+ */
7 #include <linux/loop.h>
12 #include <sys/ioctl.h>
14 #include <sys/statfs.h>
15 #include <sys/sysmacros.h>
18 #include "alloc-util.h"
19 #include "blockdev-util.h"
20 #include "btrfs-util.h"
21 #include "chattr-util.h"
23 #include "device-nodes.h"
30 #include "path-util.h"
32 #include "smack-util.h"
33 #include "sparse-endian.h"
34 #include "stat-util.h"
35 #include "string-util.h"
36 #include "time-util.h"
39 /* WARNING: Be careful with file system ioctls! When we get an fd, we
40 * need to make sure it either refers to only a regular file or
41 * directory, or that it is located on btrfs, before invoking any
42 * btrfs ioctls. The ioctl numbers are reused by some device drivers
43 * (such as DRM), and hence might have bad effects when invoked on
44 * device nodes (that reference drivers) rather than fds to normal
45 * files or directories. */
47 static int validate_subvolume_name(const char *name
) {
49 if (!filename_is_valid(name
))
52 if (strlen(name
) > BTRFS_SUBVOL_NAME_MAX
)
58 static int extract_subvolume_name(const char *path
, const char **subvolume
) {
67 r
= validate_subvolume_name(fn
);
75 int btrfs_is_filesystem(int fd
) {
80 if (fstatfs(fd
, &sfs
) < 0)
83 return F_TYPE_EQUAL(sfs
.f_type
, BTRFS_SUPER_MAGIC
);
86 int btrfs_is_subvol_fd(int fd
) {
91 /* On btrfs subvolumes always have the inode 256 */
93 if (fstat(fd
, &st
) < 0)
96 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
99 return btrfs_is_filesystem(fd
);
102 int btrfs_is_subvol(const char *path
) {
103 _cleanup_close_
int fd
= -1;
107 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
111 return btrfs_is_subvol_fd(fd
);
114 int btrfs_subvol_make_fd(int fd
, const char *subvolume
) {
115 struct btrfs_ioctl_vol_args args
= {};
116 _cleanup_close_
int real_fd
= -1;
121 r
= validate_subvolume_name(subvolume
);
125 r
= fcntl(fd
, F_GETFL
);
128 if (FLAGS_SET(r
, O_PATH
)) {
129 /* An O_PATH fd was specified, let's convert here to a proper one, as btrfs ioctl's can't deal with
132 real_fd
= fd_reopen(fd
, O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
139 strncpy(args
.name
, subvolume
, sizeof(args
.name
)-1);
141 if (ioctl(fd
, BTRFS_IOC_SUBVOL_CREATE
, &args
) < 0)
147 int btrfs_subvol_make(const char *path
) {
148 _cleanup_close_
int fd
= -1;
149 const char *subvolume
;
154 r
= extract_subvolume_name(path
, &subvolume
);
158 fd
= open_parent(path
, O_CLOEXEC
, 0);
162 return btrfs_subvol_make_fd(fd
, subvolume
);
165 int btrfs_subvol_set_read_only_fd(int fd
, bool b
) {
166 uint64_t flags
, nflags
;
171 if (fstat(fd
, &st
) < 0)
174 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
177 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
181 nflags
= flags
| BTRFS_SUBVOL_RDONLY
;
183 nflags
= flags
& ~BTRFS_SUBVOL_RDONLY
;
188 if (ioctl(fd
, BTRFS_IOC_SUBVOL_SETFLAGS
, &nflags
) < 0)
194 int btrfs_subvol_set_read_only(const char *path
, bool b
) {
195 _cleanup_close_
int fd
= -1;
197 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
201 return btrfs_subvol_set_read_only_fd(fd
, b
);
204 int btrfs_subvol_get_read_only_fd(int fd
) {
210 if (fstat(fd
, &st
) < 0)
213 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
216 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
219 return !!(flags
& BTRFS_SUBVOL_RDONLY
);
222 int btrfs_reflink(int infd
, int outfd
) {
228 /* Make sure we invoke the ioctl on a regular file, so that no device driver accidentally gets it. */
230 r
= fd_verify_regular(outfd
);
234 if (ioctl(outfd
, BTRFS_IOC_CLONE
, infd
) < 0)
240 int btrfs_clone_range(int infd
, uint64_t in_offset
, int outfd
, uint64_t out_offset
, uint64_t sz
) {
241 struct btrfs_ioctl_clone_range_args args
= {
243 .src_offset
= in_offset
,
245 .dest_offset
= out_offset
,
253 r
= fd_verify_regular(outfd
);
257 if (ioctl(outfd
, BTRFS_IOC_CLONE_RANGE
, &args
) < 0)
263 int btrfs_get_block_device_fd(int fd
, dev_t
*dev
) {
264 struct btrfs_ioctl_fs_info_args fsi
= {};
271 r
= btrfs_is_filesystem(fd
);
277 if (ioctl(fd
, BTRFS_IOC_FS_INFO
, &fsi
) < 0)
280 /* We won't do this for btrfs RAID */
281 if (fsi
.num_devices
!= 1) {
286 for (id
= 1; id
<= fsi
.max_id
; id
++) {
287 struct btrfs_ioctl_dev_info_args di
= {
292 if (ioctl(fd
, BTRFS_IOC_DEV_INFO
, &di
) < 0) {
299 if (stat((char*) di
.path
, &st
) < 0)
302 if (!S_ISBLK(st
.st_mode
))
305 if (major(st
.st_rdev
) == 0)
315 int btrfs_get_block_device(const char *path
, dev_t
*dev
) {
316 _cleanup_close_
int fd
= -1;
321 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
325 return btrfs_get_block_device_fd(fd
, dev
);
328 int btrfs_subvol_get_id_fd(int fd
, uint64_t *ret
) {
329 struct btrfs_ioctl_ino_lookup_args args
= {
330 .objectid
= BTRFS_FIRST_FREE_OBJECTID
337 r
= btrfs_is_filesystem(fd
);
343 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
) < 0)
350 int btrfs_subvol_get_id(int fd
, const char *subvol
, uint64_t *ret
) {
351 _cleanup_close_
int subvol_fd
= -1;
356 subvol_fd
= openat(fd
, subvol
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
360 return btrfs_subvol_get_id_fd(subvol_fd
, ret
);
363 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args
*args
) {
366 /* the objectid, type, offset together make up the btrfs key,
367 * which is considered a single 136byte integer when
368 * comparing. This call increases the counter by one, dealing
369 * with the overflow between the overflows */
371 if (args
->key
.min_offset
< (uint64_t) -1) {
372 args
->key
.min_offset
++;
376 if (args
->key
.min_type
< (uint8_t) -1) {
377 args
->key
.min_type
++;
378 args
->key
.min_offset
= 0;
382 if (args
->key
.min_objectid
< (uint64_t) -1) {
383 args
->key
.min_objectid
++;
384 args
->key
.min_offset
= 0;
385 args
->key
.min_type
= 0;
392 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args
*args
, const struct btrfs_ioctl_search_header
*h
) {
396 args
->key
.min_objectid
= h
->objectid
;
397 args
->key
.min_type
= h
->type
;
398 args
->key
.min_offset
= h
->offset
;
401 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
*args
) {
406 /* Compare min and max */
408 r
= CMP(args
->key
.min_objectid
, args
->key
.max_objectid
);
412 r
= CMP(args
->key
.min_type
, args
->key
.max_type
);
416 return CMP(args
->key
.min_offset
, args
->key
.max_offset
);
419 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
421 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
422 (i) < (args).key.nr_items; \
424 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
426 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
427 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
429 int btrfs_subvol_get_info_fd(int fd
, uint64_t subvol_id
, BtrfsSubvolInfo
*ret
) {
430 struct btrfs_ioctl_search_args args
= {
431 /* Tree of tree roots */
432 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
434 /* Look precisely for the subvolume items */
435 .key
.min_type
= BTRFS_ROOT_ITEM_KEY
,
436 .key
.max_type
= BTRFS_ROOT_ITEM_KEY
,
439 .key
.max_offset
= (uint64_t) -1,
441 /* No restrictions on the other components */
442 .key
.min_transid
= 0,
443 .key
.max_transid
= (uint64_t) -1,
452 if (subvol_id
== 0) {
453 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
457 r
= btrfs_is_filesystem(fd
);
464 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
466 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
467 const struct btrfs_ioctl_search_header
*sh
;
470 args
.key
.nr_items
= 256;
471 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
474 if (args
.key
.nr_items
<= 0)
477 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
479 const struct btrfs_root_item
*ri
;
481 /* Make sure we start the next search at least from this entry */
482 btrfs_ioctl_search_args_set(&args
, sh
);
484 if (sh
->objectid
!= subvol_id
)
486 if (sh
->type
!= BTRFS_ROOT_ITEM_KEY
)
489 /* Older versions of the struct lacked the otime setting */
490 if (sh
->len
< offsetof(struct btrfs_root_item
, otime
) + sizeof(struct btrfs_timespec
))
493 ri
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
495 ret
->otime
= (usec_t
) le64toh(ri
->otime
.sec
) * USEC_PER_SEC
+
496 (usec_t
) le32toh(ri
->otime
.nsec
) / NSEC_PER_USEC
;
498 ret
->subvol_id
= subvol_id
;
499 ret
->read_only
= le64toh(ri
->flags
) & BTRFS_ROOT_SUBVOL_RDONLY
;
501 assert_cc(sizeof(ri
->uuid
) == sizeof(ret
->uuid
));
502 memcpy(&ret
->uuid
, ri
->uuid
, sizeof(ret
->uuid
));
503 memcpy(&ret
->parent_uuid
, ri
->parent_uuid
, sizeof(ret
->parent_uuid
));
509 /* Increase search key by one, to read the next item, if we can. */
510 if (!btrfs_ioctl_search_args_inc(&args
))
521 int btrfs_qgroup_get_quota_fd(int fd
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
523 struct btrfs_ioctl_search_args args
= {
524 /* Tree of quota items */
525 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
527 /* The object ID is always 0 */
528 .key
.min_objectid
= 0,
529 .key
.max_objectid
= 0,
531 /* Look precisely for the quota items */
532 .key
.min_type
= BTRFS_QGROUP_STATUS_KEY
,
533 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
535 /* No restrictions on the other components */
536 .key
.min_transid
= 0,
537 .key
.max_transid
= (uint64_t) -1,
540 bool found_info
= false, found_limit
= false;
547 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
551 r
= btrfs_is_filesystem(fd
);
558 args
.key
.min_offset
= args
.key
.max_offset
= qgroupid
;
560 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
561 const struct btrfs_ioctl_search_header
*sh
;
564 args
.key
.nr_items
= 256;
565 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
566 if (errno
== ENOENT
) /* quota tree is missing: quota disabled */
572 if (args
.key
.nr_items
<= 0)
575 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
577 /* Make sure we start the next search at least from this entry */
578 btrfs_ioctl_search_args_set(&args
, sh
);
580 if (sh
->objectid
!= 0)
582 if (sh
->offset
!= qgroupid
)
585 if (sh
->type
== BTRFS_QGROUP_INFO_KEY
) {
586 const struct btrfs_qgroup_info_item
*qii
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
588 ret
->referenced
= le64toh(qii
->rfer
);
589 ret
->exclusive
= le64toh(qii
->excl
);
593 } else if (sh
->type
== BTRFS_QGROUP_LIMIT_KEY
) {
594 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
596 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_RFER
)
597 ret
->referenced_max
= le64toh(qli
->max_rfer
);
599 ret
->referenced_max
= (uint64_t) -1;
601 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_EXCL
)
602 ret
->exclusive_max
= le64toh(qli
->max_excl
);
604 ret
->exclusive_max
= (uint64_t) -1;
609 if (found_info
&& found_limit
)
613 /* Increase search key by one, to read the next item, if we can. */
614 if (!btrfs_ioctl_search_args_inc(&args
))
619 if (!found_limit
&& !found_info
)
623 ret
->referenced
= (uint64_t) -1;
624 ret
->exclusive
= (uint64_t) -1;
628 ret
->referenced_max
= (uint64_t) -1;
629 ret
->exclusive_max
= (uint64_t) -1;
635 int btrfs_qgroup_get_quota(const char *path
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
636 _cleanup_close_
int fd
= -1;
638 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
642 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
645 int btrfs_subvol_find_subtree_qgroup(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
646 uint64_t level
, lowest
= (uint64_t) -1, lowest_qgroupid
= 0;
647 _cleanup_free_
uint64_t *qgroups
= NULL
;
653 /* This finds the "subtree" qgroup for a specific
654 * subvolume. This only works for subvolumes that have been
655 * prepared with btrfs_subvol_auto_qgroup_fd() with
656 * insert_intermediary_qgroup=true (or equivalent). For others
657 * it will return the leaf qgroup instead. The two cases may
658 * be distuingished via the return value, which is 1 in case
659 * an appropriate "subtree" qgroup was found, and 0
662 if (subvol_id
== 0) {
663 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
668 r
= btrfs_qgroupid_split(subvol_id
, &level
, NULL
);
671 if (level
!= 0) /* Input must be a leaf qgroup */
674 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
678 for (i
= 0; i
< n
; i
++) {
681 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, &id
);
688 if (lowest
== (uint64_t) -1 || level
< lowest
) {
689 lowest_qgroupid
= qgroups
[i
];
694 if (lowest
== (uint64_t) -1) {
695 /* No suitable higher-level qgroup found, let's return
696 * the leaf qgroup instead, and indicate that with the
703 *ret
= lowest_qgroupid
;
707 int btrfs_subvol_get_subtree_quota_fd(int fd
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
714 /* This determines the quota data of the qgroup with the
715 * lowest level, that shares the id part with the specified
716 * subvolume. This is useful for determining the quota data
717 * for entire subvolume subtrees, as long as the subtrees have
718 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
721 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
725 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
728 int btrfs_subvol_get_subtree_quota(const char *path
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
729 _cleanup_close_
int fd
= -1;
731 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
735 return btrfs_subvol_get_subtree_quota_fd(fd
, subvol_id
, ret
);
738 int btrfs_defrag_fd(int fd
) {
743 r
= fd_verify_regular(fd
);
747 if (ioctl(fd
, BTRFS_IOC_DEFRAG
, NULL
) < 0)
753 int btrfs_defrag(const char *p
) {
754 _cleanup_close_
int fd
= -1;
756 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
760 return btrfs_defrag_fd(fd
);
763 int btrfs_quota_enable_fd(int fd
, bool b
) {
764 struct btrfs_ioctl_quota_ctl_args args
= {
765 .cmd
= b
? BTRFS_QUOTA_CTL_ENABLE
: BTRFS_QUOTA_CTL_DISABLE
,
771 r
= btrfs_is_filesystem(fd
);
777 if (ioctl(fd
, BTRFS_IOC_QUOTA_CTL
, &args
) < 0)
783 int btrfs_quota_enable(const char *path
, bool b
) {
784 _cleanup_close_
int fd
= -1;
786 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
790 return btrfs_quota_enable_fd(fd
, b
);
793 int btrfs_qgroup_set_limit_fd(int fd
, uint64_t qgroupid
, uint64_t referenced_max
) {
795 struct btrfs_ioctl_qgroup_limit_args args
= {
796 .lim
.max_rfer
= referenced_max
,
797 .lim
.flags
= BTRFS_QGROUP_LIMIT_MAX_RFER
,
805 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
809 r
= btrfs_is_filesystem(fd
);
816 args
.qgroupid
= qgroupid
;
819 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &args
) < 0) {
821 if (errno
== EBUSY
&& c
< 10) {
822 (void) btrfs_quota_scan_wait(fd
);
835 int btrfs_qgroup_set_limit(const char *path
, uint64_t qgroupid
, uint64_t referenced_max
) {
836 _cleanup_close_
int fd
= -1;
838 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
842 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
845 int btrfs_subvol_set_subtree_quota_limit_fd(int fd
, uint64_t subvol_id
, uint64_t referenced_max
) {
851 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
855 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
858 int btrfs_subvol_set_subtree_quota_limit(const char *path
, uint64_t subvol_id
, uint64_t referenced_max
) {
859 _cleanup_close_
int fd
= -1;
861 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
865 return btrfs_subvol_set_subtree_quota_limit_fd(fd
, subvol_id
, referenced_max
);
868 int btrfs_qgroupid_make(uint64_t level
, uint64_t id
, uint64_t *ret
) {
871 if (level
>= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT
)))
874 if (id
>= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
))
877 *ret
= (level
<< BTRFS_QGROUP_LEVEL_SHIFT
) | id
;
881 int btrfs_qgroupid_split(uint64_t qgroupid
, uint64_t *level
, uint64_t *id
) {
885 *level
= qgroupid
>> BTRFS_QGROUP_LEVEL_SHIFT
;
888 *id
= qgroupid
& ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
) - 1);
893 static int qgroup_create_or_destroy(int fd
, bool b
, uint64_t qgroupid
) {
895 struct btrfs_ioctl_qgroup_create_args args
= {
897 .qgroupid
= qgroupid
,
902 r
= btrfs_is_filesystem(fd
);
909 if (ioctl(fd
, BTRFS_IOC_QGROUP_CREATE
, &args
) < 0) {
911 /* If quota is not enabled, we get EINVAL. Turn this into a recognizable error */
915 if (errno
== EBUSY
&& c
< 10) {
916 (void) btrfs_quota_scan_wait(fd
);
929 int btrfs_qgroup_create(int fd
, uint64_t qgroupid
) {
930 return qgroup_create_or_destroy(fd
, true, qgroupid
);
933 int btrfs_qgroup_destroy(int fd
, uint64_t qgroupid
) {
934 return qgroup_create_or_destroy(fd
, false, qgroupid
);
937 int btrfs_qgroup_destroy_recursive(int fd
, uint64_t qgroupid
) {
938 _cleanup_free_
uint64_t *qgroups
= NULL
;
942 /* Destroys the specified qgroup, but unassigns it from all
943 * its parents first. Also, it recursively destroys all
944 * qgroups it is assigned to that have the same id part of the
945 * qgroupid as the specified group. */
947 r
= btrfs_qgroupid_split(qgroupid
, NULL
, &subvol_id
);
951 n
= btrfs_qgroup_find_parents(fd
, qgroupid
, &qgroups
);
955 for (i
= 0; i
< n
; i
++) {
958 r
= btrfs_qgroupid_split(qgroups
[i
], NULL
, &id
);
962 r
= btrfs_qgroup_unassign(fd
, qgroupid
, qgroups
[i
]);
969 /* The parent qgroupid shares the same id part with
970 * us? If so, destroy it too. */
972 (void) btrfs_qgroup_destroy_recursive(fd
, qgroups
[i
]);
975 return btrfs_qgroup_destroy(fd
, qgroupid
);
978 int btrfs_quota_scan_start(int fd
) {
979 struct btrfs_ioctl_quota_rescan_args args
= {};
983 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN
, &args
) < 0)
989 int btrfs_quota_scan_wait(int fd
) {
992 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_WAIT
) < 0)
998 int btrfs_quota_scan_ongoing(int fd
) {
999 struct btrfs_ioctl_quota_rescan_args args
= {};
1003 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_STATUS
, &args
) < 0)
1006 return !!args
.flags
;
1009 static int qgroup_assign_or_unassign(int fd
, bool b
, uint64_t child
, uint64_t parent
) {
1010 struct btrfs_ioctl_qgroup_assign_args args
= {
1018 r
= btrfs_is_filesystem(fd
);
1025 r
= ioctl(fd
, BTRFS_IOC_QGROUP_ASSIGN
, &args
);
1027 if (errno
== EBUSY
&& c
< 10) {
1028 (void) btrfs_quota_scan_wait(fd
);
1038 /* If the return value is > 0, we need to request a rescan */
1040 (void) btrfs_quota_scan_start(fd
);
1045 int btrfs_qgroup_assign(int fd
, uint64_t child
, uint64_t parent
) {
1046 return qgroup_assign_or_unassign(fd
, true, child
, parent
);
1049 int btrfs_qgroup_unassign(int fd
, uint64_t child
, uint64_t parent
) {
1050 return qgroup_assign_or_unassign(fd
, false, child
, parent
);
1053 static int subvol_remove_children(int fd
, const char *subvolume
, uint64_t subvol_id
, BtrfsRemoveFlags flags
) {
1054 struct btrfs_ioctl_search_args args
= {
1055 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1057 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1058 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1060 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1061 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1063 .key
.min_transid
= 0,
1064 .key
.max_transid
= (uint64_t) -1,
1067 struct btrfs_ioctl_vol_args vol_args
= {};
1068 _cleanup_close_
int subvol_fd
= -1;
1070 bool made_writable
= false;
1076 if (fstat(fd
, &st
) < 0)
1079 if (!S_ISDIR(st
.st_mode
))
1082 subvol_fd
= openat(fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1086 /* Let's check if this is actually a subvolume. Note that this is mostly redundant, as BTRFS_IOC_SNAP_DESTROY
1087 * would fail anyway if it is not. However, it's a good thing to check this ahead of time so that we can return
1088 * ENOTTY unconditionally in this case. This is different from the ioctl() which will return EPERM/EACCES if we
1089 * don't have the privileges to remove subvolumes, regardless if the specified directory is actually a
1090 * subvolume or not. In order to make it easy for callers to cover the "this is not a btrfs subvolume" case
1091 * let's prefer ENOTTY over EPERM/EACCES though. */
1092 r
= btrfs_is_subvol_fd(subvol_fd
);
1095 if (r
== 0) /* Not a btrfs subvolume */
1098 if (subvol_id
== 0) {
1099 r
= btrfs_subvol_get_id_fd(subvol_fd
, &subvol_id
);
1104 /* First, try to remove the subvolume. If it happens to be
1105 * already empty, this will just work. */
1106 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1107 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) >= 0) {
1108 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1111 if (!(flags
& BTRFS_REMOVE_RECURSIVE
) || errno
!= ENOTEMPTY
)
1114 /* OK, the subvolume is not empty, let's look for child
1115 * subvolumes, and remove them, first */
1117 args
.key
.min_offset
= args
.key
.max_offset
= subvol_id
;
1119 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1120 const struct btrfs_ioctl_search_header
*sh
;
1123 args
.key
.nr_items
= 256;
1124 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1127 if (args
.key
.nr_items
<= 0)
1130 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1131 _cleanup_free_
char *p
= NULL
;
1132 const struct btrfs_root_ref
*ref
;
1133 struct btrfs_ioctl_ino_lookup_args ino_args
;
1135 btrfs_ioctl_search_args_set(&args
, sh
);
1137 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1139 if (sh
->offset
!= subvol_id
)
1142 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1144 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1149 ino_args
.treeid
= subvol_id
;
1150 ino_args
.objectid
= htole64(ref
->dirid
);
1152 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1155 if (!made_writable
) {
1156 r
= btrfs_subvol_set_read_only_fd(subvol_fd
, false);
1160 made_writable
= true;
1163 if (isempty(ino_args
.name
))
1164 /* Subvolume is in the top-level
1165 * directory of the subvolume. */
1166 r
= subvol_remove_children(subvol_fd
, p
, sh
->objectid
, flags
);
1168 _cleanup_close_
int child_fd
= -1;
1170 /* Subvolume is somewhere further down,
1171 * hence we need to open the
1172 * containing directory first */
1174 child_fd
= openat(subvol_fd
, ino_args
.name
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1178 r
= subvol_remove_children(child_fd
, p
, sh
->objectid
, flags
);
1184 /* Increase search key by one, to read the next item, if we can. */
1185 if (!btrfs_ioctl_search_args_inc(&args
))
1189 /* OK, the child subvolumes should all be gone now, let's try
1190 * again to remove the subvolume */
1191 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) < 0)
1194 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
);
1198 int btrfs_subvol_remove(const char *path
, BtrfsRemoveFlags flags
) {
1199 _cleanup_close_
int fd
= -1;
1200 const char *subvolume
;
1205 r
= extract_subvolume_name(path
, &subvolume
);
1209 fd
= open_parent(path
, O_CLOEXEC
, 0);
1213 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1216 int btrfs_subvol_remove_fd(int fd
, const char *subvolume
, BtrfsRemoveFlags flags
) {
1217 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1220 int btrfs_qgroup_copy_limits(int fd
, uint64_t old_qgroupid
, uint64_t new_qgroupid
) {
1222 struct btrfs_ioctl_search_args args
= {
1223 /* Tree of quota items */
1224 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1226 /* The object ID is always 0 */
1227 .key
.min_objectid
= 0,
1228 .key
.max_objectid
= 0,
1230 /* Look precisely for the quota items */
1231 .key
.min_type
= BTRFS_QGROUP_LIMIT_KEY
,
1232 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
1234 /* For our qgroup */
1235 .key
.min_offset
= old_qgroupid
,
1236 .key
.max_offset
= old_qgroupid
,
1238 /* No restrictions on the other components */
1239 .key
.min_transid
= 0,
1240 .key
.max_transid
= (uint64_t) -1,
1245 r
= btrfs_is_filesystem(fd
);
1251 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1252 const struct btrfs_ioctl_search_header
*sh
;
1255 args
.key
.nr_items
= 256;
1256 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1257 if (errno
== ENOENT
) /* quota tree missing: quota is not enabled, hence nothing to copy */
1263 if (args
.key
.nr_items
<= 0)
1266 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1267 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1268 struct btrfs_ioctl_qgroup_limit_args qargs
;
1271 /* Make sure we start the next search at least from this entry */
1272 btrfs_ioctl_search_args_set(&args
, sh
);
1274 if (sh
->objectid
!= 0)
1276 if (sh
->type
!= BTRFS_QGROUP_LIMIT_KEY
)
1278 if (sh
->offset
!= old_qgroupid
)
1281 /* We found the entry, now copy things over. */
1283 qargs
= (struct btrfs_ioctl_qgroup_limit_args
) {
1284 .qgroupid
= new_qgroupid
,
1286 .lim
.max_rfer
= le64toh(qli
->max_rfer
),
1287 .lim
.max_excl
= le64toh(qli
->max_excl
),
1288 .lim
.rsv_rfer
= le64toh(qli
->rsv_rfer
),
1289 .lim
.rsv_excl
= le64toh(qli
->rsv_excl
),
1291 .lim
.flags
= le64toh(qli
->flags
) & (BTRFS_QGROUP_LIMIT_MAX_RFER
|
1292 BTRFS_QGROUP_LIMIT_MAX_EXCL
|
1293 BTRFS_QGROUP_LIMIT_RSV_RFER
|
1294 BTRFS_QGROUP_LIMIT_RSV_EXCL
),
1298 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &qargs
) < 0) {
1299 if (errno
== EBUSY
&& c
< 10) {
1300 (void) btrfs_quota_scan_wait(fd
);
1312 /* Increase search key by one, to read the next item, if we can. */
1313 if (!btrfs_ioctl_search_args_inc(&args
))
1320 static int copy_quota_hierarchy(int fd
, uint64_t old_subvol_id
, uint64_t new_subvol_id
) {
1321 _cleanup_free_
uint64_t *old_qgroups
= NULL
, *old_parent_qgroups
= NULL
;
1322 bool copy_from_parent
= false, insert_intermediary_qgroup
= false;
1323 int n_old_qgroups
, n_old_parent_qgroups
, r
, i
;
1324 uint64_t old_parent_id
;
1328 /* Copies a reduced form of quota information from the old to
1329 * the new subvolume. */
1331 n_old_qgroups
= btrfs_qgroup_find_parents(fd
, old_subvol_id
, &old_qgroups
);
1332 if (n_old_qgroups
<= 0) /* Nothing to copy */
1333 return n_old_qgroups
;
1335 r
= btrfs_subvol_get_parent(fd
, old_subvol_id
, &old_parent_id
);
1337 /* We have no parent, hence nothing to copy. */
1338 n_old_parent_qgroups
= 0;
1342 n_old_parent_qgroups
= btrfs_qgroup_find_parents(fd
, old_parent_id
, &old_parent_qgroups
);
1343 if (n_old_parent_qgroups
< 0)
1344 return n_old_parent_qgroups
;
1347 for (i
= 0; i
< n_old_qgroups
; i
++) {
1351 r
= btrfs_qgroupid_split(old_qgroups
[i
], NULL
, &id
);
1355 if (id
== old_subvol_id
) {
1356 /* The old subvolume was member of a qgroup
1357 * that had the same id, but a different level
1358 * as it self. Let's set up something similar
1359 * in the destination. */
1360 insert_intermediary_qgroup
= true;
1364 for (j
= 0; j
< n_old_parent_qgroups
; j
++)
1365 if (old_parent_qgroups
[j
] == old_qgroups
[i
]) {
1366 /* The old subvolume shared a common
1367 * parent qgroup with its parent
1368 * subvolume. Let's set up something
1369 * similar in the destination. */
1370 copy_from_parent
= true;
1374 if (!insert_intermediary_qgroup
&& !copy_from_parent
)
1377 return btrfs_subvol_auto_qgroup_fd(fd
, new_subvol_id
, insert_intermediary_qgroup
);
1380 static int copy_subtree_quota_limits(int fd
, uint64_t old_subvol
, uint64_t new_subvol
) {
1381 uint64_t old_subtree_qgroup
, new_subtree_qgroup
;
1385 /* First copy the leaf limits */
1386 r
= btrfs_qgroup_copy_limits(fd
, old_subvol
, new_subvol
);
1391 /* Then, try to copy the subtree limits, if there are any. */
1392 r
= btrfs_subvol_find_subtree_qgroup(fd
, old_subvol
, &old_subtree_qgroup
);
1398 r
= btrfs_subvol_find_subtree_qgroup(fd
, new_subvol
, &new_subtree_qgroup
);
1404 r
= btrfs_qgroup_copy_limits(fd
, old_subtree_qgroup
, new_subtree_qgroup
);
1411 static int subvol_snapshot_children(
1414 const char *subvolume
,
1415 uint64_t old_subvol_id
,
1416 BtrfsSnapshotFlags flags
) {
1418 struct btrfs_ioctl_search_args args
= {
1419 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1421 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1422 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1424 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1425 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1427 .key
.min_transid
= 0,
1428 .key
.max_transid
= (uint64_t) -1,
1431 struct btrfs_ioctl_vol_args_v2 vol_args
= {
1432 .flags
= flags
& BTRFS_SNAPSHOT_READ_ONLY
? BTRFS_SUBVOL_RDONLY
: 0,
1435 _cleanup_close_
int subvolume_fd
= -1;
1436 uint64_t new_subvol_id
;
1439 assert(old_fd
>= 0);
1440 assert(new_fd
>= 0);
1443 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1445 if (ioctl(new_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &vol_args
) < 0)
1448 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
) &&
1449 !(flags
& BTRFS_SNAPSHOT_QUOTA
))
1452 if (old_subvol_id
== 0) {
1453 r
= btrfs_subvol_get_id_fd(old_fd
, &old_subvol_id
);
1458 r
= btrfs_subvol_get_id(new_fd
, vol_args
.name
, &new_subvol_id
);
1462 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1463 (void) copy_quota_hierarchy(new_fd
, old_subvol_id
, new_subvol_id
);
1465 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
)) {
1467 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1468 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1473 args
.key
.min_offset
= args
.key
.max_offset
= old_subvol_id
;
1475 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1476 const struct btrfs_ioctl_search_header
*sh
;
1479 args
.key
.nr_items
= 256;
1480 if (ioctl(old_fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1483 if (args
.key
.nr_items
<= 0)
1486 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1487 _cleanup_free_
char *p
= NULL
, *c
= NULL
, *np
= NULL
;
1488 struct btrfs_ioctl_ino_lookup_args ino_args
;
1489 const struct btrfs_root_ref
*ref
;
1490 _cleanup_close_
int old_child_fd
= -1, new_child_fd
= -1;
1492 btrfs_ioctl_search_args_set(&args
, sh
);
1494 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1497 /* Avoid finding the source subvolume a second
1499 if (sh
->offset
!= old_subvol_id
)
1502 /* Avoid running into loops if the new
1503 * subvolume is below the old one. */
1504 if (sh
->objectid
== new_subvol_id
)
1507 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1508 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1513 ino_args
.treeid
= old_subvol_id
;
1514 ino_args
.objectid
= htole64(ref
->dirid
);
1516 if (ioctl(old_fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1519 /* The kernel returns an empty name if the
1520 * subvolume is in the top-level directory,
1521 * and otherwise appends a slash, so that we
1522 * can just concatenate easily here, without
1523 * adding a slash. */
1524 c
= strappend(ino_args
.name
, p
);
1528 old_child_fd
= openat(old_fd
, c
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1529 if (old_child_fd
< 0)
1532 np
= strjoin(subvolume
, "/", ino_args
.name
);
1536 new_child_fd
= openat(new_fd
, np
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1537 if (new_child_fd
< 0)
1540 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1541 /* If the snapshot is read-only we
1542 * need to mark it writable
1543 * temporarily, to put the subsnapshot
1546 if (subvolume_fd
< 0) {
1547 subvolume_fd
= openat(new_fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1548 if (subvolume_fd
< 0)
1552 r
= btrfs_subvol_set_read_only_fd(subvolume_fd
, false);
1557 /* When btrfs clones the subvolumes, child
1558 * subvolumes appear as empty directories. Remove
1559 * them, so that we can create a new snapshot
1561 if (unlinkat(new_child_fd
, p
, AT_REMOVEDIR
) < 0) {
1564 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
)
1565 (void) btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1570 r
= subvol_snapshot_children(old_child_fd
, new_child_fd
, p
, sh
->objectid
, flags
& ~BTRFS_SNAPSHOT_FALLBACK_COPY
);
1572 /* Restore the readonly flag */
1573 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1576 k
= btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1577 if (r
>= 0 && k
< 0)
1585 /* Increase search key by one, to read the next item, if we can. */
1586 if (!btrfs_ioctl_search_args_inc(&args
))
1590 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1591 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1596 int btrfs_subvol_snapshot_fd_full(
1598 const char *new_path
,
1599 BtrfsSnapshotFlags flags
,
1600 copy_progress_path_t progress_path
,
1601 copy_progress_bytes_t progress_bytes
,
1604 _cleanup_close_
int new_fd
= -1;
1605 const char *subvolume
;
1608 assert(old_fd
>= 0);
1611 r
= btrfs_is_subvol_fd(old_fd
);
1615 bool plain_directory
= false;
1617 /* If the source isn't a proper subvolume, fail unless fallback is requested */
1618 if (!(flags
& BTRFS_SNAPSHOT_FALLBACK_COPY
))
1621 r
= btrfs_subvol_make(new_path
);
1622 if (r
== -ENOTTY
&& (flags
& BTRFS_SNAPSHOT_FALLBACK_DIRECTORY
)) {
1623 /* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */
1624 if (mkdir(new_path
, 0755) < 0)
1627 plain_directory
= true;
1631 r
= copy_directory_fd_full(old_fd
, new_path
, COPY_MERGE
|COPY_REFLINK
, progress_path
, progress_bytes
, userdata
);
1635 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1637 if (plain_directory
) {
1638 /* Plain directories have no recursive read-only flag, but something pretty close to
1639 * it: the IMMUTABLE bit. Let's use this here, if this is requested. */
1641 if (flags
& BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE
)
1642 (void) chattr_path(new_path
, FS_IMMUTABLE_FL
, FS_IMMUTABLE_FL
, NULL
);
1644 r
= btrfs_subvol_set_read_only(new_path
, true);
1653 (void) rm_rf(new_path
, REMOVE_ROOT
|REMOVE_PHYSICAL
|REMOVE_SUBVOLUME
);
1657 r
= extract_subvolume_name(new_path
, &subvolume
);
1661 new_fd
= open_parent(new_path
, O_CLOEXEC
, 0);
1665 return subvol_snapshot_children(old_fd
, new_fd
, subvolume
, 0, flags
);
1668 int btrfs_subvol_snapshot_full(
1669 const char *old_path
,
1670 const char *new_path
,
1671 BtrfsSnapshotFlags flags
,
1672 copy_progress_path_t progress_path
,
1673 copy_progress_bytes_t progress_bytes
,
1676 _cleanup_close_
int old_fd
= -1;
1681 old_fd
= open(old_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1685 return btrfs_subvol_snapshot_fd_full(old_fd
, new_path
, flags
, progress_path
, progress_bytes
, userdata
);
1688 int btrfs_qgroup_find_parents(int fd
, uint64_t qgroupid
, uint64_t **ret
) {
1690 struct btrfs_ioctl_search_args args
= {
1691 /* Tree of quota items */
1692 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1694 /* Look precisely for the quota relation items */
1695 .key
.min_type
= BTRFS_QGROUP_RELATION_KEY
,
1696 .key
.max_type
= BTRFS_QGROUP_RELATION_KEY
,
1698 /* No restrictions on the other components */
1699 .key
.min_offset
= 0,
1700 .key
.max_offset
= (uint64_t) -1,
1702 .key
.min_transid
= 0,
1703 .key
.max_transid
= (uint64_t) -1,
1706 _cleanup_free_
uint64_t *items
= NULL
;
1707 size_t n_items
= 0, n_allocated
= 0;
1713 if (qgroupid
== 0) {
1714 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
1718 r
= btrfs_is_filesystem(fd
);
1725 args
.key
.min_objectid
= args
.key
.max_objectid
= qgroupid
;
1727 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1728 const struct btrfs_ioctl_search_header
*sh
;
1731 args
.key
.nr_items
= 256;
1732 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1733 if (errno
== ENOENT
) /* quota tree missing: quota is disabled */
1739 if (args
.key
.nr_items
<= 0)
1742 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1744 /* Make sure we start the next search at least from this entry */
1745 btrfs_ioctl_search_args_set(&args
, sh
);
1747 if (sh
->type
!= BTRFS_QGROUP_RELATION_KEY
)
1749 if (sh
->offset
< sh
->objectid
)
1751 if (sh
->objectid
!= qgroupid
)
1754 if (!GREEDY_REALLOC(items
, n_allocated
, n_items
+1))
1757 items
[n_items
++] = sh
->offset
;
1760 /* Increase search key by one, to read the next item, if we can. */
1761 if (!btrfs_ioctl_search_args_inc(&args
))
1770 *ret
= TAKE_PTR(items
);
1772 return (int) n_items
;
1775 int btrfs_subvol_auto_qgroup_fd(int fd
, uint64_t subvol_id
, bool insert_intermediary_qgroup
) {
1776 _cleanup_free_
uint64_t *qgroups
= NULL
;
1777 uint64_t parent_subvol
;
1778 bool changed
= false;
1784 * Sets up the specified subvolume's qgroup automatically in
1787 * If insert_intermediary_qgroup is false, the subvolume's
1788 * leaf qgroup will be assigned to the same parent qgroups as
1789 * the subvolume's parent subvolume.
1791 * If insert_intermediary_qgroup is true a new intermediary
1792 * higher-level qgroup is created, with a higher level number,
1793 * but reusing the id of the subvolume. The level number is
1794 * picked as one smaller than the lowest level qgroup the
1795 * parent subvolume is a member of. If the parent subvolume's
1796 * leaf qgroup is assigned to no higher-level qgroup a new
1797 * qgroup of level 255 is created instead. Either way, the new
1798 * qgroup is then assigned to the parent's higher-level
1799 * qgroup, and the subvolume itself is assigned to it.
1801 * If the subvolume is already assigned to a higher level
1802 * qgroup, no operation is executed.
1804 * Effectively this means: regardless if
1805 * insert_intermediary_qgroup is true or not, after this
1806 * function is invoked the subvolume will be accounted within
1807 * the same qgroups as the parent. However, if it is true, it
1808 * will also get its own higher-level qgroup, which may in
1809 * turn be used by subvolumes created beneath this subvolume
1812 * This hence defines a simple default qgroup setup for
1813 * subvolumes, as long as this function is invoked on each
1814 * created subvolume: each subvolume is always accounting
1815 * together with its immediate parents. Optionally, if
1816 * insert_intermediary_qgroup is true, it will also get a
1817 * qgroup that then includes all its own child subvolumes.
1820 if (subvol_id
== 0) {
1821 r
= btrfs_is_subvol_fd(fd
);
1827 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1832 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
1835 if (n
> 0) /* already parent qgroups set up, let's bail */
1838 qgroups
= mfree(qgroups
);
1840 r
= btrfs_subvol_get_parent(fd
, subvol_id
, &parent_subvol
);
1842 /* No parent, hence no qgroup memberships */
1847 n
= btrfs_qgroup_find_parents(fd
, parent_subvol
, &qgroups
);
1852 if (insert_intermediary_qgroup
) {
1853 uint64_t lowest
= 256, new_qgroupid
;
1854 bool created
= false;
1857 /* Determine the lowest qgroup that the parent
1858 * subvolume is assigned to. */
1860 for (i
= 0; i
< n
; i
++) {
1863 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, NULL
);
1871 if (lowest
<= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1874 r
= btrfs_qgroupid_make(lowest
- 1, subvol_id
, &new_qgroupid
);
1878 /* Create the new intermediary group, unless it already exists */
1879 r
= btrfs_qgroup_create(fd
, new_qgroupid
);
1880 if (r
< 0 && r
!= -EEXIST
)
1883 changed
= created
= true;
1885 for (i
= 0; i
< n
; i
++) {
1886 r
= btrfs_qgroup_assign(fd
, new_qgroupid
, qgroups
[i
]);
1887 if (r
< 0 && r
!= -EEXIST
) {
1889 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1897 r
= btrfs_qgroup_assign(fd
, subvol_id
, new_qgroupid
);
1898 if (r
< 0 && r
!= -EEXIST
) {
1900 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1909 /* Assign our subvolume to all the same qgroups as the parent */
1911 for (i
= 0; i
< n
; i
++) {
1912 r
= btrfs_qgroup_assign(fd
, subvol_id
, qgroups
[i
]);
1913 if (r
< 0 && r
!= -EEXIST
)
1923 int btrfs_subvol_auto_qgroup(const char *path
, uint64_t subvol_id
, bool create_intermediary_qgroup
) {
1924 _cleanup_close_
int fd
= -1;
1926 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1930 return btrfs_subvol_auto_qgroup_fd(fd
, subvol_id
, create_intermediary_qgroup
);
1933 int btrfs_subvol_get_parent(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
1935 struct btrfs_ioctl_search_args args
= {
1936 /* Tree of tree roots */
1937 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1939 /* Look precisely for the subvolume items */
1940 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1941 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1943 /* No restrictions on the other components */
1944 .key
.min_offset
= 0,
1945 .key
.max_offset
= (uint64_t) -1,
1947 .key
.min_transid
= 0,
1948 .key
.max_transid
= (uint64_t) -1,
1955 if (subvol_id
== 0) {
1956 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1960 r
= btrfs_is_filesystem(fd
);
1967 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
1969 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1970 const struct btrfs_ioctl_search_header
*sh
;
1973 args
.key
.nr_items
= 256;
1974 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1975 return negative_errno();
1977 if (args
.key
.nr_items
<= 0)
1980 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1982 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1984 if (sh
->objectid
!= subvol_id
)