1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include <linux/loop.h>
30 #include <sys/ioctl.h>
32 #include <sys/statfs.h>
33 #include <sys/sysmacros.h>
36 #ifdef HAVE_LINUX_BTRFS_H
37 #include <linux/btrfs.h>
40 #include "alloc-util.h"
41 #include "btrfs-ctree.h"
42 #include "btrfs-util.h"
48 #include "path-util.h"
49 #include "selinux-util.h"
50 #include "smack-util.h"
51 #include "sparse-endian.h"
52 #include "stat-util.h"
53 #include "string-util.h"
54 #include "time-util.h"
57 /* WARNING: Be careful with file system ioctls! When we get an fd, we
58 * need to make sure it either refers to only a regular file or
59 * directory, or that it is located on btrfs, before invoking any
60 * btrfs ioctls. The ioctl numbers are reused by some device drivers
61 * (such as DRM), and hence might have bad effects when invoked on
62 * device nodes (that reference drivers) rather than fds to normal
63 * files or directories. */
65 static int validate_subvolume_name(const char *name
) {
67 if (!filename_is_valid(name
))
70 if (strlen(name
) > BTRFS_SUBVOL_NAME_MAX
)
76 static int open_parent(const char *path
, int flags
) {
77 _cleanup_free_
char *parent
= NULL
;
82 parent
= dirname_malloc(path
);
86 fd
= open(parent
, flags
);
93 static int extract_subvolume_name(const char *path
, const char **subvolume
) {
102 r
= validate_subvolume_name(fn
);
110 int btrfs_is_filesystem(int fd
) {
115 if (fstatfs(fd
, &sfs
) < 0)
118 return F_TYPE_EQUAL(sfs
.f_type
, BTRFS_SUPER_MAGIC
);
121 int btrfs_is_subvol_fd(int fd
) {
126 /* On btrfs subvolumes always have the inode 256 */
128 if (fstat(fd
, &st
) < 0)
131 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
134 return btrfs_is_filesystem(fd
);
137 int btrfs_is_subvol(const char *path
) {
138 _cleanup_close_
int fd
= -1;
142 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
146 return btrfs_is_subvol_fd(fd
);
149 int btrfs_subvol_make(const char *path
) {
150 struct btrfs_ioctl_vol_args args
= {};
151 _cleanup_close_
int fd
= -1;
152 const char *subvolume
;
157 r
= extract_subvolume_name(path
, &subvolume
);
161 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
165 strncpy(args
.name
, subvolume
, sizeof(args
.name
)-1);
167 if (ioctl(fd
, BTRFS_IOC_SUBVOL_CREATE
, &args
) < 0)
173 int btrfs_subvol_make_label(const char *path
) {
178 r
= mac_selinux_create_file_prepare(path
, S_IFDIR
);
182 r
= btrfs_subvol_make(path
);
183 mac_selinux_create_file_clear();
188 return mac_smack_fix(path
, false, false);
191 int btrfs_subvol_set_read_only_fd(int fd
, bool b
) {
192 uint64_t flags
, nflags
;
197 if (fstat(fd
, &st
) < 0)
200 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
203 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
207 nflags
= flags
| BTRFS_SUBVOL_RDONLY
;
209 nflags
= flags
& ~BTRFS_SUBVOL_RDONLY
;
214 if (ioctl(fd
, BTRFS_IOC_SUBVOL_SETFLAGS
, &nflags
) < 0)
220 int btrfs_subvol_set_read_only(const char *path
, bool b
) {
221 _cleanup_close_
int fd
= -1;
223 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
227 return btrfs_subvol_set_read_only_fd(fd
, b
);
230 int btrfs_subvol_get_read_only_fd(int fd
) {
236 if (fstat(fd
, &st
) < 0)
239 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
242 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
245 return !!(flags
& BTRFS_SUBVOL_RDONLY
);
248 int btrfs_reflink(int infd
, int outfd
) {
255 /* Make sure we invoke the ioctl on a regular file, so that no
256 * device driver accidentally gets it. */
258 if (fstat(outfd
, &st
) < 0)
261 if (!S_ISREG(st
.st_mode
))
264 r
= ioctl(outfd
, BTRFS_IOC_CLONE
, infd
);
271 int btrfs_clone_range(int infd
, uint64_t in_offset
, int outfd
, uint64_t out_offset
, uint64_t sz
) {
272 struct btrfs_ioctl_clone_range_args args
= {
274 .src_offset
= in_offset
,
276 .dest_offset
= out_offset
,
285 if (fstat(outfd
, &st
) < 0)
288 if (!S_ISREG(st
.st_mode
))
291 r
= ioctl(outfd
, BTRFS_IOC_CLONE_RANGE
, &args
);
298 int btrfs_get_block_device_fd(int fd
, dev_t
*dev
) {
299 struct btrfs_ioctl_fs_info_args fsi
= {};
306 r
= btrfs_is_filesystem(fd
);
312 if (ioctl(fd
, BTRFS_IOC_FS_INFO
, &fsi
) < 0)
315 /* We won't do this for btrfs RAID */
316 if (fsi
.num_devices
!= 1)
319 for (id
= 1; id
<= fsi
.max_id
; id
++) {
320 struct btrfs_ioctl_dev_info_args di
= {
325 if (ioctl(fd
, BTRFS_IOC_DEV_INFO
, &di
) < 0) {
332 if (stat((char*) di
.path
, &st
) < 0)
335 if (!S_ISBLK(st
.st_mode
))
338 if (major(st
.st_rdev
) == 0)
348 int btrfs_get_block_device(const char *path
, dev_t
*dev
) {
349 _cleanup_close_
int fd
= -1;
354 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
358 return btrfs_get_block_device_fd(fd
, dev
);
361 int btrfs_subvol_get_id_fd(int fd
, uint64_t *ret
) {
362 struct btrfs_ioctl_ino_lookup_args args
= {
363 .objectid
= BTRFS_FIRST_FREE_OBJECTID
370 r
= btrfs_is_filesystem(fd
);
376 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
) < 0)
383 int btrfs_subvol_get_id(int fd
, const char *subvol
, uint64_t *ret
) {
384 _cleanup_close_
int subvol_fd
= -1;
389 subvol_fd
= openat(fd
, subvol
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
393 return btrfs_subvol_get_id_fd(subvol_fd
, ret
);
396 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args
*args
) {
399 /* the objectid, type, offset together make up the btrfs key,
400 * which is considered a single 136byte integer when
401 * comparing. This call increases the counter by one, dealing
402 * with the overflow between the overflows */
404 if (args
->key
.min_offset
< (uint64_t) -1) {
405 args
->key
.min_offset
++;
409 if (args
->key
.min_type
< (uint8_t) -1) {
410 args
->key
.min_type
++;
411 args
->key
.min_offset
= 0;
415 if (args
->key
.min_objectid
< (uint64_t) -1) {
416 args
->key
.min_objectid
++;
417 args
->key
.min_offset
= 0;
418 args
->key
.min_type
= 0;
425 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args
*args
, const struct btrfs_ioctl_search_header
*h
) {
429 args
->key
.min_objectid
= h
->objectid
;
430 args
->key
.min_type
= h
->type
;
431 args
->key
.min_offset
= h
->offset
;
434 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
*args
) {
437 /* Compare min and max */
439 if (args
->key
.min_objectid
< args
->key
.max_objectid
)
441 if (args
->key
.min_objectid
> args
->key
.max_objectid
)
444 if (args
->key
.min_type
< args
->key
.max_type
)
446 if (args
->key
.min_type
> args
->key
.max_type
)
449 if (args
->key
.min_offset
< args
->key
.max_offset
)
451 if (args
->key
.min_offset
> args
->key
.max_offset
)
457 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
459 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
460 (i) < (args).key.nr_items; \
462 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
464 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
465 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
467 int btrfs_subvol_get_info_fd(int fd
, uint64_t subvol_id
, BtrfsSubvolInfo
*ret
) {
468 struct btrfs_ioctl_search_args args
= {
469 /* Tree of tree roots */
470 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
472 /* Look precisely for the subvolume items */
473 .key
.min_type
= BTRFS_ROOT_ITEM_KEY
,
474 .key
.max_type
= BTRFS_ROOT_ITEM_KEY
,
477 .key
.max_offset
= (uint64_t) -1,
479 /* No restrictions on the other components */
480 .key
.min_transid
= 0,
481 .key
.max_transid
= (uint64_t) -1,
490 if (subvol_id
== 0) {
491 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
495 r
= btrfs_is_filesystem(fd
);
502 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
504 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
505 const struct btrfs_ioctl_search_header
*sh
;
508 args
.key
.nr_items
= 256;
509 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
512 if (args
.key
.nr_items
<= 0)
515 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
517 const struct btrfs_root_item
*ri
;
519 /* Make sure we start the next search at least from this entry */
520 btrfs_ioctl_search_args_set(&args
, sh
);
522 if (sh
->objectid
!= subvol_id
)
524 if (sh
->type
!= BTRFS_ROOT_ITEM_KEY
)
527 /* Older versions of the struct lacked the otime setting */
528 if (sh
->len
< offsetof(struct btrfs_root_item
, otime
) + sizeof(struct btrfs_timespec
))
531 ri
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
533 ret
->otime
= (usec_t
) le64toh(ri
->otime
.sec
) * USEC_PER_SEC
+
534 (usec_t
) le32toh(ri
->otime
.nsec
) / NSEC_PER_USEC
;
536 ret
->subvol_id
= subvol_id
;
537 ret
->read_only
= !!(le64toh(ri
->flags
) & BTRFS_ROOT_SUBVOL_RDONLY
);
539 assert_cc(sizeof(ri
->uuid
) == sizeof(ret
->uuid
));
540 memcpy(&ret
->uuid
, ri
->uuid
, sizeof(ret
->uuid
));
541 memcpy(&ret
->parent_uuid
, ri
->parent_uuid
, sizeof(ret
->parent_uuid
));
547 /* Increase search key by one, to read the next item, if we can. */
548 if (!btrfs_ioctl_search_args_inc(&args
))
559 int btrfs_qgroup_get_quota_fd(int fd
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
561 struct btrfs_ioctl_search_args args
= {
562 /* Tree of quota items */
563 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
565 /* The object ID is always 0 */
566 .key
.min_objectid
= 0,
567 .key
.max_objectid
= 0,
569 /* Look precisely for the quota items */
570 .key
.min_type
= BTRFS_QGROUP_STATUS_KEY
,
571 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
573 /* No restrictions on the other components */
574 .key
.min_transid
= 0,
575 .key
.max_transid
= (uint64_t) -1,
578 bool found_info
= false, found_limit
= false;
585 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
589 r
= btrfs_is_filesystem(fd
);
596 args
.key
.min_offset
= args
.key
.max_offset
= qgroupid
;
598 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
599 const struct btrfs_ioctl_search_header
*sh
;
602 args
.key
.nr_items
= 256;
603 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
604 if (errno
== ENOENT
) /* quota tree is missing: quota disabled */
610 if (args
.key
.nr_items
<= 0)
613 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
615 /* Make sure we start the next search at least from this entry */
616 btrfs_ioctl_search_args_set(&args
, sh
);
618 if (sh
->objectid
!= 0)
620 if (sh
->offset
!= qgroupid
)
623 if (sh
->type
== BTRFS_QGROUP_INFO_KEY
) {
624 const struct btrfs_qgroup_info_item
*qii
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
626 ret
->referenced
= le64toh(qii
->rfer
);
627 ret
->exclusive
= le64toh(qii
->excl
);
631 } else if (sh
->type
== BTRFS_QGROUP_LIMIT_KEY
) {
632 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
634 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_RFER
)
635 ret
->referenced_max
= le64toh(qli
->max_rfer
);
637 ret
->referenced_max
= (uint64_t) -1;
639 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_EXCL
)
640 ret
->exclusive_max
= le64toh(qli
->max_excl
);
642 ret
->exclusive_max
= (uint64_t) -1;
647 if (found_info
&& found_limit
)
651 /* Increase search key by one, to read the next item, if we can. */
652 if (!btrfs_ioctl_search_args_inc(&args
))
657 if (!found_limit
&& !found_info
)
661 ret
->referenced
= (uint64_t) -1;
662 ret
->exclusive
= (uint64_t) -1;
666 ret
->referenced_max
= (uint64_t) -1;
667 ret
->exclusive_max
= (uint64_t) -1;
673 int btrfs_qgroup_get_quota(const char *path
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
674 _cleanup_close_
int fd
= -1;
676 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
680 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
683 int btrfs_subvol_find_subtree_qgroup(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
684 uint64_t level
, lowest
= (uint64_t) -1, lowest_qgroupid
= 0;
685 _cleanup_free_
uint64_t *qgroups
= NULL
;
691 /* This finds the "subtree" qgroup for a specific
692 * subvolume. This only works for subvolumes that have been
693 * prepared with btrfs_subvol_auto_qgroup_fd() with
694 * insert_intermediary_qgroup=true (or equivalent). For others
695 * it will return the leaf qgroup instead. The two cases may
696 * be distuingished via the return value, which is 1 in case
697 * an appropriate "subtree" qgroup was found, and 0
700 if (subvol_id
== 0) {
701 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
706 r
= btrfs_qgroupid_split(subvol_id
, &level
, NULL
);
709 if (level
!= 0) /* Input must be a leaf qgroup */
712 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
716 for (i
= 0; i
< n
; i
++) {
719 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, &id
);
726 if (lowest
== (uint64_t) -1 || level
< lowest
) {
727 lowest_qgroupid
= qgroups
[i
];
732 if (lowest
== (uint64_t) -1) {
733 /* No suitable higher-level qgroup found, let's return
734 * the leaf qgroup instead, and indicate that with the
741 *ret
= lowest_qgroupid
;
745 int btrfs_subvol_get_subtree_quota_fd(int fd
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
752 /* This determines the quota data of the qgroup with the
753 * lowest level, that shares the id part with the specified
754 * subvolume. This is useful for determining the quota data
755 * for entire subvolume subtrees, as long as the subtrees have
756 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
759 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
763 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
766 int btrfs_subvol_get_subtree_quota(const char *path
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
767 _cleanup_close_
int fd
= -1;
769 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
773 return btrfs_subvol_get_subtree_quota_fd(fd
, subvol_id
, ret
);
776 int btrfs_defrag_fd(int fd
) {
781 if (fstat(fd
, &st
) < 0)
784 if (!S_ISREG(st
.st_mode
))
787 if (ioctl(fd
, BTRFS_IOC_DEFRAG
, NULL
) < 0)
793 int btrfs_defrag(const char *p
) {
794 _cleanup_close_
int fd
= -1;
796 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
800 return btrfs_defrag_fd(fd
);
803 int btrfs_quota_enable_fd(int fd
, bool b
) {
804 struct btrfs_ioctl_quota_ctl_args args
= {
805 .cmd
= b
? BTRFS_QUOTA_CTL_ENABLE
: BTRFS_QUOTA_CTL_DISABLE
,
811 r
= btrfs_is_filesystem(fd
);
817 if (ioctl(fd
, BTRFS_IOC_QUOTA_CTL
, &args
) < 0)
823 int btrfs_quota_enable(const char *path
, bool b
) {
824 _cleanup_close_
int fd
= -1;
826 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
830 return btrfs_quota_enable_fd(fd
, b
);
833 int btrfs_qgroup_set_limit_fd(int fd
, uint64_t qgroupid
, uint64_t referenced_max
) {
835 struct btrfs_ioctl_qgroup_limit_args args
= {
836 .lim
.max_rfer
= referenced_max
,
837 .lim
.flags
= BTRFS_QGROUP_LIMIT_MAX_RFER
,
845 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
849 r
= btrfs_is_filesystem(fd
);
856 args
.qgroupid
= qgroupid
;
859 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &args
) < 0) {
861 if (errno
== EBUSY
&& c
< 10) {
862 (void) btrfs_quota_scan_wait(fd
);
875 int btrfs_qgroup_set_limit(const char *path
, uint64_t qgroupid
, uint64_t referenced_max
) {
876 _cleanup_close_
int fd
= -1;
878 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
882 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
885 int btrfs_subvol_set_subtree_quota_limit_fd(int fd
, uint64_t subvol_id
, uint64_t referenced_max
) {
891 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
895 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
898 int btrfs_subvol_set_subtree_quota_limit(const char *path
, uint64_t subvol_id
, uint64_t referenced_max
) {
899 _cleanup_close_
int fd
= -1;
901 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
905 return btrfs_subvol_set_subtree_quota_limit_fd(fd
, subvol_id
, referenced_max
);
908 int btrfs_resize_loopback_fd(int fd
, uint64_t new_size
, bool grow_only
) {
909 struct btrfs_ioctl_vol_args args
= {};
910 _cleanup_free_
char *p
= NULL
, *loop
= NULL
, *backing
= NULL
;
911 _cleanup_close_
int loop_fd
= -1, backing_fd
= -1;
916 /* btrfs cannot handle file systems < 16M, hence use this as minimum */
917 if (new_size
< 16*1024*1024)
918 new_size
= 16*1024*1024;
920 r
= btrfs_get_block_device_fd(fd
, &dev
);
926 if (asprintf(&p
, "/sys/dev/block/%u:%u/loop/backing_file", major(dev
), minor(dev
)) < 0)
928 r
= read_one_line_file(p
, &backing
);
933 if (isempty(backing
) || !path_is_absolute(backing
))
936 backing_fd
= open(backing
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
940 if (fstat(backing_fd
, &st
) < 0)
942 if (!S_ISREG(st
.st_mode
))
945 if (new_size
== (uint64_t) st
.st_size
)
948 if (grow_only
&& new_size
< (uint64_t) st
.st_size
)
951 if (asprintf(&loop
, "/dev/block/%u:%u", major(dev
), minor(dev
)) < 0)
953 loop_fd
= open(loop
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
957 if (snprintf(args
.name
, sizeof(args
.name
), "%" PRIu64
, new_size
) >= (int) sizeof(args
.name
))
960 if (new_size
< (uint64_t) st
.st_size
) {
961 /* Decrease size: first decrease btrfs size, then shorten loopback */
962 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
966 if (ftruncate(backing_fd
, new_size
) < 0)
969 if (ioctl(loop_fd
, LOOP_SET_CAPACITY
, 0) < 0)
972 if (new_size
> (uint64_t) st
.st_size
) {
973 /* Increase size: first enlarge loopback, then increase btrfs size */
974 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
978 /* Make sure the free disk space is correctly updated for both file systems */
980 (void) fsync(backing_fd
);
985 int btrfs_resize_loopback(const char *p
, uint64_t new_size
, bool grow_only
) {
986 _cleanup_close_
int fd
= -1;
988 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
992 return btrfs_resize_loopback_fd(fd
, new_size
, grow_only
);
995 int btrfs_qgroupid_make(uint64_t level
, uint64_t id
, uint64_t *ret
) {
998 if (level
>= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT
)))
1001 if (id
>= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
))
1004 *ret
= (level
<< BTRFS_QGROUP_LEVEL_SHIFT
) | id
;
1008 int btrfs_qgroupid_split(uint64_t qgroupid
, uint64_t *level
, uint64_t *id
) {
1009 assert(level
|| id
);
1012 *level
= qgroupid
>> BTRFS_QGROUP_LEVEL_SHIFT
;
1015 *id
= qgroupid
& ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
) - 1);
1020 static int qgroup_create_or_destroy(int fd
, bool b
, uint64_t qgroupid
) {
1022 struct btrfs_ioctl_qgroup_create_args args
= {
1024 .qgroupid
= qgroupid
,
1029 r
= btrfs_is_filesystem(fd
);
1036 if (ioctl(fd
, BTRFS_IOC_QGROUP_CREATE
, &args
) < 0) {
1038 /* If quota is not enabled, we get EINVAL. Turn this into a recognizable error */
1039 if (errno
== EINVAL
)
1040 return -ENOPROTOOPT
;
1042 if (errno
== EBUSY
&& c
< 10) {
1043 (void) btrfs_quota_scan_wait(fd
);
1056 int btrfs_qgroup_create(int fd
, uint64_t qgroupid
) {
1057 return qgroup_create_or_destroy(fd
, true, qgroupid
);
1060 int btrfs_qgroup_destroy(int fd
, uint64_t qgroupid
) {
1061 return qgroup_create_or_destroy(fd
, false, qgroupid
);
1064 int btrfs_qgroup_destroy_recursive(int fd
, uint64_t qgroupid
) {
1065 _cleanup_free_
uint64_t *qgroups
= NULL
;
1069 /* Destroys the specified qgroup, but unassigns it from all
1070 * its parents first. Also, it recursively destroys all
1071 * qgroups it is assgined to that have the same id part of the
1072 * qgroupid as the specified group. */
1074 r
= btrfs_qgroupid_split(qgroupid
, NULL
, &subvol_id
);
1078 n
= btrfs_qgroup_find_parents(fd
, qgroupid
, &qgroups
);
1082 for (i
= 0; i
< n
; i
++) {
1085 r
= btrfs_qgroupid_split(qgroups
[i
], NULL
, &id
);
1089 r
= btrfs_qgroup_unassign(fd
, qgroupid
, qgroups
[i
]);
1093 if (id
!= subvol_id
)
1096 /* The parent qgroupid shares the same id part with
1097 * us? If so, destroy it too. */
1099 (void) btrfs_qgroup_destroy_recursive(fd
, qgroups
[i
]);
1102 return btrfs_qgroup_destroy(fd
, qgroupid
);
1105 int btrfs_quota_scan_start(int fd
) {
1106 struct btrfs_ioctl_quota_rescan_args args
= {};
1110 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN
, &args
) < 0)
1116 int btrfs_quota_scan_wait(int fd
) {
1119 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_WAIT
) < 0)
1125 int btrfs_quota_scan_ongoing(int fd
) {
1126 struct btrfs_ioctl_quota_rescan_args args
= {};
1130 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_STATUS
, &args
) < 0)
1133 return !!args
.flags
;
1136 static int qgroup_assign_or_unassign(int fd
, bool b
, uint64_t child
, uint64_t parent
) {
1137 struct btrfs_ioctl_qgroup_assign_args args
= {
1145 r
= btrfs_is_filesystem(fd
);
1152 r
= ioctl(fd
, BTRFS_IOC_QGROUP_ASSIGN
, &args
);
1154 if (errno
== EBUSY
&& c
< 10) {
1155 (void) btrfs_quota_scan_wait(fd
);
1165 /* If the return value is > 0, we need to request a rescan */
1167 (void) btrfs_quota_scan_start(fd
);
1172 int btrfs_qgroup_assign(int fd
, uint64_t child
, uint64_t parent
) {
1173 return qgroup_assign_or_unassign(fd
, true, child
, parent
);
1176 int btrfs_qgroup_unassign(int fd
, uint64_t child
, uint64_t parent
) {
1177 return qgroup_assign_or_unassign(fd
, false, child
, parent
);
1180 static int subvol_remove_children(int fd
, const char *subvolume
, uint64_t subvol_id
, BtrfsRemoveFlags flags
) {
1181 struct btrfs_ioctl_search_args args
= {
1182 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1184 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1185 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1187 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1188 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1190 .key
.min_transid
= 0,
1191 .key
.max_transid
= (uint64_t) -1,
1194 struct btrfs_ioctl_vol_args vol_args
= {};
1195 _cleanup_close_
int subvol_fd
= -1;
1197 bool made_writable
= false;
1203 if (fstat(fd
, &st
) < 0)
1206 if (!S_ISDIR(st
.st_mode
))
1209 subvol_fd
= openat(fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1213 if (subvol_id
== 0) {
1214 r
= btrfs_subvol_get_id_fd(subvol_fd
, &subvol_id
);
1219 /* First, try to remove the subvolume. If it happens to be
1220 * already empty, this will just work. */
1221 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1222 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) >= 0) {
1223 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1226 if (!(flags
& BTRFS_REMOVE_RECURSIVE
) || errno
!= ENOTEMPTY
)
1229 /* OK, the subvolume is not empty, let's look for child
1230 * subvolumes, and remove them, first */
1232 args
.key
.min_offset
= args
.key
.max_offset
= subvol_id
;
1234 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1235 const struct btrfs_ioctl_search_header
*sh
;
1238 args
.key
.nr_items
= 256;
1239 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1242 if (args
.key
.nr_items
<= 0)
1245 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1246 _cleanup_free_
char *p
= NULL
;
1247 const struct btrfs_root_ref
*ref
;
1248 struct btrfs_ioctl_ino_lookup_args ino_args
;
1250 btrfs_ioctl_search_args_set(&args
, sh
);
1252 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1254 if (sh
->offset
!= subvol_id
)
1257 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1259 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1264 ino_args
.treeid
= subvol_id
;
1265 ino_args
.objectid
= htole64(ref
->dirid
);
1267 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1270 if (!made_writable
) {
1271 r
= btrfs_subvol_set_read_only_fd(subvol_fd
, false);
1275 made_writable
= true;
1278 if (isempty(ino_args
.name
))
1279 /* Subvolume is in the top-level
1280 * directory of the subvolume. */
1281 r
= subvol_remove_children(subvol_fd
, p
, sh
->objectid
, flags
);
1283 _cleanup_close_
int child_fd
= -1;
1285 /* Subvolume is somewhere further down,
1286 * hence we need to open the
1287 * containing directory first */
1289 child_fd
= openat(subvol_fd
, ino_args
.name
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1293 r
= subvol_remove_children(child_fd
, p
, sh
->objectid
, flags
);
1299 /* Increase search key by one, to read the next item, if we can. */
1300 if (!btrfs_ioctl_search_args_inc(&args
))
1304 /* OK, the child subvolumes should all be gone now, let's try
1305 * again to remove the subvolume */
1306 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) < 0)
1309 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
);
1313 int btrfs_subvol_remove(const char *path
, BtrfsRemoveFlags flags
) {
1314 _cleanup_close_
int fd
= -1;
1315 const char *subvolume
;
1320 r
= extract_subvolume_name(path
, &subvolume
);
1324 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1328 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1331 int btrfs_subvol_remove_fd(int fd
, const char *subvolume
, BtrfsRemoveFlags flags
) {
1332 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1335 int btrfs_qgroup_copy_limits(int fd
, uint64_t old_qgroupid
, uint64_t new_qgroupid
) {
1337 struct btrfs_ioctl_search_args args
= {
1338 /* Tree of quota items */
1339 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1341 /* The object ID is always 0 */
1342 .key
.min_objectid
= 0,
1343 .key
.max_objectid
= 0,
1345 /* Look precisely for the quota items */
1346 .key
.min_type
= BTRFS_QGROUP_LIMIT_KEY
,
1347 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
1349 /* For our qgroup */
1350 .key
.min_offset
= old_qgroupid
,
1351 .key
.max_offset
= old_qgroupid
,
1353 /* No restrictions on the other components */
1354 .key
.min_transid
= 0,
1355 .key
.max_transid
= (uint64_t) -1,
1360 r
= btrfs_is_filesystem(fd
);
1366 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1367 const struct btrfs_ioctl_search_header
*sh
;
1370 args
.key
.nr_items
= 256;
1371 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1372 if (errno
== ENOENT
) /* quota tree missing: quota is not enabled, hence nothing to copy */
1378 if (args
.key
.nr_items
<= 0)
1381 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1382 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1383 struct btrfs_ioctl_qgroup_limit_args qargs
;
1386 /* Make sure we start the next search at least from this entry */
1387 btrfs_ioctl_search_args_set(&args
, sh
);
1389 if (sh
->objectid
!= 0)
1391 if (sh
->type
!= BTRFS_QGROUP_LIMIT_KEY
)
1393 if (sh
->offset
!= old_qgroupid
)
1396 /* We found the entry, now copy things over. */
1398 qargs
= (struct btrfs_ioctl_qgroup_limit_args
) {
1399 .qgroupid
= new_qgroupid
,
1401 .lim
.max_rfer
= le64toh(qli
->max_rfer
),
1402 .lim
.max_excl
= le64toh(qli
->max_excl
),
1403 .lim
.rsv_rfer
= le64toh(qli
->rsv_rfer
),
1404 .lim
.rsv_excl
= le64toh(qli
->rsv_excl
),
1406 .lim
.flags
= le64toh(qli
->flags
) & (BTRFS_QGROUP_LIMIT_MAX_RFER
|
1407 BTRFS_QGROUP_LIMIT_MAX_EXCL
|
1408 BTRFS_QGROUP_LIMIT_RSV_RFER
|
1409 BTRFS_QGROUP_LIMIT_RSV_EXCL
),
1413 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &qargs
) < 0) {
1414 if (errno
== EBUSY
&& c
< 10) {
1415 (void) btrfs_quota_scan_wait(fd
);
1427 /* Increase search key by one, to read the next item, if we can. */
1428 if (!btrfs_ioctl_search_args_inc(&args
))
1435 static int copy_quota_hierarchy(int fd
, uint64_t old_subvol_id
, uint64_t new_subvol_id
) {
1436 _cleanup_free_
uint64_t *old_qgroups
= NULL
, *old_parent_qgroups
= NULL
;
1437 bool copy_from_parent
= false, insert_intermediary_qgroup
= false;
1438 int n_old_qgroups
, n_old_parent_qgroups
, r
, i
;
1439 uint64_t old_parent_id
;
1443 /* Copies a reduced form of quota information from the old to
1444 * the new subvolume. */
1446 n_old_qgroups
= btrfs_qgroup_find_parents(fd
, old_subvol_id
, &old_qgroups
);
1447 if (n_old_qgroups
<= 0) /* Nothing to copy */
1448 return n_old_qgroups
;
1450 r
= btrfs_subvol_get_parent(fd
, old_subvol_id
, &old_parent_id
);
1452 /* We have no parent, hence nothing to copy. */
1453 n_old_parent_qgroups
= 0;
1457 n_old_parent_qgroups
= btrfs_qgroup_find_parents(fd
, old_parent_id
, &old_parent_qgroups
);
1458 if (n_old_parent_qgroups
< 0)
1459 return n_old_parent_qgroups
;
1462 for (i
= 0; i
< n_old_qgroups
; i
++) {
1466 r
= btrfs_qgroupid_split(old_qgroups
[i
], NULL
, &id
);
1470 if (id
== old_subvol_id
) {
1471 /* The old subvolume was member of a qgroup
1472 * that had the same id, but a different level
1473 * as it self. Let's set up something similar
1474 * in the destination. */
1475 insert_intermediary_qgroup
= true;
1479 for (j
= 0; j
< n_old_parent_qgroups
; j
++)
1480 if (old_parent_qgroups
[j
] == old_qgroups
[i
]) {
1481 /* The old subvolume shared a common
1482 * parent qgroup with its parent
1483 * subvolume. Let's set up something
1484 * similar in the destination. */
1485 copy_from_parent
= true;
1489 if (!insert_intermediary_qgroup
&& !copy_from_parent
)
1492 return btrfs_subvol_auto_qgroup_fd(fd
, new_subvol_id
, insert_intermediary_qgroup
);
1495 static int copy_subtree_quota_limits(int fd
, uint64_t old_subvol
, uint64_t new_subvol
) {
1496 uint64_t old_subtree_qgroup
, new_subtree_qgroup
;
1500 /* First copy the leaf limits */
1501 r
= btrfs_qgroup_copy_limits(fd
, old_subvol
, new_subvol
);
1506 /* Then, try to copy the subtree limits, if there are any. */
1507 r
= btrfs_subvol_find_subtree_qgroup(fd
, old_subvol
, &old_subtree_qgroup
);
1513 r
= btrfs_subvol_find_subtree_qgroup(fd
, new_subvol
, &new_subtree_qgroup
);
1519 r
= btrfs_qgroup_copy_limits(fd
, old_subtree_qgroup
, new_subtree_qgroup
);
1526 static int subvol_snapshot_children(int old_fd
, int new_fd
, const char *subvolume
, uint64_t old_subvol_id
, BtrfsSnapshotFlags flags
) {
1528 struct btrfs_ioctl_search_args args
= {
1529 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1531 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1532 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1534 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1535 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1537 .key
.min_transid
= 0,
1538 .key
.max_transid
= (uint64_t) -1,
1541 struct btrfs_ioctl_vol_args_v2 vol_args
= {
1542 .flags
= flags
& BTRFS_SNAPSHOT_READ_ONLY
? BTRFS_SUBVOL_RDONLY
: 0,
1545 _cleanup_close_
int subvolume_fd
= -1;
1546 uint64_t new_subvol_id
;
1549 assert(old_fd
>= 0);
1550 assert(new_fd
>= 0);
1553 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1555 if (ioctl(new_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &vol_args
) < 0)
1558 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
) &&
1559 !(flags
& BTRFS_SNAPSHOT_QUOTA
))
1562 if (old_subvol_id
== 0) {
1563 r
= btrfs_subvol_get_id_fd(old_fd
, &old_subvol_id
);
1568 r
= btrfs_subvol_get_id(new_fd
, vol_args
.name
, &new_subvol_id
);
1572 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1573 (void) copy_quota_hierarchy(new_fd
, old_subvol_id
, new_subvol_id
);
1575 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
)) {
1577 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1578 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1583 args
.key
.min_offset
= args
.key
.max_offset
= old_subvol_id
;
1585 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1586 const struct btrfs_ioctl_search_header
*sh
;
1589 args
.key
.nr_items
= 256;
1590 if (ioctl(old_fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1593 if (args
.key
.nr_items
<= 0)
1596 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1597 _cleanup_free_
char *p
= NULL
, *c
= NULL
, *np
= NULL
;
1598 struct btrfs_ioctl_ino_lookup_args ino_args
;
1599 const struct btrfs_root_ref
*ref
;
1600 _cleanup_close_
int old_child_fd
= -1, new_child_fd
= -1;
1602 btrfs_ioctl_search_args_set(&args
, sh
);
1604 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1607 /* Avoid finding the source subvolume a second
1609 if (sh
->offset
!= old_subvol_id
)
1612 /* Avoid running into loops if the new
1613 * subvolume is below the old one. */
1614 if (sh
->objectid
== new_subvol_id
)
1617 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1618 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1623 ino_args
.treeid
= old_subvol_id
;
1624 ino_args
.objectid
= htole64(ref
->dirid
);
1626 if (ioctl(old_fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1629 /* The kernel returns an empty name if the
1630 * subvolume is in the top-level directory,
1631 * and otherwise appends a slash, so that we
1632 * can just concatenate easily here, without
1633 * adding a slash. */
1634 c
= strappend(ino_args
.name
, p
);
1638 old_child_fd
= openat(old_fd
, c
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1639 if (old_child_fd
< 0)
1642 np
= strjoin(subvolume
, "/", ino_args
.name
, NULL
);
1646 new_child_fd
= openat(new_fd
, np
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1647 if (new_child_fd
< 0)
1650 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1651 /* If the snapshot is read-only we
1652 * need to mark it writable
1653 * temporarily, to put the subsnapshot
1656 if (subvolume_fd
< 0) {
1657 subvolume_fd
= openat(new_fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1658 if (subvolume_fd
< 0)
1662 r
= btrfs_subvol_set_read_only_fd(subvolume_fd
, false);
1667 /* When btrfs clones the subvolumes, child
1668 * subvolumes appear as empty directories. Remove
1669 * them, so that we can create a new snapshot
1671 if (unlinkat(new_child_fd
, p
, AT_REMOVEDIR
) < 0) {
1674 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
)
1675 (void) btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1680 r
= subvol_snapshot_children(old_child_fd
, new_child_fd
, p
, sh
->objectid
, flags
& ~BTRFS_SNAPSHOT_FALLBACK_COPY
);
1682 /* Restore the readonly flag */
1683 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1686 k
= btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1687 if (r
>= 0 && k
< 0)
1695 /* Increase search key by one, to read the next item, if we can. */
1696 if (!btrfs_ioctl_search_args_inc(&args
))
1700 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1701 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1706 int btrfs_subvol_snapshot_fd(int old_fd
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1707 _cleanup_close_
int new_fd
= -1;
1708 const char *subvolume
;
1711 assert(old_fd
>= 0);
1714 r
= btrfs_is_subvol_fd(old_fd
);
1718 if (!(flags
& BTRFS_SNAPSHOT_FALLBACK_COPY
))
1721 r
= btrfs_subvol_make(new_path
);
1725 r
= copy_directory_fd(old_fd
, new_path
, true);
1727 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1731 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1732 r
= btrfs_subvol_set_read_only(new_path
, true);
1734 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1742 r
= extract_subvolume_name(new_path
, &subvolume
);
1746 new_fd
= open_parent(new_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1750 return subvol_snapshot_children(old_fd
, new_fd
, subvolume
, 0, flags
);
1753 int btrfs_subvol_snapshot(const char *old_path
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1754 _cleanup_close_
int old_fd
= -1;
1759 old_fd
= open(old_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1763 return btrfs_subvol_snapshot_fd(old_fd
, new_path
, flags
);
1766 int btrfs_qgroup_find_parents(int fd
, uint64_t qgroupid
, uint64_t **ret
) {
1768 struct btrfs_ioctl_search_args args
= {
1769 /* Tree of quota items */
1770 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1772 /* Look precisely for the quota relation items */
1773 .key
.min_type
= BTRFS_QGROUP_RELATION_KEY
,
1774 .key
.max_type
= BTRFS_QGROUP_RELATION_KEY
,
1776 /* No restrictions on the other components */
1777 .key
.min_offset
= 0,
1778 .key
.max_offset
= (uint64_t) -1,
1780 .key
.min_transid
= 0,
1781 .key
.max_transid
= (uint64_t) -1,
1784 _cleanup_free_
uint64_t *items
= NULL
;
1785 size_t n_items
= 0, n_allocated
= 0;
1791 if (qgroupid
== 0) {
1792 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
1796 r
= btrfs_is_filesystem(fd
);
1803 args
.key
.min_objectid
= args
.key
.max_objectid
= qgroupid
;
1805 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1806 const struct btrfs_ioctl_search_header
*sh
;
1809 args
.key
.nr_items
= 256;
1810 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1811 if (errno
== ENOENT
) /* quota tree missing: quota is disabled */
1817 if (args
.key
.nr_items
<= 0)
1820 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1822 /* Make sure we start the next search at least from this entry */
1823 btrfs_ioctl_search_args_set(&args
, sh
);
1825 if (sh
->type
!= BTRFS_QGROUP_RELATION_KEY
)
1827 if (sh
->offset
< sh
->objectid
)
1829 if (sh
->objectid
!= qgroupid
)
1832 if (!GREEDY_REALLOC(items
, n_allocated
, n_items
+1))
1835 items
[n_items
++] = sh
->offset
;
1838 /* Increase search key by one, to read the next item, if we can. */
1839 if (!btrfs_ioctl_search_args_inc(&args
))
1851 return (int) n_items
;
1854 int btrfs_subvol_auto_qgroup_fd(int fd
, uint64_t subvol_id
, bool insert_intermediary_qgroup
) {
1855 _cleanup_free_
uint64_t *qgroups
= NULL
;
1856 uint64_t parent_subvol
;
1857 bool changed
= false;
1863 * Sets up the specified subvolume's qgroup automatically in
1866 * If insert_intermediary_qgroup is false, the subvolume's
1867 * leaf qgroup will be assigned to the same parent qgroups as
1868 * the subvolume's parent subvolume.
1870 * If insert_intermediary_qgroup is true a new intermediary
1871 * higher-level qgroup is created, with a higher level number,
1872 * but reusing the id of the subvolume. The level number is
1873 * picked as one smaller than the lowest level qgroup the
1874 * parent subvolume is a member of. If the parent subvolume's
1875 * leaf qgroup is assigned to no higher-level qgroup a new
1876 * qgroup of level 255 is created instead. Either way, the new
1877 * qgroup is then assigned to the parent's higher-level
1878 * qgroup, and the subvolume itself is assigned to it.
1880 * If the subvolume is already assigned to a higher level
1881 * qgroup, no operation is executed.
1883 * Effectively this means: regardless if
1884 * insert_intermediary_qgroup is true or not, after this
1885 * function is invoked the subvolume will be accounted within
1886 * the same qgroups as the parent. However, if it is true, it
1887 * will also get its own higher-level qgroup, which may in
1888 * turn be used by subvolumes created beneath this subvolume
1891 * This hence defines a simple default qgroup setup for
1892 * subvolumes, as long as this function is invoked on each
1893 * created subvolume: each subvolume is always accounting
1894 * together with its immediate parents. Optionally, if
1895 * insert_intermediary_qgroup is true, it will also get a
1896 * qgroup that then includes all its own child subvolumes.
1899 if (subvol_id
== 0) {
1900 r
= btrfs_is_subvol_fd(fd
);
1906 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1911 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
1914 if (n
> 0) /* already parent qgroups set up, let's bail */
1917 qgroups
= mfree(qgroups
);
1919 r
= btrfs_subvol_get_parent(fd
, subvol_id
, &parent_subvol
);
1921 /* No parent, hence no qgroup memberships */
1926 n
= btrfs_qgroup_find_parents(fd
, parent_subvol
, &qgroups
);
1931 if (insert_intermediary_qgroup
) {
1932 uint64_t lowest
= 256, new_qgroupid
;
1933 bool created
= false;
1936 /* Determine the lowest qgroup that the parent
1937 * subvolume is assigned to. */
1939 for (i
= 0; i
< n
; i
++) {
1942 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, NULL
);
1950 if (lowest
<= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1953 r
= btrfs_qgroupid_make(lowest
- 1, subvol_id
, &new_qgroupid
);
1957 /* Create the new intermediary group, unless it already exists */
1958 r
= btrfs_qgroup_create(fd
, new_qgroupid
);
1959 if (r
< 0 && r
!= -EEXIST
)
1962 changed
= created
= true;
1964 for (i
= 0; i
< n
; i
++) {
1965 r
= btrfs_qgroup_assign(fd
, new_qgroupid
, qgroups
[i
]);
1966 if (r
< 0 && r
!= -EEXIST
) {
1968 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1976 r
= btrfs_qgroup_assign(fd
, subvol_id
, new_qgroupid
);
1977 if (r
< 0 && r
!= -EEXIST
) {
1979 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1988 /* Assign our subvolume to all the same qgroups as the parent */
1990 for (i
= 0; i
< n
; i
++) {
1991 r
= btrfs_qgroup_assign(fd
, subvol_id
, qgroups
[i
]);
1992 if (r
< 0 && r
!= -EEXIST
)
2002 int btrfs_subvol_auto_qgroup(const char *path
, uint64_t subvol_id
, bool create_intermediary_qgroup
) {
2003 _cleanup_close_
int fd
= -1;
2005 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
2009 return btrfs_subvol_auto_qgroup_fd(fd
, subvol_id
, create_intermediary_qgroup
);
2012 int btrfs_subvol_get_parent(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
2014 struct btrfs_ioctl_search_args args
= {
2015 /* Tree of tree roots */
2016 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
2018 /* Look precisely for the subvolume items */
2019 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
2020 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
2022 /* No restrictions on the other components */
2023 .key
.min_offset
= 0,
2024 .key
.max_offset
= (uint64_t) -1,
2026 .key
.min_transid
= 0,
2027 .key
.max_transid
= (uint64_t) -1,
2034 if (subvol_id
== 0) {
2035 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
2039 r
= btrfs_is_filesystem(fd
);
2046 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
2048 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
2049 const struct btrfs_ioctl_search_header
*sh
;
2052 args
.key
.nr_items
= 256;
2053 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
2054 return negative_errno();
2056 if (args
.key
.nr_items
<= 0)
2059 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
2061 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
2063 if (sh
->objectid
!= subvol_id
)