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"
49 #include "path-util.h"
50 #include "selinux-util.h"
51 #include "smack-util.h"
52 #include "sparse-endian.h"
53 #include "stat-util.h"
54 #include "string-util.h"
55 #include "time-util.h"
58 /* WARNING: Be careful with file system ioctls! When we get an fd, we
59 * need to make sure it either refers to only a regular file or
60 * directory, or that it is located on btrfs, before invoking any
61 * btrfs ioctls. The ioctl numbers are reused by some device drivers
62 * (such as DRM), and hence might have bad effects when invoked on
63 * device nodes (that reference drivers) rather than fds to normal
64 * files or directories. */
66 static int validate_subvolume_name(const char *name
) {
68 if (!filename_is_valid(name
))
71 if (strlen(name
) > BTRFS_SUBVOL_NAME_MAX
)
77 static int open_parent(const char *path
, int flags
) {
78 _cleanup_free_
char *parent
= NULL
;
83 parent
= dirname_malloc(path
);
87 fd
= open(parent
, flags
);
94 static int extract_subvolume_name(const char *path
, const char **subvolume
) {
103 r
= validate_subvolume_name(fn
);
111 int btrfs_is_filesystem(int fd
) {
116 if (fstatfs(fd
, &sfs
) < 0)
119 return F_TYPE_EQUAL(sfs
.f_type
, BTRFS_SUPER_MAGIC
);
122 int btrfs_is_subvol_fd(int fd
) {
127 /* On btrfs subvolumes always have the inode 256 */
129 if (fstat(fd
, &st
) < 0)
132 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
135 return btrfs_is_filesystem(fd
);
138 int btrfs_is_subvol(const char *path
) {
139 _cleanup_close_
int fd
= -1;
143 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
147 return btrfs_is_subvol_fd(fd
);
150 int btrfs_subvol_make(const char *path
) {
151 struct btrfs_ioctl_vol_args args
= {};
152 _cleanup_close_
int fd
= -1;
153 const char *subvolume
;
158 r
= extract_subvolume_name(path
, &subvolume
);
162 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
166 strncpy(args
.name
, subvolume
, sizeof(args
.name
)-1);
168 if (ioctl(fd
, BTRFS_IOC_SUBVOL_CREATE
, &args
) < 0)
174 int btrfs_subvol_make_label(const char *path
) {
179 r
= mac_selinux_create_file_prepare(path
, S_IFDIR
);
183 r
= btrfs_subvol_make(path
);
184 mac_selinux_create_file_clear();
189 return mac_smack_fix(path
, false, false);
192 int btrfs_subvol_set_read_only_fd(int fd
, bool b
) {
193 uint64_t flags
, nflags
;
198 if (fstat(fd
, &st
) < 0)
201 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
204 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
208 nflags
= flags
| BTRFS_SUBVOL_RDONLY
;
210 nflags
= flags
& ~BTRFS_SUBVOL_RDONLY
;
215 if (ioctl(fd
, BTRFS_IOC_SUBVOL_SETFLAGS
, &nflags
) < 0)
221 int btrfs_subvol_set_read_only(const char *path
, bool b
) {
222 _cleanup_close_
int fd
= -1;
224 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
228 return btrfs_subvol_set_read_only_fd(fd
, b
);
231 int btrfs_subvol_get_read_only_fd(int fd
) {
237 if (fstat(fd
, &st
) < 0)
240 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
243 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
246 return !!(flags
& BTRFS_SUBVOL_RDONLY
);
249 int btrfs_reflink(int infd
, int outfd
) {
256 /* Make sure we invoke the ioctl on a regular file, so that no
257 * device driver accidentally gets it. */
259 if (fstat(outfd
, &st
) < 0)
262 if (!S_ISREG(st
.st_mode
))
265 r
= ioctl(outfd
, BTRFS_IOC_CLONE
, infd
);
272 int btrfs_clone_range(int infd
, uint64_t in_offset
, int outfd
, uint64_t out_offset
, uint64_t sz
) {
273 struct btrfs_ioctl_clone_range_args args
= {
275 .src_offset
= in_offset
,
277 .dest_offset
= out_offset
,
286 if (fstat(outfd
, &st
) < 0)
289 if (!S_ISREG(st
.st_mode
))
292 r
= ioctl(outfd
, BTRFS_IOC_CLONE_RANGE
, &args
);
299 int btrfs_get_block_device_fd(int fd
, dev_t
*dev
) {
300 struct btrfs_ioctl_fs_info_args fsi
= {};
307 r
= btrfs_is_filesystem(fd
);
313 if (ioctl(fd
, BTRFS_IOC_FS_INFO
, &fsi
) < 0)
316 /* We won't do this for btrfs RAID */
317 if (fsi
.num_devices
!= 1)
320 for (id
= 1; id
<= fsi
.max_id
; id
++) {
321 struct btrfs_ioctl_dev_info_args di
= {
326 if (ioctl(fd
, BTRFS_IOC_DEV_INFO
, &di
) < 0) {
333 if (stat((char*) di
.path
, &st
) < 0)
336 if (!S_ISBLK(st
.st_mode
))
339 if (major(st
.st_rdev
) == 0)
349 int btrfs_get_block_device(const char *path
, dev_t
*dev
) {
350 _cleanup_close_
int fd
= -1;
355 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
359 return btrfs_get_block_device_fd(fd
, dev
);
362 int btrfs_subvol_get_id_fd(int fd
, uint64_t *ret
) {
363 struct btrfs_ioctl_ino_lookup_args args
= {
364 .objectid
= BTRFS_FIRST_FREE_OBJECTID
371 r
= btrfs_is_filesystem(fd
);
377 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
) < 0)
384 int btrfs_subvol_get_id(int fd
, const char *subvol
, uint64_t *ret
) {
385 _cleanup_close_
int subvol_fd
= -1;
390 subvol_fd
= openat(fd
, subvol
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
394 return btrfs_subvol_get_id_fd(subvol_fd
, ret
);
397 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args
*args
) {
400 /* the objectid, type, offset together make up the btrfs key,
401 * which is considered a single 136byte integer when
402 * comparing. This call increases the counter by one, dealing
403 * with the overflow between the overflows */
405 if (args
->key
.min_offset
< (uint64_t) -1) {
406 args
->key
.min_offset
++;
410 if (args
->key
.min_type
< (uint8_t) -1) {
411 args
->key
.min_type
++;
412 args
->key
.min_offset
= 0;
416 if (args
->key
.min_objectid
< (uint64_t) -1) {
417 args
->key
.min_objectid
++;
418 args
->key
.min_offset
= 0;
419 args
->key
.min_type
= 0;
426 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args
*args
, const struct btrfs_ioctl_search_header
*h
) {
430 args
->key
.min_objectid
= h
->objectid
;
431 args
->key
.min_type
= h
->type
;
432 args
->key
.min_offset
= h
->offset
;
435 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
*args
) {
438 /* Compare min and max */
440 if (args
->key
.min_objectid
< args
->key
.max_objectid
)
442 if (args
->key
.min_objectid
> args
->key
.max_objectid
)
445 if (args
->key
.min_type
< args
->key
.max_type
)
447 if (args
->key
.min_type
> args
->key
.max_type
)
450 if (args
->key
.min_offset
< args
->key
.max_offset
)
452 if (args
->key
.min_offset
> args
->key
.max_offset
)
458 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
460 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
461 (i) < (args).key.nr_items; \
463 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
465 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
466 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
468 int btrfs_subvol_get_info_fd(int fd
, uint64_t subvol_id
, BtrfsSubvolInfo
*ret
) {
469 struct btrfs_ioctl_search_args args
= {
470 /* Tree of tree roots */
471 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
473 /* Look precisely for the subvolume items */
474 .key
.min_type
= BTRFS_ROOT_ITEM_KEY
,
475 .key
.max_type
= BTRFS_ROOT_ITEM_KEY
,
478 .key
.max_offset
= (uint64_t) -1,
480 /* No restrictions on the other components */
481 .key
.min_transid
= 0,
482 .key
.max_transid
= (uint64_t) -1,
491 if (subvol_id
== 0) {
492 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
496 r
= btrfs_is_filesystem(fd
);
503 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
505 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
506 const struct btrfs_ioctl_search_header
*sh
;
509 args
.key
.nr_items
= 256;
510 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
513 if (args
.key
.nr_items
<= 0)
516 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
518 const struct btrfs_root_item
*ri
;
520 /* Make sure we start the next search at least from this entry */
521 btrfs_ioctl_search_args_set(&args
, sh
);
523 if (sh
->objectid
!= subvol_id
)
525 if (sh
->type
!= BTRFS_ROOT_ITEM_KEY
)
528 /* Older versions of the struct lacked the otime setting */
529 if (sh
->len
< offsetof(struct btrfs_root_item
, otime
) + sizeof(struct btrfs_timespec
))
532 ri
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
534 ret
->otime
= (usec_t
) le64toh(ri
->otime
.sec
) * USEC_PER_SEC
+
535 (usec_t
) le32toh(ri
->otime
.nsec
) / NSEC_PER_USEC
;
537 ret
->subvol_id
= subvol_id
;
538 ret
->read_only
= !!(le64toh(ri
->flags
) & BTRFS_ROOT_SUBVOL_RDONLY
);
540 assert_cc(sizeof(ri
->uuid
) == sizeof(ret
->uuid
));
541 memcpy(&ret
->uuid
, ri
->uuid
, sizeof(ret
->uuid
));
542 memcpy(&ret
->parent_uuid
, ri
->parent_uuid
, sizeof(ret
->parent_uuid
));
548 /* Increase search key by one, to read the next item, if we can. */
549 if (!btrfs_ioctl_search_args_inc(&args
))
560 int btrfs_qgroup_get_quota_fd(int fd
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
562 struct btrfs_ioctl_search_args args
= {
563 /* Tree of quota items */
564 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
566 /* The object ID is always 0 */
567 .key
.min_objectid
= 0,
568 .key
.max_objectid
= 0,
570 /* Look precisely for the quota items */
571 .key
.min_type
= BTRFS_QGROUP_STATUS_KEY
,
572 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
574 /* No restrictions on the other components */
575 .key
.min_transid
= 0,
576 .key
.max_transid
= (uint64_t) -1,
579 bool found_info
= false, found_limit
= false;
586 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
590 r
= btrfs_is_filesystem(fd
);
597 args
.key
.min_offset
= args
.key
.max_offset
= qgroupid
;
599 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
600 const struct btrfs_ioctl_search_header
*sh
;
603 args
.key
.nr_items
= 256;
604 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
605 if (errno
== ENOENT
) /* quota tree is missing: quota disabled */
611 if (args
.key
.nr_items
<= 0)
614 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
616 /* Make sure we start the next search at least from this entry */
617 btrfs_ioctl_search_args_set(&args
, sh
);
619 if (sh
->objectid
!= 0)
621 if (sh
->offset
!= qgroupid
)
624 if (sh
->type
== BTRFS_QGROUP_INFO_KEY
) {
625 const struct btrfs_qgroup_info_item
*qii
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
627 ret
->referenced
= le64toh(qii
->rfer
);
628 ret
->exclusive
= le64toh(qii
->excl
);
632 } else if (sh
->type
== BTRFS_QGROUP_LIMIT_KEY
) {
633 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
635 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_RFER
)
636 ret
->referenced_max
= le64toh(qli
->max_rfer
);
638 ret
->referenced_max
= (uint64_t) -1;
640 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_EXCL
)
641 ret
->exclusive_max
= le64toh(qli
->max_excl
);
643 ret
->exclusive_max
= (uint64_t) -1;
648 if (found_info
&& found_limit
)
652 /* Increase search key by one, to read the next item, if we can. */
653 if (!btrfs_ioctl_search_args_inc(&args
))
658 if (!found_limit
&& !found_info
)
662 ret
->referenced
= (uint64_t) -1;
663 ret
->exclusive
= (uint64_t) -1;
667 ret
->referenced_max
= (uint64_t) -1;
668 ret
->exclusive_max
= (uint64_t) -1;
674 int btrfs_qgroup_get_quota(const char *path
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
675 _cleanup_close_
int fd
= -1;
677 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
681 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
684 int btrfs_subvol_find_subtree_qgroup(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
685 uint64_t level
, lowest
= (uint64_t) -1, lowest_qgroupid
= 0;
686 _cleanup_free_
uint64_t *qgroups
= NULL
;
692 /* This finds the "subtree" qgroup for a specific
693 * subvolume. This only works for subvolumes that have been
694 * prepared with btrfs_subvol_auto_qgroup_fd() with
695 * insert_intermediary_qgroup=true (or equivalent). For others
696 * it will return the leaf qgroup instead. The two cases may
697 * be distuingished via the return value, which is 1 in case
698 * an appropriate "subtree" qgroup was found, and 0
701 if (subvol_id
== 0) {
702 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
707 r
= btrfs_qgroupid_split(subvol_id
, &level
, NULL
);
710 if (level
!= 0) /* Input must be a leaf qgroup */
713 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
717 for (i
= 0; i
< n
; i
++) {
720 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, &id
);
727 if (lowest
== (uint64_t) -1 || level
< lowest
) {
728 lowest_qgroupid
= qgroups
[i
];
733 if (lowest
== (uint64_t) -1) {
734 /* No suitable higher-level qgroup found, let's return
735 * the leaf qgroup instead, and indicate that with the
742 *ret
= lowest_qgroupid
;
746 int btrfs_subvol_get_subtree_quota_fd(int fd
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
753 /* This determines the quota data of the qgroup with the
754 * lowest level, that shares the id part with the specified
755 * subvolume. This is useful for determining the quota data
756 * for entire subvolume subtrees, as long as the subtrees have
757 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
760 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
764 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
767 int btrfs_subvol_get_subtree_quota(const char *path
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
768 _cleanup_close_
int fd
= -1;
770 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
774 return btrfs_subvol_get_subtree_quota_fd(fd
, subvol_id
, ret
);
777 int btrfs_defrag_fd(int fd
) {
782 if (fstat(fd
, &st
) < 0)
785 if (!S_ISREG(st
.st_mode
))
788 if (ioctl(fd
, BTRFS_IOC_DEFRAG
, NULL
) < 0)
794 int btrfs_defrag(const char *p
) {
795 _cleanup_close_
int fd
= -1;
797 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
801 return btrfs_defrag_fd(fd
);
804 int btrfs_quota_enable_fd(int fd
, bool b
) {
805 struct btrfs_ioctl_quota_ctl_args args
= {
806 .cmd
= b
? BTRFS_QUOTA_CTL_ENABLE
: BTRFS_QUOTA_CTL_DISABLE
,
812 r
= btrfs_is_filesystem(fd
);
818 if (ioctl(fd
, BTRFS_IOC_QUOTA_CTL
, &args
) < 0)
824 int btrfs_quota_enable(const char *path
, bool b
) {
825 _cleanup_close_
int fd
= -1;
827 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
831 return btrfs_quota_enable_fd(fd
, b
);
834 int btrfs_qgroup_set_limit_fd(int fd
, uint64_t qgroupid
, uint64_t referenced_max
) {
836 struct btrfs_ioctl_qgroup_limit_args args
= {
837 .lim
.max_rfer
= referenced_max
,
838 .lim
.flags
= BTRFS_QGROUP_LIMIT_MAX_RFER
,
846 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
850 r
= btrfs_is_filesystem(fd
);
857 args
.qgroupid
= qgroupid
;
860 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &args
) < 0) {
862 if (errno
== EBUSY
&& c
< 10) {
863 (void) btrfs_quota_scan_wait(fd
);
876 int btrfs_qgroup_set_limit(const char *path
, uint64_t qgroupid
, uint64_t referenced_max
) {
877 _cleanup_close_
int fd
= -1;
879 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
883 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
886 int btrfs_subvol_set_subtree_quota_limit_fd(int fd
, uint64_t subvol_id
, uint64_t referenced_max
) {
892 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
896 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
899 int btrfs_subvol_set_subtree_quota_limit(const char *path
, uint64_t subvol_id
, uint64_t referenced_max
) {
900 _cleanup_close_
int fd
= -1;
902 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
906 return btrfs_subvol_set_subtree_quota_limit_fd(fd
, subvol_id
, referenced_max
);
909 int btrfs_resize_loopback_fd(int fd
, uint64_t new_size
, bool grow_only
) {
910 struct btrfs_ioctl_vol_args args
= {};
911 _cleanup_free_
char *p
= NULL
, *loop
= NULL
, *backing
= NULL
;
912 _cleanup_close_
int loop_fd
= -1, backing_fd
= -1;
917 /* In contrast to btrfs quota ioctls ftruncate() cannot make sense of "infinity" or file sizes > 2^31 */
918 if (!FILE_SIZE_VALID(new_size
))
921 /* btrfs cannot handle file systems < 16M, hence use this as minimum */
922 if (new_size
< 16*1024*1024)
923 new_size
= 16*1024*1024;
925 r
= btrfs_get_block_device_fd(fd
, &dev
);
931 if (asprintf(&p
, "/sys/dev/block/%u:%u/loop/backing_file", major(dev
), minor(dev
)) < 0)
933 r
= read_one_line_file(p
, &backing
);
938 if (isempty(backing
) || !path_is_absolute(backing
))
941 backing_fd
= open(backing
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
945 if (fstat(backing_fd
, &st
) < 0)
947 if (!S_ISREG(st
.st_mode
))
950 if (new_size
== (uint64_t) st
.st_size
)
953 if (grow_only
&& new_size
< (uint64_t) st
.st_size
)
956 if (asprintf(&loop
, "/dev/block/%u:%u", major(dev
), minor(dev
)) < 0)
958 loop_fd
= open(loop
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
962 if (snprintf(args
.name
, sizeof(args
.name
), "%" PRIu64
, new_size
) >= (int) sizeof(args
.name
))
965 if (new_size
< (uint64_t) st
.st_size
) {
966 /* Decrease size: first decrease btrfs size, then shorten loopback */
967 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
971 if (ftruncate(backing_fd
, new_size
) < 0)
974 if (ioctl(loop_fd
, LOOP_SET_CAPACITY
, 0) < 0)
977 if (new_size
> (uint64_t) st
.st_size
) {
978 /* Increase size: first enlarge loopback, then increase btrfs size */
979 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
983 /* Make sure the free disk space is correctly updated for both file systems */
985 (void) fsync(backing_fd
);
990 int btrfs_resize_loopback(const char *p
, uint64_t new_size
, bool grow_only
) {
991 _cleanup_close_
int fd
= -1;
993 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
997 return btrfs_resize_loopback_fd(fd
, new_size
, grow_only
);
1000 int btrfs_qgroupid_make(uint64_t level
, uint64_t id
, uint64_t *ret
) {
1003 if (level
>= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT
)))
1006 if (id
>= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
))
1009 *ret
= (level
<< BTRFS_QGROUP_LEVEL_SHIFT
) | id
;
1013 int btrfs_qgroupid_split(uint64_t qgroupid
, uint64_t *level
, uint64_t *id
) {
1014 assert(level
|| id
);
1017 *level
= qgroupid
>> BTRFS_QGROUP_LEVEL_SHIFT
;
1020 *id
= qgroupid
& ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
) - 1);
1025 static int qgroup_create_or_destroy(int fd
, bool b
, uint64_t qgroupid
) {
1027 struct btrfs_ioctl_qgroup_create_args args
= {
1029 .qgroupid
= qgroupid
,
1034 r
= btrfs_is_filesystem(fd
);
1041 if (ioctl(fd
, BTRFS_IOC_QGROUP_CREATE
, &args
) < 0) {
1043 /* If quota is not enabled, we get EINVAL. Turn this into a recognizable error */
1044 if (errno
== EINVAL
)
1045 return -ENOPROTOOPT
;
1047 if (errno
== EBUSY
&& c
< 10) {
1048 (void) btrfs_quota_scan_wait(fd
);
1061 int btrfs_qgroup_create(int fd
, uint64_t qgroupid
) {
1062 return qgroup_create_or_destroy(fd
, true, qgroupid
);
1065 int btrfs_qgroup_destroy(int fd
, uint64_t qgroupid
) {
1066 return qgroup_create_or_destroy(fd
, false, qgroupid
);
1069 int btrfs_qgroup_destroy_recursive(int fd
, uint64_t qgroupid
) {
1070 _cleanup_free_
uint64_t *qgroups
= NULL
;
1074 /* Destroys the specified qgroup, but unassigns it from all
1075 * its parents first. Also, it recursively destroys all
1076 * qgroups it is assgined to that have the same id part of the
1077 * qgroupid as the specified group. */
1079 r
= btrfs_qgroupid_split(qgroupid
, NULL
, &subvol_id
);
1083 n
= btrfs_qgroup_find_parents(fd
, qgroupid
, &qgroups
);
1087 for (i
= 0; i
< n
; i
++) {
1090 r
= btrfs_qgroupid_split(qgroups
[i
], NULL
, &id
);
1094 r
= btrfs_qgroup_unassign(fd
, qgroupid
, qgroups
[i
]);
1098 if (id
!= subvol_id
)
1101 /* The parent qgroupid shares the same id part with
1102 * us? If so, destroy it too. */
1104 (void) btrfs_qgroup_destroy_recursive(fd
, qgroups
[i
]);
1107 return btrfs_qgroup_destroy(fd
, qgroupid
);
1110 int btrfs_quota_scan_start(int fd
) {
1111 struct btrfs_ioctl_quota_rescan_args args
= {};
1115 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN
, &args
) < 0)
1121 int btrfs_quota_scan_wait(int fd
) {
1124 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_WAIT
) < 0)
1130 int btrfs_quota_scan_ongoing(int fd
) {
1131 struct btrfs_ioctl_quota_rescan_args args
= {};
1135 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_STATUS
, &args
) < 0)
1138 return !!args
.flags
;
1141 static int qgroup_assign_or_unassign(int fd
, bool b
, uint64_t child
, uint64_t parent
) {
1142 struct btrfs_ioctl_qgroup_assign_args args
= {
1150 r
= btrfs_is_filesystem(fd
);
1157 r
= ioctl(fd
, BTRFS_IOC_QGROUP_ASSIGN
, &args
);
1159 if (errno
== EBUSY
&& c
< 10) {
1160 (void) btrfs_quota_scan_wait(fd
);
1170 /* If the return value is > 0, we need to request a rescan */
1172 (void) btrfs_quota_scan_start(fd
);
1177 int btrfs_qgroup_assign(int fd
, uint64_t child
, uint64_t parent
) {
1178 return qgroup_assign_or_unassign(fd
, true, child
, parent
);
1181 int btrfs_qgroup_unassign(int fd
, uint64_t child
, uint64_t parent
) {
1182 return qgroup_assign_or_unassign(fd
, false, child
, parent
);
1185 static int subvol_remove_children(int fd
, const char *subvolume
, uint64_t subvol_id
, BtrfsRemoveFlags flags
) {
1186 struct btrfs_ioctl_search_args args
= {
1187 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1189 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1190 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1192 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1193 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1195 .key
.min_transid
= 0,
1196 .key
.max_transid
= (uint64_t) -1,
1199 struct btrfs_ioctl_vol_args vol_args
= {};
1200 _cleanup_close_
int subvol_fd
= -1;
1202 bool made_writable
= false;
1208 if (fstat(fd
, &st
) < 0)
1211 if (!S_ISDIR(st
.st_mode
))
1214 subvol_fd
= openat(fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1218 if (subvol_id
== 0) {
1219 r
= btrfs_subvol_get_id_fd(subvol_fd
, &subvol_id
);
1224 /* First, try to remove the subvolume. If it happens to be
1225 * already empty, this will just work. */
1226 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1227 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) >= 0) {
1228 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1231 if (!(flags
& BTRFS_REMOVE_RECURSIVE
) || errno
!= ENOTEMPTY
)
1234 /* OK, the subvolume is not empty, let's look for child
1235 * subvolumes, and remove them, first */
1237 args
.key
.min_offset
= args
.key
.max_offset
= subvol_id
;
1239 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1240 const struct btrfs_ioctl_search_header
*sh
;
1243 args
.key
.nr_items
= 256;
1244 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1247 if (args
.key
.nr_items
<= 0)
1250 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1251 _cleanup_free_
char *p
= NULL
;
1252 const struct btrfs_root_ref
*ref
;
1253 struct btrfs_ioctl_ino_lookup_args ino_args
;
1255 btrfs_ioctl_search_args_set(&args
, sh
);
1257 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1259 if (sh
->offset
!= subvol_id
)
1262 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1264 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1269 ino_args
.treeid
= subvol_id
;
1270 ino_args
.objectid
= htole64(ref
->dirid
);
1272 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1275 if (!made_writable
) {
1276 r
= btrfs_subvol_set_read_only_fd(subvol_fd
, false);
1280 made_writable
= true;
1283 if (isempty(ino_args
.name
))
1284 /* Subvolume is in the top-level
1285 * directory of the subvolume. */
1286 r
= subvol_remove_children(subvol_fd
, p
, sh
->objectid
, flags
);
1288 _cleanup_close_
int child_fd
= -1;
1290 /* Subvolume is somewhere further down,
1291 * hence we need to open the
1292 * containing directory first */
1294 child_fd
= openat(subvol_fd
, ino_args
.name
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1298 r
= subvol_remove_children(child_fd
, p
, sh
->objectid
, flags
);
1304 /* Increase search key by one, to read the next item, if we can. */
1305 if (!btrfs_ioctl_search_args_inc(&args
))
1309 /* OK, the child subvolumes should all be gone now, let's try
1310 * again to remove the subvolume */
1311 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) < 0)
1314 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
);
1318 int btrfs_subvol_remove(const char *path
, BtrfsRemoveFlags flags
) {
1319 _cleanup_close_
int fd
= -1;
1320 const char *subvolume
;
1325 r
= extract_subvolume_name(path
, &subvolume
);
1329 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1333 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1336 int btrfs_subvol_remove_fd(int fd
, const char *subvolume
, BtrfsRemoveFlags flags
) {
1337 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1340 int btrfs_qgroup_copy_limits(int fd
, uint64_t old_qgroupid
, uint64_t new_qgroupid
) {
1342 struct btrfs_ioctl_search_args args
= {
1343 /* Tree of quota items */
1344 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1346 /* The object ID is always 0 */
1347 .key
.min_objectid
= 0,
1348 .key
.max_objectid
= 0,
1350 /* Look precisely for the quota items */
1351 .key
.min_type
= BTRFS_QGROUP_LIMIT_KEY
,
1352 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
1354 /* For our qgroup */
1355 .key
.min_offset
= old_qgroupid
,
1356 .key
.max_offset
= old_qgroupid
,
1358 /* No restrictions on the other components */
1359 .key
.min_transid
= 0,
1360 .key
.max_transid
= (uint64_t) -1,
1365 r
= btrfs_is_filesystem(fd
);
1371 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1372 const struct btrfs_ioctl_search_header
*sh
;
1375 args
.key
.nr_items
= 256;
1376 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1377 if (errno
== ENOENT
) /* quota tree missing: quota is not enabled, hence nothing to copy */
1383 if (args
.key
.nr_items
<= 0)
1386 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1387 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1388 struct btrfs_ioctl_qgroup_limit_args qargs
;
1391 /* Make sure we start the next search at least from this entry */
1392 btrfs_ioctl_search_args_set(&args
, sh
);
1394 if (sh
->objectid
!= 0)
1396 if (sh
->type
!= BTRFS_QGROUP_LIMIT_KEY
)
1398 if (sh
->offset
!= old_qgroupid
)
1401 /* We found the entry, now copy things over. */
1403 qargs
= (struct btrfs_ioctl_qgroup_limit_args
) {
1404 .qgroupid
= new_qgroupid
,
1406 .lim
.max_rfer
= le64toh(qli
->max_rfer
),
1407 .lim
.max_excl
= le64toh(qli
->max_excl
),
1408 .lim
.rsv_rfer
= le64toh(qli
->rsv_rfer
),
1409 .lim
.rsv_excl
= le64toh(qli
->rsv_excl
),
1411 .lim
.flags
= le64toh(qli
->flags
) & (BTRFS_QGROUP_LIMIT_MAX_RFER
|
1412 BTRFS_QGROUP_LIMIT_MAX_EXCL
|
1413 BTRFS_QGROUP_LIMIT_RSV_RFER
|
1414 BTRFS_QGROUP_LIMIT_RSV_EXCL
),
1418 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &qargs
) < 0) {
1419 if (errno
== EBUSY
&& c
< 10) {
1420 (void) btrfs_quota_scan_wait(fd
);
1432 /* Increase search key by one, to read the next item, if we can. */
1433 if (!btrfs_ioctl_search_args_inc(&args
))
1440 static int copy_quota_hierarchy(int fd
, uint64_t old_subvol_id
, uint64_t new_subvol_id
) {
1441 _cleanup_free_
uint64_t *old_qgroups
= NULL
, *old_parent_qgroups
= NULL
;
1442 bool copy_from_parent
= false, insert_intermediary_qgroup
= false;
1443 int n_old_qgroups
, n_old_parent_qgroups
, r
, i
;
1444 uint64_t old_parent_id
;
1448 /* Copies a reduced form of quota information from the old to
1449 * the new subvolume. */
1451 n_old_qgroups
= btrfs_qgroup_find_parents(fd
, old_subvol_id
, &old_qgroups
);
1452 if (n_old_qgroups
<= 0) /* Nothing to copy */
1453 return n_old_qgroups
;
1455 r
= btrfs_subvol_get_parent(fd
, old_subvol_id
, &old_parent_id
);
1457 /* We have no parent, hence nothing to copy. */
1458 n_old_parent_qgroups
= 0;
1462 n_old_parent_qgroups
= btrfs_qgroup_find_parents(fd
, old_parent_id
, &old_parent_qgroups
);
1463 if (n_old_parent_qgroups
< 0)
1464 return n_old_parent_qgroups
;
1467 for (i
= 0; i
< n_old_qgroups
; i
++) {
1471 r
= btrfs_qgroupid_split(old_qgroups
[i
], NULL
, &id
);
1475 if (id
== old_subvol_id
) {
1476 /* The old subvolume was member of a qgroup
1477 * that had the same id, but a different level
1478 * as it self. Let's set up something similar
1479 * in the destination. */
1480 insert_intermediary_qgroup
= true;
1484 for (j
= 0; j
< n_old_parent_qgroups
; j
++)
1485 if (old_parent_qgroups
[j
] == old_qgroups
[i
]) {
1486 /* The old subvolume shared a common
1487 * parent qgroup with its parent
1488 * subvolume. Let's set up something
1489 * similar in the destination. */
1490 copy_from_parent
= true;
1494 if (!insert_intermediary_qgroup
&& !copy_from_parent
)
1497 return btrfs_subvol_auto_qgroup_fd(fd
, new_subvol_id
, insert_intermediary_qgroup
);
1500 static int copy_subtree_quota_limits(int fd
, uint64_t old_subvol
, uint64_t new_subvol
) {
1501 uint64_t old_subtree_qgroup
, new_subtree_qgroup
;
1505 /* First copy the leaf limits */
1506 r
= btrfs_qgroup_copy_limits(fd
, old_subvol
, new_subvol
);
1511 /* Then, try to copy the subtree limits, if there are any. */
1512 r
= btrfs_subvol_find_subtree_qgroup(fd
, old_subvol
, &old_subtree_qgroup
);
1518 r
= btrfs_subvol_find_subtree_qgroup(fd
, new_subvol
, &new_subtree_qgroup
);
1524 r
= btrfs_qgroup_copy_limits(fd
, old_subtree_qgroup
, new_subtree_qgroup
);
1531 static int subvol_snapshot_children(int old_fd
, int new_fd
, const char *subvolume
, uint64_t old_subvol_id
, BtrfsSnapshotFlags flags
) {
1533 struct btrfs_ioctl_search_args args
= {
1534 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1536 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1537 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1539 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1540 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1542 .key
.min_transid
= 0,
1543 .key
.max_transid
= (uint64_t) -1,
1546 struct btrfs_ioctl_vol_args_v2 vol_args
= {
1547 .flags
= flags
& BTRFS_SNAPSHOT_READ_ONLY
? BTRFS_SUBVOL_RDONLY
: 0,
1550 _cleanup_close_
int subvolume_fd
= -1;
1551 uint64_t new_subvol_id
;
1554 assert(old_fd
>= 0);
1555 assert(new_fd
>= 0);
1558 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1560 if (ioctl(new_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &vol_args
) < 0)
1563 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
) &&
1564 !(flags
& BTRFS_SNAPSHOT_QUOTA
))
1567 if (old_subvol_id
== 0) {
1568 r
= btrfs_subvol_get_id_fd(old_fd
, &old_subvol_id
);
1573 r
= btrfs_subvol_get_id(new_fd
, vol_args
.name
, &new_subvol_id
);
1577 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1578 (void) copy_quota_hierarchy(new_fd
, old_subvol_id
, new_subvol_id
);
1580 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
)) {
1582 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1583 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1588 args
.key
.min_offset
= args
.key
.max_offset
= old_subvol_id
;
1590 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1591 const struct btrfs_ioctl_search_header
*sh
;
1594 args
.key
.nr_items
= 256;
1595 if (ioctl(old_fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1598 if (args
.key
.nr_items
<= 0)
1601 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1602 _cleanup_free_
char *p
= NULL
, *c
= NULL
, *np
= NULL
;
1603 struct btrfs_ioctl_ino_lookup_args ino_args
;
1604 const struct btrfs_root_ref
*ref
;
1605 _cleanup_close_
int old_child_fd
= -1, new_child_fd
= -1;
1607 btrfs_ioctl_search_args_set(&args
, sh
);
1609 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1612 /* Avoid finding the source subvolume a second
1614 if (sh
->offset
!= old_subvol_id
)
1617 /* Avoid running into loops if the new
1618 * subvolume is below the old one. */
1619 if (sh
->objectid
== new_subvol_id
)
1622 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1623 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1628 ino_args
.treeid
= old_subvol_id
;
1629 ino_args
.objectid
= htole64(ref
->dirid
);
1631 if (ioctl(old_fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1634 /* The kernel returns an empty name if the
1635 * subvolume is in the top-level directory,
1636 * and otherwise appends a slash, so that we
1637 * can just concatenate easily here, without
1638 * adding a slash. */
1639 c
= strappend(ino_args
.name
, p
);
1643 old_child_fd
= openat(old_fd
, c
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1644 if (old_child_fd
< 0)
1647 np
= strjoin(subvolume
, "/", ino_args
.name
, NULL
);
1651 new_child_fd
= openat(new_fd
, np
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1652 if (new_child_fd
< 0)
1655 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1656 /* If the snapshot is read-only we
1657 * need to mark it writable
1658 * temporarily, to put the subsnapshot
1661 if (subvolume_fd
< 0) {
1662 subvolume_fd
= openat(new_fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1663 if (subvolume_fd
< 0)
1667 r
= btrfs_subvol_set_read_only_fd(subvolume_fd
, false);
1672 /* When btrfs clones the subvolumes, child
1673 * subvolumes appear as empty directories. Remove
1674 * them, so that we can create a new snapshot
1676 if (unlinkat(new_child_fd
, p
, AT_REMOVEDIR
) < 0) {
1679 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
)
1680 (void) btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1685 r
= subvol_snapshot_children(old_child_fd
, new_child_fd
, p
, sh
->objectid
, flags
& ~BTRFS_SNAPSHOT_FALLBACK_COPY
);
1687 /* Restore the readonly flag */
1688 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1691 k
= btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1692 if (r
>= 0 && k
< 0)
1700 /* Increase search key by one, to read the next item, if we can. */
1701 if (!btrfs_ioctl_search_args_inc(&args
))
1705 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1706 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1711 int btrfs_subvol_snapshot_fd(int old_fd
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1712 _cleanup_close_
int new_fd
= -1;
1713 const char *subvolume
;
1716 assert(old_fd
>= 0);
1719 r
= btrfs_is_subvol_fd(old_fd
);
1723 if (!(flags
& BTRFS_SNAPSHOT_FALLBACK_COPY
))
1726 r
= btrfs_subvol_make(new_path
);
1730 r
= copy_directory_fd(old_fd
, new_path
, true);
1732 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1736 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1737 r
= btrfs_subvol_set_read_only(new_path
, true);
1739 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1747 r
= extract_subvolume_name(new_path
, &subvolume
);
1751 new_fd
= open_parent(new_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1755 return subvol_snapshot_children(old_fd
, new_fd
, subvolume
, 0, flags
);
1758 int btrfs_subvol_snapshot(const char *old_path
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1759 _cleanup_close_
int old_fd
= -1;
1764 old_fd
= open(old_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1768 return btrfs_subvol_snapshot_fd(old_fd
, new_path
, flags
);
1771 int btrfs_qgroup_find_parents(int fd
, uint64_t qgroupid
, uint64_t **ret
) {
1773 struct btrfs_ioctl_search_args args
= {
1774 /* Tree of quota items */
1775 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1777 /* Look precisely for the quota relation items */
1778 .key
.min_type
= BTRFS_QGROUP_RELATION_KEY
,
1779 .key
.max_type
= BTRFS_QGROUP_RELATION_KEY
,
1781 /* No restrictions on the other components */
1782 .key
.min_offset
= 0,
1783 .key
.max_offset
= (uint64_t) -1,
1785 .key
.min_transid
= 0,
1786 .key
.max_transid
= (uint64_t) -1,
1789 _cleanup_free_
uint64_t *items
= NULL
;
1790 size_t n_items
= 0, n_allocated
= 0;
1796 if (qgroupid
== 0) {
1797 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
1801 r
= btrfs_is_filesystem(fd
);
1808 args
.key
.min_objectid
= args
.key
.max_objectid
= qgroupid
;
1810 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1811 const struct btrfs_ioctl_search_header
*sh
;
1814 args
.key
.nr_items
= 256;
1815 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1816 if (errno
== ENOENT
) /* quota tree missing: quota is disabled */
1822 if (args
.key
.nr_items
<= 0)
1825 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1827 /* Make sure we start the next search at least from this entry */
1828 btrfs_ioctl_search_args_set(&args
, sh
);
1830 if (sh
->type
!= BTRFS_QGROUP_RELATION_KEY
)
1832 if (sh
->offset
< sh
->objectid
)
1834 if (sh
->objectid
!= qgroupid
)
1837 if (!GREEDY_REALLOC(items
, n_allocated
, n_items
+1))
1840 items
[n_items
++] = sh
->offset
;
1843 /* Increase search key by one, to read the next item, if we can. */
1844 if (!btrfs_ioctl_search_args_inc(&args
))
1856 return (int) n_items
;
1859 int btrfs_subvol_auto_qgroup_fd(int fd
, uint64_t subvol_id
, bool insert_intermediary_qgroup
) {
1860 _cleanup_free_
uint64_t *qgroups
= NULL
;
1861 uint64_t parent_subvol
;
1862 bool changed
= false;
1868 * Sets up the specified subvolume's qgroup automatically in
1871 * If insert_intermediary_qgroup is false, the subvolume's
1872 * leaf qgroup will be assigned to the same parent qgroups as
1873 * the subvolume's parent subvolume.
1875 * If insert_intermediary_qgroup is true a new intermediary
1876 * higher-level qgroup is created, with a higher level number,
1877 * but reusing the id of the subvolume. The level number is
1878 * picked as one smaller than the lowest level qgroup the
1879 * parent subvolume is a member of. If the parent subvolume's
1880 * leaf qgroup is assigned to no higher-level qgroup a new
1881 * qgroup of level 255 is created instead. Either way, the new
1882 * qgroup is then assigned to the parent's higher-level
1883 * qgroup, and the subvolume itself is assigned to it.
1885 * If the subvolume is already assigned to a higher level
1886 * qgroup, no operation is executed.
1888 * Effectively this means: regardless if
1889 * insert_intermediary_qgroup is true or not, after this
1890 * function is invoked the subvolume will be accounted within
1891 * the same qgroups as the parent. However, if it is true, it
1892 * will also get its own higher-level qgroup, which may in
1893 * turn be used by subvolumes created beneath this subvolume
1896 * This hence defines a simple default qgroup setup for
1897 * subvolumes, as long as this function is invoked on each
1898 * created subvolume: each subvolume is always accounting
1899 * together with its immediate parents. Optionally, if
1900 * insert_intermediary_qgroup is true, it will also get a
1901 * qgroup that then includes all its own child subvolumes.
1904 if (subvol_id
== 0) {
1905 r
= btrfs_is_subvol_fd(fd
);
1911 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1916 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
1919 if (n
> 0) /* already parent qgroups set up, let's bail */
1922 qgroups
= mfree(qgroups
);
1924 r
= btrfs_subvol_get_parent(fd
, subvol_id
, &parent_subvol
);
1926 /* No parent, hence no qgroup memberships */
1931 n
= btrfs_qgroup_find_parents(fd
, parent_subvol
, &qgroups
);
1936 if (insert_intermediary_qgroup
) {
1937 uint64_t lowest
= 256, new_qgroupid
;
1938 bool created
= false;
1941 /* Determine the lowest qgroup that the parent
1942 * subvolume is assigned to. */
1944 for (i
= 0; i
< n
; i
++) {
1947 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, NULL
);
1955 if (lowest
<= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1958 r
= btrfs_qgroupid_make(lowest
- 1, subvol_id
, &new_qgroupid
);
1962 /* Create the new intermediary group, unless it already exists */
1963 r
= btrfs_qgroup_create(fd
, new_qgroupid
);
1964 if (r
< 0 && r
!= -EEXIST
)
1967 changed
= created
= true;
1969 for (i
= 0; i
< n
; i
++) {
1970 r
= btrfs_qgroup_assign(fd
, new_qgroupid
, qgroups
[i
]);
1971 if (r
< 0 && r
!= -EEXIST
) {
1973 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1981 r
= btrfs_qgroup_assign(fd
, subvol_id
, new_qgroupid
);
1982 if (r
< 0 && r
!= -EEXIST
) {
1984 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1993 /* Assign our subvolume to all the same qgroups as the parent */
1995 for (i
= 0; i
< n
; i
++) {
1996 r
= btrfs_qgroup_assign(fd
, subvol_id
, qgroups
[i
]);
1997 if (r
< 0 && r
!= -EEXIST
)
2007 int btrfs_subvol_auto_qgroup(const char *path
, uint64_t subvol_id
, bool create_intermediary_qgroup
) {
2008 _cleanup_close_
int fd
= -1;
2010 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
2014 return btrfs_subvol_auto_qgroup_fd(fd
, subvol_id
, create_intermediary_qgroup
);
2017 int btrfs_subvol_get_parent(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
2019 struct btrfs_ioctl_search_args args
= {
2020 /* Tree of tree roots */
2021 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
2023 /* Look precisely for the subvolume items */
2024 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
2025 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
2027 /* No restrictions on the other components */
2028 .key
.min_offset
= 0,
2029 .key
.max_offset
= (uint64_t) -1,
2031 .key
.min_transid
= 0,
2032 .key
.max_transid
= (uint64_t) -1,
2039 if (subvol_id
== 0) {
2040 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
2044 r
= btrfs_is_filesystem(fd
);
2051 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
2053 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
2054 const struct btrfs_ioctl_search_header
*sh
;
2057 args
.key
.nr_items
= 256;
2058 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
2059 return negative_errno();
2061 if (args
.key
.nr_items
<= 0)
2064 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
2066 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
2068 if (sh
->objectid
!= subvol_id
)