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 "alloc-util.h"
30 #include "btrfs-ctree.h"
31 #include "btrfs-util.h"
37 #include "path-util.h"
38 #include "selinux-util.h"
39 #include "smack-util.h"
40 #include "stat-util.h"
41 #include "string-util.h"
44 /* WARNING: Be careful with file system ioctls! When we get an fd, we
45 * need to make sure it either refers to only a regular file or
46 * directory, or that it is located on btrfs, before invoking any
47 * btrfs ioctls. The ioctl numbers are reused by some device drivers
48 * (such as DRM), and hence might have bad effects when invoked on
49 * device nodes (that reference drivers) rather than fds to normal
50 * files or directories. */
52 static int validate_subvolume_name(const char *name
) {
54 if (!filename_is_valid(name
))
57 if (strlen(name
) > BTRFS_SUBVOL_NAME_MAX
)
63 static int open_parent(const char *path
, int flags
) {
64 _cleanup_free_
char *parent
= NULL
;
69 parent
= dirname_malloc(path
);
73 fd
= open(parent
, flags
);
80 static int extract_subvolume_name(const char *path
, const char **subvolume
) {
89 r
= validate_subvolume_name(fn
);
97 int btrfs_is_filesystem(int fd
) {
102 if (fstatfs(fd
, &sfs
) < 0)
105 return F_TYPE_EQUAL(sfs
.f_type
, BTRFS_SUPER_MAGIC
);
108 int btrfs_is_subvol(int fd
) {
113 /* On btrfs subvolumes always have the inode 256 */
115 if (fstat(fd
, &st
) < 0)
118 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
121 return btrfs_is_filesystem(fd
);
124 int btrfs_subvol_make(const char *path
) {
125 struct btrfs_ioctl_vol_args args
= {};
126 _cleanup_close_
int fd
= -1;
127 const char *subvolume
;
132 r
= extract_subvolume_name(path
, &subvolume
);
136 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
140 strncpy(args
.name
, subvolume
, sizeof(args
.name
)-1);
142 if (ioctl(fd
, BTRFS_IOC_SUBVOL_CREATE
, &args
) < 0)
148 int btrfs_subvol_make_label(const char *path
) {
153 r
= mac_selinux_create_file_prepare(path
, S_IFDIR
);
157 r
= btrfs_subvol_make(path
);
158 mac_selinux_create_file_clear();
163 return mac_smack_fix(path
, false, false);
166 int btrfs_subvol_set_read_only_fd(int fd
, bool b
) {
167 uint64_t flags
, nflags
;
172 if (fstat(fd
, &st
) < 0)
175 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
178 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
182 nflags
= flags
| BTRFS_SUBVOL_RDONLY
;
184 nflags
= flags
& ~BTRFS_SUBVOL_RDONLY
;
189 if (ioctl(fd
, BTRFS_IOC_SUBVOL_SETFLAGS
, &nflags
) < 0)
195 int btrfs_subvol_set_read_only(const char *path
, bool b
) {
196 _cleanup_close_
int fd
= -1;
198 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
202 return btrfs_subvol_set_read_only_fd(fd
, b
);
205 int btrfs_subvol_get_read_only_fd(int fd
) {
211 if (fstat(fd
, &st
) < 0)
214 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
217 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
220 return !!(flags
& BTRFS_SUBVOL_RDONLY
);
223 int btrfs_reflink(int infd
, int outfd
) {
230 /* Make sure we invoke the ioctl on a regular file, so that no
231 * device driver accidentally gets it. */
233 if (fstat(outfd
, &st
) < 0)
236 if (!S_ISREG(st
.st_mode
))
239 r
= ioctl(outfd
, BTRFS_IOC_CLONE
, infd
);
246 int btrfs_clone_range(int infd
, uint64_t in_offset
, int outfd
, uint64_t out_offset
, uint64_t sz
) {
247 struct btrfs_ioctl_clone_range_args args
= {
249 .src_offset
= in_offset
,
251 .dest_offset
= out_offset
,
260 if (fstat(outfd
, &st
) < 0)
263 if (!S_ISREG(st
.st_mode
))
266 r
= ioctl(outfd
, BTRFS_IOC_CLONE_RANGE
, &args
);
273 int btrfs_get_block_device_fd(int fd
, dev_t
*dev
) {
274 struct btrfs_ioctl_fs_info_args fsi
= {};
281 r
= btrfs_is_filesystem(fd
);
287 if (ioctl(fd
, BTRFS_IOC_FS_INFO
, &fsi
) < 0)
290 /* We won't do this for btrfs RAID */
291 if (fsi
.num_devices
!= 1)
294 for (id
= 1; id
<= fsi
.max_id
; id
++) {
295 struct btrfs_ioctl_dev_info_args di
= {
300 if (ioctl(fd
, BTRFS_IOC_DEV_INFO
, &di
) < 0) {
307 if (stat((char*) di
.path
, &st
) < 0)
310 if (!S_ISBLK(st
.st_mode
))
313 if (major(st
.st_rdev
) == 0)
323 int btrfs_get_block_device(const char *path
, dev_t
*dev
) {
324 _cleanup_close_
int fd
= -1;
329 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
333 return btrfs_get_block_device_fd(fd
, dev
);
336 int btrfs_subvol_get_id_fd(int fd
, uint64_t *ret
) {
337 struct btrfs_ioctl_ino_lookup_args args
= {
338 .objectid
= BTRFS_FIRST_FREE_OBJECTID
345 r
= btrfs_is_filesystem(fd
);
351 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
) < 0)
358 int btrfs_subvol_get_id(int fd
, const char *subvol
, uint64_t *ret
) {
359 _cleanup_close_
int subvol_fd
= -1;
364 subvol_fd
= openat(fd
, subvol
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
368 return btrfs_subvol_get_id_fd(subvol_fd
, ret
);
371 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args
*args
) {
374 /* the objectid, type, offset together make up the btrfs key,
375 * which is considered a single 136byte integer when
376 * comparing. This call increases the counter by one, dealing
377 * with the overflow between the overflows */
379 if (args
->key
.min_offset
< (uint64_t) -1) {
380 args
->key
.min_offset
++;
384 if (args
->key
.min_type
< (uint8_t) -1) {
385 args
->key
.min_type
++;
386 args
->key
.min_offset
= 0;
390 if (args
->key
.min_objectid
< (uint64_t) -1) {
391 args
->key
.min_objectid
++;
392 args
->key
.min_offset
= 0;
393 args
->key
.min_type
= 0;
400 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args
*args
, const struct btrfs_ioctl_search_header
*h
) {
404 args
->key
.min_objectid
= h
->objectid
;
405 args
->key
.min_type
= h
->type
;
406 args
->key
.min_offset
= h
->offset
;
409 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
*args
) {
412 /* Compare min and max */
414 if (args
->key
.min_objectid
< args
->key
.max_objectid
)
416 if (args
->key
.min_objectid
> args
->key
.max_objectid
)
419 if (args
->key
.min_type
< args
->key
.max_type
)
421 if (args
->key
.min_type
> args
->key
.max_type
)
424 if (args
->key
.min_offset
< args
->key
.max_offset
)
426 if (args
->key
.min_offset
> args
->key
.max_offset
)
432 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
434 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
435 (i) < (args).key.nr_items; \
437 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
439 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
440 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
442 int btrfs_subvol_get_info_fd(int fd
, uint64_t subvol_id
, BtrfsSubvolInfo
*ret
) {
443 struct btrfs_ioctl_search_args args
= {
444 /* Tree of tree roots */
445 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
447 /* Look precisely for the subvolume items */
448 .key
.min_type
= BTRFS_ROOT_ITEM_KEY
,
449 .key
.max_type
= BTRFS_ROOT_ITEM_KEY
,
452 .key
.max_offset
= (uint64_t) -1,
454 /* No restrictions on the other components */
455 .key
.min_transid
= 0,
456 .key
.max_transid
= (uint64_t) -1,
465 if (subvol_id
== 0) {
466 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
470 r
= btrfs_is_filesystem(fd
);
477 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
479 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
480 const struct btrfs_ioctl_search_header
*sh
;
483 args
.key
.nr_items
= 256;
484 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
487 if (args
.key
.nr_items
<= 0)
490 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
492 const struct btrfs_root_item
*ri
;
494 /* Make sure we start the next search at least from this entry */
495 btrfs_ioctl_search_args_set(&args
, sh
);
497 if (sh
->objectid
!= subvol_id
)
499 if (sh
->type
!= BTRFS_ROOT_ITEM_KEY
)
502 /* Older versions of the struct lacked the otime setting */
503 if (sh
->len
< offsetof(struct btrfs_root_item
, otime
) + sizeof(struct btrfs_timespec
))
506 ri
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
508 ret
->otime
= (usec_t
) le64toh(ri
->otime
.sec
) * USEC_PER_SEC
+
509 (usec_t
) le32toh(ri
->otime
.nsec
) / NSEC_PER_USEC
;
511 ret
->subvol_id
= subvol_id
;
512 ret
->read_only
= !!(le64toh(ri
->flags
) & BTRFS_ROOT_SUBVOL_RDONLY
);
514 assert_cc(sizeof(ri
->uuid
) == sizeof(ret
->uuid
));
515 memcpy(&ret
->uuid
, ri
->uuid
, sizeof(ret
->uuid
));
516 memcpy(&ret
->parent_uuid
, ri
->parent_uuid
, sizeof(ret
->parent_uuid
));
522 /* Increase search key by one, to read the next item, if we can. */
523 if (!btrfs_ioctl_search_args_inc(&args
))
534 int btrfs_qgroup_get_quota_fd(int fd
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
536 struct btrfs_ioctl_search_args args
= {
537 /* Tree of quota items */
538 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
540 /* The object ID is always 0 */
541 .key
.min_objectid
= 0,
542 .key
.max_objectid
= 0,
544 /* Look precisely for the quota items */
545 .key
.min_type
= BTRFS_QGROUP_STATUS_KEY
,
546 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
548 /* No restrictions on the other components */
549 .key
.min_transid
= 0,
550 .key
.max_transid
= (uint64_t) -1,
553 bool found_info
= false, found_limit
= false;
560 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
564 r
= btrfs_is_filesystem(fd
);
571 args
.key
.min_offset
= args
.key
.max_offset
= qgroupid
;
573 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
574 const struct btrfs_ioctl_search_header
*sh
;
577 args
.key
.nr_items
= 256;
578 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
579 if (errno
== ENOENT
) /* quota tree is missing: quota disabled */
585 if (args
.key
.nr_items
<= 0)
588 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
590 /* Make sure we start the next search at least from this entry */
591 btrfs_ioctl_search_args_set(&args
, sh
);
593 if (sh
->objectid
!= 0)
595 if (sh
->offset
!= qgroupid
)
598 if (sh
->type
== BTRFS_QGROUP_INFO_KEY
) {
599 const struct btrfs_qgroup_info_item
*qii
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
601 ret
->referenced
= le64toh(qii
->rfer
);
602 ret
->exclusive
= le64toh(qii
->excl
);
606 } else if (sh
->type
== BTRFS_QGROUP_LIMIT_KEY
) {
607 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
609 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_RFER
)
610 ret
->referenced_max
= le64toh(qli
->max_rfer
);
612 ret
->referenced_max
= (uint64_t) -1;
614 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_EXCL
)
615 ret
->exclusive_max
= le64toh(qli
->max_excl
);
617 ret
->exclusive_max
= (uint64_t) -1;
622 if (found_info
&& found_limit
)
626 /* Increase search key by one, to read the next item, if we can. */
627 if (!btrfs_ioctl_search_args_inc(&args
))
632 if (!found_limit
&& !found_info
)
636 ret
->referenced
= (uint64_t) -1;
637 ret
->exclusive
= (uint64_t) -1;
641 ret
->referenced_max
= (uint64_t) -1;
642 ret
->exclusive_max
= (uint64_t) -1;
648 int btrfs_qgroup_get_quota(const char *path
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
649 _cleanup_close_
int fd
= -1;
651 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
655 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
658 int btrfs_subvol_find_subtree_qgroup(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
659 uint64_t level
, lowest
= (uint64_t) -1, lowest_qgroupid
= 0;
660 _cleanup_free_
uint64_t *qgroups
= NULL
;
666 /* This finds the "subtree" qgroup for a specific
667 * subvolume. This only works for subvolumes that have been
668 * prepared with btrfs_subvol_auto_qgroup_fd() with
669 * insert_intermediary_qgroup=true (or equivalent). For others
670 * it will return the leaf qgroup instead. The two cases may
671 * be distuingished via the return value, which is 1 in case
672 * an appropriate "subtree" qgroup was found, and 0
675 if (subvol_id
== 0) {
676 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
681 r
= btrfs_qgroupid_split(subvol_id
, &level
, NULL
);
684 if (level
!= 0) /* Input must be a leaf qgroup */
687 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
691 for (i
= 0; i
< n
; i
++) {
694 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, &id
);
701 if (lowest
== (uint64_t) -1 || level
< lowest
) {
702 lowest_qgroupid
= qgroups
[i
];
707 if (lowest
== (uint64_t) -1) {
708 /* No suitable higher-level qgroup found, let's return
709 * the leaf qgroup instead, and indicate that with the
716 *ret
= lowest_qgroupid
;
720 int btrfs_subvol_get_subtree_quota_fd(int fd
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
727 /* This determines the quota data of the qgroup with the
728 * lowest level, that shares the id part with the specified
729 * subvolume. This is useful for determining the quota data
730 * for entire subvolume subtrees, as long as the subtrees have
731 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
734 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
738 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
741 int btrfs_subvol_get_subtree_quota(const char *path
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
742 _cleanup_close_
int fd
= -1;
744 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
748 return btrfs_subvol_get_subtree_quota_fd(fd
, subvol_id
, ret
);
751 int btrfs_defrag_fd(int fd
) {
756 if (fstat(fd
, &st
) < 0)
759 if (!S_ISREG(st
.st_mode
))
762 if (ioctl(fd
, BTRFS_IOC_DEFRAG
, NULL
) < 0)
768 int btrfs_defrag(const char *p
) {
769 _cleanup_close_
int fd
= -1;
771 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
775 return btrfs_defrag_fd(fd
);
778 int btrfs_quota_enable_fd(int fd
, bool b
) {
779 struct btrfs_ioctl_quota_ctl_args args
= {
780 .cmd
= b
? BTRFS_QUOTA_CTL_ENABLE
: BTRFS_QUOTA_CTL_DISABLE
,
786 r
= btrfs_is_filesystem(fd
);
792 if (ioctl(fd
, BTRFS_IOC_QUOTA_CTL
, &args
) < 0)
798 int btrfs_quota_enable(const char *path
, bool b
) {
799 _cleanup_close_
int fd
= -1;
801 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
805 return btrfs_quota_enable_fd(fd
, b
);
808 int btrfs_qgroup_set_limit_fd(int fd
, uint64_t qgroupid
, uint64_t referenced_max
) {
810 struct btrfs_ioctl_qgroup_limit_args args
= {
811 .lim
.max_rfer
= referenced_max
,
812 .lim
.flags
= BTRFS_QGROUP_LIMIT_MAX_RFER
,
820 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
824 r
= btrfs_is_filesystem(fd
);
831 args
.qgroupid
= qgroupid
;
834 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &args
) < 0) {
836 if (errno
== EBUSY
&& c
< 10) {
837 (void) btrfs_quota_scan_wait(fd
);
850 int btrfs_qgroup_set_limit(const char *path
, uint64_t qgroupid
, uint64_t referenced_max
) {
851 _cleanup_close_
int fd
= -1;
853 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
857 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
860 int btrfs_subvol_set_subtree_quota_limit_fd(int fd
, uint64_t subvol_id
, uint64_t referenced_max
) {
866 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
870 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
873 int btrfs_subvol_set_subtree_quota_limit(const char *path
, uint64_t subvol_id
, uint64_t referenced_max
) {
874 _cleanup_close_
int fd
= -1;
876 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
880 return btrfs_subvol_set_subtree_quota_limit_fd(fd
, subvol_id
, referenced_max
);
883 int btrfs_resize_loopback_fd(int fd
, uint64_t new_size
, bool grow_only
) {
884 struct btrfs_ioctl_vol_args args
= {};
885 _cleanup_free_
char *p
= NULL
, *loop
= NULL
, *backing
= NULL
;
886 _cleanup_close_
int loop_fd
= -1, backing_fd
= -1;
891 /* btrfs cannot handle file systems < 16M, hence use this as minimum */
892 if (new_size
< 16*1024*1024)
893 new_size
= 16*1024*1024;
895 r
= btrfs_get_block_device_fd(fd
, &dev
);
901 if (asprintf(&p
, "/sys/dev/block/%u:%u/loop/backing_file", major(dev
), minor(dev
)) < 0)
903 r
= read_one_line_file(p
, &backing
);
908 if (isempty(backing
) || !path_is_absolute(backing
))
911 backing_fd
= open(backing
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
915 if (fstat(backing_fd
, &st
) < 0)
917 if (!S_ISREG(st
.st_mode
))
920 if (new_size
== (uint64_t) st
.st_size
)
923 if (grow_only
&& new_size
< (uint64_t) st
.st_size
)
926 if (asprintf(&loop
, "/dev/block/%u:%u", major(dev
), minor(dev
)) < 0)
928 loop_fd
= open(loop
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
932 if (snprintf(args
.name
, sizeof(args
.name
), "%" PRIu64
, new_size
) >= (int) sizeof(args
.name
))
935 if (new_size
< (uint64_t) st
.st_size
) {
936 /* Decrease size: first decrease btrfs size, then shorten loopback */
937 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
941 if (ftruncate(backing_fd
, new_size
) < 0)
944 if (ioctl(loop_fd
, LOOP_SET_CAPACITY
, 0) < 0)
947 if (new_size
> (uint64_t) st
.st_size
) {
948 /* Increase size: first enlarge loopback, then increase btrfs size */
949 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
953 /* Make sure the free disk space is correctly updated for both file systems */
955 (void) fsync(backing_fd
);
960 int btrfs_resize_loopback(const char *p
, uint64_t new_size
, bool grow_only
) {
961 _cleanup_close_
int fd
= -1;
963 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
967 return btrfs_resize_loopback_fd(fd
, new_size
, grow_only
);
970 int btrfs_qgroupid_make(uint64_t level
, uint64_t id
, uint64_t *ret
) {
973 if (level
>= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT
)))
976 if (id
>= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
))
979 *ret
= (level
<< BTRFS_QGROUP_LEVEL_SHIFT
) | id
;
983 int btrfs_qgroupid_split(uint64_t qgroupid
, uint64_t *level
, uint64_t *id
) {
987 *level
= qgroupid
>> BTRFS_QGROUP_LEVEL_SHIFT
;
990 *id
= qgroupid
& ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
) - 1);
995 static int qgroup_create_or_destroy(int fd
, bool b
, uint64_t qgroupid
) {
997 struct btrfs_ioctl_qgroup_create_args args
= {
999 .qgroupid
= qgroupid
,
1004 r
= btrfs_is_filesystem(fd
);
1011 if (ioctl(fd
, BTRFS_IOC_QGROUP_CREATE
, &args
) < 0) {
1013 /* If quota is not enabled, we get EINVAL. Turn this into a recognizable error */
1014 if (errno
== EINVAL
)
1015 return -ENOPROTOOPT
;
1017 if (errno
== EBUSY
&& c
< 10) {
1018 (void) btrfs_quota_scan_wait(fd
);
1031 int btrfs_qgroup_create(int fd
, uint64_t qgroupid
) {
1032 return qgroup_create_or_destroy(fd
, true, qgroupid
);
1035 int btrfs_qgroup_destroy(int fd
, uint64_t qgroupid
) {
1036 return qgroup_create_or_destroy(fd
, false, qgroupid
);
1039 int btrfs_qgroup_destroy_recursive(int fd
, uint64_t qgroupid
) {
1040 _cleanup_free_
uint64_t *qgroups
= NULL
;
1044 /* Destroys the specified qgroup, but unassigns it from all
1045 * its parents first. Also, it recursively destroys all
1046 * qgroups it is assgined to that have the same id part of the
1047 * qgroupid as the specified group. */
1049 r
= btrfs_qgroupid_split(qgroupid
, NULL
, &subvol_id
);
1053 n
= btrfs_qgroup_find_parents(fd
, qgroupid
, &qgroups
);
1057 for (i
= 0; i
< n
; i
++) {
1060 r
= btrfs_qgroupid_split(qgroups
[i
], NULL
, &id
);
1064 r
= btrfs_qgroup_unassign(fd
, qgroupid
, qgroups
[i
]);
1068 if (id
!= subvol_id
)
1071 /* The parent qgroupid shares the same id part with
1072 * us? If so, destroy it too. */
1074 (void) btrfs_qgroup_destroy_recursive(fd
, qgroups
[i
]);
1077 return btrfs_qgroup_destroy(fd
, qgroupid
);
1080 int btrfs_quota_scan_start(int fd
) {
1081 struct btrfs_ioctl_quota_rescan_args args
= {};
1085 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN
, &args
) < 0)
1091 int btrfs_quota_scan_wait(int fd
) {
1094 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_WAIT
) < 0)
1100 int btrfs_quota_scan_ongoing(int fd
) {
1101 struct btrfs_ioctl_quota_rescan_args args
= {};
1105 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_STATUS
, &args
) < 0)
1108 return !!args
.flags
;
1111 static int qgroup_assign_or_unassign(int fd
, bool b
, uint64_t child
, uint64_t parent
) {
1112 struct btrfs_ioctl_qgroup_assign_args args
= {
1120 r
= btrfs_is_filesystem(fd
);
1127 r
= ioctl(fd
, BTRFS_IOC_QGROUP_ASSIGN
, &args
);
1129 if (errno
== EBUSY
&& c
< 10) {
1130 (void) btrfs_quota_scan_wait(fd
);
1140 /* If the return value is > 0, we need to request a rescan */
1142 (void) btrfs_quota_scan_start(fd
);
1147 int btrfs_qgroup_assign(int fd
, uint64_t child
, uint64_t parent
) {
1148 return qgroup_assign_or_unassign(fd
, true, child
, parent
);
1151 int btrfs_qgroup_unassign(int fd
, uint64_t child
, uint64_t parent
) {
1152 return qgroup_assign_or_unassign(fd
, false, child
, parent
);
1155 static int subvol_remove_children(int fd
, const char *subvolume
, uint64_t subvol_id
, BtrfsRemoveFlags flags
) {
1156 struct btrfs_ioctl_search_args args
= {
1157 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1159 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1160 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1162 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1163 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1165 .key
.min_transid
= 0,
1166 .key
.max_transid
= (uint64_t) -1,
1169 struct btrfs_ioctl_vol_args vol_args
= {};
1170 _cleanup_close_
int subvol_fd
= -1;
1172 bool made_writable
= false;
1178 if (fstat(fd
, &st
) < 0)
1181 if (!S_ISDIR(st
.st_mode
))
1184 subvol_fd
= openat(fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1188 if (subvol_id
== 0) {
1189 r
= btrfs_subvol_get_id_fd(subvol_fd
, &subvol_id
);
1194 /* First, try to remove the subvolume. If it happens to be
1195 * already empty, this will just work. */
1196 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1197 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) >= 0) {
1198 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1201 if (!(flags
& BTRFS_REMOVE_RECURSIVE
) || errno
!= ENOTEMPTY
)
1204 /* OK, the subvolume is not empty, let's look for child
1205 * subvolumes, and remove them, first */
1207 args
.key
.min_offset
= args
.key
.max_offset
= subvol_id
;
1209 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1210 const struct btrfs_ioctl_search_header
*sh
;
1213 args
.key
.nr_items
= 256;
1214 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1217 if (args
.key
.nr_items
<= 0)
1220 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1221 _cleanup_free_
char *p
= NULL
;
1222 const struct btrfs_root_ref
*ref
;
1223 struct btrfs_ioctl_ino_lookup_args ino_args
;
1225 btrfs_ioctl_search_args_set(&args
, sh
);
1227 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1229 if (sh
->offset
!= subvol_id
)
1232 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1234 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1239 ino_args
.treeid
= subvol_id
;
1240 ino_args
.objectid
= htole64(ref
->dirid
);
1242 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1245 if (!made_writable
) {
1246 r
= btrfs_subvol_set_read_only_fd(subvol_fd
, false);
1250 made_writable
= true;
1253 if (isempty(ino_args
.name
))
1254 /* Subvolume is in the top-level
1255 * directory of the subvolume. */
1256 r
= subvol_remove_children(subvol_fd
, p
, sh
->objectid
, flags
);
1258 _cleanup_close_
int child_fd
= -1;
1260 /* Subvolume is somewhere further down,
1261 * hence we need to open the
1262 * containing directory first */
1264 child_fd
= openat(subvol_fd
, ino_args
.name
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1268 r
= subvol_remove_children(child_fd
, p
, sh
->objectid
, flags
);
1274 /* Increase search key by one, to read the next item, if we can. */
1275 if (!btrfs_ioctl_search_args_inc(&args
))
1279 /* OK, the child subvolumes should all be gone now, let's try
1280 * again to remove the subvolume */
1281 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) < 0)
1284 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
);
1288 int btrfs_subvol_remove(const char *path
, BtrfsRemoveFlags flags
) {
1289 _cleanup_close_
int fd
= -1;
1290 const char *subvolume
;
1295 r
= extract_subvolume_name(path
, &subvolume
);
1299 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1303 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1306 int btrfs_subvol_remove_fd(int fd
, const char *subvolume
, BtrfsRemoveFlags flags
) {
1307 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1310 int btrfs_qgroup_copy_limits(int fd
, uint64_t old_qgroupid
, uint64_t new_qgroupid
) {
1312 struct btrfs_ioctl_search_args args
= {
1313 /* Tree of quota items */
1314 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1316 /* The object ID is always 0 */
1317 .key
.min_objectid
= 0,
1318 .key
.max_objectid
= 0,
1320 /* Look precisely for the quota items */
1321 .key
.min_type
= BTRFS_QGROUP_LIMIT_KEY
,
1322 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
1324 /* For our qgroup */
1325 .key
.min_offset
= old_qgroupid
,
1326 .key
.max_offset
= old_qgroupid
,
1328 /* No restrictions on the other components */
1329 .key
.min_transid
= 0,
1330 .key
.max_transid
= (uint64_t) -1,
1335 r
= btrfs_is_filesystem(fd
);
1341 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1342 const struct btrfs_ioctl_search_header
*sh
;
1345 args
.key
.nr_items
= 256;
1346 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1347 if (errno
== ENOENT
) /* quota tree missing: quota is not enabled, hence nothing to copy */
1353 if (args
.key
.nr_items
<= 0)
1356 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1357 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1358 struct btrfs_ioctl_qgroup_limit_args qargs
;
1361 /* Make sure we start the next search at least from this entry */
1362 btrfs_ioctl_search_args_set(&args
, sh
);
1364 if (sh
->objectid
!= 0)
1366 if (sh
->type
!= BTRFS_QGROUP_LIMIT_KEY
)
1368 if (sh
->offset
!= old_qgroupid
)
1371 /* We found the entry, now copy things over. */
1373 qargs
= (struct btrfs_ioctl_qgroup_limit_args
) {
1374 .qgroupid
= new_qgroupid
,
1376 .lim
.max_rfer
= le64toh(qli
->max_rfer
),
1377 .lim
.max_excl
= le64toh(qli
->max_excl
),
1378 .lim
.rsv_rfer
= le64toh(qli
->rsv_rfer
),
1379 .lim
.rsv_excl
= le64toh(qli
->rsv_excl
),
1381 .lim
.flags
= le64toh(qli
->flags
) & (BTRFS_QGROUP_LIMIT_MAX_RFER
|
1382 BTRFS_QGROUP_LIMIT_MAX_EXCL
|
1383 BTRFS_QGROUP_LIMIT_RSV_RFER
|
1384 BTRFS_QGROUP_LIMIT_RSV_EXCL
),
1388 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &qargs
) < 0) {
1389 if (errno
== EBUSY
&& c
< 10) {
1390 (void) btrfs_quota_scan_wait(fd
);
1402 /* Increase search key by one, to read the next item, if we can. */
1403 if (!btrfs_ioctl_search_args_inc(&args
))
1410 static int copy_quota_hierarchy(int fd
, uint64_t old_subvol_id
, uint64_t new_subvol_id
) {
1411 _cleanup_free_
uint64_t *old_qgroups
= NULL
, *old_parent_qgroups
= NULL
;
1412 bool copy_from_parent
= false, insert_intermediary_qgroup
= false;
1413 int n_old_qgroups
, n_old_parent_qgroups
, r
, i
;
1414 uint64_t old_parent_id
;
1418 /* Copies a reduced form of quota information from the old to
1419 * the new subvolume. */
1421 n_old_qgroups
= btrfs_qgroup_find_parents(fd
, old_subvol_id
, &old_qgroups
);
1422 if (n_old_qgroups
<= 0) /* Nothing to copy */
1423 return n_old_qgroups
;
1425 r
= btrfs_subvol_get_parent(fd
, old_subvol_id
, &old_parent_id
);
1427 /* We have no parent, hence nothing to copy. */
1428 n_old_parent_qgroups
= 0;
1432 n_old_parent_qgroups
= btrfs_qgroup_find_parents(fd
, old_parent_id
, &old_parent_qgroups
);
1433 if (n_old_parent_qgroups
< 0)
1434 return n_old_parent_qgroups
;
1437 for (i
= 0; i
< n_old_qgroups
; i
++) {
1441 r
= btrfs_qgroupid_split(old_qgroups
[i
], NULL
, &id
);
1445 if (id
== old_subvol_id
) {
1446 /* The old subvolume was member of a qgroup
1447 * that had the same id, but a different level
1448 * as it self. Let's set up something similar
1449 * in the destination. */
1450 insert_intermediary_qgroup
= true;
1454 for (j
= 0; j
< n_old_parent_qgroups
; j
++)
1455 if (old_parent_qgroups
[j
] == old_qgroups
[i
]) {
1456 /* The old subvolume shared a common
1457 * parent qgroup with its parent
1458 * subvolume. Let's set up something
1459 * similar in the destination. */
1460 copy_from_parent
= true;
1464 if (!insert_intermediary_qgroup
&& !copy_from_parent
)
1467 return btrfs_subvol_auto_qgroup_fd(fd
, new_subvol_id
, insert_intermediary_qgroup
);
1470 static int copy_subtree_quota_limits(int fd
, uint64_t old_subvol
, uint64_t new_subvol
) {
1471 uint64_t old_subtree_qgroup
, new_subtree_qgroup
;
1475 /* First copy the leaf limits */
1476 r
= btrfs_qgroup_copy_limits(fd
, old_subvol
, new_subvol
);
1481 /* Then, try to copy the subtree limits, if there are any. */
1482 r
= btrfs_subvol_find_subtree_qgroup(fd
, old_subvol
, &old_subtree_qgroup
);
1488 r
= btrfs_subvol_find_subtree_qgroup(fd
, new_subvol
, &new_subtree_qgroup
);
1494 r
= btrfs_qgroup_copy_limits(fd
, old_subtree_qgroup
, new_subtree_qgroup
);
1501 static int subvol_snapshot_children(int old_fd
, int new_fd
, const char *subvolume
, uint64_t old_subvol_id
, BtrfsSnapshotFlags flags
) {
1503 struct btrfs_ioctl_search_args args
= {
1504 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1506 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1507 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1509 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1510 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1512 .key
.min_transid
= 0,
1513 .key
.max_transid
= (uint64_t) -1,
1516 struct btrfs_ioctl_vol_args_v2 vol_args
= {
1517 .flags
= flags
& BTRFS_SNAPSHOT_READ_ONLY
? BTRFS_SUBVOL_RDONLY
: 0,
1520 _cleanup_close_
int subvolume_fd
= -1;
1521 uint64_t new_subvol_id
;
1524 assert(old_fd
>= 0);
1525 assert(new_fd
>= 0);
1528 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1530 if (ioctl(new_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &vol_args
) < 0)
1533 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
) &&
1534 !(flags
& BTRFS_SNAPSHOT_QUOTA
))
1537 if (old_subvol_id
== 0) {
1538 r
= btrfs_subvol_get_id_fd(old_fd
, &old_subvol_id
);
1543 r
= btrfs_subvol_get_id(new_fd
, vol_args
.name
, &new_subvol_id
);
1547 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1548 (void) copy_quota_hierarchy(new_fd
, old_subvol_id
, new_subvol_id
);
1550 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
)) {
1552 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1553 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1558 args
.key
.min_offset
= args
.key
.max_offset
= old_subvol_id
;
1560 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1561 const struct btrfs_ioctl_search_header
*sh
;
1564 args
.key
.nr_items
= 256;
1565 if (ioctl(old_fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1568 if (args
.key
.nr_items
<= 0)
1571 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1572 _cleanup_free_
char *p
= NULL
, *c
= NULL
, *np
= NULL
;
1573 struct btrfs_ioctl_ino_lookup_args ino_args
;
1574 const struct btrfs_root_ref
*ref
;
1575 _cleanup_close_
int old_child_fd
= -1, new_child_fd
= -1;
1577 btrfs_ioctl_search_args_set(&args
, sh
);
1579 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1582 /* Avoid finding the source subvolume a second
1584 if (sh
->offset
!= old_subvol_id
)
1587 /* Avoid running into loops if the new
1588 * subvolume is below the old one. */
1589 if (sh
->objectid
== new_subvol_id
)
1592 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1593 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1598 ino_args
.treeid
= old_subvol_id
;
1599 ino_args
.objectid
= htole64(ref
->dirid
);
1601 if (ioctl(old_fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1604 /* The kernel returns an empty name if the
1605 * subvolume is in the top-level directory,
1606 * and otherwise appends a slash, so that we
1607 * can just concatenate easily here, without
1608 * adding a slash. */
1609 c
= strappend(ino_args
.name
, p
);
1613 old_child_fd
= openat(old_fd
, c
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1614 if (old_child_fd
< 0)
1617 np
= strjoin(subvolume
, "/", ino_args
.name
, NULL
);
1621 new_child_fd
= openat(new_fd
, np
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1622 if (new_child_fd
< 0)
1625 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1626 /* If the snapshot is read-only we
1627 * need to mark it writable
1628 * temporarily, to put the subsnapshot
1631 if (subvolume_fd
< 0) {
1632 subvolume_fd
= openat(new_fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1633 if (subvolume_fd
< 0)
1637 r
= btrfs_subvol_set_read_only_fd(subvolume_fd
, false);
1642 /* When btrfs clones the subvolumes, child
1643 * subvolumes appear as empty directories. Remove
1644 * them, so that we can create a new snapshot
1646 if (unlinkat(new_child_fd
, p
, AT_REMOVEDIR
) < 0) {
1649 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
)
1650 (void) btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1655 r
= subvol_snapshot_children(old_child_fd
, new_child_fd
, p
, sh
->objectid
, flags
& ~BTRFS_SNAPSHOT_FALLBACK_COPY
);
1657 /* Restore the readonly flag */
1658 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1661 k
= btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1662 if (r
>= 0 && k
< 0)
1670 /* Increase search key by one, to read the next item, if we can. */
1671 if (!btrfs_ioctl_search_args_inc(&args
))
1675 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1676 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1681 int btrfs_subvol_snapshot_fd(int old_fd
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1682 _cleanup_close_
int new_fd
= -1;
1683 const char *subvolume
;
1686 assert(old_fd
>= 0);
1689 r
= btrfs_is_subvol(old_fd
);
1693 if (!(flags
& BTRFS_SNAPSHOT_FALLBACK_COPY
))
1696 r
= btrfs_subvol_make(new_path
);
1700 r
= copy_directory_fd(old_fd
, new_path
, true);
1702 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1706 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1707 r
= btrfs_subvol_set_read_only(new_path
, true);
1709 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1717 r
= extract_subvolume_name(new_path
, &subvolume
);
1721 new_fd
= open_parent(new_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1725 return subvol_snapshot_children(old_fd
, new_fd
, subvolume
, 0, flags
);
1728 int btrfs_subvol_snapshot(const char *old_path
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1729 _cleanup_close_
int old_fd
= -1;
1734 old_fd
= open(old_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1738 return btrfs_subvol_snapshot_fd(old_fd
, new_path
, flags
);
1741 int btrfs_qgroup_find_parents(int fd
, uint64_t qgroupid
, uint64_t **ret
) {
1743 struct btrfs_ioctl_search_args args
= {
1744 /* Tree of quota items */
1745 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1747 /* Look precisely for the quota relation items */
1748 .key
.min_type
= BTRFS_QGROUP_RELATION_KEY
,
1749 .key
.max_type
= BTRFS_QGROUP_RELATION_KEY
,
1751 /* No restrictions on the other components */
1752 .key
.min_offset
= 0,
1753 .key
.max_offset
= (uint64_t) -1,
1755 .key
.min_transid
= 0,
1756 .key
.max_transid
= (uint64_t) -1,
1759 _cleanup_free_
uint64_t *items
= NULL
;
1760 size_t n_items
= 0, n_allocated
= 0;
1766 if (qgroupid
== 0) {
1767 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
1771 r
= btrfs_is_filesystem(fd
);
1778 args
.key
.min_objectid
= args
.key
.max_objectid
= qgroupid
;
1780 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1781 const struct btrfs_ioctl_search_header
*sh
;
1784 args
.key
.nr_items
= 256;
1785 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1786 if (errno
== ENOENT
) /* quota tree missing: quota is disabled */
1792 if (args
.key
.nr_items
<= 0)
1795 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1797 /* Make sure we start the next search at least from this entry */
1798 btrfs_ioctl_search_args_set(&args
, sh
);
1800 if (sh
->type
!= BTRFS_QGROUP_RELATION_KEY
)
1802 if (sh
->offset
< sh
->objectid
)
1804 if (sh
->objectid
!= qgroupid
)
1807 if (!GREEDY_REALLOC(items
, n_allocated
, n_items
+1))
1810 items
[n_items
++] = sh
->offset
;
1813 /* Increase search key by one, to read the next item, if we can. */
1814 if (!btrfs_ioctl_search_args_inc(&args
))
1826 return (int) n_items
;
1829 int btrfs_subvol_auto_qgroup_fd(int fd
, uint64_t subvol_id
, bool insert_intermediary_qgroup
) {
1830 _cleanup_free_
uint64_t *qgroups
= NULL
;
1831 uint64_t parent_subvol
;
1832 bool changed
= false;
1838 * Sets up the specified subvolume's qgroup automatically in
1841 * If insert_intermediary_qgroup is false, the subvolume's
1842 * leaf qgroup will be assigned to the same parent qgroups as
1843 * the subvolume's parent subvolume.
1845 * If insert_intermediary_qgroup is true a new intermediary
1846 * higher-level qgroup is created, with a higher level number,
1847 * but reusing the id of the subvolume. The level number is
1848 * picked as one smaller than the lowest level qgroup the
1849 * parent subvolume is a member of. If the parent subvolume's
1850 * leaf qgroup is assigned to no higher-level qgroup a new
1851 * qgroup of level 255 is created instead. Either way, the new
1852 * qgroup is then assigned to the parent's higher-level
1853 * qgroup, and the subvolume itself is assigned to it.
1855 * If the subvolume is already assigned to a higher level
1856 * qgroup, no operation is executed.
1858 * Effectively this means: regardless if
1859 * insert_intermediary_qgroup is true or not, after this
1860 * function is invoked the subvolume will be accounted within
1861 * the same qgroups as the parent. However, if it is true, it
1862 * will also get its own higher-level qgroup, which may in
1863 * turn be used by subvolumes created beneath this subvolume
1866 * This hence defines a simple default qgroup setup for
1867 * subvolumes, as long as this function is invoked on each
1868 * created subvolume: each subvolume is always accounting
1869 * together with its immediate parents. Optionally, if
1870 * insert_intermediary_qgroup is true, it will also get a
1871 * qgroup that then includes all its own child subvolumes.
1874 if (subvol_id
== 0) {
1875 r
= btrfs_is_subvol(fd
);
1881 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1886 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
1889 if (n
> 0) /* already parent qgroups set up, let's bail */
1892 qgroups
= mfree(qgroups
);
1894 r
= btrfs_subvol_get_parent(fd
, subvol_id
, &parent_subvol
);
1896 /* No parent, hence no qgroup memberships */
1901 n
= btrfs_qgroup_find_parents(fd
, parent_subvol
, &qgroups
);
1906 if (insert_intermediary_qgroup
) {
1907 uint64_t lowest
= 256, new_qgroupid
;
1908 bool created
= false;
1911 /* Determine the lowest qgroup that the parent
1912 * subvolume is assigned to. */
1914 for (i
= 0; i
< n
; i
++) {
1917 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, NULL
);
1925 if (lowest
<= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1928 r
= btrfs_qgroupid_make(lowest
- 1, subvol_id
, &new_qgroupid
);
1932 /* Create the new intermediary group, unless it already exists */
1933 r
= btrfs_qgroup_create(fd
, new_qgroupid
);
1934 if (r
< 0 && r
!= -EEXIST
)
1937 changed
= created
= true;
1939 for (i
= 0; i
< n
; i
++) {
1940 r
= btrfs_qgroup_assign(fd
, new_qgroupid
, qgroups
[i
]);
1941 if (r
< 0 && r
!= -EEXIST
) {
1943 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1951 r
= btrfs_qgroup_assign(fd
, subvol_id
, new_qgroupid
);
1952 if (r
< 0 && r
!= -EEXIST
) {
1954 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1963 /* Assign our subvolume to all the same qgroups as the parent */
1965 for (i
= 0; i
< n
; i
++) {
1966 r
= btrfs_qgroup_assign(fd
, subvol_id
, qgroups
[i
]);
1967 if (r
< 0 && r
!= -EEXIST
)
1977 int btrfs_subvol_auto_qgroup(const char *path
, uint64_t subvol_id
, bool create_intermediary_qgroup
) {
1978 _cleanup_close_
int fd
= -1;
1980 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1984 return btrfs_subvol_auto_qgroup_fd(fd
, subvol_id
, create_intermediary_qgroup
);
1987 int btrfs_subvol_get_parent(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
1989 struct btrfs_ioctl_search_args args
= {
1990 /* Tree of tree roots */
1991 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1993 /* Look precisely for the subvolume items */
1994 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1995 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1997 /* No restrictions on the other components */
1998 .key
.min_offset
= 0,
1999 .key
.max_offset
= (uint64_t) -1,
2001 .key
.min_transid
= 0,
2002 .key
.max_transid
= (uint64_t) -1,
2009 if (subvol_id
== 0) {
2010 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
2014 r
= btrfs_is_filesystem(fd
);
2021 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
2023 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
2024 const struct btrfs_ioctl_search_header
*sh
;
2027 args
.key
.nr_items
= 256;
2028 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
2031 if (args
.key
.nr_items
<= 0)
2034 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
2036 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
2038 if (sh
->objectid
!= subvol_id
)