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"
22 #include "device-nodes.h"
28 #include "path-util.h"
30 #include "smack-util.h"
31 #include "sparse-endian.h"
32 #include "stat-util.h"
33 #include "string-util.h"
34 #include "time-util.h"
37 /* WARNING: Be careful with file system ioctls! When we get an fd, we
38 * need to make sure it either refers to only a regular file or
39 * directory, or that it is located on btrfs, before invoking any
40 * btrfs ioctls. The ioctl numbers are reused by some device drivers
41 * (such as DRM), and hence might have bad effects when invoked on
42 * device nodes (that reference drivers) rather than fds to normal
43 * files or directories. */
45 static int validate_subvolume_name(const char *name
) {
47 if (!filename_is_valid(name
))
50 if (strlen(name
) > BTRFS_SUBVOL_NAME_MAX
)
56 static int extract_subvolume_name(const char *path
, const char **subvolume
) {
65 r
= validate_subvolume_name(fn
);
73 int btrfs_is_filesystem(int fd
) {
78 if (fstatfs(fd
, &sfs
) < 0)
81 return F_TYPE_EQUAL(sfs
.f_type
, BTRFS_SUPER_MAGIC
);
84 int btrfs_is_subvol_fd(int fd
) {
89 /* On btrfs subvolumes always have the inode 256 */
91 if (fstat(fd
, &st
) < 0)
94 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
97 return btrfs_is_filesystem(fd
);
100 int btrfs_is_subvol(const char *path
) {
101 _cleanup_close_
int fd
= -1;
105 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
109 return btrfs_is_subvol_fd(fd
);
112 int btrfs_subvol_make_fd(int fd
, const char *subvolume
) {
113 struct btrfs_ioctl_vol_args args
= {};
114 _cleanup_close_
int real_fd
= -1;
119 r
= validate_subvolume_name(subvolume
);
123 r
= fcntl(fd
, F_GETFL
);
126 if (FLAGS_SET(r
, O_PATH
)) {
127 /* An O_PATH fd was specified, let's convert here to a proper one, as btrfs ioctl's can't deal with
130 real_fd
= fd_reopen(fd
, O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
137 strncpy(args
.name
, subvolume
, sizeof(args
.name
)-1);
139 if (ioctl(fd
, BTRFS_IOC_SUBVOL_CREATE
, &args
) < 0)
145 int btrfs_subvol_make(const char *path
) {
146 _cleanup_close_
int fd
= -1;
147 const char *subvolume
;
152 r
= extract_subvolume_name(path
, &subvolume
);
156 fd
= open_parent(path
, O_CLOEXEC
, 0);
160 return btrfs_subvol_make_fd(fd
, subvolume
);
163 int btrfs_subvol_make_fallback(const char *path
, mode_t mode
) {
164 mode_t old
, combined
;
169 /* Let's work like mkdir(), i.e. take the specified mode, and mask it with the current umask. */
171 combined
= old
| ~mode
;
172 if (combined
!= ~mode
)
174 r
= btrfs_subvol_make(path
);
178 return 1; /* subvol worked */
182 if (mkdir(path
, mode
) < 0)
185 return 0; /* plain directory */
188 int btrfs_subvol_set_read_only_fd(int fd
, bool b
) {
189 uint64_t flags
, nflags
;
194 if (fstat(fd
, &st
) < 0)
197 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
200 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
203 nflags
= UPDATE_FLAG(flags
, BTRFS_SUBVOL_RDONLY
, b
);
207 if (ioctl(fd
, BTRFS_IOC_SUBVOL_SETFLAGS
, &nflags
) < 0)
213 int btrfs_subvol_set_read_only(const char *path
, bool b
) {
214 _cleanup_close_
int fd
= -1;
216 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
220 return btrfs_subvol_set_read_only_fd(fd
, b
);
223 int btrfs_subvol_get_read_only_fd(int fd
) {
229 if (fstat(fd
, &st
) < 0)
232 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
235 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
238 return !!(flags
& BTRFS_SUBVOL_RDONLY
);
241 int btrfs_reflink(int infd
, int outfd
) {
247 /* Make sure we invoke the ioctl on a regular file, so that no device driver accidentally gets it. */
249 r
= fd_verify_regular(outfd
);
253 if (ioctl(outfd
, BTRFS_IOC_CLONE
, infd
) < 0)
259 int btrfs_clone_range(int infd
, uint64_t in_offset
, int outfd
, uint64_t out_offset
, uint64_t sz
) {
260 struct btrfs_ioctl_clone_range_args args
= {
262 .src_offset
= in_offset
,
264 .dest_offset
= out_offset
,
272 r
= fd_verify_regular(outfd
);
276 if (ioctl(outfd
, BTRFS_IOC_CLONE_RANGE
, &args
) < 0)
282 int btrfs_get_block_device_fd(int fd
, dev_t
*dev
) {
283 struct btrfs_ioctl_fs_info_args fsi
= {};
290 r
= btrfs_is_filesystem(fd
);
296 if (ioctl(fd
, BTRFS_IOC_FS_INFO
, &fsi
) < 0)
299 /* We won't do this for btrfs RAID */
300 if (fsi
.num_devices
!= 1) {
305 for (id
= 1; id
<= fsi
.max_id
; id
++) {
306 struct btrfs_ioctl_dev_info_args di
= {
311 if (ioctl(fd
, BTRFS_IOC_DEV_INFO
, &di
) < 0) {
318 /* For the root fs — when no initrd is involved — btrfs returns /dev/root on any kernels from
319 * the past few years. That sucks, as we have no API to determine the actual root then. let's
320 * return an recognizable error for this case, so that the caller can maybe print a nice
321 * message about this.
323 * https://bugzilla.kernel.org/show_bug.cgi?id=89721 */
324 if (path_equal((char*) di
.path
, "/dev/root"))
327 if (stat((char*) di
.path
, &st
) < 0)
330 if (!S_ISBLK(st
.st_mode
))
333 if (major(st
.st_rdev
) == 0)
343 int btrfs_get_block_device(const char *path
, dev_t
*dev
) {
344 _cleanup_close_
int fd
= -1;
349 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
353 return btrfs_get_block_device_fd(fd
, dev
);
356 int btrfs_subvol_get_id_fd(int fd
, uint64_t *ret
) {
357 struct btrfs_ioctl_ino_lookup_args args
= {
358 .objectid
= BTRFS_FIRST_FREE_OBJECTID
365 r
= btrfs_is_filesystem(fd
);
371 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
) < 0)
378 int btrfs_subvol_get_id(int fd
, const char *subvol
, uint64_t *ret
) {
379 _cleanup_close_
int subvol_fd
= -1;
384 subvol_fd
= openat(fd
, subvol
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
388 return btrfs_subvol_get_id_fd(subvol_fd
, ret
);
391 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args
*args
) {
394 /* the objectid, type, offset together make up the btrfs key,
395 * which is considered a single 136byte integer when
396 * comparing. This call increases the counter by one, dealing
397 * with the overflow between the overflows */
399 if (args
->key
.min_offset
< (uint64_t) -1) {
400 args
->key
.min_offset
++;
404 if (args
->key
.min_type
< (uint8_t) -1) {
405 args
->key
.min_type
++;
406 args
->key
.min_offset
= 0;
410 if (args
->key
.min_objectid
< (uint64_t) -1) {
411 args
->key
.min_objectid
++;
412 args
->key
.min_offset
= 0;
413 args
->key
.min_type
= 0;
420 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args
*args
, const struct btrfs_ioctl_search_header
*h
) {
424 args
->key
.min_objectid
= h
->objectid
;
425 args
->key
.min_type
= h
->type
;
426 args
->key
.min_offset
= h
->offset
;
429 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
*args
) {
434 /* Compare min and max */
436 r
= CMP(args
->key
.min_objectid
, args
->key
.max_objectid
);
440 r
= CMP(args
->key
.min_type
, args
->key
.max_type
);
444 return CMP(args
->key
.min_offset
, args
->key
.max_offset
);
447 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
449 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
450 (i) < (args).key.nr_items; \
452 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
454 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
455 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
457 int btrfs_subvol_get_info_fd(int fd
, uint64_t subvol_id
, BtrfsSubvolInfo
*ret
) {
458 struct btrfs_ioctl_search_args args
= {
459 /* Tree of tree roots */
460 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
462 /* Look precisely for the subvolume items */
463 .key
.min_type
= BTRFS_ROOT_ITEM_KEY
,
464 .key
.max_type
= BTRFS_ROOT_ITEM_KEY
,
467 .key
.max_offset
= (uint64_t) -1,
469 /* No restrictions on the other components */
470 .key
.min_transid
= 0,
471 .key
.max_transid
= (uint64_t) -1,
480 if (subvol_id
== 0) {
481 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
485 r
= btrfs_is_filesystem(fd
);
492 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
494 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
495 const struct btrfs_ioctl_search_header
*sh
;
498 args
.key
.nr_items
= 256;
499 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
502 if (args
.key
.nr_items
<= 0)
505 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
507 const struct btrfs_root_item
*ri
;
509 /* Make sure we start the next search at least from this entry */
510 btrfs_ioctl_search_args_set(&args
, sh
);
512 if (sh
->objectid
!= subvol_id
)
514 if (sh
->type
!= BTRFS_ROOT_ITEM_KEY
)
517 /* Older versions of the struct lacked the otime setting */
518 if (sh
->len
< offsetof(struct btrfs_root_item
, otime
) + sizeof(struct btrfs_timespec
))
521 ri
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
523 ret
->otime
= (usec_t
) le64toh(ri
->otime
.sec
) * USEC_PER_SEC
+
524 (usec_t
) le32toh(ri
->otime
.nsec
) / NSEC_PER_USEC
;
526 ret
->subvol_id
= subvol_id
;
527 ret
->read_only
= le64toh(ri
->flags
) & BTRFS_ROOT_SUBVOL_RDONLY
;
529 assert_cc(sizeof(ri
->uuid
) == sizeof(ret
->uuid
));
530 memcpy(&ret
->uuid
, ri
->uuid
, sizeof(ret
->uuid
));
531 memcpy(&ret
->parent_uuid
, ri
->parent_uuid
, sizeof(ret
->parent_uuid
));
537 /* Increase search key by one, to read the next item, if we can. */
538 if (!btrfs_ioctl_search_args_inc(&args
))
549 int btrfs_qgroup_get_quota_fd(int fd
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
551 struct btrfs_ioctl_search_args args
= {
552 /* Tree of quota items */
553 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
555 /* The object ID is always 0 */
556 .key
.min_objectid
= 0,
557 .key
.max_objectid
= 0,
559 /* Look precisely for the quota items */
560 .key
.min_type
= BTRFS_QGROUP_STATUS_KEY
,
561 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
563 /* No restrictions on the other components */
564 .key
.min_transid
= 0,
565 .key
.max_transid
= (uint64_t) -1,
568 bool found_info
= false, found_limit
= false;
575 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
579 r
= btrfs_is_filesystem(fd
);
586 args
.key
.min_offset
= args
.key
.max_offset
= qgroupid
;
588 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
589 const struct btrfs_ioctl_search_header
*sh
;
592 args
.key
.nr_items
= 256;
593 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
594 if (errno
== ENOENT
) /* quota tree is missing: quota disabled */
600 if (args
.key
.nr_items
<= 0)
603 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
605 /* Make sure we start the next search at least from this entry */
606 btrfs_ioctl_search_args_set(&args
, sh
);
608 if (sh
->objectid
!= 0)
610 if (sh
->offset
!= qgroupid
)
613 if (sh
->type
== BTRFS_QGROUP_INFO_KEY
) {
614 const struct btrfs_qgroup_info_item
*qii
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
616 ret
->referenced
= le64toh(qii
->rfer
);
617 ret
->exclusive
= le64toh(qii
->excl
);
621 } else if (sh
->type
== BTRFS_QGROUP_LIMIT_KEY
) {
622 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
624 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_RFER
)
625 ret
->referenced_max
= le64toh(qli
->max_rfer
);
627 ret
->referenced_max
= (uint64_t) -1;
629 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_EXCL
)
630 ret
->exclusive_max
= le64toh(qli
->max_excl
);
632 ret
->exclusive_max
= (uint64_t) -1;
637 if (found_info
&& found_limit
)
641 /* Increase search key by one, to read the next item, if we can. */
642 if (!btrfs_ioctl_search_args_inc(&args
))
647 if (!found_limit
&& !found_info
)
651 ret
->referenced
= (uint64_t) -1;
652 ret
->exclusive
= (uint64_t) -1;
656 ret
->referenced_max
= (uint64_t) -1;
657 ret
->exclusive_max
= (uint64_t) -1;
663 int btrfs_qgroup_get_quota(const char *path
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
664 _cleanup_close_
int fd
= -1;
666 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
670 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
673 int btrfs_subvol_find_subtree_qgroup(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
674 uint64_t level
, lowest
= (uint64_t) -1, lowest_qgroupid
= 0;
675 _cleanup_free_
uint64_t *qgroups
= NULL
;
681 /* This finds the "subtree" qgroup for a specific
682 * subvolume. This only works for subvolumes that have been
683 * prepared with btrfs_subvol_auto_qgroup_fd() with
684 * insert_intermediary_qgroup=true (or equivalent). For others
685 * it will return the leaf qgroup instead. The two cases may
686 * be distuingished via the return value, which is 1 in case
687 * an appropriate "subtree" qgroup was found, and 0
690 if (subvol_id
== 0) {
691 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
696 r
= btrfs_qgroupid_split(subvol_id
, &level
, NULL
);
699 if (level
!= 0) /* Input must be a leaf qgroup */
702 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
706 for (i
= 0; i
< n
; i
++) {
709 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, &id
);
716 if (lowest
== (uint64_t) -1 || level
< lowest
) {
717 lowest_qgroupid
= qgroups
[i
];
722 if (lowest
== (uint64_t) -1) {
723 /* No suitable higher-level qgroup found, let's return
724 * the leaf qgroup instead, and indicate that with the
731 *ret
= lowest_qgroupid
;
735 int btrfs_subvol_get_subtree_quota_fd(int fd
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
742 /* This determines the quota data of the qgroup with the
743 * lowest level, that shares the id part with the specified
744 * subvolume. This is useful for determining the quota data
745 * for entire subvolume subtrees, as long as the subtrees have
746 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
749 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
753 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
756 int btrfs_subvol_get_subtree_quota(const char *path
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
757 _cleanup_close_
int fd
= -1;
759 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
763 return btrfs_subvol_get_subtree_quota_fd(fd
, subvol_id
, ret
);
766 int btrfs_defrag_fd(int fd
) {
771 r
= fd_verify_regular(fd
);
775 if (ioctl(fd
, BTRFS_IOC_DEFRAG
, NULL
) < 0)
781 int btrfs_defrag(const char *p
) {
782 _cleanup_close_
int fd
= -1;
784 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
788 return btrfs_defrag_fd(fd
);
791 int btrfs_quota_enable_fd(int fd
, bool b
) {
792 struct btrfs_ioctl_quota_ctl_args args
= {
793 .cmd
= b
? BTRFS_QUOTA_CTL_ENABLE
: BTRFS_QUOTA_CTL_DISABLE
,
799 r
= btrfs_is_filesystem(fd
);
805 if (ioctl(fd
, BTRFS_IOC_QUOTA_CTL
, &args
) < 0)
811 int btrfs_quota_enable(const char *path
, bool b
) {
812 _cleanup_close_
int fd
= -1;
814 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
818 return btrfs_quota_enable_fd(fd
, b
);
821 int btrfs_qgroup_set_limit_fd(int fd
, uint64_t qgroupid
, uint64_t referenced_max
) {
823 struct btrfs_ioctl_qgroup_limit_args args
= {
824 .lim
.max_rfer
= referenced_max
,
825 .lim
.flags
= BTRFS_QGROUP_LIMIT_MAX_RFER
,
833 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
837 r
= btrfs_is_filesystem(fd
);
844 args
.qgroupid
= qgroupid
;
847 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &args
) < 0) {
849 if (errno
== EBUSY
&& c
< 10) {
850 (void) btrfs_quota_scan_wait(fd
);
863 int btrfs_qgroup_set_limit(const char *path
, uint64_t qgroupid
, uint64_t referenced_max
) {
864 _cleanup_close_
int fd
= -1;
866 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
870 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
873 int btrfs_subvol_set_subtree_quota_limit_fd(int fd
, uint64_t subvol_id
, uint64_t referenced_max
) {
879 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
883 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
886 int btrfs_subvol_set_subtree_quota_limit(const char *path
, uint64_t subvol_id
, uint64_t referenced_max
) {
887 _cleanup_close_
int fd
= -1;
889 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
893 return btrfs_subvol_set_subtree_quota_limit_fd(fd
, subvol_id
, referenced_max
);
896 int btrfs_qgroupid_make(uint64_t level
, uint64_t id
, uint64_t *ret
) {
899 if (level
>= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT
)))
902 if (id
>= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
))
905 *ret
= (level
<< BTRFS_QGROUP_LEVEL_SHIFT
) | id
;
909 int btrfs_qgroupid_split(uint64_t qgroupid
, uint64_t *level
, uint64_t *id
) {
913 *level
= qgroupid
>> BTRFS_QGROUP_LEVEL_SHIFT
;
916 *id
= qgroupid
& ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
) - 1);
921 static int qgroup_create_or_destroy(int fd
, bool b
, uint64_t qgroupid
) {
923 struct btrfs_ioctl_qgroup_create_args args
= {
925 .qgroupid
= qgroupid
,
930 r
= btrfs_is_filesystem(fd
);
937 if (ioctl(fd
, BTRFS_IOC_QGROUP_CREATE
, &args
) < 0) {
939 /* On old kernels if quota is not enabled, we get EINVAL. On newer kernels we get
940 * ENOTCONN. Let's always convert this to ENOTCONN to make this recognizable
941 * everywhere the same way. */
943 if (IN_SET(errno
, EINVAL
, ENOTCONN
))
946 if (errno
== EBUSY
&& c
< 10) {
947 (void) btrfs_quota_scan_wait(fd
);
960 int btrfs_qgroup_create(int fd
, uint64_t qgroupid
) {
961 return qgroup_create_or_destroy(fd
, true, qgroupid
);
964 int btrfs_qgroup_destroy(int fd
, uint64_t qgroupid
) {
965 return qgroup_create_or_destroy(fd
, false, qgroupid
);
968 int btrfs_qgroup_destroy_recursive(int fd
, uint64_t qgroupid
) {
969 _cleanup_free_
uint64_t *qgroups
= NULL
;
973 /* Destroys the specified qgroup, but unassigns it from all
974 * its parents first. Also, it recursively destroys all
975 * qgroups it is assigned to that have the same id part of the
976 * qgroupid as the specified group. */
978 r
= btrfs_qgroupid_split(qgroupid
, NULL
, &subvol_id
);
982 n
= btrfs_qgroup_find_parents(fd
, qgroupid
, &qgroups
);
986 for (i
= 0; i
< n
; i
++) {
989 r
= btrfs_qgroupid_split(qgroups
[i
], NULL
, &id
);
993 r
= btrfs_qgroup_unassign(fd
, qgroupid
, qgroups
[i
]);
1000 /* The parent qgroupid shares the same id part with
1001 * us? If so, destroy it too. */
1003 (void) btrfs_qgroup_destroy_recursive(fd
, qgroups
[i
]);
1006 return btrfs_qgroup_destroy(fd
, qgroupid
);
1009 int btrfs_quota_scan_start(int fd
) {
1010 struct btrfs_ioctl_quota_rescan_args args
= {};
1014 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN
, &args
) < 0)
1020 int btrfs_quota_scan_wait(int fd
) {
1023 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_WAIT
) < 0)
1029 int btrfs_quota_scan_ongoing(int fd
) {
1030 struct btrfs_ioctl_quota_rescan_args args
= {};
1034 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_STATUS
, &args
) < 0)
1037 return !!args
.flags
;
1040 static int qgroup_assign_or_unassign(int fd
, bool b
, uint64_t child
, uint64_t parent
) {
1041 struct btrfs_ioctl_qgroup_assign_args args
= {
1049 r
= btrfs_is_filesystem(fd
);
1056 r
= ioctl(fd
, BTRFS_IOC_QGROUP_ASSIGN
, &args
);
1058 if (errno
== EBUSY
&& c
< 10) {
1059 (void) btrfs_quota_scan_wait(fd
);
1069 /* If the return value is > 0, we need to request a rescan */
1071 (void) btrfs_quota_scan_start(fd
);
1076 int btrfs_qgroup_assign(int fd
, uint64_t child
, uint64_t parent
) {
1077 return qgroup_assign_or_unassign(fd
, true, child
, parent
);
1080 int btrfs_qgroup_unassign(int fd
, uint64_t child
, uint64_t parent
) {
1081 return qgroup_assign_or_unassign(fd
, false, child
, parent
);
1084 static int subvol_remove_children(int fd
, const char *subvolume
, uint64_t subvol_id
, BtrfsRemoveFlags flags
) {
1085 struct btrfs_ioctl_search_args args
= {
1086 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1088 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1089 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1091 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1092 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1094 .key
.min_transid
= 0,
1095 .key
.max_transid
= (uint64_t) -1,
1098 struct btrfs_ioctl_vol_args vol_args
= {};
1099 _cleanup_close_
int subvol_fd
= -1;
1101 bool made_writable
= false;
1107 if (fstat(fd
, &st
) < 0)
1110 if (!S_ISDIR(st
.st_mode
))
1113 subvol_fd
= openat(fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1117 /* Let's check if this is actually a subvolume. Note that this is mostly redundant, as BTRFS_IOC_SNAP_DESTROY
1118 * would fail anyway if it is not. However, it's a good thing to check this ahead of time so that we can return
1119 * ENOTTY unconditionally in this case. This is different from the ioctl() which will return EPERM/EACCES if we
1120 * don't have the privileges to remove subvolumes, regardless if the specified directory is actually a
1121 * subvolume or not. In order to make it easy for callers to cover the "this is not a btrfs subvolume" case
1122 * let's prefer ENOTTY over EPERM/EACCES though. */
1123 r
= btrfs_is_subvol_fd(subvol_fd
);
1126 if (r
== 0) /* Not a btrfs subvolume */
1129 if (subvol_id
== 0) {
1130 r
= btrfs_subvol_get_id_fd(subvol_fd
, &subvol_id
);
1135 /* First, try to remove the subvolume. If it happens to be
1136 * already empty, this will just work. */
1137 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1138 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) >= 0) {
1139 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1142 if (!(flags
& BTRFS_REMOVE_RECURSIVE
) || errno
!= ENOTEMPTY
)
1145 /* OK, the subvolume is not empty, let's look for child
1146 * subvolumes, and remove them, first */
1148 args
.key
.min_offset
= args
.key
.max_offset
= subvol_id
;
1150 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1151 const struct btrfs_ioctl_search_header
*sh
;
1154 args
.key
.nr_items
= 256;
1155 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1158 if (args
.key
.nr_items
<= 0)
1161 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1162 _cleanup_free_
char *p
= NULL
;
1163 const struct btrfs_root_ref
*ref
;
1165 btrfs_ioctl_search_args_set(&args
, sh
);
1167 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1169 if (sh
->offset
!= subvol_id
)
1172 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1174 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1178 struct btrfs_ioctl_ino_lookup_args ino_args
= {
1179 .treeid
= subvol_id
,
1180 .objectid
= htole64(ref
->dirid
),
1183 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1186 if (!made_writable
) {
1187 r
= btrfs_subvol_set_read_only_fd(subvol_fd
, false);
1191 made_writable
= true;
1194 if (isempty(ino_args
.name
))
1195 /* Subvolume is in the top-level
1196 * directory of the subvolume. */
1197 r
= subvol_remove_children(subvol_fd
, p
, sh
->objectid
, flags
);
1199 _cleanup_close_
int child_fd
= -1;
1201 /* Subvolume is somewhere further down,
1202 * hence we need to open the
1203 * containing directory first */
1205 child_fd
= openat(subvol_fd
, ino_args
.name
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1209 r
= subvol_remove_children(child_fd
, p
, sh
->objectid
, flags
);
1215 /* Increase search key by one, to read the next item, if we can. */
1216 if (!btrfs_ioctl_search_args_inc(&args
))
1220 /* OK, the child subvolumes should all be gone now, let's try
1221 * again to remove the subvolume */
1222 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) < 0)
1225 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
);
1229 int btrfs_subvol_remove(const char *path
, BtrfsRemoveFlags flags
) {
1230 _cleanup_close_
int fd
= -1;
1231 const char *subvolume
;
1236 r
= extract_subvolume_name(path
, &subvolume
);
1240 fd
= open_parent(path
, O_CLOEXEC
, 0);
1244 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1247 int btrfs_subvol_remove_fd(int fd
, const char *subvolume
, BtrfsRemoveFlags flags
) {
1248 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1251 int btrfs_qgroup_copy_limits(int fd
, uint64_t old_qgroupid
, uint64_t new_qgroupid
) {
1253 struct btrfs_ioctl_search_args args
= {
1254 /* Tree of quota items */
1255 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1257 /* The object ID is always 0 */
1258 .key
.min_objectid
= 0,
1259 .key
.max_objectid
= 0,
1261 /* Look precisely for the quota items */
1262 .key
.min_type
= BTRFS_QGROUP_LIMIT_KEY
,
1263 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
1265 /* For our qgroup */
1266 .key
.min_offset
= old_qgroupid
,
1267 .key
.max_offset
= old_qgroupid
,
1269 /* No restrictions on the other components */
1270 .key
.min_transid
= 0,
1271 .key
.max_transid
= (uint64_t) -1,
1276 r
= btrfs_is_filesystem(fd
);
1282 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1283 const struct btrfs_ioctl_search_header
*sh
;
1286 args
.key
.nr_items
= 256;
1287 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1288 if (errno
== ENOENT
) /* quota tree missing: quota is not enabled, hence nothing to copy */
1294 if (args
.key
.nr_items
<= 0)
1297 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1298 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1299 struct btrfs_ioctl_qgroup_limit_args qargs
;
1302 /* Make sure we start the next search at least from this entry */
1303 btrfs_ioctl_search_args_set(&args
, sh
);
1305 if (sh
->objectid
!= 0)
1307 if (sh
->type
!= BTRFS_QGROUP_LIMIT_KEY
)
1309 if (sh
->offset
!= old_qgroupid
)
1312 /* We found the entry, now copy things over. */
1314 qargs
= (struct btrfs_ioctl_qgroup_limit_args
) {
1315 .qgroupid
= new_qgroupid
,
1317 .lim
.max_rfer
= le64toh(qli
->max_rfer
),
1318 .lim
.max_excl
= le64toh(qli
->max_excl
),
1319 .lim
.rsv_rfer
= le64toh(qli
->rsv_rfer
),
1320 .lim
.rsv_excl
= le64toh(qli
->rsv_excl
),
1322 .lim
.flags
= le64toh(qli
->flags
) & (BTRFS_QGROUP_LIMIT_MAX_RFER
|
1323 BTRFS_QGROUP_LIMIT_MAX_EXCL
|
1324 BTRFS_QGROUP_LIMIT_RSV_RFER
|
1325 BTRFS_QGROUP_LIMIT_RSV_EXCL
),
1329 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &qargs
) < 0) {
1330 if (errno
== EBUSY
&& c
< 10) {
1331 (void) btrfs_quota_scan_wait(fd
);
1343 /* Increase search key by one, to read the next item, if we can. */
1344 if (!btrfs_ioctl_search_args_inc(&args
))
1351 static int copy_quota_hierarchy(int fd
, uint64_t old_subvol_id
, uint64_t new_subvol_id
) {
1352 _cleanup_free_
uint64_t *old_qgroups
= NULL
, *old_parent_qgroups
= NULL
;
1353 bool copy_from_parent
= false, insert_intermediary_qgroup
= false;
1354 int n_old_qgroups
, n_old_parent_qgroups
, r
, i
;
1355 uint64_t old_parent_id
;
1359 /* Copies a reduced form of quota information from the old to
1360 * the new subvolume. */
1362 n_old_qgroups
= btrfs_qgroup_find_parents(fd
, old_subvol_id
, &old_qgroups
);
1363 if (n_old_qgroups
<= 0) /* Nothing to copy */
1364 return n_old_qgroups
;
1366 r
= btrfs_subvol_get_parent(fd
, old_subvol_id
, &old_parent_id
);
1368 /* We have no parent, hence nothing to copy. */
1369 n_old_parent_qgroups
= 0;
1373 n_old_parent_qgroups
= btrfs_qgroup_find_parents(fd
, old_parent_id
, &old_parent_qgroups
);
1374 if (n_old_parent_qgroups
< 0)
1375 return n_old_parent_qgroups
;
1378 for (i
= 0; i
< n_old_qgroups
; i
++) {
1382 r
= btrfs_qgroupid_split(old_qgroups
[i
], NULL
, &id
);
1386 if (id
== old_subvol_id
) {
1387 /* The old subvolume was member of a qgroup
1388 * that had the same id, but a different level
1389 * as it self. Let's set up something similar
1390 * in the destination. */
1391 insert_intermediary_qgroup
= true;
1395 for (j
= 0; j
< n_old_parent_qgroups
; j
++)
1396 if (old_parent_qgroups
[j
] == old_qgroups
[i
])
1397 /* The old subvolume shared a common
1398 * parent qgroup with its parent
1399 * subvolume. Let's set up something
1400 * similar in the destination. */
1401 copy_from_parent
= true;
1404 if (!insert_intermediary_qgroup
&& !copy_from_parent
)
1407 return btrfs_subvol_auto_qgroup_fd(fd
, new_subvol_id
, insert_intermediary_qgroup
);
1410 static int copy_subtree_quota_limits(int fd
, uint64_t old_subvol
, uint64_t new_subvol
) {
1411 uint64_t old_subtree_qgroup
, new_subtree_qgroup
;
1415 /* First copy the leaf limits */
1416 r
= btrfs_qgroup_copy_limits(fd
, old_subvol
, new_subvol
);
1421 /* Then, try to copy the subtree limits, if there are any. */
1422 r
= btrfs_subvol_find_subtree_qgroup(fd
, old_subvol
, &old_subtree_qgroup
);
1428 r
= btrfs_subvol_find_subtree_qgroup(fd
, new_subvol
, &new_subtree_qgroup
);
1434 r
= btrfs_qgroup_copy_limits(fd
, old_subtree_qgroup
, new_subtree_qgroup
);
1441 static int subvol_snapshot_children(
1444 const char *subvolume
,
1445 uint64_t old_subvol_id
,
1446 BtrfsSnapshotFlags flags
) {
1448 struct btrfs_ioctl_search_args args
= {
1449 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1451 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1452 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1454 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1455 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1457 .key
.min_transid
= 0,
1458 .key
.max_transid
= (uint64_t) -1,
1461 struct btrfs_ioctl_vol_args_v2 vol_args
= {
1462 .flags
= flags
& BTRFS_SNAPSHOT_READ_ONLY
? BTRFS_SUBVOL_RDONLY
: 0,
1465 _cleanup_close_
int subvolume_fd
= -1;
1466 uint64_t new_subvol_id
;
1469 assert(old_fd
>= 0);
1470 assert(new_fd
>= 0);
1473 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1475 if (ioctl(new_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &vol_args
) < 0)
1478 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
) &&
1479 !(flags
& BTRFS_SNAPSHOT_QUOTA
))
1482 if (old_subvol_id
== 0) {
1483 r
= btrfs_subvol_get_id_fd(old_fd
, &old_subvol_id
);
1488 r
= btrfs_subvol_get_id(new_fd
, vol_args
.name
, &new_subvol_id
);
1492 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1493 (void) copy_quota_hierarchy(new_fd
, old_subvol_id
, new_subvol_id
);
1495 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
)) {
1497 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1498 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1503 args
.key
.min_offset
= args
.key
.max_offset
= old_subvol_id
;
1505 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1506 const struct btrfs_ioctl_search_header
*sh
;
1509 args
.key
.nr_items
= 256;
1510 if (ioctl(old_fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1513 if (args
.key
.nr_items
<= 0)
1516 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1517 _cleanup_free_
char *p
= NULL
, *c
= NULL
, *np
= NULL
;
1518 const struct btrfs_root_ref
*ref
;
1519 _cleanup_close_
int old_child_fd
= -1, new_child_fd
= -1;
1521 btrfs_ioctl_search_args_set(&args
, sh
);
1523 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1526 /* Avoid finding the source subvolume a second
1528 if (sh
->offset
!= old_subvol_id
)
1531 /* Avoid running into loops if the new
1532 * subvolume is below the old one. */
1533 if (sh
->objectid
== new_subvol_id
)
1536 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1537 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1541 struct btrfs_ioctl_ino_lookup_args ino_args
= {
1542 .treeid
= old_subvol_id
,
1543 .objectid
= htole64(ref
->dirid
),
1546 if (ioctl(old_fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1549 c
= path_join(ino_args
.name
, p
);
1553 old_child_fd
= openat(old_fd
, c
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1554 if (old_child_fd
< 0)
1557 np
= path_join(subvolume
, ino_args
.name
);
1561 new_child_fd
= openat(new_fd
, np
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1562 if (new_child_fd
< 0)
1565 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1566 /* If the snapshot is read-only we
1567 * need to mark it writable
1568 * temporarily, to put the subsnapshot
1571 if (subvolume_fd
< 0) {
1572 subvolume_fd
= openat(new_fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1573 if (subvolume_fd
< 0)
1577 r
= btrfs_subvol_set_read_only_fd(subvolume_fd
, false);
1582 /* When btrfs clones the subvolumes, child
1583 * subvolumes appear as empty directories. Remove
1584 * them, so that we can create a new snapshot
1586 if (unlinkat(new_child_fd
, p
, AT_REMOVEDIR
) < 0) {
1589 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
)
1590 (void) btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1595 r
= subvol_snapshot_children(old_child_fd
, new_child_fd
, p
, sh
->objectid
, flags
& ~BTRFS_SNAPSHOT_FALLBACK_COPY
);
1597 /* Restore the readonly flag */
1598 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1601 k
= btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1602 if (r
>= 0 && k
< 0)
1610 /* Increase search key by one, to read the next item, if we can. */
1611 if (!btrfs_ioctl_search_args_inc(&args
))
1615 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1616 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1621 int btrfs_subvol_snapshot_fd_full(
1623 const char *new_path
,
1624 BtrfsSnapshotFlags flags
,
1625 copy_progress_path_t progress_path
,
1626 copy_progress_bytes_t progress_bytes
,
1629 _cleanup_close_
int new_fd
= -1;
1630 const char *subvolume
;
1633 assert(old_fd
>= 0);
1636 r
= btrfs_is_subvol_fd(old_fd
);
1640 bool plain_directory
= false;
1642 /* If the source isn't a proper subvolume, fail unless fallback is requested */
1643 if (!(flags
& BTRFS_SNAPSHOT_FALLBACK_COPY
))
1646 r
= btrfs_subvol_make(new_path
);
1647 if (r
== -ENOTTY
&& (flags
& BTRFS_SNAPSHOT_FALLBACK_DIRECTORY
)) {
1648 /* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */
1649 if (mkdir(new_path
, 0755) < 0)
1652 plain_directory
= true;
1656 r
= copy_directory_fd_full(
1658 COPY_MERGE
|COPY_REFLINK
|COPY_SAME_MOUNT
|COPY_HARDLINKS
|(FLAGS_SET(flags
, BTRFS_SNAPSHOT_SIGINT
) ? COPY_SIGINT
: 0),
1659 progress_path
, progress_bytes
, userdata
);
1663 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1665 if (plain_directory
) {
1666 /* Plain directories have no recursive read-only flag, but something pretty close to
1667 * it: the IMMUTABLE bit. Let's use this here, if this is requested. */
1669 if (flags
& BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE
)
1670 (void) chattr_path(new_path
, FS_IMMUTABLE_FL
, FS_IMMUTABLE_FL
, NULL
);
1672 r
= btrfs_subvol_set_read_only(new_path
, true);
1681 (void) rm_rf(new_path
, REMOVE_ROOT
|REMOVE_PHYSICAL
|REMOVE_SUBVOLUME
);
1685 r
= extract_subvolume_name(new_path
, &subvolume
);
1689 new_fd
= open_parent(new_path
, O_CLOEXEC
, 0);
1693 return subvol_snapshot_children(old_fd
, new_fd
, subvolume
, 0, flags
);
1696 int btrfs_subvol_snapshot_full(
1697 const char *old_path
,
1698 const char *new_path
,
1699 BtrfsSnapshotFlags flags
,
1700 copy_progress_path_t progress_path
,
1701 copy_progress_bytes_t progress_bytes
,
1704 _cleanup_close_
int old_fd
= -1;
1709 old_fd
= open(old_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1713 return btrfs_subvol_snapshot_fd_full(old_fd
, new_path
, flags
, progress_path
, progress_bytes
, userdata
);
1716 int btrfs_qgroup_find_parents(int fd
, uint64_t qgroupid
, uint64_t **ret
) {
1718 struct btrfs_ioctl_search_args args
= {
1719 /* Tree of quota items */
1720 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1722 /* Look precisely for the quota relation items */
1723 .key
.min_type
= BTRFS_QGROUP_RELATION_KEY
,
1724 .key
.max_type
= BTRFS_QGROUP_RELATION_KEY
,
1726 /* No restrictions on the other components */
1727 .key
.min_offset
= 0,
1728 .key
.max_offset
= (uint64_t) -1,
1730 .key
.min_transid
= 0,
1731 .key
.max_transid
= (uint64_t) -1,
1734 _cleanup_free_
uint64_t *items
= NULL
;
1735 size_t n_items
= 0, n_allocated
= 0;
1741 if (qgroupid
== 0) {
1742 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
1746 r
= btrfs_is_filesystem(fd
);
1753 args
.key
.min_objectid
= args
.key
.max_objectid
= qgroupid
;
1755 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1756 const struct btrfs_ioctl_search_header
*sh
;
1759 args
.key
.nr_items
= 256;
1760 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1761 if (errno
== ENOENT
) /* quota tree missing: quota is disabled */
1767 if (args
.key
.nr_items
<= 0)
1770 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1772 /* Make sure we start the next search at least from this entry */
1773 btrfs_ioctl_search_args_set(&args
, sh
);
1775 if (sh
->type
!= BTRFS_QGROUP_RELATION_KEY
)
1777 if (sh
->offset
< sh
->objectid
)
1779 if (sh
->objectid
!= qgroupid
)
1782 if (!GREEDY_REALLOC(items
, n_allocated
, n_items
+1))
1785 items
[n_items
++] = sh
->offset
;
1788 /* Increase search key by one, to read the next item, if we can. */
1789 if (!btrfs_ioctl_search_args_inc(&args
))
1798 *ret
= TAKE_PTR(items
);
1800 return (int) n_items
;
1803 int btrfs_subvol_auto_qgroup_fd(int fd
, uint64_t subvol_id
, bool insert_intermediary_qgroup
) {
1804 _cleanup_free_
uint64_t *qgroups
= NULL
;
1805 uint64_t parent_subvol
;
1806 bool changed
= false;
1812 * Sets up the specified subvolume's qgroup automatically in
1815 * If insert_intermediary_qgroup is false, the subvolume's
1816 * leaf qgroup will be assigned to the same parent qgroups as
1817 * the subvolume's parent subvolume.
1819 * If insert_intermediary_qgroup is true a new intermediary
1820 * higher-level qgroup is created, with a higher level number,
1821 * but reusing the id of the subvolume. The level number is
1822 * picked as one smaller than the lowest level qgroup the
1823 * parent subvolume is a member of. If the parent subvolume's
1824 * leaf qgroup is assigned to no higher-level qgroup a new
1825 * qgroup of level 255 is created instead. Either way, the new
1826 * qgroup is then assigned to the parent's higher-level
1827 * qgroup, and the subvolume itself is assigned to it.
1829 * If the subvolume is already assigned to a higher level
1830 * qgroup, no operation is executed.
1832 * Effectively this means: regardless if
1833 * insert_intermediary_qgroup is true or not, after this
1834 * function is invoked the subvolume will be accounted within
1835 * the same qgroups as the parent. However, if it is true, it
1836 * will also get its own higher-level qgroup, which may in
1837 * turn be used by subvolumes created beneath this subvolume
1840 * This hence defines a simple default qgroup setup for
1841 * subvolumes, as long as this function is invoked on each
1842 * created subvolume: each subvolume is always accounting
1843 * together with its immediate parents. Optionally, if
1844 * insert_intermediary_qgroup is true, it will also get a
1845 * qgroup that then includes all its own child subvolumes.
1848 if (subvol_id
== 0) {
1849 r
= btrfs_is_subvol_fd(fd
);
1855 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1860 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
1863 if (n
> 0) /* already parent qgroups set up, let's bail */
1866 qgroups
= mfree(qgroups
);
1868 r
= btrfs_subvol_get_parent(fd
, subvol_id
, &parent_subvol
);
1870 /* No parent, hence no qgroup memberships */
1875 n
= btrfs_qgroup_find_parents(fd
, parent_subvol
, &qgroups
);
1880 if (insert_intermediary_qgroup
) {
1881 uint64_t lowest
= 256, new_qgroupid
;
1882 bool created
= false;
1885 /* Determine the lowest qgroup that the parent
1886 * subvolume is assigned to. */
1888 for (i
= 0; i
< n
; i
++) {
1891 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, NULL
);
1899 if (lowest
<= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1902 r
= btrfs_qgroupid_make(lowest
- 1, subvol_id
, &new_qgroupid
);
1906 /* Create the new intermediary group, unless it already exists */
1907 r
= btrfs_qgroup_create(fd
, new_qgroupid
);
1908 if (r
< 0 && r
!= -EEXIST
)
1911 changed
= created
= true;
1913 for (i
= 0; i
< n
; i
++) {
1914 r
= btrfs_qgroup_assign(fd
, new_qgroupid
, qgroups
[i
]);
1915 if (r
< 0 && r
!= -EEXIST
) {
1917 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1925 r
= btrfs_qgroup_assign(fd
, subvol_id
, new_qgroupid
);
1926 if (r
< 0 && r
!= -EEXIST
) {
1928 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1937 /* Assign our subvolume to all the same qgroups as the parent */
1939 for (i
= 0; i
< n
; i
++) {
1940 r
= btrfs_qgroup_assign(fd
, subvol_id
, qgroups
[i
]);
1941 if (r
< 0 && r
!= -EEXIST
)
1951 int btrfs_subvol_auto_qgroup(const char *path
, uint64_t subvol_id
, bool create_intermediary_qgroup
) {
1952 _cleanup_close_
int fd
= -1;
1954 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1958 return btrfs_subvol_auto_qgroup_fd(fd
, subvol_id
, create_intermediary_qgroup
);
1961 int btrfs_subvol_get_parent(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
1963 struct btrfs_ioctl_search_args args
= {
1964 /* Tree of tree roots */
1965 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1967 /* Look precisely for the subvolume items */
1968 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1969 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1971 /* No restrictions on the other components */
1972 .key
.min_offset
= 0,
1973 .key
.max_offset
= (uint64_t) -1,
1975 .key
.min_transid
= 0,
1976 .key
.max_transid
= (uint64_t) -1,
1983 if (subvol_id
== 0) {
1984 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1988 r
= btrfs_is_filesystem(fd
);
1995 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
1997 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1998 const struct btrfs_ioctl_search_header
*sh
;
2001 args
.key
.nr_items
= 256;
2002 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
2003 return negative_errno();
2005 if (args
.key
.nr_items
<= 0)
2008 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
2010 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
2012 if (sh
->objectid
!= subvol_id
)