1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 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 #if HAVE_LINUX_BTRFS_H
37 #include <linux/btrfs.h>
40 #include "alloc-util.h"
41 #include "btrfs-ctree.h"
42 #include "btrfs-util.h"
43 #include "chattr-util.h"
50 #include "path-util.h"
52 #include "selinux-util.h"
53 #include "smack-util.h"
54 #include "sparse-endian.h"
55 #include "stat-util.h"
56 #include "string-util.h"
57 #include "time-util.h"
60 /* WARNING: Be careful with file system ioctls! When we get an fd, we
61 * need to make sure it either refers to only a regular file or
62 * directory, or that it is located on btrfs, before invoking any
63 * btrfs ioctls. The ioctl numbers are reused by some device drivers
64 * (such as DRM), and hence might have bad effects when invoked on
65 * device nodes (that reference drivers) rather than fds to normal
66 * files or directories. */
68 static int validate_subvolume_name(const char *name
) {
70 if (!filename_is_valid(name
))
73 if (strlen(name
) > BTRFS_SUBVOL_NAME_MAX
)
79 static int open_parent(const char *path
, int flags
) {
80 _cleanup_free_
char *parent
= NULL
;
85 parent
= dirname_malloc(path
);
89 fd
= open(parent
, flags
);
96 static int extract_subvolume_name(const char *path
, const char **subvolume
) {
105 r
= validate_subvolume_name(fn
);
113 int btrfs_is_filesystem(int fd
) {
118 if (fstatfs(fd
, &sfs
) < 0)
121 return F_TYPE_EQUAL(sfs
.f_type
, BTRFS_SUPER_MAGIC
);
124 int btrfs_is_subvol_fd(int fd
) {
129 /* On btrfs subvolumes always have the inode 256 */
131 if (fstat(fd
, &st
) < 0)
134 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
137 return btrfs_is_filesystem(fd
);
140 int btrfs_is_subvol(const char *path
) {
141 _cleanup_close_
int fd
= -1;
145 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
149 return btrfs_is_subvol_fd(fd
);
152 int btrfs_subvol_make(const char *path
) {
153 struct btrfs_ioctl_vol_args args
= {};
154 _cleanup_close_
int fd
= -1;
155 const char *subvolume
;
160 r
= extract_subvolume_name(path
, &subvolume
);
164 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
168 strncpy(args
.name
, subvolume
, sizeof(args
.name
)-1);
170 if (ioctl(fd
, BTRFS_IOC_SUBVOL_CREATE
, &args
) < 0)
176 int btrfs_subvol_make_label(const char *path
) {
181 r
= mac_selinux_create_file_prepare(path
, S_IFDIR
);
185 r
= btrfs_subvol_make(path
);
186 mac_selinux_create_file_clear();
191 return mac_smack_fix(path
, false, false);
194 int btrfs_subvol_set_read_only_fd(int fd
, bool b
) {
195 uint64_t flags
, nflags
;
200 if (fstat(fd
, &st
) < 0)
203 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
206 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
210 nflags
= flags
| BTRFS_SUBVOL_RDONLY
;
212 nflags
= flags
& ~BTRFS_SUBVOL_RDONLY
;
217 if (ioctl(fd
, BTRFS_IOC_SUBVOL_SETFLAGS
, &nflags
) < 0)
223 int btrfs_subvol_set_read_only(const char *path
, bool b
) {
224 _cleanup_close_
int fd
= -1;
226 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
230 return btrfs_subvol_set_read_only_fd(fd
, b
);
233 int btrfs_subvol_get_read_only_fd(int fd
) {
239 if (fstat(fd
, &st
) < 0)
242 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
245 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
248 return !!(flags
& BTRFS_SUBVOL_RDONLY
);
251 int btrfs_reflink(int infd
, int outfd
) {
258 /* Make sure we invoke the ioctl on a regular file, so that no
259 * device driver accidentally gets it. */
261 if (fstat(outfd
, &st
) < 0)
264 if (!S_ISREG(st
.st_mode
))
267 r
= ioctl(outfd
, BTRFS_IOC_CLONE
, infd
);
274 int btrfs_clone_range(int infd
, uint64_t in_offset
, int outfd
, uint64_t out_offset
, uint64_t sz
) {
275 struct btrfs_ioctl_clone_range_args args
= {
277 .src_offset
= in_offset
,
279 .dest_offset
= out_offset
,
288 if (fstat(outfd
, &st
) < 0)
291 if (!S_ISREG(st
.st_mode
))
294 r
= ioctl(outfd
, BTRFS_IOC_CLONE_RANGE
, &args
);
301 int btrfs_get_block_device_fd(int fd
, dev_t
*dev
) {
302 struct btrfs_ioctl_fs_info_args fsi
= {};
309 r
= btrfs_is_filesystem(fd
);
315 if (ioctl(fd
, BTRFS_IOC_FS_INFO
, &fsi
) < 0)
318 /* We won't do this for btrfs RAID */
319 if (fsi
.num_devices
!= 1)
322 for (id
= 1; id
<= fsi
.max_id
; id
++) {
323 struct btrfs_ioctl_dev_info_args di
= {
328 if (ioctl(fd
, BTRFS_IOC_DEV_INFO
, &di
) < 0) {
335 if (stat((char*) di
.path
, &st
) < 0)
338 if (!S_ISBLK(st
.st_mode
))
341 if (major(st
.st_rdev
) == 0)
351 int btrfs_get_block_device(const char *path
, dev_t
*dev
) {
352 _cleanup_close_
int fd
= -1;
357 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
361 return btrfs_get_block_device_fd(fd
, dev
);
364 int btrfs_subvol_get_id_fd(int fd
, uint64_t *ret
) {
365 struct btrfs_ioctl_ino_lookup_args args
= {
366 .objectid
= BTRFS_FIRST_FREE_OBJECTID
373 r
= btrfs_is_filesystem(fd
);
379 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
) < 0)
386 int btrfs_subvol_get_id(int fd
, const char *subvol
, uint64_t *ret
) {
387 _cleanup_close_
int subvol_fd
= -1;
392 subvol_fd
= openat(fd
, subvol
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
396 return btrfs_subvol_get_id_fd(subvol_fd
, ret
);
399 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args
*args
) {
402 /* the objectid, type, offset together make up the btrfs key,
403 * which is considered a single 136byte integer when
404 * comparing. This call increases the counter by one, dealing
405 * with the overflow between the overflows */
407 if (args
->key
.min_offset
< (uint64_t) -1) {
408 args
->key
.min_offset
++;
412 if (args
->key
.min_type
< (uint8_t) -1) {
413 args
->key
.min_type
++;
414 args
->key
.min_offset
= 0;
418 if (args
->key
.min_objectid
< (uint64_t) -1) {
419 args
->key
.min_objectid
++;
420 args
->key
.min_offset
= 0;
421 args
->key
.min_type
= 0;
428 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args
*args
, const struct btrfs_ioctl_search_header
*h
) {
432 args
->key
.min_objectid
= h
->objectid
;
433 args
->key
.min_type
= h
->type
;
434 args
->key
.min_offset
= h
->offset
;
437 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
*args
) {
440 /* Compare min and max */
442 if (args
->key
.min_objectid
< args
->key
.max_objectid
)
444 if (args
->key
.min_objectid
> args
->key
.max_objectid
)
447 if (args
->key
.min_type
< args
->key
.max_type
)
449 if (args
->key
.min_type
> args
->key
.max_type
)
452 if (args
->key
.min_offset
< args
->key
.max_offset
)
454 if (args
->key
.min_offset
> args
->key
.max_offset
)
460 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
462 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
463 (i) < (args).key.nr_items; \
465 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
467 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
468 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
470 int btrfs_subvol_get_info_fd(int fd
, uint64_t subvol_id
, BtrfsSubvolInfo
*ret
) {
471 struct btrfs_ioctl_search_args args
= {
472 /* Tree of tree roots */
473 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
475 /* Look precisely for the subvolume items */
476 .key
.min_type
= BTRFS_ROOT_ITEM_KEY
,
477 .key
.max_type
= BTRFS_ROOT_ITEM_KEY
,
480 .key
.max_offset
= (uint64_t) -1,
482 /* No restrictions on the other components */
483 .key
.min_transid
= 0,
484 .key
.max_transid
= (uint64_t) -1,
493 if (subvol_id
== 0) {
494 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
498 r
= btrfs_is_filesystem(fd
);
505 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
507 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
508 const struct btrfs_ioctl_search_header
*sh
;
511 args
.key
.nr_items
= 256;
512 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
515 if (args
.key
.nr_items
<= 0)
518 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
520 const struct btrfs_root_item
*ri
;
522 /* Make sure we start the next search at least from this entry */
523 btrfs_ioctl_search_args_set(&args
, sh
);
525 if (sh
->objectid
!= subvol_id
)
527 if (sh
->type
!= BTRFS_ROOT_ITEM_KEY
)
530 /* Older versions of the struct lacked the otime setting */
531 if (sh
->len
< offsetof(struct btrfs_root_item
, otime
) + sizeof(struct btrfs_timespec
))
534 ri
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
536 ret
->otime
= (usec_t
) le64toh(ri
->otime
.sec
) * USEC_PER_SEC
+
537 (usec_t
) le32toh(ri
->otime
.nsec
) / NSEC_PER_USEC
;
539 ret
->subvol_id
= subvol_id
;
540 ret
->read_only
= !!(le64toh(ri
->flags
) & BTRFS_ROOT_SUBVOL_RDONLY
);
542 assert_cc(sizeof(ri
->uuid
) == sizeof(ret
->uuid
));
543 memcpy(&ret
->uuid
, ri
->uuid
, sizeof(ret
->uuid
));
544 memcpy(&ret
->parent_uuid
, ri
->parent_uuid
, sizeof(ret
->parent_uuid
));
550 /* Increase search key by one, to read the next item, if we can. */
551 if (!btrfs_ioctl_search_args_inc(&args
))
562 int btrfs_qgroup_get_quota_fd(int fd
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
564 struct btrfs_ioctl_search_args args
= {
565 /* Tree of quota items */
566 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
568 /* The object ID is always 0 */
569 .key
.min_objectid
= 0,
570 .key
.max_objectid
= 0,
572 /* Look precisely for the quota items */
573 .key
.min_type
= BTRFS_QGROUP_STATUS_KEY
,
574 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
576 /* No restrictions on the other components */
577 .key
.min_transid
= 0,
578 .key
.max_transid
= (uint64_t) -1,
581 bool found_info
= false, found_limit
= false;
588 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
592 r
= btrfs_is_filesystem(fd
);
599 args
.key
.min_offset
= args
.key
.max_offset
= qgroupid
;
601 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
602 const struct btrfs_ioctl_search_header
*sh
;
605 args
.key
.nr_items
= 256;
606 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
607 if (errno
== ENOENT
) /* quota tree is missing: quota disabled */
613 if (args
.key
.nr_items
<= 0)
616 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
618 /* Make sure we start the next search at least from this entry */
619 btrfs_ioctl_search_args_set(&args
, sh
);
621 if (sh
->objectid
!= 0)
623 if (sh
->offset
!= qgroupid
)
626 if (sh
->type
== BTRFS_QGROUP_INFO_KEY
) {
627 const struct btrfs_qgroup_info_item
*qii
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
629 ret
->referenced
= le64toh(qii
->rfer
);
630 ret
->exclusive
= le64toh(qii
->excl
);
634 } else if (sh
->type
== BTRFS_QGROUP_LIMIT_KEY
) {
635 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
637 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_RFER
)
638 ret
->referenced_max
= le64toh(qli
->max_rfer
);
640 ret
->referenced_max
= (uint64_t) -1;
642 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_EXCL
)
643 ret
->exclusive_max
= le64toh(qli
->max_excl
);
645 ret
->exclusive_max
= (uint64_t) -1;
650 if (found_info
&& found_limit
)
654 /* Increase search key by one, to read the next item, if we can. */
655 if (!btrfs_ioctl_search_args_inc(&args
))
660 if (!found_limit
&& !found_info
)
664 ret
->referenced
= (uint64_t) -1;
665 ret
->exclusive
= (uint64_t) -1;
669 ret
->referenced_max
= (uint64_t) -1;
670 ret
->exclusive_max
= (uint64_t) -1;
676 int btrfs_qgroup_get_quota(const char *path
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
677 _cleanup_close_
int fd
= -1;
679 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
683 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
686 int btrfs_subvol_find_subtree_qgroup(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
687 uint64_t level
, lowest
= (uint64_t) -1, lowest_qgroupid
= 0;
688 _cleanup_free_
uint64_t *qgroups
= NULL
;
694 /* This finds the "subtree" qgroup for a specific
695 * subvolume. This only works for subvolumes that have been
696 * prepared with btrfs_subvol_auto_qgroup_fd() with
697 * insert_intermediary_qgroup=true (or equivalent). For others
698 * it will return the leaf qgroup instead. The two cases may
699 * be distuingished via the return value, which is 1 in case
700 * an appropriate "subtree" qgroup was found, and 0
703 if (subvol_id
== 0) {
704 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
709 r
= btrfs_qgroupid_split(subvol_id
, &level
, NULL
);
712 if (level
!= 0) /* Input must be a leaf qgroup */
715 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
719 for (i
= 0; i
< n
; i
++) {
722 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, &id
);
729 if (lowest
== (uint64_t) -1 || level
< lowest
) {
730 lowest_qgroupid
= qgroups
[i
];
735 if (lowest
== (uint64_t) -1) {
736 /* No suitable higher-level qgroup found, let's return
737 * the leaf qgroup instead, and indicate that with the
744 *ret
= lowest_qgroupid
;
748 int btrfs_subvol_get_subtree_quota_fd(int fd
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
755 /* This determines the quota data of the qgroup with the
756 * lowest level, that shares the id part with the specified
757 * subvolume. This is useful for determining the quota data
758 * for entire subvolume subtrees, as long as the subtrees have
759 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
762 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
766 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
769 int btrfs_subvol_get_subtree_quota(const char *path
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
770 _cleanup_close_
int fd
= -1;
772 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
776 return btrfs_subvol_get_subtree_quota_fd(fd
, subvol_id
, ret
);
779 int btrfs_defrag_fd(int fd
) {
784 if (fstat(fd
, &st
) < 0)
787 if (!S_ISREG(st
.st_mode
))
790 if (ioctl(fd
, BTRFS_IOC_DEFRAG
, NULL
) < 0)
796 int btrfs_defrag(const char *p
) {
797 _cleanup_close_
int fd
= -1;
799 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
803 return btrfs_defrag_fd(fd
);
806 int btrfs_quota_enable_fd(int fd
, bool b
) {
807 struct btrfs_ioctl_quota_ctl_args args
= {
808 .cmd
= b
? BTRFS_QUOTA_CTL_ENABLE
: BTRFS_QUOTA_CTL_DISABLE
,
814 r
= btrfs_is_filesystem(fd
);
820 if (ioctl(fd
, BTRFS_IOC_QUOTA_CTL
, &args
) < 0)
826 int btrfs_quota_enable(const char *path
, bool b
) {
827 _cleanup_close_
int fd
= -1;
829 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
833 return btrfs_quota_enable_fd(fd
, b
);
836 int btrfs_qgroup_set_limit_fd(int fd
, uint64_t qgroupid
, uint64_t referenced_max
) {
838 struct btrfs_ioctl_qgroup_limit_args args
= {
839 .lim
.max_rfer
= referenced_max
,
840 .lim
.flags
= BTRFS_QGROUP_LIMIT_MAX_RFER
,
848 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
852 r
= btrfs_is_filesystem(fd
);
859 args
.qgroupid
= qgroupid
;
862 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &args
) < 0) {
864 if (errno
== EBUSY
&& c
< 10) {
865 (void) btrfs_quota_scan_wait(fd
);
878 int btrfs_qgroup_set_limit(const char *path
, uint64_t qgroupid
, uint64_t referenced_max
) {
879 _cleanup_close_
int fd
= -1;
881 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
885 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
888 int btrfs_subvol_set_subtree_quota_limit_fd(int fd
, uint64_t subvol_id
, uint64_t referenced_max
) {
894 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
898 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
901 int btrfs_subvol_set_subtree_quota_limit(const char *path
, uint64_t subvol_id
, uint64_t referenced_max
) {
902 _cleanup_close_
int fd
= -1;
904 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
908 return btrfs_subvol_set_subtree_quota_limit_fd(fd
, subvol_id
, referenced_max
);
911 int btrfs_resize_loopback_fd(int fd
, uint64_t new_size
, bool grow_only
) {
912 struct btrfs_ioctl_vol_args args
= {};
913 _cleanup_free_
char *p
= NULL
, *loop
= NULL
, *backing
= NULL
;
914 _cleanup_close_
int loop_fd
= -1, backing_fd
= -1;
919 /* In contrast to btrfs quota ioctls ftruncate() cannot make sense of "infinity" or file sizes > 2^31 */
920 if (!FILE_SIZE_VALID(new_size
))
923 /* btrfs cannot handle file systems < 16M, hence use this as minimum */
924 if (new_size
< 16*1024*1024)
925 new_size
= 16*1024*1024;
927 r
= btrfs_get_block_device_fd(fd
, &dev
);
933 if (asprintf(&p
, "/sys/dev/block/%u:%u/loop/backing_file", major(dev
), minor(dev
)) < 0)
935 r
= read_one_line_file(p
, &backing
);
940 if (isempty(backing
) || !path_is_absolute(backing
))
943 backing_fd
= open(backing
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
947 if (fstat(backing_fd
, &st
) < 0)
949 if (!S_ISREG(st
.st_mode
))
952 if (new_size
== (uint64_t) st
.st_size
)
955 if (grow_only
&& new_size
< (uint64_t) st
.st_size
)
958 if (asprintf(&loop
, "/dev/block/%u:%u", major(dev
), minor(dev
)) < 0)
960 loop_fd
= open(loop
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
964 if (snprintf(args
.name
, sizeof(args
.name
), "%" PRIu64
, new_size
) >= (int) sizeof(args
.name
))
967 if (new_size
< (uint64_t) st
.st_size
) {
968 /* Decrease size: first decrease btrfs size, then shorten loopback */
969 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
973 if (ftruncate(backing_fd
, new_size
) < 0)
976 if (ioctl(loop_fd
, LOOP_SET_CAPACITY
, 0) < 0)
979 if (new_size
> (uint64_t) st
.st_size
) {
980 /* Increase size: first enlarge loopback, then increase btrfs size */
981 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
985 /* Make sure the free disk space is correctly updated for both file systems */
987 (void) fsync(backing_fd
);
992 int btrfs_resize_loopback(const char *p
, uint64_t new_size
, bool grow_only
) {
993 _cleanup_close_
int fd
= -1;
995 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
999 return btrfs_resize_loopback_fd(fd
, new_size
, grow_only
);
1002 int btrfs_qgroupid_make(uint64_t level
, uint64_t id
, uint64_t *ret
) {
1005 if (level
>= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT
)))
1008 if (id
>= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
))
1011 *ret
= (level
<< BTRFS_QGROUP_LEVEL_SHIFT
) | id
;
1015 int btrfs_qgroupid_split(uint64_t qgroupid
, uint64_t *level
, uint64_t *id
) {
1016 assert(level
|| id
);
1019 *level
= qgroupid
>> BTRFS_QGROUP_LEVEL_SHIFT
;
1022 *id
= qgroupid
& ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
) - 1);
1027 static int qgroup_create_or_destroy(int fd
, bool b
, uint64_t qgroupid
) {
1029 struct btrfs_ioctl_qgroup_create_args args
= {
1031 .qgroupid
= qgroupid
,
1036 r
= btrfs_is_filesystem(fd
);
1043 if (ioctl(fd
, BTRFS_IOC_QGROUP_CREATE
, &args
) < 0) {
1045 /* If quota is not enabled, we get EINVAL. Turn this into a recognizable error */
1046 if (errno
== EINVAL
)
1047 return -ENOPROTOOPT
;
1049 if (errno
== EBUSY
&& c
< 10) {
1050 (void) btrfs_quota_scan_wait(fd
);
1063 int btrfs_qgroup_create(int fd
, uint64_t qgroupid
) {
1064 return qgroup_create_or_destroy(fd
, true, qgroupid
);
1067 int btrfs_qgroup_destroy(int fd
, uint64_t qgroupid
) {
1068 return qgroup_create_or_destroy(fd
, false, qgroupid
);
1071 int btrfs_qgroup_destroy_recursive(int fd
, uint64_t qgroupid
) {
1072 _cleanup_free_
uint64_t *qgroups
= NULL
;
1076 /* Destroys the specified qgroup, but unassigns it from all
1077 * its parents first. Also, it recursively destroys all
1078 * qgroups it is assgined to that have the same id part of the
1079 * qgroupid as the specified group. */
1081 r
= btrfs_qgroupid_split(qgroupid
, NULL
, &subvol_id
);
1085 n
= btrfs_qgroup_find_parents(fd
, qgroupid
, &qgroups
);
1089 for (i
= 0; i
< n
; i
++) {
1092 r
= btrfs_qgroupid_split(qgroups
[i
], NULL
, &id
);
1096 r
= btrfs_qgroup_unassign(fd
, qgroupid
, qgroups
[i
]);
1100 if (id
!= subvol_id
)
1103 /* The parent qgroupid shares the same id part with
1104 * us? If so, destroy it too. */
1106 (void) btrfs_qgroup_destroy_recursive(fd
, qgroups
[i
]);
1109 return btrfs_qgroup_destroy(fd
, qgroupid
);
1112 int btrfs_quota_scan_start(int fd
) {
1113 struct btrfs_ioctl_quota_rescan_args args
= {};
1117 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN
, &args
) < 0)
1123 int btrfs_quota_scan_wait(int fd
) {
1126 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_WAIT
) < 0)
1132 int btrfs_quota_scan_ongoing(int fd
) {
1133 struct btrfs_ioctl_quota_rescan_args args
= {};
1137 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_STATUS
, &args
) < 0)
1140 return !!args
.flags
;
1143 static int qgroup_assign_or_unassign(int fd
, bool b
, uint64_t child
, uint64_t parent
) {
1144 struct btrfs_ioctl_qgroup_assign_args args
= {
1152 r
= btrfs_is_filesystem(fd
);
1159 r
= ioctl(fd
, BTRFS_IOC_QGROUP_ASSIGN
, &args
);
1161 if (errno
== EBUSY
&& c
< 10) {
1162 (void) btrfs_quota_scan_wait(fd
);
1172 /* If the return value is > 0, we need to request a rescan */
1174 (void) btrfs_quota_scan_start(fd
);
1179 int btrfs_qgroup_assign(int fd
, uint64_t child
, uint64_t parent
) {
1180 return qgroup_assign_or_unassign(fd
, true, child
, parent
);
1183 int btrfs_qgroup_unassign(int fd
, uint64_t child
, uint64_t parent
) {
1184 return qgroup_assign_or_unassign(fd
, false, child
, parent
);
1187 static int subvol_remove_children(int fd
, const char *subvolume
, uint64_t subvol_id
, BtrfsRemoveFlags flags
) {
1188 struct btrfs_ioctl_search_args args
= {
1189 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1191 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1192 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1194 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1195 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1197 .key
.min_transid
= 0,
1198 .key
.max_transid
= (uint64_t) -1,
1201 struct btrfs_ioctl_vol_args vol_args
= {};
1202 _cleanup_close_
int subvol_fd
= -1;
1204 bool made_writable
= false;
1210 if (fstat(fd
, &st
) < 0)
1213 if (!S_ISDIR(st
.st_mode
))
1216 subvol_fd
= openat(fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1220 if (subvol_id
== 0) {
1221 r
= btrfs_subvol_get_id_fd(subvol_fd
, &subvol_id
);
1226 /* First, try to remove the subvolume. If it happens to be
1227 * already empty, this will just work. */
1228 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1229 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) >= 0) {
1230 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1233 if (!(flags
& BTRFS_REMOVE_RECURSIVE
) || errno
!= ENOTEMPTY
)
1236 /* OK, the subvolume is not empty, let's look for child
1237 * subvolumes, and remove them, first */
1239 args
.key
.min_offset
= args
.key
.max_offset
= subvol_id
;
1241 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1242 const struct btrfs_ioctl_search_header
*sh
;
1245 args
.key
.nr_items
= 256;
1246 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1249 if (args
.key
.nr_items
<= 0)
1252 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1253 _cleanup_free_
char *p
= NULL
;
1254 const struct btrfs_root_ref
*ref
;
1255 struct btrfs_ioctl_ino_lookup_args ino_args
;
1257 btrfs_ioctl_search_args_set(&args
, sh
);
1259 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1261 if (sh
->offset
!= subvol_id
)
1264 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1266 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1271 ino_args
.treeid
= subvol_id
;
1272 ino_args
.objectid
= htole64(ref
->dirid
);
1274 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1277 if (!made_writable
) {
1278 r
= btrfs_subvol_set_read_only_fd(subvol_fd
, false);
1282 made_writable
= true;
1285 if (isempty(ino_args
.name
))
1286 /* Subvolume is in the top-level
1287 * directory of the subvolume. */
1288 r
= subvol_remove_children(subvol_fd
, p
, sh
->objectid
, flags
);
1290 _cleanup_close_
int child_fd
= -1;
1292 /* Subvolume is somewhere further down,
1293 * hence we need to open the
1294 * containing directory first */
1296 child_fd
= openat(subvol_fd
, ino_args
.name
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1300 r
= subvol_remove_children(child_fd
, p
, sh
->objectid
, flags
);
1306 /* Increase search key by one, to read the next item, if we can. */
1307 if (!btrfs_ioctl_search_args_inc(&args
))
1311 /* OK, the child subvolumes should all be gone now, let's try
1312 * again to remove the subvolume */
1313 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) < 0)
1316 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
);
1320 int btrfs_subvol_remove(const char *path
, BtrfsRemoveFlags flags
) {
1321 _cleanup_close_
int fd
= -1;
1322 const char *subvolume
;
1327 r
= extract_subvolume_name(path
, &subvolume
);
1331 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1335 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1338 int btrfs_subvol_remove_fd(int fd
, const char *subvolume
, BtrfsRemoveFlags flags
) {
1339 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1342 int btrfs_qgroup_copy_limits(int fd
, uint64_t old_qgroupid
, uint64_t new_qgroupid
) {
1344 struct btrfs_ioctl_search_args args
= {
1345 /* Tree of quota items */
1346 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1348 /* The object ID is always 0 */
1349 .key
.min_objectid
= 0,
1350 .key
.max_objectid
= 0,
1352 /* Look precisely for the quota items */
1353 .key
.min_type
= BTRFS_QGROUP_LIMIT_KEY
,
1354 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
1356 /* For our qgroup */
1357 .key
.min_offset
= old_qgroupid
,
1358 .key
.max_offset
= old_qgroupid
,
1360 /* No restrictions on the other components */
1361 .key
.min_transid
= 0,
1362 .key
.max_transid
= (uint64_t) -1,
1367 r
= btrfs_is_filesystem(fd
);
1373 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1374 const struct btrfs_ioctl_search_header
*sh
;
1377 args
.key
.nr_items
= 256;
1378 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1379 if (errno
== ENOENT
) /* quota tree missing: quota is not enabled, hence nothing to copy */
1385 if (args
.key
.nr_items
<= 0)
1388 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1389 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1390 struct btrfs_ioctl_qgroup_limit_args qargs
;
1393 /* Make sure we start the next search at least from this entry */
1394 btrfs_ioctl_search_args_set(&args
, sh
);
1396 if (sh
->objectid
!= 0)
1398 if (sh
->type
!= BTRFS_QGROUP_LIMIT_KEY
)
1400 if (sh
->offset
!= old_qgroupid
)
1403 /* We found the entry, now copy things over. */
1405 qargs
= (struct btrfs_ioctl_qgroup_limit_args
) {
1406 .qgroupid
= new_qgroupid
,
1408 .lim
.max_rfer
= le64toh(qli
->max_rfer
),
1409 .lim
.max_excl
= le64toh(qli
->max_excl
),
1410 .lim
.rsv_rfer
= le64toh(qli
->rsv_rfer
),
1411 .lim
.rsv_excl
= le64toh(qli
->rsv_excl
),
1413 .lim
.flags
= le64toh(qli
->flags
) & (BTRFS_QGROUP_LIMIT_MAX_RFER
|
1414 BTRFS_QGROUP_LIMIT_MAX_EXCL
|
1415 BTRFS_QGROUP_LIMIT_RSV_RFER
|
1416 BTRFS_QGROUP_LIMIT_RSV_EXCL
),
1420 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &qargs
) < 0) {
1421 if (errno
== EBUSY
&& c
< 10) {
1422 (void) btrfs_quota_scan_wait(fd
);
1434 /* Increase search key by one, to read the next item, if we can. */
1435 if (!btrfs_ioctl_search_args_inc(&args
))
1442 static int copy_quota_hierarchy(int fd
, uint64_t old_subvol_id
, uint64_t new_subvol_id
) {
1443 _cleanup_free_
uint64_t *old_qgroups
= NULL
, *old_parent_qgroups
= NULL
;
1444 bool copy_from_parent
= false, insert_intermediary_qgroup
= false;
1445 int n_old_qgroups
, n_old_parent_qgroups
, r
, i
;
1446 uint64_t old_parent_id
;
1450 /* Copies a reduced form of quota information from the old to
1451 * the new subvolume. */
1453 n_old_qgroups
= btrfs_qgroup_find_parents(fd
, old_subvol_id
, &old_qgroups
);
1454 if (n_old_qgroups
<= 0) /* Nothing to copy */
1455 return n_old_qgroups
;
1457 r
= btrfs_subvol_get_parent(fd
, old_subvol_id
, &old_parent_id
);
1459 /* We have no parent, hence nothing to copy. */
1460 n_old_parent_qgroups
= 0;
1464 n_old_parent_qgroups
= btrfs_qgroup_find_parents(fd
, old_parent_id
, &old_parent_qgroups
);
1465 if (n_old_parent_qgroups
< 0)
1466 return n_old_parent_qgroups
;
1469 for (i
= 0; i
< n_old_qgroups
; i
++) {
1473 r
= btrfs_qgroupid_split(old_qgroups
[i
], NULL
, &id
);
1477 if (id
== old_subvol_id
) {
1478 /* The old subvolume was member of a qgroup
1479 * that had the same id, but a different level
1480 * as it self. Let's set up something similar
1481 * in the destination. */
1482 insert_intermediary_qgroup
= true;
1486 for (j
= 0; j
< n_old_parent_qgroups
; j
++)
1487 if (old_parent_qgroups
[j
] == old_qgroups
[i
]) {
1488 /* The old subvolume shared a common
1489 * parent qgroup with its parent
1490 * subvolume. Let's set up something
1491 * similar in the destination. */
1492 copy_from_parent
= true;
1496 if (!insert_intermediary_qgroup
&& !copy_from_parent
)
1499 return btrfs_subvol_auto_qgroup_fd(fd
, new_subvol_id
, insert_intermediary_qgroup
);
1502 static int copy_subtree_quota_limits(int fd
, uint64_t old_subvol
, uint64_t new_subvol
) {
1503 uint64_t old_subtree_qgroup
, new_subtree_qgroup
;
1507 /* First copy the leaf limits */
1508 r
= btrfs_qgroup_copy_limits(fd
, old_subvol
, new_subvol
);
1513 /* Then, try to copy the subtree limits, if there are any. */
1514 r
= btrfs_subvol_find_subtree_qgroup(fd
, old_subvol
, &old_subtree_qgroup
);
1520 r
= btrfs_subvol_find_subtree_qgroup(fd
, new_subvol
, &new_subtree_qgroup
);
1526 r
= btrfs_qgroup_copy_limits(fd
, old_subtree_qgroup
, new_subtree_qgroup
);
1533 static int subvol_snapshot_children(int old_fd
, int new_fd
, const char *subvolume
, uint64_t old_subvol_id
, BtrfsSnapshotFlags flags
) {
1535 struct btrfs_ioctl_search_args args
= {
1536 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1538 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1539 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1541 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1542 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1544 .key
.min_transid
= 0,
1545 .key
.max_transid
= (uint64_t) -1,
1548 struct btrfs_ioctl_vol_args_v2 vol_args
= {
1549 .flags
= flags
& BTRFS_SNAPSHOT_READ_ONLY
? BTRFS_SUBVOL_RDONLY
: 0,
1552 _cleanup_close_
int subvolume_fd
= -1;
1553 uint64_t new_subvol_id
;
1556 assert(old_fd
>= 0);
1557 assert(new_fd
>= 0);
1560 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1562 if (ioctl(new_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &vol_args
) < 0)
1565 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
) &&
1566 !(flags
& BTRFS_SNAPSHOT_QUOTA
))
1569 if (old_subvol_id
== 0) {
1570 r
= btrfs_subvol_get_id_fd(old_fd
, &old_subvol_id
);
1575 r
= btrfs_subvol_get_id(new_fd
, vol_args
.name
, &new_subvol_id
);
1579 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1580 (void) copy_quota_hierarchy(new_fd
, old_subvol_id
, new_subvol_id
);
1582 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
)) {
1584 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1585 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1590 args
.key
.min_offset
= args
.key
.max_offset
= old_subvol_id
;
1592 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1593 const struct btrfs_ioctl_search_header
*sh
;
1596 args
.key
.nr_items
= 256;
1597 if (ioctl(old_fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1600 if (args
.key
.nr_items
<= 0)
1603 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1604 _cleanup_free_
char *p
= NULL
, *c
= NULL
, *np
= NULL
;
1605 struct btrfs_ioctl_ino_lookup_args ino_args
;
1606 const struct btrfs_root_ref
*ref
;
1607 _cleanup_close_
int old_child_fd
= -1, new_child_fd
= -1;
1609 btrfs_ioctl_search_args_set(&args
, sh
);
1611 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1614 /* Avoid finding the source subvolume a second
1616 if (sh
->offset
!= old_subvol_id
)
1619 /* Avoid running into loops if the new
1620 * subvolume is below the old one. */
1621 if (sh
->objectid
== new_subvol_id
)
1624 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1625 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1630 ino_args
.treeid
= old_subvol_id
;
1631 ino_args
.objectid
= htole64(ref
->dirid
);
1633 if (ioctl(old_fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1636 /* The kernel returns an empty name if the
1637 * subvolume is in the top-level directory,
1638 * and otherwise appends a slash, so that we
1639 * can just concatenate easily here, without
1640 * adding a slash. */
1641 c
= strappend(ino_args
.name
, p
);
1645 old_child_fd
= openat(old_fd
, c
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1646 if (old_child_fd
< 0)
1649 np
= strjoin(subvolume
, "/", ino_args
.name
);
1653 new_child_fd
= openat(new_fd
, np
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1654 if (new_child_fd
< 0)
1657 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1658 /* If the snapshot is read-only we
1659 * need to mark it writable
1660 * temporarily, to put the subsnapshot
1663 if (subvolume_fd
< 0) {
1664 subvolume_fd
= openat(new_fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1665 if (subvolume_fd
< 0)
1669 r
= btrfs_subvol_set_read_only_fd(subvolume_fd
, false);
1674 /* When btrfs clones the subvolumes, child
1675 * subvolumes appear as empty directories. Remove
1676 * them, so that we can create a new snapshot
1678 if (unlinkat(new_child_fd
, p
, AT_REMOVEDIR
) < 0) {
1681 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
)
1682 (void) btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1687 r
= subvol_snapshot_children(old_child_fd
, new_child_fd
, p
, sh
->objectid
, flags
& ~BTRFS_SNAPSHOT_FALLBACK_COPY
);
1689 /* Restore the readonly flag */
1690 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1693 k
= btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1694 if (r
>= 0 && k
< 0)
1702 /* Increase search key by one, to read the next item, if we can. */
1703 if (!btrfs_ioctl_search_args_inc(&args
))
1707 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1708 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1713 int btrfs_subvol_snapshot_fd(int old_fd
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1714 _cleanup_close_
int new_fd
= -1;
1715 const char *subvolume
;
1718 assert(old_fd
>= 0);
1721 r
= btrfs_is_subvol_fd(old_fd
);
1725 bool plain_directory
= false;
1727 /* If the source isn't a proper subvolume, fail unless fallback is requested */
1728 if (!(flags
& BTRFS_SNAPSHOT_FALLBACK_COPY
))
1731 r
= btrfs_subvol_make(new_path
);
1732 if (r
== -ENOTTY
&& (flags
& BTRFS_SNAPSHOT_FALLBACK_DIRECTORY
)) {
1733 /* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */
1734 if (mkdir(new_path
, 0755) < 0)
1737 plain_directory
= true;
1741 r
= copy_directory_fd(old_fd
, new_path
, COPY_MERGE
|COPY_REFLINK
);
1745 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1747 if (plain_directory
) {
1748 /* Plain directories have no recursive read-only flag, but something pretty close to
1749 * it: the IMMUTABLE bit. Let's use this here, if this is requested. */
1751 if (flags
& BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE
)
1752 (void) chattr_path(new_path
, FS_IMMUTABLE_FL
, FS_IMMUTABLE_FL
);
1754 r
= btrfs_subvol_set_read_only(new_path
, true);
1763 (void) rm_rf(new_path
, REMOVE_ROOT
|REMOVE_PHYSICAL
|REMOVE_SUBVOLUME
);
1767 r
= extract_subvolume_name(new_path
, &subvolume
);
1771 new_fd
= open_parent(new_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1775 return subvol_snapshot_children(old_fd
, new_fd
, subvolume
, 0, flags
);
1778 int btrfs_subvol_snapshot(const char *old_path
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1779 _cleanup_close_
int old_fd
= -1;
1784 old_fd
= open(old_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1788 return btrfs_subvol_snapshot_fd(old_fd
, new_path
, flags
);
1791 int btrfs_qgroup_find_parents(int fd
, uint64_t qgroupid
, uint64_t **ret
) {
1793 struct btrfs_ioctl_search_args args
= {
1794 /* Tree of quota items */
1795 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1797 /* Look precisely for the quota relation items */
1798 .key
.min_type
= BTRFS_QGROUP_RELATION_KEY
,
1799 .key
.max_type
= BTRFS_QGROUP_RELATION_KEY
,
1801 /* No restrictions on the other components */
1802 .key
.min_offset
= 0,
1803 .key
.max_offset
= (uint64_t) -1,
1805 .key
.min_transid
= 0,
1806 .key
.max_transid
= (uint64_t) -1,
1809 _cleanup_free_
uint64_t *items
= NULL
;
1810 size_t n_items
= 0, n_allocated
= 0;
1816 if (qgroupid
== 0) {
1817 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
1821 r
= btrfs_is_filesystem(fd
);
1828 args
.key
.min_objectid
= args
.key
.max_objectid
= qgroupid
;
1830 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1831 const struct btrfs_ioctl_search_header
*sh
;
1834 args
.key
.nr_items
= 256;
1835 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1836 if (errno
== ENOENT
) /* quota tree missing: quota is disabled */
1842 if (args
.key
.nr_items
<= 0)
1845 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1847 /* Make sure we start the next search at least from this entry */
1848 btrfs_ioctl_search_args_set(&args
, sh
);
1850 if (sh
->type
!= BTRFS_QGROUP_RELATION_KEY
)
1852 if (sh
->offset
< sh
->objectid
)
1854 if (sh
->objectid
!= qgroupid
)
1857 if (!GREEDY_REALLOC(items
, n_allocated
, n_items
+1))
1860 items
[n_items
++] = sh
->offset
;
1863 /* Increase search key by one, to read the next item, if we can. */
1864 if (!btrfs_ioctl_search_args_inc(&args
))
1876 return (int) n_items
;
1879 int btrfs_subvol_auto_qgroup_fd(int fd
, uint64_t subvol_id
, bool insert_intermediary_qgroup
) {
1880 _cleanup_free_
uint64_t *qgroups
= NULL
;
1881 uint64_t parent_subvol
;
1882 bool changed
= false;
1888 * Sets up the specified subvolume's qgroup automatically in
1891 * If insert_intermediary_qgroup is false, the subvolume's
1892 * leaf qgroup will be assigned to the same parent qgroups as
1893 * the subvolume's parent subvolume.
1895 * If insert_intermediary_qgroup is true a new intermediary
1896 * higher-level qgroup is created, with a higher level number,
1897 * but reusing the id of the subvolume. The level number is
1898 * picked as one smaller than the lowest level qgroup the
1899 * parent subvolume is a member of. If the parent subvolume's
1900 * leaf qgroup is assigned to no higher-level qgroup a new
1901 * qgroup of level 255 is created instead. Either way, the new
1902 * qgroup is then assigned to the parent's higher-level
1903 * qgroup, and the subvolume itself is assigned to it.
1905 * If the subvolume is already assigned to a higher level
1906 * qgroup, no operation is executed.
1908 * Effectively this means: regardless if
1909 * insert_intermediary_qgroup is true or not, after this
1910 * function is invoked the subvolume will be accounted within
1911 * the same qgroups as the parent. However, if it is true, it
1912 * will also get its own higher-level qgroup, which may in
1913 * turn be used by subvolumes created beneath this subvolume
1916 * This hence defines a simple default qgroup setup for
1917 * subvolumes, as long as this function is invoked on each
1918 * created subvolume: each subvolume is always accounting
1919 * together with its immediate parents. Optionally, if
1920 * insert_intermediary_qgroup is true, it will also get a
1921 * qgroup that then includes all its own child subvolumes.
1924 if (subvol_id
== 0) {
1925 r
= btrfs_is_subvol_fd(fd
);
1931 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1936 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
1939 if (n
> 0) /* already parent qgroups set up, let's bail */
1942 qgroups
= mfree(qgroups
);
1944 r
= btrfs_subvol_get_parent(fd
, subvol_id
, &parent_subvol
);
1946 /* No parent, hence no qgroup memberships */
1951 n
= btrfs_qgroup_find_parents(fd
, parent_subvol
, &qgroups
);
1956 if (insert_intermediary_qgroup
) {
1957 uint64_t lowest
= 256, new_qgroupid
;
1958 bool created
= false;
1961 /* Determine the lowest qgroup that the parent
1962 * subvolume is assigned to. */
1964 for (i
= 0; i
< n
; i
++) {
1967 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, NULL
);
1975 if (lowest
<= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1978 r
= btrfs_qgroupid_make(lowest
- 1, subvol_id
, &new_qgroupid
);
1982 /* Create the new intermediary group, unless it already exists */
1983 r
= btrfs_qgroup_create(fd
, new_qgroupid
);
1984 if (r
< 0 && r
!= -EEXIST
)
1987 changed
= created
= true;
1989 for (i
= 0; i
< n
; i
++) {
1990 r
= btrfs_qgroup_assign(fd
, new_qgroupid
, qgroups
[i
]);
1991 if (r
< 0 && r
!= -EEXIST
) {
1993 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
2001 r
= btrfs_qgroup_assign(fd
, subvol_id
, new_qgroupid
);
2002 if (r
< 0 && r
!= -EEXIST
) {
2004 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
2013 /* Assign our subvolume to all the same qgroups as the parent */
2015 for (i
= 0; i
< n
; i
++) {
2016 r
= btrfs_qgroup_assign(fd
, subvol_id
, qgroups
[i
]);
2017 if (r
< 0 && r
!= -EEXIST
)
2027 int btrfs_subvol_auto_qgroup(const char *path
, uint64_t subvol_id
, bool create_intermediary_qgroup
) {
2028 _cleanup_close_
int fd
= -1;
2030 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
2034 return btrfs_subvol_auto_qgroup_fd(fd
, subvol_id
, create_intermediary_qgroup
);
2037 int btrfs_subvol_get_parent(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
2039 struct btrfs_ioctl_search_args args
= {
2040 /* Tree of tree roots */
2041 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
2043 /* Look precisely for the subvolume items */
2044 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
2045 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
2047 /* No restrictions on the other components */
2048 .key
.min_offset
= 0,
2049 .key
.max_offset
= (uint64_t) -1,
2051 .key
.min_transid
= 0,
2052 .key
.max_transid
= (uint64_t) -1,
2059 if (subvol_id
== 0) {
2060 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
2064 r
= btrfs_is_filesystem(fd
);
2071 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
2073 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
2074 const struct btrfs_ioctl_search_header
*sh
;
2077 args
.key
.nr_items
= 256;
2078 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
2079 return negative_errno();
2081 if (args
.key
.nr_items
<= 0)
2084 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
2086 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
2088 if (sh
->objectid
!= subvol_id
)