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 #ifdef HAVE_LINUX_BTRFS_H
26 #include <linux/btrfs.h>
29 #include "btrfs-ctree.h"
30 #include "btrfs-util.h"
36 #include "path-util.h"
37 #include "selinux-util.h"
38 #include "smack-util.h"
39 #include "string-util.h"
42 /* WARNING: Be careful with file system ioctls! When we get an fd, we
43 * need to make sure it either refers to only a regular file or
44 * directory, or that it is located on btrfs, before invoking any
45 * btrfs ioctls. The ioctl numbers are reused by some device drivers
46 * (such as DRM), and hence might have bad effects when invoked on
47 * device nodes (that reference drivers) rather than fds to normal
48 * files or directories. */
50 static int validate_subvolume_name(const char *name
) {
52 if (!filename_is_valid(name
))
55 if (strlen(name
) > BTRFS_SUBVOL_NAME_MAX
)
61 static int open_parent(const char *path
, int flags
) {
62 _cleanup_free_
char *parent
= NULL
;
67 parent
= dirname_malloc(path
);
71 fd
= open(parent
, flags
);
78 static int extract_subvolume_name(const char *path
, const char **subvolume
) {
87 r
= validate_subvolume_name(fn
);
95 int btrfs_is_filesystem(int fd
) {
100 if (fstatfs(fd
, &sfs
) < 0)
103 return F_TYPE_EQUAL(sfs
.f_type
, BTRFS_SUPER_MAGIC
);
106 int btrfs_is_subvol(int fd
) {
111 /* On btrfs subvolumes always have the inode 256 */
113 if (fstat(fd
, &st
) < 0)
116 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
119 return btrfs_is_filesystem(fd
);
122 int btrfs_subvol_make(const char *path
) {
123 struct btrfs_ioctl_vol_args args
= {};
124 _cleanup_close_
int fd
= -1;
125 const char *subvolume
;
130 r
= extract_subvolume_name(path
, &subvolume
);
134 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
138 strncpy(args
.name
, subvolume
, sizeof(args
.name
)-1);
140 if (ioctl(fd
, BTRFS_IOC_SUBVOL_CREATE
, &args
) < 0)
146 int btrfs_subvol_make_label(const char *path
) {
151 r
= mac_selinux_create_file_prepare(path
, S_IFDIR
);
155 r
= btrfs_subvol_make(path
);
156 mac_selinux_create_file_clear();
161 return mac_smack_fix(path
, false, false);
164 int btrfs_subvol_set_read_only_fd(int fd
, bool b
) {
165 uint64_t flags
, nflags
;
170 if (fstat(fd
, &st
) < 0)
173 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
176 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
180 nflags
= flags
| BTRFS_SUBVOL_RDONLY
;
182 nflags
= flags
& ~BTRFS_SUBVOL_RDONLY
;
187 if (ioctl(fd
, BTRFS_IOC_SUBVOL_SETFLAGS
, &nflags
) < 0)
193 int btrfs_subvol_set_read_only(const char *path
, bool b
) {
194 _cleanup_close_
int fd
= -1;
196 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
200 return btrfs_subvol_set_read_only_fd(fd
, b
);
203 int btrfs_subvol_get_read_only_fd(int fd
) {
209 if (fstat(fd
, &st
) < 0)
212 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
215 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
218 return !!(flags
& BTRFS_SUBVOL_RDONLY
);
221 int btrfs_reflink(int infd
, int outfd
) {
228 /* Make sure we invoke the ioctl on a regular file, so that no
229 * device driver accidentally gets it. */
231 if (fstat(outfd
, &st
) < 0)
234 if (!S_ISREG(st
.st_mode
))
237 r
= ioctl(outfd
, BTRFS_IOC_CLONE
, infd
);
244 int btrfs_clone_range(int infd
, uint64_t in_offset
, int outfd
, uint64_t out_offset
, uint64_t sz
) {
245 struct btrfs_ioctl_clone_range_args args
= {
247 .src_offset
= in_offset
,
249 .dest_offset
= out_offset
,
258 if (fstat(outfd
, &st
) < 0)
261 if (!S_ISREG(st
.st_mode
))
264 r
= ioctl(outfd
, BTRFS_IOC_CLONE_RANGE
, &args
);
271 int btrfs_get_block_device_fd(int fd
, dev_t
*dev
) {
272 struct btrfs_ioctl_fs_info_args fsi
= {};
279 r
= btrfs_is_filesystem(fd
);
285 if (ioctl(fd
, BTRFS_IOC_FS_INFO
, &fsi
) < 0)
288 /* We won't do this for btrfs RAID */
289 if (fsi
.num_devices
!= 1)
292 for (id
= 1; id
<= fsi
.max_id
; id
++) {
293 struct btrfs_ioctl_dev_info_args di
= {
298 if (ioctl(fd
, BTRFS_IOC_DEV_INFO
, &di
) < 0) {
305 if (stat((char*) di
.path
, &st
) < 0)
308 if (!S_ISBLK(st
.st_mode
))
311 if (major(st
.st_rdev
) == 0)
321 int btrfs_get_block_device(const char *path
, dev_t
*dev
) {
322 _cleanup_close_
int fd
= -1;
327 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
331 return btrfs_get_block_device_fd(fd
, dev
);
334 int btrfs_subvol_get_id_fd(int fd
, uint64_t *ret
) {
335 struct btrfs_ioctl_ino_lookup_args args
= {
336 .objectid
= BTRFS_FIRST_FREE_OBJECTID
343 r
= btrfs_is_filesystem(fd
);
349 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
) < 0)
356 int btrfs_subvol_get_id(int fd
, const char *subvol
, uint64_t *ret
) {
357 _cleanup_close_
int subvol_fd
= -1;
362 subvol_fd
= openat(fd
, subvol
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
366 return btrfs_subvol_get_id_fd(subvol_fd
, ret
);
369 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args
*args
) {
372 /* the objectid, type, offset together make up the btrfs key,
373 * which is considered a single 136byte integer when
374 * comparing. This call increases the counter by one, dealing
375 * with the overflow between the overflows */
377 if (args
->key
.min_offset
< (uint64_t) -1) {
378 args
->key
.min_offset
++;
382 if (args
->key
.min_type
< (uint8_t) -1) {
383 args
->key
.min_type
++;
384 args
->key
.min_offset
= 0;
388 if (args
->key
.min_objectid
< (uint64_t) -1) {
389 args
->key
.min_objectid
++;
390 args
->key
.min_offset
= 0;
391 args
->key
.min_type
= 0;
398 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args
*args
, const struct btrfs_ioctl_search_header
*h
) {
402 args
->key
.min_objectid
= h
->objectid
;
403 args
->key
.min_type
= h
->type
;
404 args
->key
.min_offset
= h
->offset
;
407 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
*args
) {
410 /* Compare min and max */
412 if (args
->key
.min_objectid
< args
->key
.max_objectid
)
414 if (args
->key
.min_objectid
> args
->key
.max_objectid
)
417 if (args
->key
.min_type
< args
->key
.max_type
)
419 if (args
->key
.min_type
> args
->key
.max_type
)
422 if (args
->key
.min_offset
< args
->key
.max_offset
)
424 if (args
->key
.min_offset
> args
->key
.max_offset
)
430 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
432 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
433 (i) < (args).key.nr_items; \
435 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
437 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
438 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
440 int btrfs_subvol_get_info_fd(int fd
, uint64_t subvol_id
, BtrfsSubvolInfo
*ret
) {
441 struct btrfs_ioctl_search_args args
= {
442 /* Tree of tree roots */
443 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
445 /* Look precisely for the subvolume items */
446 .key
.min_type
= BTRFS_ROOT_ITEM_KEY
,
447 .key
.max_type
= BTRFS_ROOT_ITEM_KEY
,
450 .key
.max_offset
= (uint64_t) -1,
452 /* No restrictions on the other components */
453 .key
.min_transid
= 0,
454 .key
.max_transid
= (uint64_t) -1,
463 if (subvol_id
== 0) {
464 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
468 r
= btrfs_is_filesystem(fd
);
475 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
477 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
478 const struct btrfs_ioctl_search_header
*sh
;
481 args
.key
.nr_items
= 256;
482 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
485 if (args
.key
.nr_items
<= 0)
488 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
490 const struct btrfs_root_item
*ri
;
492 /* Make sure we start the next search at least from this entry */
493 btrfs_ioctl_search_args_set(&args
, sh
);
495 if (sh
->objectid
!= subvol_id
)
497 if (sh
->type
!= BTRFS_ROOT_ITEM_KEY
)
500 /* Older versions of the struct lacked the otime setting */
501 if (sh
->len
< offsetof(struct btrfs_root_item
, otime
) + sizeof(struct btrfs_timespec
))
504 ri
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
506 ret
->otime
= (usec_t
) le64toh(ri
->otime
.sec
) * USEC_PER_SEC
+
507 (usec_t
) le32toh(ri
->otime
.nsec
) / NSEC_PER_USEC
;
509 ret
->subvol_id
= subvol_id
;
510 ret
->read_only
= !!(le64toh(ri
->flags
) & BTRFS_ROOT_SUBVOL_RDONLY
);
512 assert_cc(sizeof(ri
->uuid
) == sizeof(ret
->uuid
));
513 memcpy(&ret
->uuid
, ri
->uuid
, sizeof(ret
->uuid
));
514 memcpy(&ret
->parent_uuid
, ri
->parent_uuid
, sizeof(ret
->parent_uuid
));
520 /* Increase search key by one, to read the next item, if we can. */
521 if (!btrfs_ioctl_search_args_inc(&args
))
532 int btrfs_qgroup_get_quota_fd(int fd
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
534 struct btrfs_ioctl_search_args args
= {
535 /* Tree of quota items */
536 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
538 /* The object ID is always 0 */
539 .key
.min_objectid
= 0,
540 .key
.max_objectid
= 0,
542 /* Look precisely for the quota items */
543 .key
.min_type
= BTRFS_QGROUP_STATUS_KEY
,
544 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
546 /* No restrictions on the other components */
547 .key
.min_transid
= 0,
548 .key
.max_transid
= (uint64_t) -1,
551 bool found_info
= false, found_limit
= false;
558 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
562 r
= btrfs_is_filesystem(fd
);
569 args
.key
.min_offset
= args
.key
.max_offset
= qgroupid
;
571 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
572 const struct btrfs_ioctl_search_header
*sh
;
575 args
.key
.nr_items
= 256;
576 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
579 if (args
.key
.nr_items
<= 0)
582 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
584 /* Make sure we start the next search at least from this entry */
585 btrfs_ioctl_search_args_set(&args
, sh
);
587 if (sh
->objectid
!= 0)
589 if (sh
->offset
!= qgroupid
)
592 if (sh
->type
== BTRFS_QGROUP_INFO_KEY
) {
593 const struct btrfs_qgroup_info_item
*qii
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
595 ret
->referenced
= le64toh(qii
->rfer
);
596 ret
->exclusive
= le64toh(qii
->excl
);
600 } else if (sh
->type
== BTRFS_QGROUP_LIMIT_KEY
) {
601 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
603 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_RFER
)
604 ret
->referenced_max
= le64toh(qli
->max_rfer
);
606 ret
->referenced_max
= (uint64_t) -1;
608 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_EXCL
)
609 ret
->exclusive_max
= le64toh(qli
->max_excl
);
611 ret
->exclusive_max
= (uint64_t) -1;
616 if (found_info
&& found_limit
)
620 /* Increase search key by one, to read the next item, if we can. */
621 if (!btrfs_ioctl_search_args_inc(&args
))
626 if (!found_limit
&& !found_info
)
630 ret
->referenced
= (uint64_t) -1;
631 ret
->exclusive
= (uint64_t) -1;
635 ret
->referenced_max
= (uint64_t) -1;
636 ret
->exclusive_max
= (uint64_t) -1;
642 int btrfs_qgroup_get_quota(const char *path
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
643 _cleanup_close_
int fd
= -1;
645 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
649 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
652 int btrfs_subvol_find_subtree_qgroup(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
653 uint64_t level
, lowest
= (uint64_t) -1, lowest_qgroupid
= 0;
654 _cleanup_free_
uint64_t *qgroups
= NULL
;
660 /* This finds the "subtree" qgroup for a specific
661 * subvolume. This only works for subvolumes that have been
662 * prepared with btrfs_subvol_auto_qgroup_fd() with
663 * insert_intermediary_qgroup=true (or equivalent). For others
664 * it will return the leaf qgroup instead. The two cases may
665 * be distuingished via the return value, which is 1 in case
666 * an appropriate "subtree" qgroup was found, and 0
669 if (subvol_id
== 0) {
670 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
675 r
= btrfs_qgroupid_split(subvol_id
, &level
, NULL
);
678 if (level
!= 0) /* Input must be a leaf qgroup */
681 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
685 for (i
= 0; i
< n
; i
++) {
688 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, &id
);
695 if (lowest
== (uint64_t) -1 || level
< lowest
) {
696 lowest_qgroupid
= qgroups
[i
];
701 if (lowest
== (uint64_t) -1) {
702 /* No suitable higher-level qgroup found, let's return
703 * the leaf qgroup instead, and indicate that with the
710 *ret
= lowest_qgroupid
;
714 int btrfs_subvol_get_subtree_quota_fd(int fd
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
721 /* This determines the quota data of the qgroup with the
722 * lowest level, that shares the id part with the specified
723 * subvolume. This is useful for determining the quota data
724 * for entire subvolume subtrees, as long as the subtrees have
725 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
728 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
732 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
735 int btrfs_subvol_get_subtree_quota(const char *path
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
736 _cleanup_close_
int fd
= -1;
738 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
742 return btrfs_subvol_get_subtree_quota_fd(fd
, subvol_id
, ret
);
745 int btrfs_defrag_fd(int fd
) {
750 if (fstat(fd
, &st
) < 0)
753 if (!S_ISREG(st
.st_mode
))
756 if (ioctl(fd
, BTRFS_IOC_DEFRAG
, NULL
) < 0)
762 int btrfs_defrag(const char *p
) {
763 _cleanup_close_
int fd
= -1;
765 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
769 return btrfs_defrag_fd(fd
);
772 int btrfs_quota_enable_fd(int fd
, bool b
) {
773 struct btrfs_ioctl_quota_ctl_args args
= {
774 .cmd
= b
? BTRFS_QUOTA_CTL_ENABLE
: BTRFS_QUOTA_CTL_DISABLE
,
780 r
= btrfs_is_filesystem(fd
);
786 if (ioctl(fd
, BTRFS_IOC_QUOTA_CTL
, &args
) < 0)
792 int btrfs_quota_enable(const char *path
, bool b
) {
793 _cleanup_close_
int fd
= -1;
795 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
799 return btrfs_quota_enable_fd(fd
, b
);
802 int btrfs_qgroup_set_limit_fd(int fd
, uint64_t qgroupid
, uint64_t referenced_max
) {
804 struct btrfs_ioctl_qgroup_limit_args args
= {
805 .lim
.max_rfer
= referenced_max
,
806 .lim
.flags
= BTRFS_QGROUP_LIMIT_MAX_RFER
,
814 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
818 r
= btrfs_is_filesystem(fd
);
825 args
.qgroupid
= qgroupid
;
828 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &args
) < 0) {
830 if (errno
== EBUSY
&& c
< 10) {
831 (void) btrfs_quota_scan_wait(fd
);
844 int btrfs_qgroup_set_limit(const char *path
, uint64_t qgroupid
, uint64_t referenced_max
) {
845 _cleanup_close_
int fd
= -1;
847 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
851 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
854 int btrfs_subvol_set_subtree_quota_limit_fd(int fd
, uint64_t subvol_id
, uint64_t referenced_max
) {
860 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
864 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
867 int btrfs_subvol_set_subtree_quota_limit(const char *path
, uint64_t subvol_id
, uint64_t referenced_max
) {
868 _cleanup_close_
int fd
= -1;
870 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
874 return btrfs_subvol_set_subtree_quota_limit_fd(fd
, subvol_id
, referenced_max
);
877 int btrfs_resize_loopback_fd(int fd
, uint64_t new_size
, bool grow_only
) {
878 struct btrfs_ioctl_vol_args args
= {};
879 _cleanup_free_
char *p
= NULL
, *loop
= NULL
, *backing
= NULL
;
880 _cleanup_close_
int loop_fd
= -1, backing_fd
= -1;
885 /* btrfs cannot handle file systems < 16M, hence use this as minimum */
886 if (new_size
< 16*1024*1024)
887 new_size
= 16*1024*1024;
889 r
= btrfs_get_block_device_fd(fd
, &dev
);
895 if (asprintf(&p
, "/sys/dev/block/%u:%u/loop/backing_file", major(dev
), minor(dev
)) < 0)
897 r
= read_one_line_file(p
, &backing
);
902 if (isempty(backing
) || !path_is_absolute(backing
))
905 backing_fd
= open(backing
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
909 if (fstat(backing_fd
, &st
) < 0)
911 if (!S_ISREG(st
.st_mode
))
914 if (new_size
== (uint64_t) st
.st_size
)
917 if (grow_only
&& new_size
< (uint64_t) st
.st_size
)
920 if (asprintf(&loop
, "/dev/block/%u:%u", major(dev
), minor(dev
)) < 0)
922 loop_fd
= open(loop
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
926 if (snprintf(args
.name
, sizeof(args
.name
), "%" PRIu64
, new_size
) >= (int) sizeof(args
.name
))
929 if (new_size
< (uint64_t) st
.st_size
) {
930 /* Decrease size: first decrease btrfs size, then shorten loopback */
931 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
935 if (ftruncate(backing_fd
, new_size
) < 0)
938 if (ioctl(loop_fd
, LOOP_SET_CAPACITY
, 0) < 0)
941 if (new_size
> (uint64_t) st
.st_size
) {
942 /* Increase size: first enlarge loopback, then increase btrfs size */
943 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
947 /* Make sure the free disk space is correctly updated for both file systems */
949 (void) fsync(backing_fd
);
954 int btrfs_resize_loopback(const char *p
, uint64_t new_size
, bool grow_only
) {
955 _cleanup_close_
int fd
= -1;
957 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
961 return btrfs_resize_loopback_fd(fd
, new_size
, grow_only
);
964 int btrfs_qgroupid_make(uint64_t level
, uint64_t id
, uint64_t *ret
) {
967 if (level
>= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT
)))
970 if (id
>= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
))
973 *ret
= (level
<< BTRFS_QGROUP_LEVEL_SHIFT
) | id
;
977 int btrfs_qgroupid_split(uint64_t qgroupid
, uint64_t *level
, uint64_t *id
) {
981 *level
= qgroupid
>> BTRFS_QGROUP_LEVEL_SHIFT
;
984 *id
= qgroupid
& ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
) - 1);
989 static int qgroup_create_or_destroy(int fd
, bool b
, uint64_t qgroupid
) {
991 struct btrfs_ioctl_qgroup_create_args args
= {
993 .qgroupid
= qgroupid
,
998 r
= btrfs_is_filesystem(fd
);
1005 if (ioctl(fd
, BTRFS_IOC_QGROUP_CREATE
, &args
) < 0) {
1007 if (errno
== EBUSY
&& c
< 10) {
1008 (void) btrfs_quota_scan_wait(fd
);
1021 int btrfs_qgroup_create(int fd
, uint64_t qgroupid
) {
1022 return qgroup_create_or_destroy(fd
, true, qgroupid
);
1025 int btrfs_qgroup_destroy(int fd
, uint64_t qgroupid
) {
1026 return qgroup_create_or_destroy(fd
, false, qgroupid
);
1029 int btrfs_qgroup_destroy_recursive(int fd
, uint64_t qgroupid
) {
1030 _cleanup_free_
uint64_t *qgroups
= NULL
;
1034 /* Destroys the specified qgroup, but unassigns it from all
1035 * its parents first. Also, it recursively destroys all
1036 * qgroups it is assgined to that have the same id part of the
1037 * qgroupid as the specified group. */
1039 r
= btrfs_qgroupid_split(qgroupid
, NULL
, &subvol_id
);
1043 n
= btrfs_qgroup_find_parents(fd
, qgroupid
, &qgroups
);
1047 for (i
= 0; i
< n
; i
++) {
1050 r
= btrfs_qgroupid_split(qgroups
[i
], NULL
, &id
);
1054 r
= btrfs_qgroup_unassign(fd
, qgroupid
, qgroups
[i
]);
1058 if (id
!= subvol_id
)
1061 /* The parent qgroupid shares the same id part with
1062 * us? If so, destroy it too. */
1064 (void) btrfs_qgroup_destroy_recursive(fd
, qgroups
[i
]);
1067 return btrfs_qgroup_destroy(fd
, qgroupid
);
1070 int btrfs_quota_scan_start(int fd
) {
1071 struct btrfs_ioctl_quota_rescan_args args
= {};
1075 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN
, &args
) < 0)
1081 int btrfs_quota_scan_wait(int fd
) {
1084 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_WAIT
) < 0)
1090 int btrfs_quota_scan_ongoing(int fd
) {
1091 struct btrfs_ioctl_quota_rescan_args args
= {};
1095 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_STATUS
, &args
) < 0)
1098 return !!args
.flags
;
1101 static int qgroup_assign_or_unassign(int fd
, bool b
, uint64_t child
, uint64_t parent
) {
1102 struct btrfs_ioctl_qgroup_assign_args args
= {
1110 r
= btrfs_is_filesystem(fd
);
1117 r
= ioctl(fd
, BTRFS_IOC_QGROUP_ASSIGN
, &args
);
1119 if (errno
== EBUSY
&& c
< 10) {
1120 (void) btrfs_quota_scan_wait(fd
);
1130 /* If the return value is > 0, we need to request a rescan */
1132 (void) btrfs_quota_scan_start(fd
);
1137 int btrfs_qgroup_assign(int fd
, uint64_t child
, uint64_t parent
) {
1138 return qgroup_assign_or_unassign(fd
, true, child
, parent
);
1141 int btrfs_qgroup_unassign(int fd
, uint64_t child
, uint64_t parent
) {
1142 return qgroup_assign_or_unassign(fd
, false, child
, parent
);
1145 static int subvol_remove_children(int fd
, const char *subvolume
, uint64_t subvol_id
, BtrfsRemoveFlags flags
) {
1146 struct btrfs_ioctl_search_args args
= {
1147 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1149 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1150 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1152 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1153 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1155 .key
.min_transid
= 0,
1156 .key
.max_transid
= (uint64_t) -1,
1159 struct btrfs_ioctl_vol_args vol_args
= {};
1160 _cleanup_close_
int subvol_fd
= -1;
1162 bool made_writable
= false;
1168 if (fstat(fd
, &st
) < 0)
1171 if (!S_ISDIR(st
.st_mode
))
1174 subvol_fd
= openat(fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1178 if (subvol_id
== 0) {
1179 r
= btrfs_subvol_get_id_fd(subvol_fd
, &subvol_id
);
1184 /* First, try to remove the subvolume. If it happens to be
1185 * already empty, this will just work. */
1186 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1187 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) >= 0) {
1188 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1191 if (!(flags
& BTRFS_REMOVE_RECURSIVE
) || errno
!= ENOTEMPTY
)
1194 /* OK, the subvolume is not empty, let's look for child
1195 * subvolumes, and remove them, first */
1197 args
.key
.min_offset
= args
.key
.max_offset
= subvol_id
;
1199 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1200 const struct btrfs_ioctl_search_header
*sh
;
1203 args
.key
.nr_items
= 256;
1204 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1207 if (args
.key
.nr_items
<= 0)
1210 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1211 _cleanup_free_
char *p
= NULL
;
1212 const struct btrfs_root_ref
*ref
;
1213 struct btrfs_ioctl_ino_lookup_args ino_args
;
1215 btrfs_ioctl_search_args_set(&args
, sh
);
1217 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1219 if (sh
->offset
!= subvol_id
)
1222 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1224 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1229 ino_args
.treeid
= subvol_id
;
1230 ino_args
.objectid
= htole64(ref
->dirid
);
1232 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1235 if (!made_writable
) {
1236 r
= btrfs_subvol_set_read_only_fd(subvol_fd
, false);
1240 made_writable
= true;
1243 if (isempty(ino_args
.name
))
1244 /* Subvolume is in the top-level
1245 * directory of the subvolume. */
1246 r
= subvol_remove_children(subvol_fd
, p
, sh
->objectid
, flags
);
1248 _cleanup_close_
int child_fd
= -1;
1250 /* Subvolume is somewhere further down,
1251 * hence we need to open the
1252 * containing directory first */
1254 child_fd
= openat(subvol_fd
, ino_args
.name
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1258 r
= subvol_remove_children(child_fd
, p
, sh
->objectid
, flags
);
1264 /* Increase search key by one, to read the next item, if we can. */
1265 if (!btrfs_ioctl_search_args_inc(&args
))
1269 /* OK, the child subvolumes should all be gone now, let's try
1270 * again to remove the subvolume */
1271 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) < 0)
1274 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
);
1278 int btrfs_subvol_remove(const char *path
, BtrfsRemoveFlags flags
) {
1279 _cleanup_close_
int fd
= -1;
1280 const char *subvolume
;
1285 r
= extract_subvolume_name(path
, &subvolume
);
1289 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1293 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1296 int btrfs_subvol_remove_fd(int fd
, const char *subvolume
, BtrfsRemoveFlags flags
) {
1297 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1300 int btrfs_qgroup_copy_limits(int fd
, uint64_t old_qgroupid
, uint64_t new_qgroupid
) {
1302 struct btrfs_ioctl_search_args args
= {
1303 /* Tree of quota items */
1304 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1306 /* The object ID is always 0 */
1307 .key
.min_objectid
= 0,
1308 .key
.max_objectid
= 0,
1310 /* Look precisely for the quota items */
1311 .key
.min_type
= BTRFS_QGROUP_LIMIT_KEY
,
1312 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
1314 /* For our qgroup */
1315 .key
.min_offset
= old_qgroupid
,
1316 .key
.max_offset
= old_qgroupid
,
1318 /* No restrictions on the other components */
1319 .key
.min_transid
= 0,
1320 .key
.max_transid
= (uint64_t) -1,
1325 r
= btrfs_is_filesystem(fd
);
1331 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1332 const struct btrfs_ioctl_search_header
*sh
;
1335 args
.key
.nr_items
= 256;
1336 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1339 if (args
.key
.nr_items
<= 0)
1342 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1343 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1344 struct btrfs_ioctl_qgroup_limit_args qargs
;
1347 /* Make sure we start the next search at least from this entry */
1348 btrfs_ioctl_search_args_set(&args
, sh
);
1350 if (sh
->objectid
!= 0)
1352 if (sh
->type
!= BTRFS_QGROUP_LIMIT_KEY
)
1354 if (sh
->offset
!= old_qgroupid
)
1357 /* We found the entry, now copy things over. */
1359 qargs
= (struct btrfs_ioctl_qgroup_limit_args
) {
1360 .qgroupid
= new_qgroupid
,
1362 .lim
.max_rfer
= le64toh(qli
->max_rfer
),
1363 .lim
.max_excl
= le64toh(qli
->max_excl
),
1364 .lim
.rsv_rfer
= le64toh(qli
->rsv_rfer
),
1365 .lim
.rsv_excl
= le64toh(qli
->rsv_excl
),
1367 .lim
.flags
= le64toh(qli
->flags
) & (BTRFS_QGROUP_LIMIT_MAX_RFER
|
1368 BTRFS_QGROUP_LIMIT_MAX_EXCL
|
1369 BTRFS_QGROUP_LIMIT_RSV_RFER
|
1370 BTRFS_QGROUP_LIMIT_RSV_EXCL
),
1374 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &qargs
) < 0) {
1375 if (errno
== EBUSY
&& c
< 10) {
1376 (void) btrfs_quota_scan_wait(fd
);
1388 /* Increase search key by one, to read the next item, if we can. */
1389 if (!btrfs_ioctl_search_args_inc(&args
))
1396 static int copy_quota_hierarchy(int fd
, uint64_t old_subvol_id
, uint64_t new_subvol_id
) {
1397 _cleanup_free_
uint64_t *old_qgroups
= NULL
, *old_parent_qgroups
= NULL
;
1398 bool copy_from_parent
= false, insert_intermediary_qgroup
= false;
1399 int n_old_qgroups
, n_old_parent_qgroups
, r
, i
;
1400 uint64_t old_parent_id
;
1404 /* Copies a reduced form of quota information from the old to
1405 * the new subvolume. */
1407 n_old_qgroups
= btrfs_qgroup_find_parents(fd
, old_subvol_id
, &old_qgroups
);
1408 if (n_old_qgroups
<= 0) /* Nothing to copy */
1409 return n_old_qgroups
;
1411 r
= btrfs_subvol_get_parent(fd
, old_subvol_id
, &old_parent_id
);
1415 n_old_parent_qgroups
= btrfs_qgroup_find_parents(fd
, old_parent_id
, &old_parent_qgroups
);
1416 if (n_old_parent_qgroups
< 0)
1417 return n_old_parent_qgroups
;
1419 for (i
= 0; i
< n_old_qgroups
; i
++) {
1423 r
= btrfs_qgroupid_split(old_qgroups
[i
], NULL
, &id
);
1427 if (id
== old_subvol_id
) {
1428 /* The old subvolume was member of a qgroup
1429 * that had the same id, but a different level
1430 * as it self. Let's set up something similar
1431 * in the destination. */
1432 insert_intermediary_qgroup
= true;
1436 for (j
= 0; j
< n_old_parent_qgroups
; j
++)
1437 if (old_parent_qgroups
[j
] == old_qgroups
[i
]) {
1438 /* The old subvolume shared a common
1439 * parent qgroup with its parent
1440 * subvolume. Let's set up something
1441 * similar in the destination. */
1442 copy_from_parent
= true;
1446 if (!insert_intermediary_qgroup
&& !copy_from_parent
)
1449 return btrfs_subvol_auto_qgroup_fd(fd
, new_subvol_id
, insert_intermediary_qgroup
);
1452 static int copy_subtree_quota_limits(int fd
, uint64_t old_subvol
, uint64_t new_subvol
) {
1453 uint64_t old_subtree_qgroup
, new_subtree_qgroup
;
1457 /* First copy the leaf limits */
1458 r
= btrfs_qgroup_copy_limits(fd
, old_subvol
, new_subvol
);
1463 /* Then, try to copy the subtree limits, if there are any. */
1464 r
= btrfs_subvol_find_subtree_qgroup(fd
, old_subvol
, &old_subtree_qgroup
);
1470 r
= btrfs_subvol_find_subtree_qgroup(fd
, new_subvol
, &new_subtree_qgroup
);
1476 r
= btrfs_qgroup_copy_limits(fd
, old_subtree_qgroup
, new_subtree_qgroup
);
1483 static int subvol_snapshot_children(int old_fd
, int new_fd
, const char *subvolume
, uint64_t old_subvol_id
, BtrfsSnapshotFlags flags
) {
1485 struct btrfs_ioctl_search_args args
= {
1486 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1488 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1489 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1491 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1492 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1494 .key
.min_transid
= 0,
1495 .key
.max_transid
= (uint64_t) -1,
1498 struct btrfs_ioctl_vol_args_v2 vol_args
= {
1499 .flags
= flags
& BTRFS_SNAPSHOT_READ_ONLY
? BTRFS_SUBVOL_RDONLY
: 0,
1502 _cleanup_close_
int subvolume_fd
= -1;
1503 uint64_t new_subvol_id
;
1506 assert(old_fd
>= 0);
1507 assert(new_fd
>= 0);
1510 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1512 if (ioctl(new_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &vol_args
) < 0)
1515 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
) &&
1516 !(flags
& BTRFS_SNAPSHOT_QUOTA
))
1519 if (old_subvol_id
== 0) {
1520 r
= btrfs_subvol_get_id_fd(old_fd
, &old_subvol_id
);
1525 r
= btrfs_subvol_get_id(new_fd
, vol_args
.name
, &new_subvol_id
);
1529 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1530 (void) copy_quota_hierarchy(new_fd
, old_subvol_id
, new_subvol_id
);
1532 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
)) {
1534 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1535 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1540 args
.key
.min_offset
= args
.key
.max_offset
= old_subvol_id
;
1542 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1543 const struct btrfs_ioctl_search_header
*sh
;
1546 args
.key
.nr_items
= 256;
1547 if (ioctl(old_fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1550 if (args
.key
.nr_items
<= 0)
1553 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1554 _cleanup_free_
char *p
= NULL
, *c
= NULL
, *np
= NULL
;
1555 struct btrfs_ioctl_ino_lookup_args ino_args
;
1556 const struct btrfs_root_ref
*ref
;
1557 _cleanup_close_
int old_child_fd
= -1, new_child_fd
= -1;
1559 btrfs_ioctl_search_args_set(&args
, sh
);
1561 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1564 /* Avoid finding the source subvolume a second
1566 if (sh
->offset
!= old_subvol_id
)
1569 /* Avoid running into loops if the new
1570 * subvolume is below the old one. */
1571 if (sh
->objectid
== new_subvol_id
)
1574 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1575 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1580 ino_args
.treeid
= old_subvol_id
;
1581 ino_args
.objectid
= htole64(ref
->dirid
);
1583 if (ioctl(old_fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1586 /* The kernel returns an empty name if the
1587 * subvolume is in the top-level directory,
1588 * and otherwise appends a slash, so that we
1589 * can just concatenate easily here, without
1590 * adding a slash. */
1591 c
= strappend(ino_args
.name
, p
);
1595 old_child_fd
= openat(old_fd
, c
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1596 if (old_child_fd
< 0)
1599 np
= strjoin(subvolume
, "/", ino_args
.name
, NULL
);
1603 new_child_fd
= openat(new_fd
, np
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1604 if (new_child_fd
< 0)
1607 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1608 /* If the snapshot is read-only we
1609 * need to mark it writable
1610 * temporarily, to put the subsnapshot
1613 if (subvolume_fd
< 0) {
1614 subvolume_fd
= openat(new_fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1615 if (subvolume_fd
< 0)
1619 r
= btrfs_subvol_set_read_only_fd(subvolume_fd
, false);
1624 /* When btrfs clones the subvolumes, child
1625 * subvolumes appear as empty directories. Remove
1626 * them, so that we can create a new snapshot
1628 if (unlinkat(new_child_fd
, p
, AT_REMOVEDIR
) < 0) {
1631 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
)
1632 (void) btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1637 r
= subvol_snapshot_children(old_child_fd
, new_child_fd
, p
, sh
->objectid
, flags
& ~BTRFS_SNAPSHOT_FALLBACK_COPY
);
1639 /* Restore the readonly flag */
1640 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1643 k
= btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1644 if (r
>= 0 && k
< 0)
1652 /* Increase search key by one, to read the next item, if we can. */
1653 if (!btrfs_ioctl_search_args_inc(&args
))
1657 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1658 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1663 int btrfs_subvol_snapshot_fd(int old_fd
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1664 _cleanup_close_
int new_fd
= -1;
1665 const char *subvolume
;
1668 assert(old_fd
>= 0);
1671 r
= btrfs_is_subvol(old_fd
);
1675 if (!(flags
& BTRFS_SNAPSHOT_FALLBACK_COPY
))
1678 r
= btrfs_subvol_make(new_path
);
1682 r
= copy_directory_fd(old_fd
, new_path
, true);
1684 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1688 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1689 r
= btrfs_subvol_set_read_only(new_path
, true);
1691 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1699 r
= extract_subvolume_name(new_path
, &subvolume
);
1703 new_fd
= open_parent(new_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1707 return subvol_snapshot_children(old_fd
, new_fd
, subvolume
, 0, flags
);
1710 int btrfs_subvol_snapshot(const char *old_path
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1711 _cleanup_close_
int old_fd
= -1;
1716 old_fd
= open(old_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1720 return btrfs_subvol_snapshot_fd(old_fd
, new_path
, flags
);
1723 int btrfs_qgroup_find_parents(int fd
, uint64_t qgroupid
, uint64_t **ret
) {
1725 struct btrfs_ioctl_search_args args
= {
1726 /* Tree of quota items */
1727 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1729 /* Look precisely for the quota relation items */
1730 .key
.min_type
= BTRFS_QGROUP_RELATION_KEY
,
1731 .key
.max_type
= BTRFS_QGROUP_RELATION_KEY
,
1733 /* No restrictions on the other components */
1734 .key
.min_offset
= 0,
1735 .key
.max_offset
= (uint64_t) -1,
1737 .key
.min_transid
= 0,
1738 .key
.max_transid
= (uint64_t) -1,
1741 _cleanup_free_
uint64_t *items
= NULL
;
1742 size_t n_items
= 0, n_allocated
= 0;
1748 if (qgroupid
== 0) {
1749 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
1753 r
= btrfs_is_filesystem(fd
);
1760 args
.key
.min_objectid
= args
.key
.max_objectid
= qgroupid
;
1762 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1763 const struct btrfs_ioctl_search_header
*sh
;
1766 args
.key
.nr_items
= 256;
1767 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1770 if (args
.key
.nr_items
<= 0)
1773 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1775 /* Make sure we start the next search at least from this entry */
1776 btrfs_ioctl_search_args_set(&args
, sh
);
1778 if (sh
->type
!= BTRFS_QGROUP_RELATION_KEY
)
1780 if (sh
->offset
< sh
->objectid
)
1782 if (sh
->objectid
!= qgroupid
)
1785 if (!GREEDY_REALLOC(items
, n_allocated
, n_items
+1))
1788 items
[n_items
++] = sh
->offset
;
1791 /* Increase search key by one, to read the next item, if we can. */
1792 if (!btrfs_ioctl_search_args_inc(&args
))
1804 return (int) n_items
;
1807 int btrfs_subvol_auto_qgroup_fd(int fd
, uint64_t subvol_id
, bool insert_intermediary_qgroup
) {
1808 _cleanup_free_
uint64_t *qgroups
= NULL
;
1809 uint64_t parent_subvol
;
1810 bool changed
= false;
1816 * Sets up the specified subvolume's qgroup automatically in
1819 * If insert_intermediary_qgroup is false, the subvolume's
1820 * leaf qgroup will be assigned to the same parent qgroups as
1821 * the subvolume's parent subvolume.
1823 * If insert_intermediary_qgroup is true a new intermediary
1824 * higher-level qgroup is created, with a higher level number,
1825 * but reusing the id of the subvolume. The level number is
1826 * picked as one smaller than the lowest level qgroup the
1827 * parent subvolume is a member of. If the parent subvolume's
1828 * leaf qgroup is assigned to no higher-level qgroup a new
1829 * qgroup of level 255 is created instead. Either way, the new
1830 * qgroup is then assigned to the parent's higher-level
1831 * qgroup, and the subvolume itself is assigned to it.
1833 * If the subvolume is already assigned to a higher level
1834 * qgroup, no operation is executed.
1836 * Effectively this means: regardless if
1837 * insert_intermediary_qgroup is true or not, after this
1838 * function is invoked the subvolume will be accounted within
1839 * the same qgroups as the parent. However, if it is true, it
1840 * will also get its own higher-level qgroup, which may in
1841 * turn be used by subvolumes created beneath this subvolume
1844 * This hence defines a simple default qgroup setup for
1845 * subvolumes, as long as this function is invoked on each
1846 * created subvolume: each subvolume is always accounting
1847 * together with its immediate parents. Optionally, if
1848 * insert_intermediary_qgroup is true, it will also get a
1849 * qgroup that then includes all its own child subvolumes.
1852 if (subvol_id
== 0) {
1853 r
= btrfs_is_subvol(fd
);
1859 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1864 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
1867 if (n
> 0) /* already parent qgroups set up, let's bail */
1870 r
= btrfs_subvol_get_parent(fd
, subvol_id
, &parent_subvol
);
1874 qgroups
= mfree(qgroups
);
1875 n
= btrfs_qgroup_find_parents(fd
, parent_subvol
, &qgroups
);
1879 if (insert_intermediary_qgroup
) {
1880 uint64_t lowest
= 256, new_qgroupid
;
1881 bool created
= false;
1884 /* Determine the lowest qgroup that the parent
1885 * subvolume is assigned to. */
1887 for (i
= 0; i
< n
; i
++) {
1890 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, NULL
);
1898 if (lowest
<= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1901 r
= btrfs_qgroupid_make(lowest
- 1, subvol_id
, &new_qgroupid
);
1905 /* Create the new intermediary group, unless it already exists */
1906 r
= btrfs_qgroup_create(fd
, new_qgroupid
);
1907 if (r
< 0 && r
!= -EEXIST
)
1910 changed
= created
= true;
1912 for (i
= 0; i
< n
; i
++) {
1913 r
= btrfs_qgroup_assign(fd
, new_qgroupid
, qgroups
[i
]);
1914 if (r
< 0 && r
!= -EEXIST
) {
1916 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1924 r
= btrfs_qgroup_assign(fd
, subvol_id
, new_qgroupid
);
1925 if (r
< 0 && r
!= -EEXIST
) {
1927 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1936 /* Assign our subvolume to all the same qgroups as the parent */
1938 for (i
= 0; i
< n
; i
++) {
1939 r
= btrfs_qgroup_assign(fd
, subvol_id
, qgroups
[i
]);
1940 if (r
< 0 && r
!= -EEXIST
)
1950 int btrfs_subvol_auto_qgroup(const char *path
, uint64_t subvol_id
, bool create_intermediary_qgroup
) {
1951 _cleanup_close_
int fd
= -1;
1953 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1957 return btrfs_subvol_auto_qgroup_fd(fd
, subvol_id
, create_intermediary_qgroup
);
1960 int btrfs_subvol_get_parent(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
1962 struct btrfs_ioctl_search_args args
= {
1963 /* Tree of tree roots */
1964 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1966 /* Look precisely for the subvolume items */
1967 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1968 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1970 /* No restrictions on the other components */
1971 .key
.min_offset
= 0,
1972 .key
.max_offset
= (uint64_t) -1,
1974 .key
.min_transid
= 0,
1975 .key
.max_transid
= (uint64_t) -1,
1982 if (subvol_id
== 0) {
1983 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1987 r
= btrfs_is_filesystem(fd
);
1994 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
1996 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1997 const struct btrfs_ioctl_search_header
*sh
;
2000 args
.key
.nr_items
= 256;
2001 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
2004 if (args
.key
.nr_items
<= 0)
2007 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
2009 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
2011 if (sh
->objectid
!= subvol_id
)