2 This file is part of systemd.
4 Copyright 2014 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <linux/loop.h>
28 #include <sys/ioctl.h>
30 #include <sys/statfs.h>
31 #include <sys/sysmacros.h>
34 #ifdef HAVE_LINUX_BTRFS_H
35 #include <linux/btrfs.h>
38 #include "alloc-util.h"
39 #include "btrfs-ctree.h"
40 #include "btrfs-util.h"
47 #include "path-util.h"
48 #include "selinux-util.h"
49 #include "smack-util.h"
50 #include "sparse-endian.h"
51 #include "stat-util.h"
52 #include "string-util.h"
53 #include "time-util.h"
56 /* WARNING: Be careful with file system ioctls! When we get an fd, we
57 * need to make sure it either refers to only a regular file or
58 * directory, or that it is located on btrfs, before invoking any
59 * btrfs ioctls. The ioctl numbers are reused by some device drivers
60 * (such as DRM), and hence might have bad effects when invoked on
61 * device nodes (that reference drivers) rather than fds to normal
62 * files or directories. */
64 static int validate_subvolume_name(const char *name
) {
66 if (!filename_is_valid(name
))
69 if (strlen(name
) > BTRFS_SUBVOL_NAME_MAX
)
75 static int open_parent(const char *path
, int flags
) {
76 _cleanup_free_
char *parent
= NULL
;
81 parent
= dirname_malloc(path
);
85 fd
= open(parent
, flags
);
92 static int extract_subvolume_name(const char *path
, const char **subvolume
) {
101 r
= validate_subvolume_name(fn
);
109 int btrfs_is_filesystem(int fd
) {
114 if (fstatfs(fd
, &sfs
) < 0)
117 return F_TYPE_EQUAL(sfs
.f_type
, BTRFS_SUPER_MAGIC
);
120 int btrfs_is_subvol_fd(int fd
) {
125 /* On btrfs subvolumes always have the inode 256 */
127 if (fstat(fd
, &st
) < 0)
130 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
133 return btrfs_is_filesystem(fd
);
136 int btrfs_is_subvol(const char *path
) {
137 _cleanup_close_
int fd
= -1;
141 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
145 return btrfs_is_subvol_fd(fd
);
148 int btrfs_subvol_make(const char *path
) {
149 struct btrfs_ioctl_vol_args args
= {};
150 _cleanup_close_
int fd
= -1;
151 const char *subvolume
;
156 r
= extract_subvolume_name(path
, &subvolume
);
160 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
164 strncpy(args
.name
, subvolume
, sizeof(args
.name
)-1);
166 if (ioctl(fd
, BTRFS_IOC_SUBVOL_CREATE
, &args
) < 0)
172 int btrfs_subvol_make_label(const char *path
) {
177 r
= mac_selinux_create_file_prepare(path
, S_IFDIR
);
181 r
= btrfs_subvol_make(path
);
182 mac_selinux_create_file_clear();
187 return mac_smack_fix(path
, false, false);
190 int btrfs_subvol_set_read_only_fd(int fd
, bool b
) {
191 uint64_t flags
, nflags
;
196 if (fstat(fd
, &st
) < 0)
199 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
202 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
206 nflags
= flags
| BTRFS_SUBVOL_RDONLY
;
208 nflags
= flags
& ~BTRFS_SUBVOL_RDONLY
;
213 if (ioctl(fd
, BTRFS_IOC_SUBVOL_SETFLAGS
, &nflags
) < 0)
219 int btrfs_subvol_set_read_only(const char *path
, bool b
) {
220 _cleanup_close_
int fd
= -1;
222 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
226 return btrfs_subvol_set_read_only_fd(fd
, b
);
229 int btrfs_subvol_get_read_only_fd(int fd
) {
235 if (fstat(fd
, &st
) < 0)
238 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
241 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
244 return !!(flags
& BTRFS_SUBVOL_RDONLY
);
247 int btrfs_reflink(int infd
, int outfd
) {
254 /* Make sure we invoke the ioctl on a regular file, so that no
255 * device driver accidentally gets it. */
257 if (fstat(outfd
, &st
) < 0)
260 if (!S_ISREG(st
.st_mode
))
263 r
= ioctl(outfd
, BTRFS_IOC_CLONE
, infd
);
270 int btrfs_clone_range(int infd
, uint64_t in_offset
, int outfd
, uint64_t out_offset
, uint64_t sz
) {
271 struct btrfs_ioctl_clone_range_args args
= {
273 .src_offset
= in_offset
,
275 .dest_offset
= out_offset
,
284 if (fstat(outfd
, &st
) < 0)
287 if (!S_ISREG(st
.st_mode
))
290 r
= ioctl(outfd
, BTRFS_IOC_CLONE_RANGE
, &args
);
297 int btrfs_get_block_device_fd(int fd
, dev_t
*dev
) {
298 struct btrfs_ioctl_fs_info_args fsi
= {};
305 r
= btrfs_is_filesystem(fd
);
311 if (ioctl(fd
, BTRFS_IOC_FS_INFO
, &fsi
) < 0)
314 /* We won't do this for btrfs RAID */
315 if (fsi
.num_devices
!= 1)
318 for (id
= 1; id
<= fsi
.max_id
; id
++) {
319 struct btrfs_ioctl_dev_info_args di
= {
324 if (ioctl(fd
, BTRFS_IOC_DEV_INFO
, &di
) < 0) {
331 if (stat((char*) di
.path
, &st
) < 0)
334 if (!S_ISBLK(st
.st_mode
))
337 if (major(st
.st_rdev
) == 0)
347 int btrfs_get_block_device(const char *path
, dev_t
*dev
) {
348 _cleanup_close_
int fd
= -1;
353 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
357 return btrfs_get_block_device_fd(fd
, dev
);
360 int btrfs_subvol_get_id_fd(int fd
, uint64_t *ret
) {
361 struct btrfs_ioctl_ino_lookup_args args
= {
362 .objectid
= BTRFS_FIRST_FREE_OBJECTID
369 r
= btrfs_is_filesystem(fd
);
375 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
) < 0)
382 int btrfs_subvol_get_id(int fd
, const char *subvol
, uint64_t *ret
) {
383 _cleanup_close_
int subvol_fd
= -1;
388 subvol_fd
= openat(fd
, subvol
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
392 return btrfs_subvol_get_id_fd(subvol_fd
, ret
);
395 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args
*args
) {
398 /* the objectid, type, offset together make up the btrfs key,
399 * which is considered a single 136byte integer when
400 * comparing. This call increases the counter by one, dealing
401 * with the overflow between the overflows */
403 if (args
->key
.min_offset
< (uint64_t) -1) {
404 args
->key
.min_offset
++;
408 if (args
->key
.min_type
< (uint8_t) -1) {
409 args
->key
.min_type
++;
410 args
->key
.min_offset
= 0;
414 if (args
->key
.min_objectid
< (uint64_t) -1) {
415 args
->key
.min_objectid
++;
416 args
->key
.min_offset
= 0;
417 args
->key
.min_type
= 0;
424 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args
*args
, const struct btrfs_ioctl_search_header
*h
) {
428 args
->key
.min_objectid
= h
->objectid
;
429 args
->key
.min_type
= h
->type
;
430 args
->key
.min_offset
= h
->offset
;
433 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
*args
) {
436 /* Compare min and max */
438 if (args
->key
.min_objectid
< args
->key
.max_objectid
)
440 if (args
->key
.min_objectid
> args
->key
.max_objectid
)
443 if (args
->key
.min_type
< args
->key
.max_type
)
445 if (args
->key
.min_type
> args
->key
.max_type
)
448 if (args
->key
.min_offset
< args
->key
.max_offset
)
450 if (args
->key
.min_offset
> args
->key
.max_offset
)
456 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
458 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
459 (i) < (args).key.nr_items; \
461 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
463 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
464 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
466 int btrfs_subvol_get_info_fd(int fd
, uint64_t subvol_id
, BtrfsSubvolInfo
*ret
) {
467 struct btrfs_ioctl_search_args args
= {
468 /* Tree of tree roots */
469 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
471 /* Look precisely for the subvolume items */
472 .key
.min_type
= BTRFS_ROOT_ITEM_KEY
,
473 .key
.max_type
= BTRFS_ROOT_ITEM_KEY
,
476 .key
.max_offset
= (uint64_t) -1,
478 /* No restrictions on the other components */
479 .key
.min_transid
= 0,
480 .key
.max_transid
= (uint64_t) -1,
489 if (subvol_id
== 0) {
490 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
494 r
= btrfs_is_filesystem(fd
);
501 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
503 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
504 const struct btrfs_ioctl_search_header
*sh
;
507 args
.key
.nr_items
= 256;
508 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
511 if (args
.key
.nr_items
<= 0)
514 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
516 const struct btrfs_root_item
*ri
;
518 /* Make sure we start the next search at least from this entry */
519 btrfs_ioctl_search_args_set(&args
, sh
);
521 if (sh
->objectid
!= subvol_id
)
523 if (sh
->type
!= BTRFS_ROOT_ITEM_KEY
)
526 /* Older versions of the struct lacked the otime setting */
527 if (sh
->len
< offsetof(struct btrfs_root_item
, otime
) + sizeof(struct btrfs_timespec
))
530 ri
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
532 ret
->otime
= (usec_t
) le64toh(ri
->otime
.sec
) * USEC_PER_SEC
+
533 (usec_t
) le32toh(ri
->otime
.nsec
) / NSEC_PER_USEC
;
535 ret
->subvol_id
= subvol_id
;
536 ret
->read_only
= !!(le64toh(ri
->flags
) & BTRFS_ROOT_SUBVOL_RDONLY
);
538 assert_cc(sizeof(ri
->uuid
) == sizeof(ret
->uuid
));
539 memcpy(&ret
->uuid
, ri
->uuid
, sizeof(ret
->uuid
));
540 memcpy(&ret
->parent_uuid
, ri
->parent_uuid
, sizeof(ret
->parent_uuid
));
546 /* Increase search key by one, to read the next item, if we can. */
547 if (!btrfs_ioctl_search_args_inc(&args
))
558 int btrfs_qgroup_get_quota_fd(int fd
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
560 struct btrfs_ioctl_search_args args
= {
561 /* Tree of quota items */
562 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
564 /* The object ID is always 0 */
565 .key
.min_objectid
= 0,
566 .key
.max_objectid
= 0,
568 /* Look precisely for the quota items */
569 .key
.min_type
= BTRFS_QGROUP_STATUS_KEY
,
570 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
572 /* No restrictions on the other components */
573 .key
.min_transid
= 0,
574 .key
.max_transid
= (uint64_t) -1,
577 bool found_info
= false, found_limit
= false;
584 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
588 r
= btrfs_is_filesystem(fd
);
595 args
.key
.min_offset
= args
.key
.max_offset
= qgroupid
;
597 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
598 const struct btrfs_ioctl_search_header
*sh
;
601 args
.key
.nr_items
= 256;
602 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
603 if (errno
== ENOENT
) /* quota tree is missing: quota disabled */
609 if (args
.key
.nr_items
<= 0)
612 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
614 /* Make sure we start the next search at least from this entry */
615 btrfs_ioctl_search_args_set(&args
, sh
);
617 if (sh
->objectid
!= 0)
619 if (sh
->offset
!= qgroupid
)
622 if (sh
->type
== BTRFS_QGROUP_INFO_KEY
) {
623 const struct btrfs_qgroup_info_item
*qii
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
625 ret
->referenced
= le64toh(qii
->rfer
);
626 ret
->exclusive
= le64toh(qii
->excl
);
630 } else if (sh
->type
== BTRFS_QGROUP_LIMIT_KEY
) {
631 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
633 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_RFER
)
634 ret
->referenced_max
= le64toh(qli
->max_rfer
);
636 ret
->referenced_max
= (uint64_t) -1;
638 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_EXCL
)
639 ret
->exclusive_max
= le64toh(qli
->max_excl
);
641 ret
->exclusive_max
= (uint64_t) -1;
646 if (found_info
&& found_limit
)
650 /* Increase search key by one, to read the next item, if we can. */
651 if (!btrfs_ioctl_search_args_inc(&args
))
656 if (!found_limit
&& !found_info
)
660 ret
->referenced
= (uint64_t) -1;
661 ret
->exclusive
= (uint64_t) -1;
665 ret
->referenced_max
= (uint64_t) -1;
666 ret
->exclusive_max
= (uint64_t) -1;
672 int btrfs_qgroup_get_quota(const char *path
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
673 _cleanup_close_
int fd
= -1;
675 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
679 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
682 int btrfs_subvol_find_subtree_qgroup(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
683 uint64_t level
, lowest
= (uint64_t) -1, lowest_qgroupid
= 0;
684 _cleanup_free_
uint64_t *qgroups
= NULL
;
690 /* This finds the "subtree" qgroup for a specific
691 * subvolume. This only works for subvolumes that have been
692 * prepared with btrfs_subvol_auto_qgroup_fd() with
693 * insert_intermediary_qgroup=true (or equivalent). For others
694 * it will return the leaf qgroup instead. The two cases may
695 * be distuingished via the return value, which is 1 in case
696 * an appropriate "subtree" qgroup was found, and 0
699 if (subvol_id
== 0) {
700 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
705 r
= btrfs_qgroupid_split(subvol_id
, &level
, NULL
);
708 if (level
!= 0) /* Input must be a leaf qgroup */
711 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
715 for (i
= 0; i
< n
; i
++) {
718 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, &id
);
725 if (lowest
== (uint64_t) -1 || level
< lowest
) {
726 lowest_qgroupid
= qgroups
[i
];
731 if (lowest
== (uint64_t) -1) {
732 /* No suitable higher-level qgroup found, let's return
733 * the leaf qgroup instead, and indicate that with the
740 *ret
= lowest_qgroupid
;
744 int btrfs_subvol_get_subtree_quota_fd(int fd
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
751 /* This determines the quota data of the qgroup with the
752 * lowest level, that shares the id part with the specified
753 * subvolume. This is useful for determining the quota data
754 * for entire subvolume subtrees, as long as the subtrees have
755 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
758 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
762 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
765 int btrfs_subvol_get_subtree_quota(const char *path
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
766 _cleanup_close_
int fd
= -1;
768 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
772 return btrfs_subvol_get_subtree_quota_fd(fd
, subvol_id
, ret
);
775 int btrfs_defrag_fd(int fd
) {
780 if (fstat(fd
, &st
) < 0)
783 if (!S_ISREG(st
.st_mode
))
786 if (ioctl(fd
, BTRFS_IOC_DEFRAG
, NULL
) < 0)
792 int btrfs_defrag(const char *p
) {
793 _cleanup_close_
int fd
= -1;
795 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
799 return btrfs_defrag_fd(fd
);
802 int btrfs_quota_enable_fd(int fd
, bool b
) {
803 struct btrfs_ioctl_quota_ctl_args args
= {
804 .cmd
= b
? BTRFS_QUOTA_CTL_ENABLE
: BTRFS_QUOTA_CTL_DISABLE
,
810 r
= btrfs_is_filesystem(fd
);
816 if (ioctl(fd
, BTRFS_IOC_QUOTA_CTL
, &args
) < 0)
822 int btrfs_quota_enable(const char *path
, bool b
) {
823 _cleanup_close_
int fd
= -1;
825 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
829 return btrfs_quota_enable_fd(fd
, b
);
832 int btrfs_qgroup_set_limit_fd(int fd
, uint64_t qgroupid
, uint64_t referenced_max
) {
834 struct btrfs_ioctl_qgroup_limit_args args
= {
835 .lim
.max_rfer
= referenced_max
,
836 .lim
.flags
= BTRFS_QGROUP_LIMIT_MAX_RFER
,
844 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
848 r
= btrfs_is_filesystem(fd
);
855 args
.qgroupid
= qgroupid
;
858 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &args
) < 0) {
860 if (errno
== EBUSY
&& c
< 10) {
861 (void) btrfs_quota_scan_wait(fd
);
874 int btrfs_qgroup_set_limit(const char *path
, uint64_t qgroupid
, uint64_t referenced_max
) {
875 _cleanup_close_
int fd
= -1;
877 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
881 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
884 int btrfs_subvol_set_subtree_quota_limit_fd(int fd
, uint64_t subvol_id
, uint64_t referenced_max
) {
890 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
894 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
897 int btrfs_subvol_set_subtree_quota_limit(const char *path
, uint64_t subvol_id
, uint64_t referenced_max
) {
898 _cleanup_close_
int fd
= -1;
900 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
904 return btrfs_subvol_set_subtree_quota_limit_fd(fd
, subvol_id
, referenced_max
);
907 int btrfs_resize_loopback_fd(int fd
, uint64_t new_size
, bool grow_only
) {
908 struct btrfs_ioctl_vol_args args
= {};
909 _cleanup_free_
char *p
= NULL
, *loop
= NULL
, *backing
= NULL
;
910 _cleanup_close_
int loop_fd
= -1, backing_fd
= -1;
915 /* In contrast to btrfs quota ioctls ftruncate() cannot make sense of "infinity" or file sizes > 2^31 */
916 if (!FILE_SIZE_VALID(new_size
))
919 /* btrfs cannot handle file systems < 16M, hence use this as minimum */
920 if (new_size
< 16*1024*1024)
921 new_size
= 16*1024*1024;
923 r
= btrfs_get_block_device_fd(fd
, &dev
);
929 if (asprintf(&p
, "/sys/dev/block/%u:%u/loop/backing_file", major(dev
), minor(dev
)) < 0)
931 r
= read_one_line_file(p
, &backing
);
936 if (isempty(backing
) || !path_is_absolute(backing
))
939 backing_fd
= open(backing
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
943 if (fstat(backing_fd
, &st
) < 0)
945 if (!S_ISREG(st
.st_mode
))
948 if (new_size
== (uint64_t) st
.st_size
)
951 if (grow_only
&& new_size
< (uint64_t) st
.st_size
)
954 if (asprintf(&loop
, "/dev/block/%u:%u", major(dev
), minor(dev
)) < 0)
956 loop_fd
= open(loop
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
960 if (snprintf(args
.name
, sizeof(args
.name
), "%" PRIu64
, new_size
) >= (int) sizeof(args
.name
))
963 if (new_size
< (uint64_t) st
.st_size
) {
964 /* Decrease size: first decrease btrfs size, then shorten loopback */
965 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
969 if (ftruncate(backing_fd
, new_size
) < 0)
972 if (ioctl(loop_fd
, LOOP_SET_CAPACITY
, 0) < 0)
975 if (new_size
> (uint64_t) st
.st_size
) {
976 /* Increase size: first enlarge loopback, then increase btrfs size */
977 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
981 /* Make sure the free disk space is correctly updated for both file systems */
983 (void) fsync(backing_fd
);
988 int btrfs_resize_loopback(const char *p
, uint64_t new_size
, bool grow_only
) {
989 _cleanup_close_
int fd
= -1;
991 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
995 return btrfs_resize_loopback_fd(fd
, new_size
, grow_only
);
998 int btrfs_qgroupid_make(uint64_t level
, uint64_t id
, uint64_t *ret
) {
1001 if (level
>= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT
)))
1004 if (id
>= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
))
1007 *ret
= (level
<< BTRFS_QGROUP_LEVEL_SHIFT
) | id
;
1011 int btrfs_qgroupid_split(uint64_t qgroupid
, uint64_t *level
, uint64_t *id
) {
1012 assert(level
|| id
);
1015 *level
= qgroupid
>> BTRFS_QGROUP_LEVEL_SHIFT
;
1018 *id
= qgroupid
& ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
) - 1);
1023 static int qgroup_create_or_destroy(int fd
, bool b
, uint64_t qgroupid
) {
1025 struct btrfs_ioctl_qgroup_create_args args
= {
1027 .qgroupid
= qgroupid
,
1032 r
= btrfs_is_filesystem(fd
);
1039 if (ioctl(fd
, BTRFS_IOC_QGROUP_CREATE
, &args
) < 0) {
1041 /* If quota is not enabled, we get EINVAL. Turn this into a recognizable error */
1042 if (errno
== EINVAL
)
1043 return -ENOPROTOOPT
;
1045 if (errno
== EBUSY
&& c
< 10) {
1046 (void) btrfs_quota_scan_wait(fd
);
1059 int btrfs_qgroup_create(int fd
, uint64_t qgroupid
) {
1060 return qgroup_create_or_destroy(fd
, true, qgroupid
);
1063 int btrfs_qgroup_destroy(int fd
, uint64_t qgroupid
) {
1064 return qgroup_create_or_destroy(fd
, false, qgroupid
);
1067 int btrfs_qgroup_destroy_recursive(int fd
, uint64_t qgroupid
) {
1068 _cleanup_free_
uint64_t *qgroups
= NULL
;
1072 /* Destroys the specified qgroup, but unassigns it from all
1073 * its parents first. Also, it recursively destroys all
1074 * qgroups it is assgined to that have the same id part of the
1075 * qgroupid as the specified group. */
1077 r
= btrfs_qgroupid_split(qgroupid
, NULL
, &subvol_id
);
1081 n
= btrfs_qgroup_find_parents(fd
, qgroupid
, &qgroups
);
1085 for (i
= 0; i
< n
; i
++) {
1088 r
= btrfs_qgroupid_split(qgroups
[i
], NULL
, &id
);
1092 r
= btrfs_qgroup_unassign(fd
, qgroupid
, qgroups
[i
]);
1096 if (id
!= subvol_id
)
1099 /* The parent qgroupid shares the same id part with
1100 * us? If so, destroy it too. */
1102 (void) btrfs_qgroup_destroy_recursive(fd
, qgroups
[i
]);
1105 return btrfs_qgroup_destroy(fd
, qgroupid
);
1108 int btrfs_quota_scan_start(int fd
) {
1109 struct btrfs_ioctl_quota_rescan_args args
= {};
1113 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN
, &args
) < 0)
1119 int btrfs_quota_scan_wait(int fd
) {
1122 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_WAIT
) < 0)
1128 int btrfs_quota_scan_ongoing(int fd
) {
1129 struct btrfs_ioctl_quota_rescan_args args
= {};
1133 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_STATUS
, &args
) < 0)
1136 return !!args
.flags
;
1139 static int qgroup_assign_or_unassign(int fd
, bool b
, uint64_t child
, uint64_t parent
) {
1140 struct btrfs_ioctl_qgroup_assign_args args
= {
1148 r
= btrfs_is_filesystem(fd
);
1155 r
= ioctl(fd
, BTRFS_IOC_QGROUP_ASSIGN
, &args
);
1157 if (errno
== EBUSY
&& c
< 10) {
1158 (void) btrfs_quota_scan_wait(fd
);
1168 /* If the return value is > 0, we need to request a rescan */
1170 (void) btrfs_quota_scan_start(fd
);
1175 int btrfs_qgroup_assign(int fd
, uint64_t child
, uint64_t parent
) {
1176 return qgroup_assign_or_unassign(fd
, true, child
, parent
);
1179 int btrfs_qgroup_unassign(int fd
, uint64_t child
, uint64_t parent
) {
1180 return qgroup_assign_or_unassign(fd
, false, child
, parent
);
1183 static int subvol_remove_children(int fd
, const char *subvolume
, uint64_t subvol_id
, BtrfsRemoveFlags flags
) {
1184 struct btrfs_ioctl_search_args args
= {
1185 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1187 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1188 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1190 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1191 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1193 .key
.min_transid
= 0,
1194 .key
.max_transid
= (uint64_t) -1,
1197 struct btrfs_ioctl_vol_args vol_args
= {};
1198 _cleanup_close_
int subvol_fd
= -1;
1200 bool made_writable
= false;
1206 if (fstat(fd
, &st
) < 0)
1209 if (!S_ISDIR(st
.st_mode
))
1212 subvol_fd
= openat(fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1216 if (subvol_id
== 0) {
1217 r
= btrfs_subvol_get_id_fd(subvol_fd
, &subvol_id
);
1222 /* First, try to remove the subvolume. If it happens to be
1223 * already empty, this will just work. */
1224 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1225 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) >= 0) {
1226 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1229 if (!(flags
& BTRFS_REMOVE_RECURSIVE
) || errno
!= ENOTEMPTY
)
1232 /* OK, the subvolume is not empty, let's look for child
1233 * subvolumes, and remove them, first */
1235 args
.key
.min_offset
= args
.key
.max_offset
= subvol_id
;
1237 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1238 const struct btrfs_ioctl_search_header
*sh
;
1241 args
.key
.nr_items
= 256;
1242 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1245 if (args
.key
.nr_items
<= 0)
1248 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1249 _cleanup_free_
char *p
= NULL
;
1250 const struct btrfs_root_ref
*ref
;
1251 struct btrfs_ioctl_ino_lookup_args ino_args
;
1253 btrfs_ioctl_search_args_set(&args
, sh
);
1255 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1257 if (sh
->offset
!= subvol_id
)
1260 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1262 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1267 ino_args
.treeid
= subvol_id
;
1268 ino_args
.objectid
= htole64(ref
->dirid
);
1270 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1273 if (!made_writable
) {
1274 r
= btrfs_subvol_set_read_only_fd(subvol_fd
, false);
1278 made_writable
= true;
1281 if (isempty(ino_args
.name
))
1282 /* Subvolume is in the top-level
1283 * directory of the subvolume. */
1284 r
= subvol_remove_children(subvol_fd
, p
, sh
->objectid
, flags
);
1286 _cleanup_close_
int child_fd
= -1;
1288 /* Subvolume is somewhere further down,
1289 * hence we need to open the
1290 * containing directory first */
1292 child_fd
= openat(subvol_fd
, ino_args
.name
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1296 r
= subvol_remove_children(child_fd
, p
, sh
->objectid
, flags
);
1302 /* Increase search key by one, to read the next item, if we can. */
1303 if (!btrfs_ioctl_search_args_inc(&args
))
1307 /* OK, the child subvolumes should all be gone now, let's try
1308 * again to remove the subvolume */
1309 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) < 0)
1312 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
);
1316 int btrfs_subvol_remove(const char *path
, BtrfsRemoveFlags flags
) {
1317 _cleanup_close_
int fd
= -1;
1318 const char *subvolume
;
1323 r
= extract_subvolume_name(path
, &subvolume
);
1327 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1331 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1334 int btrfs_subvol_remove_fd(int fd
, const char *subvolume
, BtrfsRemoveFlags flags
) {
1335 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1338 int btrfs_qgroup_copy_limits(int fd
, uint64_t old_qgroupid
, uint64_t new_qgroupid
) {
1340 struct btrfs_ioctl_search_args args
= {
1341 /* Tree of quota items */
1342 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1344 /* The object ID is always 0 */
1345 .key
.min_objectid
= 0,
1346 .key
.max_objectid
= 0,
1348 /* Look precisely for the quota items */
1349 .key
.min_type
= BTRFS_QGROUP_LIMIT_KEY
,
1350 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
1352 /* For our qgroup */
1353 .key
.min_offset
= old_qgroupid
,
1354 .key
.max_offset
= old_qgroupid
,
1356 /* No restrictions on the other components */
1357 .key
.min_transid
= 0,
1358 .key
.max_transid
= (uint64_t) -1,
1363 r
= btrfs_is_filesystem(fd
);
1369 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1370 const struct btrfs_ioctl_search_header
*sh
;
1373 args
.key
.nr_items
= 256;
1374 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1375 if (errno
== ENOENT
) /* quota tree missing: quota is not enabled, hence nothing to copy */
1381 if (args
.key
.nr_items
<= 0)
1384 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1385 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1386 struct btrfs_ioctl_qgroup_limit_args qargs
;
1389 /* Make sure we start the next search at least from this entry */
1390 btrfs_ioctl_search_args_set(&args
, sh
);
1392 if (sh
->objectid
!= 0)
1394 if (sh
->type
!= BTRFS_QGROUP_LIMIT_KEY
)
1396 if (sh
->offset
!= old_qgroupid
)
1399 /* We found the entry, now copy things over. */
1401 qargs
= (struct btrfs_ioctl_qgroup_limit_args
) {
1402 .qgroupid
= new_qgroupid
,
1404 .lim
.max_rfer
= le64toh(qli
->max_rfer
),
1405 .lim
.max_excl
= le64toh(qli
->max_excl
),
1406 .lim
.rsv_rfer
= le64toh(qli
->rsv_rfer
),
1407 .lim
.rsv_excl
= le64toh(qli
->rsv_excl
),
1409 .lim
.flags
= le64toh(qli
->flags
) & (BTRFS_QGROUP_LIMIT_MAX_RFER
|
1410 BTRFS_QGROUP_LIMIT_MAX_EXCL
|
1411 BTRFS_QGROUP_LIMIT_RSV_RFER
|
1412 BTRFS_QGROUP_LIMIT_RSV_EXCL
),
1416 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &qargs
) < 0) {
1417 if (errno
== EBUSY
&& c
< 10) {
1418 (void) btrfs_quota_scan_wait(fd
);
1430 /* Increase search key by one, to read the next item, if we can. */
1431 if (!btrfs_ioctl_search_args_inc(&args
))
1438 static int copy_quota_hierarchy(int fd
, uint64_t old_subvol_id
, uint64_t new_subvol_id
) {
1439 _cleanup_free_
uint64_t *old_qgroups
= NULL
, *old_parent_qgroups
= NULL
;
1440 bool copy_from_parent
= false, insert_intermediary_qgroup
= false;
1441 int n_old_qgroups
, n_old_parent_qgroups
, r
, i
;
1442 uint64_t old_parent_id
;
1446 /* Copies a reduced form of quota information from the old to
1447 * the new subvolume. */
1449 n_old_qgroups
= btrfs_qgroup_find_parents(fd
, old_subvol_id
, &old_qgroups
);
1450 if (n_old_qgroups
<= 0) /* Nothing to copy */
1451 return n_old_qgroups
;
1453 r
= btrfs_subvol_get_parent(fd
, old_subvol_id
, &old_parent_id
);
1455 /* We have no parent, hence nothing to copy. */
1456 n_old_parent_qgroups
= 0;
1460 n_old_parent_qgroups
= btrfs_qgroup_find_parents(fd
, old_parent_id
, &old_parent_qgroups
);
1461 if (n_old_parent_qgroups
< 0)
1462 return n_old_parent_qgroups
;
1465 for (i
= 0; i
< n_old_qgroups
; i
++) {
1469 r
= btrfs_qgroupid_split(old_qgroups
[i
], NULL
, &id
);
1473 if (id
== old_subvol_id
) {
1474 /* The old subvolume was member of a qgroup
1475 * that had the same id, but a different level
1476 * as it self. Let's set up something similar
1477 * in the destination. */
1478 insert_intermediary_qgroup
= true;
1482 for (j
= 0; j
< n_old_parent_qgroups
; j
++)
1483 if (old_parent_qgroups
[j
] == old_qgroups
[i
]) {
1484 /* The old subvolume shared a common
1485 * parent qgroup with its parent
1486 * subvolume. Let's set up something
1487 * similar in the destination. */
1488 copy_from_parent
= true;
1492 if (!insert_intermediary_qgroup
&& !copy_from_parent
)
1495 return btrfs_subvol_auto_qgroup_fd(fd
, new_subvol_id
, insert_intermediary_qgroup
);
1498 static int copy_subtree_quota_limits(int fd
, uint64_t old_subvol
, uint64_t new_subvol
) {
1499 uint64_t old_subtree_qgroup
, new_subtree_qgroup
;
1503 /* First copy the leaf limits */
1504 r
= btrfs_qgroup_copy_limits(fd
, old_subvol
, new_subvol
);
1509 /* Then, try to copy the subtree limits, if there are any. */
1510 r
= btrfs_subvol_find_subtree_qgroup(fd
, old_subvol
, &old_subtree_qgroup
);
1516 r
= btrfs_subvol_find_subtree_qgroup(fd
, new_subvol
, &new_subtree_qgroup
);
1522 r
= btrfs_qgroup_copy_limits(fd
, old_subtree_qgroup
, new_subtree_qgroup
);
1529 static int subvol_snapshot_children(int old_fd
, int new_fd
, const char *subvolume
, uint64_t old_subvol_id
, BtrfsSnapshotFlags flags
) {
1531 struct btrfs_ioctl_search_args args
= {
1532 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1534 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1535 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1537 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1538 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1540 .key
.min_transid
= 0,
1541 .key
.max_transid
= (uint64_t) -1,
1544 struct btrfs_ioctl_vol_args_v2 vol_args
= {
1545 .flags
= flags
& BTRFS_SNAPSHOT_READ_ONLY
? BTRFS_SUBVOL_RDONLY
: 0,
1548 _cleanup_close_
int subvolume_fd
= -1;
1549 uint64_t new_subvol_id
;
1552 assert(old_fd
>= 0);
1553 assert(new_fd
>= 0);
1556 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1558 if (ioctl(new_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &vol_args
) < 0)
1561 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
) &&
1562 !(flags
& BTRFS_SNAPSHOT_QUOTA
))
1565 if (old_subvol_id
== 0) {
1566 r
= btrfs_subvol_get_id_fd(old_fd
, &old_subvol_id
);
1571 r
= btrfs_subvol_get_id(new_fd
, vol_args
.name
, &new_subvol_id
);
1575 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1576 (void) copy_quota_hierarchy(new_fd
, old_subvol_id
, new_subvol_id
);
1578 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
)) {
1580 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1581 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1586 args
.key
.min_offset
= args
.key
.max_offset
= old_subvol_id
;
1588 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1589 const struct btrfs_ioctl_search_header
*sh
;
1592 args
.key
.nr_items
= 256;
1593 if (ioctl(old_fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1596 if (args
.key
.nr_items
<= 0)
1599 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1600 _cleanup_free_
char *p
= NULL
, *c
= NULL
, *np
= NULL
;
1601 struct btrfs_ioctl_ino_lookup_args ino_args
;
1602 const struct btrfs_root_ref
*ref
;
1603 _cleanup_close_
int old_child_fd
= -1, new_child_fd
= -1;
1605 btrfs_ioctl_search_args_set(&args
, sh
);
1607 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1610 /* Avoid finding the source subvolume a second
1612 if (sh
->offset
!= old_subvol_id
)
1615 /* Avoid running into loops if the new
1616 * subvolume is below the old one. */
1617 if (sh
->objectid
== new_subvol_id
)
1620 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1621 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1626 ino_args
.treeid
= old_subvol_id
;
1627 ino_args
.objectid
= htole64(ref
->dirid
);
1629 if (ioctl(old_fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1632 /* The kernel returns an empty name if the
1633 * subvolume is in the top-level directory,
1634 * and otherwise appends a slash, so that we
1635 * can just concatenate easily here, without
1636 * adding a slash. */
1637 c
= strappend(ino_args
.name
, p
);
1641 old_child_fd
= openat(old_fd
, c
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1642 if (old_child_fd
< 0)
1645 np
= strjoin(subvolume
, "/", ino_args
.name
, NULL
);
1649 new_child_fd
= openat(new_fd
, np
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1650 if (new_child_fd
< 0)
1653 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1654 /* If the snapshot is read-only we
1655 * need to mark it writable
1656 * temporarily, to put the subsnapshot
1659 if (subvolume_fd
< 0) {
1660 subvolume_fd
= openat(new_fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1661 if (subvolume_fd
< 0)
1665 r
= btrfs_subvol_set_read_only_fd(subvolume_fd
, false);
1670 /* When btrfs clones the subvolumes, child
1671 * subvolumes appear as empty directories. Remove
1672 * them, so that we can create a new snapshot
1674 if (unlinkat(new_child_fd
, p
, AT_REMOVEDIR
) < 0) {
1677 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
)
1678 (void) btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1683 r
= subvol_snapshot_children(old_child_fd
, new_child_fd
, p
, sh
->objectid
, flags
& ~BTRFS_SNAPSHOT_FALLBACK_COPY
);
1685 /* Restore the readonly flag */
1686 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1689 k
= btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1690 if (r
>= 0 && k
< 0)
1698 /* Increase search key by one, to read the next item, if we can. */
1699 if (!btrfs_ioctl_search_args_inc(&args
))
1703 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1704 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1709 int btrfs_subvol_snapshot_fd(int old_fd
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1710 _cleanup_close_
int new_fd
= -1;
1711 const char *subvolume
;
1714 assert(old_fd
>= 0);
1717 r
= btrfs_is_subvol_fd(old_fd
);
1721 if (!(flags
& BTRFS_SNAPSHOT_FALLBACK_COPY
))
1724 r
= btrfs_subvol_make(new_path
);
1728 r
= copy_directory_fd(old_fd
, new_path
, true);
1730 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1734 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1735 r
= btrfs_subvol_set_read_only(new_path
, true);
1737 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1745 r
= extract_subvolume_name(new_path
, &subvolume
);
1749 new_fd
= open_parent(new_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1753 return subvol_snapshot_children(old_fd
, new_fd
, subvolume
, 0, flags
);
1756 int btrfs_subvol_snapshot(const char *old_path
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1757 _cleanup_close_
int old_fd
= -1;
1762 old_fd
= open(old_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1766 return btrfs_subvol_snapshot_fd(old_fd
, new_path
, flags
);
1769 int btrfs_qgroup_find_parents(int fd
, uint64_t qgroupid
, uint64_t **ret
) {
1771 struct btrfs_ioctl_search_args args
= {
1772 /* Tree of quota items */
1773 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1775 /* Look precisely for the quota relation items */
1776 .key
.min_type
= BTRFS_QGROUP_RELATION_KEY
,
1777 .key
.max_type
= BTRFS_QGROUP_RELATION_KEY
,
1779 /* No restrictions on the other components */
1780 .key
.min_offset
= 0,
1781 .key
.max_offset
= (uint64_t) -1,
1783 .key
.min_transid
= 0,
1784 .key
.max_transid
= (uint64_t) -1,
1787 _cleanup_free_
uint64_t *items
= NULL
;
1788 size_t n_items
= 0, n_allocated
= 0;
1794 if (qgroupid
== 0) {
1795 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
1799 r
= btrfs_is_filesystem(fd
);
1806 args
.key
.min_objectid
= args
.key
.max_objectid
= qgroupid
;
1808 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1809 const struct btrfs_ioctl_search_header
*sh
;
1812 args
.key
.nr_items
= 256;
1813 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1814 if (errno
== ENOENT
) /* quota tree missing: quota is disabled */
1820 if (args
.key
.nr_items
<= 0)
1823 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1825 /* Make sure we start the next search at least from this entry */
1826 btrfs_ioctl_search_args_set(&args
, sh
);
1828 if (sh
->type
!= BTRFS_QGROUP_RELATION_KEY
)
1830 if (sh
->offset
< sh
->objectid
)
1832 if (sh
->objectid
!= qgroupid
)
1835 if (!GREEDY_REALLOC(items
, n_allocated
, n_items
+1))
1838 items
[n_items
++] = sh
->offset
;
1841 /* Increase search key by one, to read the next item, if we can. */
1842 if (!btrfs_ioctl_search_args_inc(&args
))
1854 return (int) n_items
;
1857 int btrfs_subvol_auto_qgroup_fd(int fd
, uint64_t subvol_id
, bool insert_intermediary_qgroup
) {
1858 _cleanup_free_
uint64_t *qgroups
= NULL
;
1859 uint64_t parent_subvol
;
1860 bool changed
= false;
1866 * Sets up the specified subvolume's qgroup automatically in
1869 * If insert_intermediary_qgroup is false, the subvolume's
1870 * leaf qgroup will be assigned to the same parent qgroups as
1871 * the subvolume's parent subvolume.
1873 * If insert_intermediary_qgroup is true a new intermediary
1874 * higher-level qgroup is created, with a higher level number,
1875 * but reusing the id of the subvolume. The level number is
1876 * picked as one smaller than the lowest level qgroup the
1877 * parent subvolume is a member of. If the parent subvolume's
1878 * leaf qgroup is assigned to no higher-level qgroup a new
1879 * qgroup of level 255 is created instead. Either way, the new
1880 * qgroup is then assigned to the parent's higher-level
1881 * qgroup, and the subvolume itself is assigned to it.
1883 * If the subvolume is already assigned to a higher level
1884 * qgroup, no operation is executed.
1886 * Effectively this means: regardless if
1887 * insert_intermediary_qgroup is true or not, after this
1888 * function is invoked the subvolume will be accounted within
1889 * the same qgroups as the parent. However, if it is true, it
1890 * will also get its own higher-level qgroup, which may in
1891 * turn be used by subvolumes created beneath this subvolume
1894 * This hence defines a simple default qgroup setup for
1895 * subvolumes, as long as this function is invoked on each
1896 * created subvolume: each subvolume is always accounting
1897 * together with its immediate parents. Optionally, if
1898 * insert_intermediary_qgroup is true, it will also get a
1899 * qgroup that then includes all its own child subvolumes.
1902 if (subvol_id
== 0) {
1903 r
= btrfs_is_subvol_fd(fd
);
1909 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1914 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
1917 if (n
> 0) /* already parent qgroups set up, let's bail */
1920 qgroups
= mfree(qgroups
);
1922 r
= btrfs_subvol_get_parent(fd
, subvol_id
, &parent_subvol
);
1924 /* No parent, hence no qgroup memberships */
1929 n
= btrfs_qgroup_find_parents(fd
, parent_subvol
, &qgroups
);
1934 if (insert_intermediary_qgroup
) {
1935 uint64_t lowest
= 256, new_qgroupid
;
1936 bool created
= false;
1939 /* Determine the lowest qgroup that the parent
1940 * subvolume is assigned to. */
1942 for (i
= 0; i
< n
; i
++) {
1945 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, NULL
);
1953 if (lowest
<= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1956 r
= btrfs_qgroupid_make(lowest
- 1, subvol_id
, &new_qgroupid
);
1960 /* Create the new intermediary group, unless it already exists */
1961 r
= btrfs_qgroup_create(fd
, new_qgroupid
);
1962 if (r
< 0 && r
!= -EEXIST
)
1965 changed
= created
= true;
1967 for (i
= 0; i
< n
; i
++) {
1968 r
= btrfs_qgroup_assign(fd
, new_qgroupid
, qgroups
[i
]);
1969 if (r
< 0 && r
!= -EEXIST
) {
1971 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1979 r
= btrfs_qgroup_assign(fd
, subvol_id
, new_qgroupid
);
1980 if (r
< 0 && r
!= -EEXIST
) {
1982 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1991 /* Assign our subvolume to all the same qgroups as the parent */
1993 for (i
= 0; i
< n
; i
++) {
1994 r
= btrfs_qgroup_assign(fd
, subvol_id
, qgroups
[i
]);
1995 if (r
< 0 && r
!= -EEXIST
)
2005 int btrfs_subvol_auto_qgroup(const char *path
, uint64_t subvol_id
, bool create_intermediary_qgroup
) {
2006 _cleanup_close_
int fd
= -1;
2008 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
2012 return btrfs_subvol_auto_qgroup_fd(fd
, subvol_id
, create_intermediary_qgroup
);
2015 int btrfs_subvol_get_parent(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
2017 struct btrfs_ioctl_search_args args
= {
2018 /* Tree of tree roots */
2019 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
2021 /* Look precisely for the subvolume items */
2022 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
2023 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
2025 /* No restrictions on the other components */
2026 .key
.min_offset
= 0,
2027 .key
.max_offset
= (uint64_t) -1,
2029 .key
.min_transid
= 0,
2030 .key
.max_transid
= (uint64_t) -1,
2037 if (subvol_id
== 0) {
2038 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
2042 r
= btrfs_is_filesystem(fd
);
2049 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
2051 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
2052 const struct btrfs_ioctl_search_header
*sh
;
2055 args
.key
.nr_items
= 256;
2056 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
2057 return negative_errno();
2059 if (args
.key
.nr_items
<= 0)
2062 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
2064 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
2066 if (sh
->objectid
!= subvol_id
)