1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Lennart Poettering
12 #include <linux/loop.h>
17 #include <sys/ioctl.h>
19 #include <sys/statfs.h>
20 #include <sys/sysmacros.h>
23 #if HAVE_LINUX_BTRFS_H
24 #include <linux/btrfs.h>
27 #include "alloc-util.h"
28 #include "blockdev-util.h"
29 #include "btrfs-ctree.h"
30 #include "btrfs-util.h"
31 #include "chattr-util.h"
33 #include "device-nodes.h"
39 #include "path-util.h"
41 #include "smack-util.h"
42 #include "sparse-endian.h"
43 #include "stat-util.h"
44 #include "string-util.h"
45 #include "time-util.h"
48 /* WARNING: Be careful with file system ioctls! When we get an fd, we
49 * need to make sure it either refers to only a regular file or
50 * directory, or that it is located on btrfs, before invoking any
51 * btrfs ioctls. The ioctl numbers are reused by some device drivers
52 * (such as DRM), and hence might have bad effects when invoked on
53 * device nodes (that reference drivers) rather than fds to normal
54 * files or directories. */
56 static int validate_subvolume_name(const char *name
) {
58 if (!filename_is_valid(name
))
61 if (strlen(name
) > BTRFS_SUBVOL_NAME_MAX
)
67 static int open_parent(const char *path
, int flags
) {
68 _cleanup_free_
char *parent
= NULL
;
73 parent
= dirname_malloc(path
);
77 fd
= open(parent
, flags
);
84 static int extract_subvolume_name(const char *path
, const char **subvolume
) {
93 r
= validate_subvolume_name(fn
);
101 int btrfs_is_filesystem(int fd
) {
106 if (fstatfs(fd
, &sfs
) < 0)
109 return F_TYPE_EQUAL(sfs
.f_type
, BTRFS_SUPER_MAGIC
);
112 int btrfs_is_subvol_fd(int fd
) {
117 /* On btrfs subvolumes always have the inode 256 */
119 if (fstat(fd
, &st
) < 0)
122 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
125 return btrfs_is_filesystem(fd
);
128 int btrfs_is_subvol(const char *path
) {
129 _cleanup_close_
int fd
= -1;
133 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
137 return btrfs_is_subvol_fd(fd
);
140 int btrfs_subvol_make(const char *path
) {
141 struct btrfs_ioctl_vol_args args
= {};
142 _cleanup_close_
int fd
= -1;
143 const char *subvolume
;
148 r
= extract_subvolume_name(path
, &subvolume
);
152 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
156 strncpy(args
.name
, subvolume
, sizeof(args
.name
)-1);
158 if (ioctl(fd
, BTRFS_IOC_SUBVOL_CREATE
, &args
) < 0)
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 (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
176 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
180 nflags
= flags
| BTRFS_SUBVOL_RDONLY
;
182 nflags
= flags
& ~BTRFS_SUBVOL_RDONLY
;
187 if (ioctl(fd
, BTRFS_IOC_SUBVOL_SETFLAGS
, &nflags
) < 0)
193 int btrfs_subvol_set_read_only(const char *path
, bool b
) {
194 _cleanup_close_
int fd
= -1;
196 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
200 return btrfs_subvol_set_read_only_fd(fd
, b
);
203 int btrfs_subvol_get_read_only_fd(int fd
) {
209 if (fstat(fd
, &st
) < 0)
212 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
215 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
218 return !!(flags
& BTRFS_SUBVOL_RDONLY
);
221 int btrfs_reflink(int infd
, int outfd
) {
227 /* Make sure we invoke the ioctl on a regular file, so that no device driver accidentally gets it. */
229 r
= fd_verify_regular(outfd
);
233 if (ioctl(outfd
, BTRFS_IOC_CLONE
, infd
) < 0)
239 int btrfs_clone_range(int infd
, uint64_t in_offset
, int outfd
, uint64_t out_offset
, uint64_t sz
) {
240 struct btrfs_ioctl_clone_range_args args
= {
242 .src_offset
= in_offset
,
244 .dest_offset
= out_offset
,
252 r
= fd_verify_regular(outfd
);
256 if (ioctl(outfd
, BTRFS_IOC_CLONE_RANGE
, &args
) < 0)
262 int btrfs_get_block_device_fd(int fd
, dev_t
*dev
) {
263 struct btrfs_ioctl_fs_info_args fsi
= {};
270 r
= btrfs_is_filesystem(fd
);
276 if (ioctl(fd
, BTRFS_IOC_FS_INFO
, &fsi
) < 0)
279 /* We won't do this for btrfs RAID */
280 if (fsi
.num_devices
!= 1)
283 for (id
= 1; id
<= fsi
.max_id
; id
++) {
284 struct btrfs_ioctl_dev_info_args di
= {
289 if (ioctl(fd
, BTRFS_IOC_DEV_INFO
, &di
) < 0) {
296 if (stat((char*) di
.path
, &st
) < 0)
299 if (!S_ISBLK(st
.st_mode
))
302 if (major(st
.st_rdev
) == 0)
312 int btrfs_get_block_device(const char *path
, dev_t
*dev
) {
313 _cleanup_close_
int fd
= -1;
318 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
322 return btrfs_get_block_device_fd(fd
, dev
);
325 int btrfs_subvol_get_id_fd(int fd
, uint64_t *ret
) {
326 struct btrfs_ioctl_ino_lookup_args args
= {
327 .objectid
= BTRFS_FIRST_FREE_OBJECTID
334 r
= btrfs_is_filesystem(fd
);
340 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
) < 0)
347 int btrfs_subvol_get_id(int fd
, const char *subvol
, uint64_t *ret
) {
348 _cleanup_close_
int subvol_fd
= -1;
353 subvol_fd
= openat(fd
, subvol
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
357 return btrfs_subvol_get_id_fd(subvol_fd
, ret
);
360 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args
*args
) {
363 /* the objectid, type, offset together make up the btrfs key,
364 * which is considered a single 136byte integer when
365 * comparing. This call increases the counter by one, dealing
366 * with the overflow between the overflows */
368 if (args
->key
.min_offset
< (uint64_t) -1) {
369 args
->key
.min_offset
++;
373 if (args
->key
.min_type
< (uint8_t) -1) {
374 args
->key
.min_type
++;
375 args
->key
.min_offset
= 0;
379 if (args
->key
.min_objectid
< (uint64_t) -1) {
380 args
->key
.min_objectid
++;
381 args
->key
.min_offset
= 0;
382 args
->key
.min_type
= 0;
389 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args
*args
, const struct btrfs_ioctl_search_header
*h
) {
393 args
->key
.min_objectid
= h
->objectid
;
394 args
->key
.min_type
= h
->type
;
395 args
->key
.min_offset
= h
->offset
;
398 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
*args
) {
401 /* Compare min and max */
403 if (args
->key
.min_objectid
< args
->key
.max_objectid
)
405 if (args
->key
.min_objectid
> args
->key
.max_objectid
)
408 if (args
->key
.min_type
< args
->key
.max_type
)
410 if (args
->key
.min_type
> args
->key
.max_type
)
413 if (args
->key
.min_offset
< args
->key
.max_offset
)
415 if (args
->key
.min_offset
> args
->key
.max_offset
)
421 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
423 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
424 (i) < (args).key.nr_items; \
426 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
428 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
429 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
431 int btrfs_subvol_get_info_fd(int fd
, uint64_t subvol_id
, BtrfsSubvolInfo
*ret
) {
432 struct btrfs_ioctl_search_args args
= {
433 /* Tree of tree roots */
434 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
436 /* Look precisely for the subvolume items */
437 .key
.min_type
= BTRFS_ROOT_ITEM_KEY
,
438 .key
.max_type
= BTRFS_ROOT_ITEM_KEY
,
441 .key
.max_offset
= (uint64_t) -1,
443 /* No restrictions on the other components */
444 .key
.min_transid
= 0,
445 .key
.max_transid
= (uint64_t) -1,
454 if (subvol_id
== 0) {
455 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
459 r
= btrfs_is_filesystem(fd
);
466 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
468 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
469 const struct btrfs_ioctl_search_header
*sh
;
472 args
.key
.nr_items
= 256;
473 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
476 if (args
.key
.nr_items
<= 0)
479 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
481 const struct btrfs_root_item
*ri
;
483 /* Make sure we start the next search at least from this entry */
484 btrfs_ioctl_search_args_set(&args
, sh
);
486 if (sh
->objectid
!= subvol_id
)
488 if (sh
->type
!= BTRFS_ROOT_ITEM_KEY
)
491 /* Older versions of the struct lacked the otime setting */
492 if (sh
->len
< offsetof(struct btrfs_root_item
, otime
) + sizeof(struct btrfs_timespec
))
495 ri
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
497 ret
->otime
= (usec_t
) le64toh(ri
->otime
.sec
) * USEC_PER_SEC
+
498 (usec_t
) le32toh(ri
->otime
.nsec
) / NSEC_PER_USEC
;
500 ret
->subvol_id
= subvol_id
;
501 ret
->read_only
= !!(le64toh(ri
->flags
) & BTRFS_ROOT_SUBVOL_RDONLY
);
503 assert_cc(sizeof(ri
->uuid
) == sizeof(ret
->uuid
));
504 memcpy(&ret
->uuid
, ri
->uuid
, sizeof(ret
->uuid
));
505 memcpy(&ret
->parent_uuid
, ri
->parent_uuid
, sizeof(ret
->parent_uuid
));
511 /* Increase search key by one, to read the next item, if we can. */
512 if (!btrfs_ioctl_search_args_inc(&args
))
523 int btrfs_qgroup_get_quota_fd(int fd
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
525 struct btrfs_ioctl_search_args args
= {
526 /* Tree of quota items */
527 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
529 /* The object ID is always 0 */
530 .key
.min_objectid
= 0,
531 .key
.max_objectid
= 0,
533 /* Look precisely for the quota items */
534 .key
.min_type
= BTRFS_QGROUP_STATUS_KEY
,
535 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
537 /* No restrictions on the other components */
538 .key
.min_transid
= 0,
539 .key
.max_transid
= (uint64_t) -1,
542 bool found_info
= false, found_limit
= false;
549 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
553 r
= btrfs_is_filesystem(fd
);
560 args
.key
.min_offset
= args
.key
.max_offset
= qgroupid
;
562 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
563 const struct btrfs_ioctl_search_header
*sh
;
566 args
.key
.nr_items
= 256;
567 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
568 if (errno
== ENOENT
) /* quota tree is missing: quota disabled */
574 if (args
.key
.nr_items
<= 0)
577 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
579 /* Make sure we start the next search at least from this entry */
580 btrfs_ioctl_search_args_set(&args
, sh
);
582 if (sh
->objectid
!= 0)
584 if (sh
->offset
!= qgroupid
)
587 if (sh
->type
== BTRFS_QGROUP_INFO_KEY
) {
588 const struct btrfs_qgroup_info_item
*qii
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
590 ret
->referenced
= le64toh(qii
->rfer
);
591 ret
->exclusive
= le64toh(qii
->excl
);
595 } else if (sh
->type
== BTRFS_QGROUP_LIMIT_KEY
) {
596 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
598 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_RFER
)
599 ret
->referenced_max
= le64toh(qli
->max_rfer
);
601 ret
->referenced_max
= (uint64_t) -1;
603 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_EXCL
)
604 ret
->exclusive_max
= le64toh(qli
->max_excl
);
606 ret
->exclusive_max
= (uint64_t) -1;
611 if (found_info
&& found_limit
)
615 /* Increase search key by one, to read the next item, if we can. */
616 if (!btrfs_ioctl_search_args_inc(&args
))
621 if (!found_limit
&& !found_info
)
625 ret
->referenced
= (uint64_t) -1;
626 ret
->exclusive
= (uint64_t) -1;
630 ret
->referenced_max
= (uint64_t) -1;
631 ret
->exclusive_max
= (uint64_t) -1;
637 int btrfs_qgroup_get_quota(const char *path
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
638 _cleanup_close_
int fd
= -1;
640 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
644 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
647 int btrfs_subvol_find_subtree_qgroup(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
648 uint64_t level
, lowest
= (uint64_t) -1, lowest_qgroupid
= 0;
649 _cleanup_free_
uint64_t *qgroups
= NULL
;
655 /* This finds the "subtree" qgroup for a specific
656 * subvolume. This only works for subvolumes that have been
657 * prepared with btrfs_subvol_auto_qgroup_fd() with
658 * insert_intermediary_qgroup=true (or equivalent). For others
659 * it will return the leaf qgroup instead. The two cases may
660 * be distuingished via the return value, which is 1 in case
661 * an appropriate "subtree" qgroup was found, and 0
664 if (subvol_id
== 0) {
665 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
670 r
= btrfs_qgroupid_split(subvol_id
, &level
, NULL
);
673 if (level
!= 0) /* Input must be a leaf qgroup */
676 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
680 for (i
= 0; i
< n
; i
++) {
683 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, &id
);
690 if (lowest
== (uint64_t) -1 || level
< lowest
) {
691 lowest_qgroupid
= qgroups
[i
];
696 if (lowest
== (uint64_t) -1) {
697 /* No suitable higher-level qgroup found, let's return
698 * the leaf qgroup instead, and indicate that with the
705 *ret
= lowest_qgroupid
;
709 int btrfs_subvol_get_subtree_quota_fd(int fd
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
716 /* This determines the quota data of the qgroup with the
717 * lowest level, that shares the id part with the specified
718 * subvolume. This is useful for determining the quota data
719 * for entire subvolume subtrees, as long as the subtrees have
720 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
723 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
727 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
730 int btrfs_subvol_get_subtree_quota(const char *path
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
731 _cleanup_close_
int fd
= -1;
733 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
737 return btrfs_subvol_get_subtree_quota_fd(fd
, subvol_id
, ret
);
740 int btrfs_defrag_fd(int fd
) {
745 r
= fd_verify_regular(fd
);
749 if (ioctl(fd
, BTRFS_IOC_DEFRAG
, NULL
) < 0)
755 int btrfs_defrag(const char *p
) {
756 _cleanup_close_
int fd
= -1;
758 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
762 return btrfs_defrag_fd(fd
);
765 int btrfs_quota_enable_fd(int fd
, bool b
) {
766 struct btrfs_ioctl_quota_ctl_args args
= {
767 .cmd
= b
? BTRFS_QUOTA_CTL_ENABLE
: BTRFS_QUOTA_CTL_DISABLE
,
773 r
= btrfs_is_filesystem(fd
);
779 if (ioctl(fd
, BTRFS_IOC_QUOTA_CTL
, &args
) < 0)
785 int btrfs_quota_enable(const char *path
, bool b
) {
786 _cleanup_close_
int fd
= -1;
788 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
792 return btrfs_quota_enable_fd(fd
, b
);
795 int btrfs_qgroup_set_limit_fd(int fd
, uint64_t qgroupid
, uint64_t referenced_max
) {
797 struct btrfs_ioctl_qgroup_limit_args args
= {
798 .lim
.max_rfer
= referenced_max
,
799 .lim
.flags
= BTRFS_QGROUP_LIMIT_MAX_RFER
,
807 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
811 r
= btrfs_is_filesystem(fd
);
818 args
.qgroupid
= qgroupid
;
821 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &args
) < 0) {
823 if (errno
== EBUSY
&& c
< 10) {
824 (void) btrfs_quota_scan_wait(fd
);
837 int btrfs_qgroup_set_limit(const char *path
, uint64_t qgroupid
, uint64_t referenced_max
) {
838 _cleanup_close_
int fd
= -1;
840 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
844 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
847 int btrfs_subvol_set_subtree_quota_limit_fd(int fd
, uint64_t subvol_id
, uint64_t referenced_max
) {
853 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
857 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
860 int btrfs_subvol_set_subtree_quota_limit(const char *path
, uint64_t subvol_id
, uint64_t referenced_max
) {
861 _cleanup_close_
int fd
= -1;
863 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
867 return btrfs_subvol_set_subtree_quota_limit_fd(fd
, subvol_id
, referenced_max
);
870 int btrfs_resize_loopback_fd(int fd
, uint64_t new_size
, bool grow_only
) {
871 struct btrfs_ioctl_vol_args args
= {};
872 char p
[SYS_BLOCK_PATH_MAX("/loop/backing_file")];
873 _cleanup_free_
char *backing
= NULL
;
874 _cleanup_close_
int loop_fd
= -1, backing_fd
= -1;
879 /* In contrast to btrfs quota ioctls ftruncate() cannot make sense of "infinity" or file sizes > 2^31 */
880 if (!FILE_SIZE_VALID(new_size
))
883 /* btrfs cannot handle file systems < 16M, hence use this as minimum */
884 if (new_size
< 16*1024*1024)
885 new_size
= 16*1024*1024;
887 r
= btrfs_get_block_device_fd(fd
, &dev
);
893 xsprintf_sys_block_path(p
, "/loop/backing_file", dev
);
894 r
= read_one_line_file(p
, &backing
);
899 if (isempty(backing
) || !path_is_absolute(backing
))
902 backing_fd
= open(backing
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
906 if (fstat(backing_fd
, &st
) < 0)
908 if (!S_ISREG(st
.st_mode
))
911 if (new_size
== (uint64_t) st
.st_size
)
914 if (grow_only
&& new_size
< (uint64_t) st
.st_size
)
917 xsprintf_sys_block_path(p
, NULL
, dev
);
918 loop_fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
922 if (snprintf(args
.name
, sizeof(args
.name
), "%" PRIu64
, new_size
) >= (int) sizeof(args
.name
))
925 if (new_size
< (uint64_t) st
.st_size
) {
926 /* Decrease size: first decrease btrfs size, then shorten loopback */
927 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
931 if (ftruncate(backing_fd
, new_size
) < 0)
934 if (ioctl(loop_fd
, LOOP_SET_CAPACITY
, 0) < 0)
937 if (new_size
> (uint64_t) st
.st_size
) {
938 /* Increase size: first enlarge loopback, then increase btrfs size */
939 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
943 /* Make sure the free disk space is correctly updated for both file systems */
945 (void) fsync(backing_fd
);
950 int btrfs_resize_loopback(const char *p
, uint64_t new_size
, bool grow_only
) {
951 _cleanup_close_
int fd
= -1;
953 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
957 return btrfs_resize_loopback_fd(fd
, new_size
, grow_only
);
960 int btrfs_qgroupid_make(uint64_t level
, uint64_t id
, uint64_t *ret
) {
963 if (level
>= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT
)))
966 if (id
>= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
))
969 *ret
= (level
<< BTRFS_QGROUP_LEVEL_SHIFT
) | id
;
973 int btrfs_qgroupid_split(uint64_t qgroupid
, uint64_t *level
, uint64_t *id
) {
977 *level
= qgroupid
>> BTRFS_QGROUP_LEVEL_SHIFT
;
980 *id
= qgroupid
& ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
) - 1);
985 static int qgroup_create_or_destroy(int fd
, bool b
, uint64_t qgroupid
) {
987 struct btrfs_ioctl_qgroup_create_args args
= {
989 .qgroupid
= qgroupid
,
994 r
= btrfs_is_filesystem(fd
);
1001 if (ioctl(fd
, BTRFS_IOC_QGROUP_CREATE
, &args
) < 0) {
1003 /* If quota is not enabled, we get EINVAL. Turn this into a recognizable error */
1004 if (errno
== EINVAL
)
1005 return -ENOPROTOOPT
;
1007 if (errno
== EBUSY
&& c
< 10) {
1008 (void) btrfs_quota_scan_wait(fd
);
1021 int btrfs_qgroup_create(int fd
, uint64_t qgroupid
) {
1022 return qgroup_create_or_destroy(fd
, true, qgroupid
);
1025 int btrfs_qgroup_destroy(int fd
, uint64_t qgroupid
) {
1026 return qgroup_create_or_destroy(fd
, false, qgroupid
);
1029 int btrfs_qgroup_destroy_recursive(int fd
, uint64_t qgroupid
) {
1030 _cleanup_free_
uint64_t *qgroups
= NULL
;
1034 /* Destroys the specified qgroup, but unassigns it from all
1035 * its parents first. Also, it recursively destroys all
1036 * qgroups it is assgined to that have the same id part of the
1037 * qgroupid as the specified group. */
1039 r
= btrfs_qgroupid_split(qgroupid
, NULL
, &subvol_id
);
1043 n
= btrfs_qgroup_find_parents(fd
, qgroupid
, &qgroups
);
1047 for (i
= 0; i
< n
; i
++) {
1050 r
= btrfs_qgroupid_split(qgroups
[i
], NULL
, &id
);
1054 r
= btrfs_qgroup_unassign(fd
, qgroupid
, qgroups
[i
]);
1058 if (id
!= subvol_id
)
1061 /* The parent qgroupid shares the same id part with
1062 * us? If so, destroy it too. */
1064 (void) btrfs_qgroup_destroy_recursive(fd
, qgroups
[i
]);
1067 return btrfs_qgroup_destroy(fd
, qgroupid
);
1070 int btrfs_quota_scan_start(int fd
) {
1071 struct btrfs_ioctl_quota_rescan_args args
= {};
1075 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN
, &args
) < 0)
1081 int btrfs_quota_scan_wait(int fd
) {
1084 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_WAIT
) < 0)
1090 int btrfs_quota_scan_ongoing(int fd
) {
1091 struct btrfs_ioctl_quota_rescan_args args
= {};
1095 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_STATUS
, &args
) < 0)
1098 return !!args
.flags
;
1101 static int qgroup_assign_or_unassign(int fd
, bool b
, uint64_t child
, uint64_t parent
) {
1102 struct btrfs_ioctl_qgroup_assign_args args
= {
1110 r
= btrfs_is_filesystem(fd
);
1117 r
= ioctl(fd
, BTRFS_IOC_QGROUP_ASSIGN
, &args
);
1119 if (errno
== EBUSY
&& c
< 10) {
1120 (void) btrfs_quota_scan_wait(fd
);
1130 /* If the return value is > 0, we need to request a rescan */
1132 (void) btrfs_quota_scan_start(fd
);
1137 int btrfs_qgroup_assign(int fd
, uint64_t child
, uint64_t parent
) {
1138 return qgroup_assign_or_unassign(fd
, true, child
, parent
);
1141 int btrfs_qgroup_unassign(int fd
, uint64_t child
, uint64_t parent
) {
1142 return qgroup_assign_or_unassign(fd
, false, child
, parent
);
1145 static int subvol_remove_children(int fd
, const char *subvolume
, uint64_t subvol_id
, BtrfsRemoveFlags flags
) {
1146 struct btrfs_ioctl_search_args args
= {
1147 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1149 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1150 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1152 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1153 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1155 .key
.min_transid
= 0,
1156 .key
.max_transid
= (uint64_t) -1,
1159 struct btrfs_ioctl_vol_args vol_args
= {};
1160 _cleanup_close_
int subvol_fd
= -1;
1162 bool made_writable
= false;
1168 if (fstat(fd
, &st
) < 0)
1171 if (!S_ISDIR(st
.st_mode
))
1174 subvol_fd
= openat(fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1178 if (subvol_id
== 0) {
1179 r
= btrfs_subvol_get_id_fd(subvol_fd
, &subvol_id
);
1184 /* First, try to remove the subvolume. If it happens to be
1185 * already empty, this will just work. */
1186 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1187 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) >= 0) {
1188 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1191 if (!(flags
& BTRFS_REMOVE_RECURSIVE
) || errno
!= ENOTEMPTY
)
1194 /* OK, the subvolume is not empty, let's look for child
1195 * subvolumes, and remove them, first */
1197 args
.key
.min_offset
= args
.key
.max_offset
= subvol_id
;
1199 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1200 const struct btrfs_ioctl_search_header
*sh
;
1203 args
.key
.nr_items
= 256;
1204 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1207 if (args
.key
.nr_items
<= 0)
1210 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1211 _cleanup_free_
char *p
= NULL
;
1212 const struct btrfs_root_ref
*ref
;
1213 struct btrfs_ioctl_ino_lookup_args ino_args
;
1215 btrfs_ioctl_search_args_set(&args
, sh
);
1217 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1219 if (sh
->offset
!= subvol_id
)
1222 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1224 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1229 ino_args
.treeid
= subvol_id
;
1230 ino_args
.objectid
= htole64(ref
->dirid
);
1232 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1235 if (!made_writable
) {
1236 r
= btrfs_subvol_set_read_only_fd(subvol_fd
, false);
1240 made_writable
= true;
1243 if (isempty(ino_args
.name
))
1244 /* Subvolume is in the top-level
1245 * directory of the subvolume. */
1246 r
= subvol_remove_children(subvol_fd
, p
, sh
->objectid
, flags
);
1248 _cleanup_close_
int child_fd
= -1;
1250 /* Subvolume is somewhere further down,
1251 * hence we need to open the
1252 * containing directory first */
1254 child_fd
= openat(subvol_fd
, ino_args
.name
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1258 r
= subvol_remove_children(child_fd
, p
, sh
->objectid
, flags
);
1264 /* Increase search key by one, to read the next item, if we can. */
1265 if (!btrfs_ioctl_search_args_inc(&args
))
1269 /* OK, the child subvolumes should all be gone now, let's try
1270 * again to remove the subvolume */
1271 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) < 0)
1274 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
);
1278 int btrfs_subvol_remove(const char *path
, BtrfsRemoveFlags flags
) {
1279 _cleanup_close_
int fd
= -1;
1280 const char *subvolume
;
1285 r
= extract_subvolume_name(path
, &subvolume
);
1289 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1293 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1296 int btrfs_subvol_remove_fd(int fd
, const char *subvolume
, BtrfsRemoveFlags flags
) {
1297 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1300 int btrfs_qgroup_copy_limits(int fd
, uint64_t old_qgroupid
, uint64_t new_qgroupid
) {
1302 struct btrfs_ioctl_search_args args
= {
1303 /* Tree of quota items */
1304 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1306 /* The object ID is always 0 */
1307 .key
.min_objectid
= 0,
1308 .key
.max_objectid
= 0,
1310 /* Look precisely for the quota items */
1311 .key
.min_type
= BTRFS_QGROUP_LIMIT_KEY
,
1312 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
1314 /* For our qgroup */
1315 .key
.min_offset
= old_qgroupid
,
1316 .key
.max_offset
= old_qgroupid
,
1318 /* No restrictions on the other components */
1319 .key
.min_transid
= 0,
1320 .key
.max_transid
= (uint64_t) -1,
1325 r
= btrfs_is_filesystem(fd
);
1331 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1332 const struct btrfs_ioctl_search_header
*sh
;
1335 args
.key
.nr_items
= 256;
1336 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1337 if (errno
== ENOENT
) /* quota tree missing: quota is not enabled, hence nothing to copy */
1343 if (args
.key
.nr_items
<= 0)
1346 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1347 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1348 struct btrfs_ioctl_qgroup_limit_args qargs
;
1351 /* Make sure we start the next search at least from this entry */
1352 btrfs_ioctl_search_args_set(&args
, sh
);
1354 if (sh
->objectid
!= 0)
1356 if (sh
->type
!= BTRFS_QGROUP_LIMIT_KEY
)
1358 if (sh
->offset
!= old_qgroupid
)
1361 /* We found the entry, now copy things over. */
1363 qargs
= (struct btrfs_ioctl_qgroup_limit_args
) {
1364 .qgroupid
= new_qgroupid
,
1366 .lim
.max_rfer
= le64toh(qli
->max_rfer
),
1367 .lim
.max_excl
= le64toh(qli
->max_excl
),
1368 .lim
.rsv_rfer
= le64toh(qli
->rsv_rfer
),
1369 .lim
.rsv_excl
= le64toh(qli
->rsv_excl
),
1371 .lim
.flags
= le64toh(qli
->flags
) & (BTRFS_QGROUP_LIMIT_MAX_RFER
|
1372 BTRFS_QGROUP_LIMIT_MAX_EXCL
|
1373 BTRFS_QGROUP_LIMIT_RSV_RFER
|
1374 BTRFS_QGROUP_LIMIT_RSV_EXCL
),
1378 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &qargs
) < 0) {
1379 if (errno
== EBUSY
&& c
< 10) {
1380 (void) btrfs_quota_scan_wait(fd
);
1392 /* Increase search key by one, to read the next item, if we can. */
1393 if (!btrfs_ioctl_search_args_inc(&args
))
1400 static int copy_quota_hierarchy(int fd
, uint64_t old_subvol_id
, uint64_t new_subvol_id
) {
1401 _cleanup_free_
uint64_t *old_qgroups
= NULL
, *old_parent_qgroups
= NULL
;
1402 bool copy_from_parent
= false, insert_intermediary_qgroup
= false;
1403 int n_old_qgroups
, n_old_parent_qgroups
, r
, i
;
1404 uint64_t old_parent_id
;
1408 /* Copies a reduced form of quota information from the old to
1409 * the new subvolume. */
1411 n_old_qgroups
= btrfs_qgroup_find_parents(fd
, old_subvol_id
, &old_qgroups
);
1412 if (n_old_qgroups
<= 0) /* Nothing to copy */
1413 return n_old_qgroups
;
1415 r
= btrfs_subvol_get_parent(fd
, old_subvol_id
, &old_parent_id
);
1417 /* We have no parent, hence nothing to copy. */
1418 n_old_parent_qgroups
= 0;
1422 n_old_parent_qgroups
= btrfs_qgroup_find_parents(fd
, old_parent_id
, &old_parent_qgroups
);
1423 if (n_old_parent_qgroups
< 0)
1424 return n_old_parent_qgroups
;
1427 for (i
= 0; i
< n_old_qgroups
; i
++) {
1431 r
= btrfs_qgroupid_split(old_qgroups
[i
], NULL
, &id
);
1435 if (id
== old_subvol_id
) {
1436 /* The old subvolume was member of a qgroup
1437 * that had the same id, but a different level
1438 * as it self. Let's set up something similar
1439 * in the destination. */
1440 insert_intermediary_qgroup
= true;
1444 for (j
= 0; j
< n_old_parent_qgroups
; j
++)
1445 if (old_parent_qgroups
[j
] == old_qgroups
[i
]) {
1446 /* The old subvolume shared a common
1447 * parent qgroup with its parent
1448 * subvolume. Let's set up something
1449 * similar in the destination. */
1450 copy_from_parent
= true;
1454 if (!insert_intermediary_qgroup
&& !copy_from_parent
)
1457 return btrfs_subvol_auto_qgroup_fd(fd
, new_subvol_id
, insert_intermediary_qgroup
);
1460 static int copy_subtree_quota_limits(int fd
, uint64_t old_subvol
, uint64_t new_subvol
) {
1461 uint64_t old_subtree_qgroup
, new_subtree_qgroup
;
1465 /* First copy the leaf limits */
1466 r
= btrfs_qgroup_copy_limits(fd
, old_subvol
, new_subvol
);
1471 /* Then, try to copy the subtree limits, if there are any. */
1472 r
= btrfs_subvol_find_subtree_qgroup(fd
, old_subvol
, &old_subtree_qgroup
);
1478 r
= btrfs_subvol_find_subtree_qgroup(fd
, new_subvol
, &new_subtree_qgroup
);
1484 r
= btrfs_qgroup_copy_limits(fd
, old_subtree_qgroup
, new_subtree_qgroup
);
1491 static int subvol_snapshot_children(int old_fd
, int new_fd
, const char *subvolume
, uint64_t old_subvol_id
, BtrfsSnapshotFlags flags
) {
1493 struct btrfs_ioctl_search_args args
= {
1494 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1496 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1497 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1499 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1500 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1502 .key
.min_transid
= 0,
1503 .key
.max_transid
= (uint64_t) -1,
1506 struct btrfs_ioctl_vol_args_v2 vol_args
= {
1507 .flags
= flags
& BTRFS_SNAPSHOT_READ_ONLY
? BTRFS_SUBVOL_RDONLY
: 0,
1510 _cleanup_close_
int subvolume_fd
= -1;
1511 uint64_t new_subvol_id
;
1514 assert(old_fd
>= 0);
1515 assert(new_fd
>= 0);
1518 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1520 if (ioctl(new_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &vol_args
) < 0)
1523 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
) &&
1524 !(flags
& BTRFS_SNAPSHOT_QUOTA
))
1527 if (old_subvol_id
== 0) {
1528 r
= btrfs_subvol_get_id_fd(old_fd
, &old_subvol_id
);
1533 r
= btrfs_subvol_get_id(new_fd
, vol_args
.name
, &new_subvol_id
);
1537 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1538 (void) copy_quota_hierarchy(new_fd
, old_subvol_id
, new_subvol_id
);
1540 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
)) {
1542 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1543 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1548 args
.key
.min_offset
= args
.key
.max_offset
= old_subvol_id
;
1550 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1551 const struct btrfs_ioctl_search_header
*sh
;
1554 args
.key
.nr_items
= 256;
1555 if (ioctl(old_fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1558 if (args
.key
.nr_items
<= 0)
1561 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1562 _cleanup_free_
char *p
= NULL
, *c
= NULL
, *np
= NULL
;
1563 struct btrfs_ioctl_ino_lookup_args ino_args
;
1564 const struct btrfs_root_ref
*ref
;
1565 _cleanup_close_
int old_child_fd
= -1, new_child_fd
= -1;
1567 btrfs_ioctl_search_args_set(&args
, sh
);
1569 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1572 /* Avoid finding the source subvolume a second
1574 if (sh
->offset
!= old_subvol_id
)
1577 /* Avoid running into loops if the new
1578 * subvolume is below the old one. */
1579 if (sh
->objectid
== new_subvol_id
)
1582 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1583 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1588 ino_args
.treeid
= old_subvol_id
;
1589 ino_args
.objectid
= htole64(ref
->dirid
);
1591 if (ioctl(old_fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1594 /* The kernel returns an empty name if the
1595 * subvolume is in the top-level directory,
1596 * and otherwise appends a slash, so that we
1597 * can just concatenate easily here, without
1598 * adding a slash. */
1599 c
= strappend(ino_args
.name
, p
);
1603 old_child_fd
= openat(old_fd
, c
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1604 if (old_child_fd
< 0)
1607 np
= strjoin(subvolume
, "/", ino_args
.name
);
1611 new_child_fd
= openat(new_fd
, np
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1612 if (new_child_fd
< 0)
1615 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1616 /* If the snapshot is read-only we
1617 * need to mark it writable
1618 * temporarily, to put the subsnapshot
1621 if (subvolume_fd
< 0) {
1622 subvolume_fd
= openat(new_fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1623 if (subvolume_fd
< 0)
1627 r
= btrfs_subvol_set_read_only_fd(subvolume_fd
, false);
1632 /* When btrfs clones the subvolumes, child
1633 * subvolumes appear as empty directories. Remove
1634 * them, so that we can create a new snapshot
1636 if (unlinkat(new_child_fd
, p
, AT_REMOVEDIR
) < 0) {
1639 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
)
1640 (void) btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1645 r
= subvol_snapshot_children(old_child_fd
, new_child_fd
, p
, sh
->objectid
, flags
& ~BTRFS_SNAPSHOT_FALLBACK_COPY
);
1647 /* Restore the readonly flag */
1648 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1651 k
= btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1652 if (r
>= 0 && k
< 0)
1660 /* Increase search key by one, to read the next item, if we can. */
1661 if (!btrfs_ioctl_search_args_inc(&args
))
1665 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1666 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1671 int btrfs_subvol_snapshot_fd(int old_fd
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1672 _cleanup_close_
int new_fd
= -1;
1673 const char *subvolume
;
1676 assert(old_fd
>= 0);
1679 r
= btrfs_is_subvol_fd(old_fd
);
1683 bool plain_directory
= false;
1685 /* If the source isn't a proper subvolume, fail unless fallback is requested */
1686 if (!(flags
& BTRFS_SNAPSHOT_FALLBACK_COPY
))
1689 r
= btrfs_subvol_make(new_path
);
1690 if (r
== -ENOTTY
&& (flags
& BTRFS_SNAPSHOT_FALLBACK_DIRECTORY
)) {
1691 /* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */
1692 if (mkdir(new_path
, 0755) < 0)
1695 plain_directory
= true;
1699 r
= copy_directory_fd(old_fd
, new_path
, COPY_MERGE
|COPY_REFLINK
);
1703 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1705 if (plain_directory
) {
1706 /* Plain directories have no recursive read-only flag, but something pretty close to
1707 * it: the IMMUTABLE bit. Let's use this here, if this is requested. */
1709 if (flags
& BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE
)
1710 (void) chattr_path(new_path
, FS_IMMUTABLE_FL
, FS_IMMUTABLE_FL
);
1712 r
= btrfs_subvol_set_read_only(new_path
, true);
1721 (void) rm_rf(new_path
, REMOVE_ROOT
|REMOVE_PHYSICAL
|REMOVE_SUBVOLUME
);
1725 r
= extract_subvolume_name(new_path
, &subvolume
);
1729 new_fd
= open_parent(new_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1733 return subvol_snapshot_children(old_fd
, new_fd
, subvolume
, 0, flags
);
1736 int btrfs_subvol_snapshot(const char *old_path
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1737 _cleanup_close_
int old_fd
= -1;
1742 old_fd
= open(old_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1746 return btrfs_subvol_snapshot_fd(old_fd
, new_path
, flags
);
1749 int btrfs_qgroup_find_parents(int fd
, uint64_t qgroupid
, uint64_t **ret
) {
1751 struct btrfs_ioctl_search_args args
= {
1752 /* Tree of quota items */
1753 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1755 /* Look precisely for the quota relation items */
1756 .key
.min_type
= BTRFS_QGROUP_RELATION_KEY
,
1757 .key
.max_type
= BTRFS_QGROUP_RELATION_KEY
,
1759 /* No restrictions on the other components */
1760 .key
.min_offset
= 0,
1761 .key
.max_offset
= (uint64_t) -1,
1763 .key
.min_transid
= 0,
1764 .key
.max_transid
= (uint64_t) -1,
1767 _cleanup_free_
uint64_t *items
= NULL
;
1768 size_t n_items
= 0, n_allocated
= 0;
1774 if (qgroupid
== 0) {
1775 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
1779 r
= btrfs_is_filesystem(fd
);
1786 args
.key
.min_objectid
= args
.key
.max_objectid
= qgroupid
;
1788 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1789 const struct btrfs_ioctl_search_header
*sh
;
1792 args
.key
.nr_items
= 256;
1793 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1794 if (errno
== ENOENT
) /* quota tree missing: quota is disabled */
1800 if (args
.key
.nr_items
<= 0)
1803 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1805 /* Make sure we start the next search at least from this entry */
1806 btrfs_ioctl_search_args_set(&args
, sh
);
1808 if (sh
->type
!= BTRFS_QGROUP_RELATION_KEY
)
1810 if (sh
->offset
< sh
->objectid
)
1812 if (sh
->objectid
!= qgroupid
)
1815 if (!GREEDY_REALLOC(items
, n_allocated
, n_items
+1))
1818 items
[n_items
++] = sh
->offset
;
1821 /* Increase search key by one, to read the next item, if we can. */
1822 if (!btrfs_ioctl_search_args_inc(&args
))
1831 *ret
= TAKE_PTR(items
);
1833 return (int) n_items
;
1836 int btrfs_subvol_auto_qgroup_fd(int fd
, uint64_t subvol_id
, bool insert_intermediary_qgroup
) {
1837 _cleanup_free_
uint64_t *qgroups
= NULL
;
1838 uint64_t parent_subvol
;
1839 bool changed
= false;
1845 * Sets up the specified subvolume's qgroup automatically in
1848 * If insert_intermediary_qgroup is false, the subvolume's
1849 * leaf qgroup will be assigned to the same parent qgroups as
1850 * the subvolume's parent subvolume.
1852 * If insert_intermediary_qgroup is true a new intermediary
1853 * higher-level qgroup is created, with a higher level number,
1854 * but reusing the id of the subvolume. The level number is
1855 * picked as one smaller than the lowest level qgroup the
1856 * parent subvolume is a member of. If the parent subvolume's
1857 * leaf qgroup is assigned to no higher-level qgroup a new
1858 * qgroup of level 255 is created instead. Either way, the new
1859 * qgroup is then assigned to the parent's higher-level
1860 * qgroup, and the subvolume itself is assigned to it.
1862 * If the subvolume is already assigned to a higher level
1863 * qgroup, no operation is executed.
1865 * Effectively this means: regardless if
1866 * insert_intermediary_qgroup is true or not, after this
1867 * function is invoked the subvolume will be accounted within
1868 * the same qgroups as the parent. However, if it is true, it
1869 * will also get its own higher-level qgroup, which may in
1870 * turn be used by subvolumes created beneath this subvolume
1873 * This hence defines a simple default qgroup setup for
1874 * subvolumes, as long as this function is invoked on each
1875 * created subvolume: each subvolume is always accounting
1876 * together with its immediate parents. Optionally, if
1877 * insert_intermediary_qgroup is true, it will also get a
1878 * qgroup that then includes all its own child subvolumes.
1881 if (subvol_id
== 0) {
1882 r
= btrfs_is_subvol_fd(fd
);
1888 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1893 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
1896 if (n
> 0) /* already parent qgroups set up, let's bail */
1899 qgroups
= mfree(qgroups
);
1901 r
= btrfs_subvol_get_parent(fd
, subvol_id
, &parent_subvol
);
1903 /* No parent, hence no qgroup memberships */
1908 n
= btrfs_qgroup_find_parents(fd
, parent_subvol
, &qgroups
);
1913 if (insert_intermediary_qgroup
) {
1914 uint64_t lowest
= 256, new_qgroupid
;
1915 bool created
= false;
1918 /* Determine the lowest qgroup that the parent
1919 * subvolume is assigned to. */
1921 for (i
= 0; i
< n
; i
++) {
1924 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, NULL
);
1932 if (lowest
<= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1935 r
= btrfs_qgroupid_make(lowest
- 1, subvol_id
, &new_qgroupid
);
1939 /* Create the new intermediary group, unless it already exists */
1940 r
= btrfs_qgroup_create(fd
, new_qgroupid
);
1941 if (r
< 0 && r
!= -EEXIST
)
1944 changed
= created
= true;
1946 for (i
= 0; i
< n
; i
++) {
1947 r
= btrfs_qgroup_assign(fd
, new_qgroupid
, qgroups
[i
]);
1948 if (r
< 0 && r
!= -EEXIST
) {
1950 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1958 r
= btrfs_qgroup_assign(fd
, subvol_id
, new_qgroupid
);
1959 if (r
< 0 && r
!= -EEXIST
) {
1961 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1970 /* Assign our subvolume to all the same qgroups as the parent */
1972 for (i
= 0; i
< n
; i
++) {
1973 r
= btrfs_qgroup_assign(fd
, subvol_id
, qgroups
[i
]);
1974 if (r
< 0 && r
!= -EEXIST
)
1984 int btrfs_subvol_auto_qgroup(const char *path
, uint64_t subvol_id
, bool create_intermediary_qgroup
) {
1985 _cleanup_close_
int fd
= -1;
1987 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1991 return btrfs_subvol_auto_qgroup_fd(fd
, subvol_id
, create_intermediary_qgroup
);
1994 int btrfs_subvol_get_parent(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
1996 struct btrfs_ioctl_search_args args
= {
1997 /* Tree of tree roots */
1998 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
2000 /* Look precisely for the subvolume items */
2001 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
2002 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
2004 /* No restrictions on the other components */
2005 .key
.min_offset
= 0,
2006 .key
.max_offset
= (uint64_t) -1,
2008 .key
.min_transid
= 0,
2009 .key
.max_transid
= (uint64_t) -1,
2016 if (subvol_id
== 0) {
2017 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
2021 r
= btrfs_is_filesystem(fd
);
2028 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
2030 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
2031 const struct btrfs_ioctl_search_header
*sh
;
2034 args
.key
.nr_items
= 256;
2035 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
2036 return negative_errno();
2038 if (args
.key
.nr_items
<= 0)
2041 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
2043 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
2045 if (sh
->objectid
!= subvol_id
)