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"
34 #include "path-util.h"
35 #include "selinux-util.h"
36 #include "smack-util.h"
37 #include "string-util.h"
39 #include "btrfs-util.h"
41 /* WARNING: Be careful with file system ioctls! When we get an fd, we
42 * need to make sure it either refers to only a regular file or
43 * directory, or that it is located on btrfs, before invoking any
44 * btrfs ioctls. The ioctl numbers are reused by some device drivers
45 * (such as DRM), and hence might have bad effects when invoked on
46 * device nodes (that reference drivers) rather than fds to normal
47 * files or directories. */
49 static int validate_subvolume_name(const char *name
) {
51 if (!filename_is_valid(name
))
54 if (strlen(name
) > BTRFS_SUBVOL_NAME_MAX
)
60 static int open_parent(const char *path
, int flags
) {
61 _cleanup_free_
char *parent
= NULL
;
66 r
= path_get_parent(path
, &parent
);
70 fd
= open(parent
, flags
);
77 static int extract_subvolume_name(const char *path
, const char **subvolume
) {
86 r
= validate_subvolume_name(fn
);
94 int btrfs_is_filesystem(int fd
) {
99 if (fstatfs(fd
, &sfs
) < 0)
102 return F_TYPE_EQUAL(sfs
.f_type
, BTRFS_SUPER_MAGIC
);
105 int btrfs_is_subvol(int fd
) {
110 /* On btrfs subvolumes always have the inode 256 */
112 if (fstat(fd
, &st
) < 0)
115 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
118 return btrfs_is_filesystem(fd
);
121 int btrfs_subvol_make(const char *path
) {
122 struct btrfs_ioctl_vol_args args
= {};
123 _cleanup_close_
int fd
= -1;
124 const char *subvolume
;
129 r
= extract_subvolume_name(path
, &subvolume
);
133 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
137 strncpy(args
.name
, subvolume
, sizeof(args
.name
)-1);
139 if (ioctl(fd
, BTRFS_IOC_SUBVOL_CREATE
, &args
) < 0)
145 int btrfs_subvol_make_label(const char *path
) {
150 r
= mac_selinux_create_file_prepare(path
, S_IFDIR
);
154 r
= btrfs_subvol_make(path
);
155 mac_selinux_create_file_clear();
160 return mac_smack_fix(path
, false, false);
163 int btrfs_subvol_set_read_only_fd(int fd
, bool b
) {
164 uint64_t flags
, nflags
;
169 if (fstat(fd
, &st
) < 0)
172 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
175 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
179 nflags
= flags
| BTRFS_SUBVOL_RDONLY
;
181 nflags
= flags
& ~BTRFS_SUBVOL_RDONLY
;
186 if (ioctl(fd
, BTRFS_IOC_SUBVOL_SETFLAGS
, &nflags
) < 0)
192 int btrfs_subvol_set_read_only(const char *path
, bool b
) {
193 _cleanup_close_
int fd
= -1;
195 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
199 return btrfs_subvol_set_read_only_fd(fd
, b
);
202 int btrfs_subvol_get_read_only_fd(int fd
) {
208 if (fstat(fd
, &st
) < 0)
211 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
214 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
217 return !!(flags
& BTRFS_SUBVOL_RDONLY
);
220 int btrfs_reflink(int infd
, int outfd
) {
227 /* Make sure we invoke the ioctl on a regular file, so that no
228 * device driver accidentally gets it. */
230 if (fstat(outfd
, &st
) < 0)
233 if (!S_ISREG(st
.st_mode
))
236 r
= ioctl(outfd
, BTRFS_IOC_CLONE
, infd
);
243 int btrfs_clone_range(int infd
, uint64_t in_offset
, int outfd
, uint64_t out_offset
, uint64_t sz
) {
244 struct btrfs_ioctl_clone_range_args args
= {
246 .src_offset
= in_offset
,
248 .dest_offset
= out_offset
,
257 if (fstat(outfd
, &st
) < 0)
260 if (!S_ISREG(st
.st_mode
))
263 r
= ioctl(outfd
, BTRFS_IOC_CLONE_RANGE
, &args
);
270 int btrfs_get_block_device_fd(int fd
, dev_t
*dev
) {
271 struct btrfs_ioctl_fs_info_args fsi
= {};
278 r
= btrfs_is_filesystem(fd
);
284 if (ioctl(fd
, BTRFS_IOC_FS_INFO
, &fsi
) < 0)
287 /* We won't do this for btrfs RAID */
288 if (fsi
.num_devices
!= 1)
291 for (id
= 1; id
<= fsi
.max_id
; id
++) {
292 struct btrfs_ioctl_dev_info_args di
= {
297 if (ioctl(fd
, BTRFS_IOC_DEV_INFO
, &di
) < 0) {
304 if (stat((char*) di
.path
, &st
) < 0)
307 if (!S_ISBLK(st
.st_mode
))
310 if (major(st
.st_rdev
) == 0)
320 int btrfs_get_block_device(const char *path
, dev_t
*dev
) {
321 _cleanup_close_
int fd
= -1;
326 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
330 return btrfs_get_block_device_fd(fd
, dev
);
333 int btrfs_subvol_get_id_fd(int fd
, uint64_t *ret
) {
334 struct btrfs_ioctl_ino_lookup_args args
= {
335 .objectid
= BTRFS_FIRST_FREE_OBJECTID
342 r
= btrfs_is_filesystem(fd
);
348 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
) < 0)
355 int btrfs_subvol_get_id(int fd
, const char *subvol
, uint64_t *ret
) {
356 _cleanup_close_
int subvol_fd
= -1;
361 subvol_fd
= openat(fd
, subvol
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
365 return btrfs_subvol_get_id_fd(subvol_fd
, ret
);
368 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args
*args
) {
371 /* the objectid, type, offset together make up the btrfs key,
372 * which is considered a single 136byte integer when
373 * comparing. This call increases the counter by one, dealing
374 * with the overflow between the overflows */
376 if (args
->key
.min_offset
< (uint64_t) -1) {
377 args
->key
.min_offset
++;
381 if (args
->key
.min_type
< (uint8_t) -1) {
382 args
->key
.min_type
++;
383 args
->key
.min_offset
= 0;
387 if (args
->key
.min_objectid
< (uint64_t) -1) {
388 args
->key
.min_objectid
++;
389 args
->key
.min_offset
= 0;
390 args
->key
.min_type
= 0;
397 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args
*args
, const struct btrfs_ioctl_search_header
*h
) {
401 args
->key
.min_objectid
= h
->objectid
;
402 args
->key
.min_type
= h
->type
;
403 args
->key
.min_offset
= h
->offset
;
406 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
*args
) {
409 /* Compare min and max */
411 if (args
->key
.min_objectid
< args
->key
.max_objectid
)
413 if (args
->key
.min_objectid
> args
->key
.max_objectid
)
416 if (args
->key
.min_type
< args
->key
.max_type
)
418 if (args
->key
.min_type
> args
->key
.max_type
)
421 if (args
->key
.min_offset
< args
->key
.max_offset
)
423 if (args
->key
.min_offset
> args
->key
.max_offset
)
429 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
431 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
432 (i) < (args).key.nr_items; \
434 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
436 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
437 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
439 int btrfs_subvol_get_info_fd(int fd
, uint64_t subvol_id
, BtrfsSubvolInfo
*ret
) {
440 struct btrfs_ioctl_search_args args
= {
441 /* Tree of tree roots */
442 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
444 /* Look precisely for the subvolume items */
445 .key
.min_type
= BTRFS_ROOT_ITEM_KEY
,
446 .key
.max_type
= BTRFS_ROOT_ITEM_KEY
,
449 .key
.max_offset
= (uint64_t) -1,
451 /* No restrictions on the other components */
452 .key
.min_transid
= 0,
453 .key
.max_transid
= (uint64_t) -1,
462 if (subvol_id
== 0) {
463 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
467 r
= btrfs_is_filesystem(fd
);
474 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
476 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
477 const struct btrfs_ioctl_search_header
*sh
;
480 args
.key
.nr_items
= 256;
481 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
484 if (args
.key
.nr_items
<= 0)
487 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
489 const struct btrfs_root_item
*ri
;
491 /* Make sure we start the next search at least from this entry */
492 btrfs_ioctl_search_args_set(&args
, sh
);
494 if (sh
->objectid
!= subvol_id
)
496 if (sh
->type
!= BTRFS_ROOT_ITEM_KEY
)
499 /* Older versions of the struct lacked the otime setting */
500 if (sh
->len
< offsetof(struct btrfs_root_item
, otime
) + sizeof(struct btrfs_timespec
))
503 ri
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
505 ret
->otime
= (usec_t
) le64toh(ri
->otime
.sec
) * USEC_PER_SEC
+
506 (usec_t
) le32toh(ri
->otime
.nsec
) / NSEC_PER_USEC
;
508 ret
->subvol_id
= subvol_id
;
509 ret
->read_only
= !!(le64toh(ri
->flags
) & BTRFS_ROOT_SUBVOL_RDONLY
);
511 assert_cc(sizeof(ri
->uuid
) == sizeof(ret
->uuid
));
512 memcpy(&ret
->uuid
, ri
->uuid
, sizeof(ret
->uuid
));
513 memcpy(&ret
->parent_uuid
, ri
->parent_uuid
, sizeof(ret
->parent_uuid
));
519 /* Increase search key by one, to read the next item, if we can. */
520 if (!btrfs_ioctl_search_args_inc(&args
))
531 int btrfs_qgroup_get_quota_fd(int fd
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
533 struct btrfs_ioctl_search_args args
= {
534 /* Tree of quota items */
535 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
537 /* The object ID is always 0 */
538 .key
.min_objectid
= 0,
539 .key
.max_objectid
= 0,
541 /* Look precisely for the quota items */
542 .key
.min_type
= BTRFS_QGROUP_STATUS_KEY
,
543 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
545 /* No restrictions on the other components */
546 .key
.min_transid
= 0,
547 .key
.max_transid
= (uint64_t) -1,
550 bool found_info
= false, found_limit
= false;
557 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
561 r
= btrfs_is_filesystem(fd
);
568 args
.key
.min_offset
= args
.key
.max_offset
= qgroupid
;
570 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
571 const struct btrfs_ioctl_search_header
*sh
;
574 args
.key
.nr_items
= 256;
575 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
578 if (args
.key
.nr_items
<= 0)
581 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
583 /* Make sure we start the next search at least from this entry */
584 btrfs_ioctl_search_args_set(&args
, sh
);
586 if (sh
->objectid
!= 0)
588 if (sh
->offset
!= qgroupid
)
591 if (sh
->type
== BTRFS_QGROUP_INFO_KEY
) {
592 const struct btrfs_qgroup_info_item
*qii
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
594 ret
->referenced
= le64toh(qii
->rfer
);
595 ret
->exclusive
= le64toh(qii
->excl
);
599 } else if (sh
->type
== BTRFS_QGROUP_LIMIT_KEY
) {
600 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
602 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_RFER
)
603 ret
->referenced_max
= le64toh(qli
->max_rfer
);
605 ret
->referenced_max
= (uint64_t) -1;
607 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_EXCL
)
608 ret
->exclusive_max
= le64toh(qli
->max_excl
);
610 ret
->exclusive_max
= (uint64_t) -1;
615 if (found_info
&& found_limit
)
619 /* Increase search key by one, to read the next item, if we can. */
620 if (!btrfs_ioctl_search_args_inc(&args
))
625 if (!found_limit
&& !found_info
)
629 ret
->referenced
= (uint64_t) -1;
630 ret
->exclusive
= (uint64_t) -1;
634 ret
->referenced_max
= (uint64_t) -1;
635 ret
->exclusive_max
= (uint64_t) -1;
641 int btrfs_qgroup_get_quota(const char *path
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
642 _cleanup_close_
int fd
= -1;
644 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
648 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
651 int btrfs_subvol_find_subtree_qgroup(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
652 uint64_t level
, lowest
= (uint64_t) -1, lowest_qgroupid
= 0;
653 _cleanup_free_
uint64_t *qgroups
= NULL
;
659 /* This finds the "subtree" qgroup for a specific
660 * subvolume. This only works for subvolumes that have been
661 * prepared with btrfs_subvol_auto_qgroup_fd() with
662 * insert_intermediary_qgroup=true (or equivalent). For others
663 * it will return the leaf qgroup instead. The two cases may
664 * be distuingished via the return value, which is 1 in case
665 * an appropriate "subtree" qgroup was found, and 0
668 if (subvol_id
== 0) {
669 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
674 r
= btrfs_qgroupid_split(subvol_id
, &level
, NULL
);
677 if (level
!= 0) /* Input must be a leaf qgroup */
680 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
684 for (i
= 0; i
< n
; i
++) {
687 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, &id
);
694 if (lowest
== (uint64_t) -1 || level
< lowest
) {
695 lowest_qgroupid
= qgroups
[i
];
700 if (lowest
== (uint64_t) -1) {
701 /* No suitable higher-level qgroup found, let's return
702 * the leaf qgroup instead, and indicate that with the
709 *ret
= lowest_qgroupid
;
713 int btrfs_subvol_get_subtree_quota_fd(int fd
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
720 /* This determines the quota data of the qgroup with the
721 * lowest level, that shares the id part with the specified
722 * subvolume. This is useful for determining the quota data
723 * for entire subvolume subtrees, as long as the subtrees have
724 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
727 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
731 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
734 int btrfs_subvol_get_subtree_quota(const char *path
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
735 _cleanup_close_
int fd
= -1;
737 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
741 return btrfs_subvol_get_subtree_quota_fd(fd
, subvol_id
, ret
);
744 int btrfs_defrag_fd(int fd
) {
749 if (fstat(fd
, &st
) < 0)
752 if (!S_ISREG(st
.st_mode
))
755 if (ioctl(fd
, BTRFS_IOC_DEFRAG
, NULL
) < 0)
761 int btrfs_defrag(const char *p
) {
762 _cleanup_close_
int fd
= -1;
764 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
768 return btrfs_defrag_fd(fd
);
771 int btrfs_quota_enable_fd(int fd
, bool b
) {
772 struct btrfs_ioctl_quota_ctl_args args
= {
773 .cmd
= b
? BTRFS_QUOTA_CTL_ENABLE
: BTRFS_QUOTA_CTL_DISABLE
,
779 r
= btrfs_is_filesystem(fd
);
785 if (ioctl(fd
, BTRFS_IOC_QUOTA_CTL
, &args
) < 0)
791 int btrfs_quota_enable(const char *path
, bool b
) {
792 _cleanup_close_
int fd
= -1;
794 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
798 return btrfs_quota_enable_fd(fd
, b
);
801 int btrfs_qgroup_set_limit_fd(int fd
, uint64_t qgroupid
, uint64_t referenced_max
) {
803 struct btrfs_ioctl_qgroup_limit_args args
= {
804 .lim
.max_rfer
= referenced_max
,
805 .lim
.flags
= BTRFS_QGROUP_LIMIT_MAX_RFER
,
813 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
817 r
= btrfs_is_filesystem(fd
);
824 args
.qgroupid
= qgroupid
;
827 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &args
) < 0) {
829 if (errno
== EBUSY
&& c
< 10) {
830 (void) btrfs_quota_scan_wait(fd
);
843 int btrfs_qgroup_set_limit(const char *path
, uint64_t qgroupid
, uint64_t referenced_max
) {
844 _cleanup_close_
int fd
= -1;
846 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
850 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
853 int btrfs_subvol_set_subtree_quota_limit_fd(int fd
, uint64_t subvol_id
, uint64_t referenced_max
) {
859 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
863 return btrfs_qgroup_set_limit_fd(fd
, qgroupid
, referenced_max
);
866 int btrfs_subvol_set_subtree_quota_limit(const char *path
, uint64_t subvol_id
, uint64_t referenced_max
) {
867 _cleanup_close_
int fd
= -1;
869 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
873 return btrfs_subvol_set_subtree_quota_limit_fd(fd
, subvol_id
, referenced_max
);
876 int btrfs_resize_loopback_fd(int fd
, uint64_t new_size
, bool grow_only
) {
877 struct btrfs_ioctl_vol_args args
= {};
878 _cleanup_free_
char *p
= NULL
, *loop
= NULL
, *backing
= NULL
;
879 _cleanup_close_
int loop_fd
= -1, backing_fd
= -1;
884 /* btrfs cannot handle file systems < 16M, hence use this as minimum */
885 if (new_size
< 16*1024*1024)
886 new_size
= 16*1024*1024;
888 r
= btrfs_get_block_device_fd(fd
, &dev
);
894 if (asprintf(&p
, "/sys/dev/block/%u:%u/loop/backing_file", major(dev
), minor(dev
)) < 0)
896 r
= read_one_line_file(p
, &backing
);
901 if (isempty(backing
) || !path_is_absolute(backing
))
904 backing_fd
= open(backing
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
908 if (fstat(backing_fd
, &st
) < 0)
910 if (!S_ISREG(st
.st_mode
))
913 if (new_size
== (uint64_t) st
.st_size
)
916 if (grow_only
&& new_size
< (uint64_t) st
.st_size
)
919 if (asprintf(&loop
, "/dev/block/%u:%u", major(dev
), minor(dev
)) < 0)
921 loop_fd
= open(loop
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
925 if (snprintf(args
.name
, sizeof(args
.name
), "%" PRIu64
, new_size
) >= (int) sizeof(args
.name
))
928 if (new_size
< (uint64_t) st
.st_size
) {
929 /* Decrease size: first decrease btrfs size, then shorten loopback */
930 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
934 if (ftruncate(backing_fd
, new_size
) < 0)
937 if (ioctl(loop_fd
, LOOP_SET_CAPACITY
, 0) < 0)
940 if (new_size
> (uint64_t) st
.st_size
) {
941 /* Increase size: first enlarge loopback, then increase btrfs size */
942 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
946 /* Make sure the free disk space is correctly updated for both file systems */
948 (void) fsync(backing_fd
);
953 int btrfs_resize_loopback(const char *p
, uint64_t new_size
, bool grow_only
) {
954 _cleanup_close_
int fd
= -1;
956 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
960 return btrfs_resize_loopback_fd(fd
, new_size
, grow_only
);
963 int btrfs_qgroupid_make(uint64_t level
, uint64_t id
, uint64_t *ret
) {
966 if (level
>= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT
)))
969 if (id
>= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
))
972 *ret
= (level
<< BTRFS_QGROUP_LEVEL_SHIFT
) | id
;
976 int btrfs_qgroupid_split(uint64_t qgroupid
, uint64_t *level
, uint64_t *id
) {
980 *level
= qgroupid
>> BTRFS_QGROUP_LEVEL_SHIFT
;
983 *id
= qgroupid
& ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
) - 1);
988 static int qgroup_create_or_destroy(int fd
, bool b
, uint64_t qgroupid
) {
990 struct btrfs_ioctl_qgroup_create_args args
= {
992 .qgroupid
= qgroupid
,
997 r
= btrfs_is_filesystem(fd
);
1004 if (ioctl(fd
, BTRFS_IOC_QGROUP_CREATE
, &args
) < 0) {
1006 if (errno
== EBUSY
&& c
< 10) {
1007 (void) btrfs_quota_scan_wait(fd
);
1020 int btrfs_qgroup_create(int fd
, uint64_t qgroupid
) {
1021 return qgroup_create_or_destroy(fd
, true, qgroupid
);
1024 int btrfs_qgroup_destroy(int fd
, uint64_t qgroupid
) {
1025 return qgroup_create_or_destroy(fd
, false, qgroupid
);
1028 int btrfs_qgroup_destroy_recursive(int fd
, uint64_t qgroupid
) {
1029 _cleanup_free_
uint64_t *qgroups
= NULL
;
1033 /* Destroys the specified qgroup, but unassigns it from all
1034 * its parents first. Also, it recursively destroys all
1035 * qgroups it is assgined to that have the same id part of the
1036 * qgroupid as the specified group. */
1038 r
= btrfs_qgroupid_split(qgroupid
, NULL
, &subvol_id
);
1042 n
= btrfs_qgroup_find_parents(fd
, qgroupid
, &qgroups
);
1046 for (i
= 0; i
< n
; i
++) {
1049 r
= btrfs_qgroupid_split(qgroups
[i
], NULL
, &id
);
1053 r
= btrfs_qgroup_unassign(fd
, qgroupid
, qgroups
[i
]);
1057 if (id
!= subvol_id
)
1060 /* The parent qgroupid shares the same id part with
1061 * us? If so, destroy it too. */
1063 (void) btrfs_qgroup_destroy_recursive(fd
, qgroups
[i
]);
1066 return btrfs_qgroup_destroy(fd
, qgroupid
);
1069 int btrfs_quota_scan_start(int fd
) {
1070 struct btrfs_ioctl_quota_rescan_args args
= {};
1074 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN
, &args
) < 0)
1080 int btrfs_quota_scan_wait(int fd
) {
1083 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_WAIT
) < 0)
1089 int btrfs_quota_scan_ongoing(int fd
) {
1090 struct btrfs_ioctl_quota_rescan_args args
= {};
1094 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_STATUS
, &args
) < 0)
1097 return !!args
.flags
;
1100 static int qgroup_assign_or_unassign(int fd
, bool b
, uint64_t child
, uint64_t parent
) {
1101 struct btrfs_ioctl_qgroup_assign_args args
= {
1109 r
= btrfs_is_filesystem(fd
);
1116 r
= ioctl(fd
, BTRFS_IOC_QGROUP_ASSIGN
, &args
);
1118 if (errno
== EBUSY
&& c
< 10) {
1119 (void) btrfs_quota_scan_wait(fd
);
1129 /* If the return value is > 0, we need to request a rescan */
1131 (void) btrfs_quota_scan_start(fd
);
1136 int btrfs_qgroup_assign(int fd
, uint64_t child
, uint64_t parent
) {
1137 return qgroup_assign_or_unassign(fd
, true, child
, parent
);
1140 int btrfs_qgroup_unassign(int fd
, uint64_t child
, uint64_t parent
) {
1141 return qgroup_assign_or_unassign(fd
, false, child
, parent
);
1144 static int subvol_remove_children(int fd
, const char *subvolume
, uint64_t subvol_id
, BtrfsRemoveFlags flags
) {
1145 struct btrfs_ioctl_search_args args
= {
1146 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1148 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1149 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1151 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1152 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1154 .key
.min_transid
= 0,
1155 .key
.max_transid
= (uint64_t) -1,
1158 struct btrfs_ioctl_vol_args vol_args
= {};
1159 _cleanup_close_
int subvol_fd
= -1;
1161 bool made_writable
= false;
1167 if (fstat(fd
, &st
) < 0)
1170 if (!S_ISDIR(st
.st_mode
))
1173 subvol_fd
= openat(fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1177 if (subvol_id
== 0) {
1178 r
= btrfs_subvol_get_id_fd(subvol_fd
, &subvol_id
);
1183 /* First, try to remove the subvolume. If it happens to be
1184 * already empty, this will just work. */
1185 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1186 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) >= 0) {
1187 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1190 if (!(flags
& BTRFS_REMOVE_RECURSIVE
) || errno
!= ENOTEMPTY
)
1193 /* OK, the subvolume is not empty, let's look for child
1194 * subvolumes, and remove them, first */
1196 args
.key
.min_offset
= args
.key
.max_offset
= subvol_id
;
1198 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1199 const struct btrfs_ioctl_search_header
*sh
;
1202 args
.key
.nr_items
= 256;
1203 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1206 if (args
.key
.nr_items
<= 0)
1209 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1210 _cleanup_free_
char *p
= NULL
;
1211 const struct btrfs_root_ref
*ref
;
1212 struct btrfs_ioctl_ino_lookup_args ino_args
;
1214 btrfs_ioctl_search_args_set(&args
, sh
);
1216 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1218 if (sh
->offset
!= subvol_id
)
1221 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1223 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1228 ino_args
.treeid
= subvol_id
;
1229 ino_args
.objectid
= htole64(ref
->dirid
);
1231 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1234 if (!made_writable
) {
1235 r
= btrfs_subvol_set_read_only_fd(subvol_fd
, false);
1239 made_writable
= true;
1242 if (isempty(ino_args
.name
))
1243 /* Subvolume is in the top-level
1244 * directory of the subvolume. */
1245 r
= subvol_remove_children(subvol_fd
, p
, sh
->objectid
, flags
);
1247 _cleanup_close_
int child_fd
= -1;
1249 /* Subvolume is somewhere further down,
1250 * hence we need to open the
1251 * containing directory first */
1253 child_fd
= openat(subvol_fd
, ino_args
.name
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1257 r
= subvol_remove_children(child_fd
, p
, sh
->objectid
, flags
);
1263 /* Increase search key by one, to read the next item, if we can. */
1264 if (!btrfs_ioctl_search_args_inc(&args
))
1268 /* OK, the child subvolumes should all be gone now, let's try
1269 * again to remove the subvolume */
1270 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) < 0)
1273 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
);
1277 int btrfs_subvol_remove(const char *path
, BtrfsRemoveFlags flags
) {
1278 _cleanup_close_
int fd
= -1;
1279 const char *subvolume
;
1284 r
= extract_subvolume_name(path
, &subvolume
);
1288 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1292 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1295 int btrfs_subvol_remove_fd(int fd
, const char *subvolume
, BtrfsRemoveFlags flags
) {
1296 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1299 int btrfs_qgroup_copy_limits(int fd
, uint64_t old_qgroupid
, uint64_t new_qgroupid
) {
1301 struct btrfs_ioctl_search_args args
= {
1302 /* Tree of quota items */
1303 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1305 /* The object ID is always 0 */
1306 .key
.min_objectid
= 0,
1307 .key
.max_objectid
= 0,
1309 /* Look precisely for the quota items */
1310 .key
.min_type
= BTRFS_QGROUP_LIMIT_KEY
,
1311 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
1313 /* For our qgroup */
1314 .key
.min_offset
= old_qgroupid
,
1315 .key
.max_offset
= old_qgroupid
,
1317 /* No restrictions on the other components */
1318 .key
.min_transid
= 0,
1319 .key
.max_transid
= (uint64_t) -1,
1324 r
= btrfs_is_filesystem(fd
);
1330 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1331 const struct btrfs_ioctl_search_header
*sh
;
1334 args
.key
.nr_items
= 256;
1335 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1338 if (args
.key
.nr_items
<= 0)
1341 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1342 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1343 struct btrfs_ioctl_qgroup_limit_args qargs
;
1346 /* Make sure we start the next search at least from this entry */
1347 btrfs_ioctl_search_args_set(&args
, sh
);
1349 if (sh
->objectid
!= 0)
1351 if (sh
->type
!= BTRFS_QGROUP_LIMIT_KEY
)
1353 if (sh
->offset
!= old_qgroupid
)
1356 /* We found the entry, now copy things over. */
1358 qargs
= (struct btrfs_ioctl_qgroup_limit_args
) {
1359 .qgroupid
= new_qgroupid
,
1361 .lim
.max_rfer
= le64toh(qli
->max_rfer
),
1362 .lim
.max_excl
= le64toh(qli
->max_excl
),
1363 .lim
.rsv_rfer
= le64toh(qli
->rsv_rfer
),
1364 .lim
.rsv_excl
= le64toh(qli
->rsv_excl
),
1366 .lim
.flags
= le64toh(qli
->flags
) & (BTRFS_QGROUP_LIMIT_MAX_RFER
|
1367 BTRFS_QGROUP_LIMIT_MAX_EXCL
|
1368 BTRFS_QGROUP_LIMIT_RSV_RFER
|
1369 BTRFS_QGROUP_LIMIT_RSV_EXCL
),
1373 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &qargs
) < 0) {
1374 if (errno
== EBUSY
&& c
< 10) {
1375 (void) btrfs_quota_scan_wait(fd
);
1387 /* Increase search key by one, to read the next item, if we can. */
1388 if (!btrfs_ioctl_search_args_inc(&args
))
1395 static int copy_quota_hierarchy(int fd
, uint64_t old_subvol_id
, uint64_t new_subvol_id
) {
1396 _cleanup_free_
uint64_t *old_qgroups
= NULL
, *old_parent_qgroups
= NULL
;
1397 bool copy_from_parent
= false, insert_intermediary_qgroup
= false;
1398 int n_old_qgroups
, n_old_parent_qgroups
, r
, i
;
1399 uint64_t old_parent_id
;
1403 /* Copies a reduced form of quota information from the old to
1404 * the new subvolume. */
1406 n_old_qgroups
= btrfs_qgroup_find_parents(fd
, old_subvol_id
, &old_qgroups
);
1407 if (n_old_qgroups
<= 0) /* Nothing to copy */
1408 return n_old_qgroups
;
1410 r
= btrfs_subvol_get_parent(fd
, old_subvol_id
, &old_parent_id
);
1414 n_old_parent_qgroups
= btrfs_qgroup_find_parents(fd
, old_parent_id
, &old_parent_qgroups
);
1415 if (n_old_parent_qgroups
< 0)
1416 return n_old_parent_qgroups
;
1418 for (i
= 0; i
< n_old_qgroups
; i
++) {
1422 r
= btrfs_qgroupid_split(old_qgroups
[i
], NULL
, &id
);
1426 if (id
== old_subvol_id
) {
1427 /* The old subvolume was member of a qgroup
1428 * that had the same id, but a different level
1429 * as it self. Let's set up something similar
1430 * in the destination. */
1431 insert_intermediary_qgroup
= true;
1435 for (j
= 0; j
< n_old_parent_qgroups
; j
++)
1436 if (old_parent_qgroups
[j
] == old_qgroups
[i
]) {
1437 /* The old subvolume shared a common
1438 * parent qgroup with its parent
1439 * subvolume. Let's set up something
1440 * similar in the destination. */
1441 copy_from_parent
= true;
1445 if (!insert_intermediary_qgroup
&& !copy_from_parent
)
1448 return btrfs_subvol_auto_qgroup_fd(fd
, new_subvol_id
, insert_intermediary_qgroup
);
1451 static int copy_subtree_quota_limits(int fd
, uint64_t old_subvol
, uint64_t new_subvol
) {
1452 uint64_t old_subtree_qgroup
, new_subtree_qgroup
;
1456 /* First copy the leaf limits */
1457 r
= btrfs_qgroup_copy_limits(fd
, old_subvol
, new_subvol
);
1462 /* Then, try to copy the subtree limits, if there are any. */
1463 r
= btrfs_subvol_find_subtree_qgroup(fd
, old_subvol
, &old_subtree_qgroup
);
1469 r
= btrfs_subvol_find_subtree_qgroup(fd
, new_subvol
, &new_subtree_qgroup
);
1475 r
= btrfs_qgroup_copy_limits(fd
, old_subtree_qgroup
, new_subtree_qgroup
);
1482 static int subvol_snapshot_children(int old_fd
, int new_fd
, const char *subvolume
, uint64_t old_subvol_id
, BtrfsSnapshotFlags flags
) {
1484 struct btrfs_ioctl_search_args args
= {
1485 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1487 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1488 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1490 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1491 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1493 .key
.min_transid
= 0,
1494 .key
.max_transid
= (uint64_t) -1,
1497 struct btrfs_ioctl_vol_args_v2 vol_args
= {
1498 .flags
= flags
& BTRFS_SNAPSHOT_READ_ONLY
? BTRFS_SUBVOL_RDONLY
: 0,
1501 _cleanup_close_
int subvolume_fd
= -1;
1502 uint64_t new_subvol_id
;
1505 assert(old_fd
>= 0);
1506 assert(new_fd
>= 0);
1509 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1511 if (ioctl(new_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &vol_args
) < 0)
1514 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
) &&
1515 !(flags
& BTRFS_SNAPSHOT_QUOTA
))
1518 if (old_subvol_id
== 0) {
1519 r
= btrfs_subvol_get_id_fd(old_fd
, &old_subvol_id
);
1524 r
= btrfs_subvol_get_id(new_fd
, vol_args
.name
, &new_subvol_id
);
1528 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1529 (void) copy_quota_hierarchy(new_fd
, old_subvol_id
, new_subvol_id
);
1531 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
)) {
1533 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1534 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1539 args
.key
.min_offset
= args
.key
.max_offset
= old_subvol_id
;
1541 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1542 const struct btrfs_ioctl_search_header
*sh
;
1545 args
.key
.nr_items
= 256;
1546 if (ioctl(old_fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1549 if (args
.key
.nr_items
<= 0)
1552 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1553 _cleanup_free_
char *p
= NULL
, *c
= NULL
, *np
= NULL
;
1554 struct btrfs_ioctl_ino_lookup_args ino_args
;
1555 const struct btrfs_root_ref
*ref
;
1556 _cleanup_close_
int old_child_fd
= -1, new_child_fd
= -1;
1558 btrfs_ioctl_search_args_set(&args
, sh
);
1560 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1563 /* Avoid finding the source subvolume a second
1565 if (sh
->offset
!= old_subvol_id
)
1568 /* Avoid running into loops if the new
1569 * subvolume is below the old one. */
1570 if (sh
->objectid
== new_subvol_id
)
1573 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1574 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1579 ino_args
.treeid
= old_subvol_id
;
1580 ino_args
.objectid
= htole64(ref
->dirid
);
1582 if (ioctl(old_fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1585 /* The kernel returns an empty name if the
1586 * subvolume is in the top-level directory,
1587 * and otherwise appends a slash, so that we
1588 * can just concatenate easily here, without
1589 * adding a slash. */
1590 c
= strappend(ino_args
.name
, p
);
1594 old_child_fd
= openat(old_fd
, c
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1595 if (old_child_fd
< 0)
1598 np
= strjoin(subvolume
, "/", ino_args
.name
, NULL
);
1602 new_child_fd
= openat(new_fd
, np
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1603 if (new_child_fd
< 0)
1606 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1607 /* If the snapshot is read-only we
1608 * need to mark it writable
1609 * temporarily, to put the subsnapshot
1612 if (subvolume_fd
< 0) {
1613 subvolume_fd
= openat(new_fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1614 if (subvolume_fd
< 0)
1618 r
= btrfs_subvol_set_read_only_fd(subvolume_fd
, false);
1623 /* When btrfs clones the subvolumes, child
1624 * subvolumes appear as empty directories. Remove
1625 * them, so that we can create a new snapshot
1627 if (unlinkat(new_child_fd
, p
, AT_REMOVEDIR
) < 0) {
1630 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
)
1631 (void) btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1636 r
= subvol_snapshot_children(old_child_fd
, new_child_fd
, p
, sh
->objectid
, flags
& ~BTRFS_SNAPSHOT_FALLBACK_COPY
);
1638 /* Restore the readonly flag */
1639 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1642 k
= btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1643 if (r
>= 0 && k
< 0)
1651 /* Increase search key by one, to read the next item, if we can. */
1652 if (!btrfs_ioctl_search_args_inc(&args
))
1656 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1657 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1662 int btrfs_subvol_snapshot_fd(int old_fd
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1663 _cleanup_close_
int new_fd
= -1;
1664 const char *subvolume
;
1667 assert(old_fd
>= 0);
1670 r
= btrfs_is_subvol(old_fd
);
1674 if (!(flags
& BTRFS_SNAPSHOT_FALLBACK_COPY
))
1677 r
= btrfs_subvol_make(new_path
);
1681 r
= copy_directory_fd(old_fd
, new_path
, true);
1683 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1687 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1688 r
= btrfs_subvol_set_read_only(new_path
, true);
1690 (void) btrfs_subvol_remove(new_path
, BTRFS_REMOVE_QUOTA
);
1698 r
= extract_subvolume_name(new_path
, &subvolume
);
1702 new_fd
= open_parent(new_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1706 return subvol_snapshot_children(old_fd
, new_fd
, subvolume
, 0, flags
);
1709 int btrfs_subvol_snapshot(const char *old_path
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1710 _cleanup_close_
int old_fd
= -1;
1715 old_fd
= open(old_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1719 return btrfs_subvol_snapshot_fd(old_fd
, new_path
, flags
);
1722 int btrfs_qgroup_find_parents(int fd
, uint64_t qgroupid
, uint64_t **ret
) {
1724 struct btrfs_ioctl_search_args args
= {
1725 /* Tree of quota items */
1726 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1728 /* Look precisely for the quota relation items */
1729 .key
.min_type
= BTRFS_QGROUP_RELATION_KEY
,
1730 .key
.max_type
= BTRFS_QGROUP_RELATION_KEY
,
1732 /* No restrictions on the other components */
1733 .key
.min_offset
= 0,
1734 .key
.max_offset
= (uint64_t) -1,
1736 .key
.min_transid
= 0,
1737 .key
.max_transid
= (uint64_t) -1,
1740 _cleanup_free_
uint64_t *items
= NULL
;
1741 size_t n_items
= 0, n_allocated
= 0;
1747 if (qgroupid
== 0) {
1748 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
1752 r
= btrfs_is_filesystem(fd
);
1759 args
.key
.min_objectid
= args
.key
.max_objectid
= qgroupid
;
1761 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1762 const struct btrfs_ioctl_search_header
*sh
;
1765 args
.key
.nr_items
= 256;
1766 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1769 if (args
.key
.nr_items
<= 0)
1772 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1774 /* Make sure we start the next search at least from this entry */
1775 btrfs_ioctl_search_args_set(&args
, sh
);
1777 if (sh
->type
!= BTRFS_QGROUP_RELATION_KEY
)
1779 if (sh
->offset
< sh
->objectid
)
1781 if (sh
->objectid
!= qgroupid
)
1784 if (!GREEDY_REALLOC(items
, n_allocated
, n_items
+1))
1787 items
[n_items
++] = sh
->offset
;
1790 /* Increase search key by one, to read the next item, if we can. */
1791 if (!btrfs_ioctl_search_args_inc(&args
))
1803 return (int) n_items
;
1806 int btrfs_subvol_auto_qgroup_fd(int fd
, uint64_t subvol_id
, bool insert_intermediary_qgroup
) {
1807 _cleanup_free_
uint64_t *qgroups
= NULL
;
1808 uint64_t parent_subvol
;
1809 bool changed
= false;
1815 * Sets up the specified subvolume's qgroup automatically in
1818 * If insert_intermediary_qgroup is false, the subvolume's
1819 * leaf qgroup will be assigned to the same parent qgroups as
1820 * the subvolume's parent subvolume.
1822 * If insert_intermediary_qgroup is true a new intermediary
1823 * higher-level qgroup is created, with a higher level number,
1824 * but reusing the id of the subvolume. The level number is
1825 * picked as one smaller than the lowest level qgroup the
1826 * parent subvolume is a member of. If the parent subvolume's
1827 * leaf qgroup is assigned to no higher-level qgroup a new
1828 * qgroup of level 255 is created instead. Either way, the new
1829 * qgroup is then assigned to the parent's higher-level
1830 * qgroup, and the subvolume itself is assigned to it.
1832 * If the subvolume is already assigned to a higher level
1833 * qgroup, no operation is executed.
1835 * Effectively this means: regardless if
1836 * insert_intermediary_qgroup is true or not, after this
1837 * function is invoked the subvolume will be accounted within
1838 * the same qgroups as the parent. However, if it is true, it
1839 * will also get its own higher-level qgroup, which may in
1840 * turn be used by subvolumes created beneath this subvolume
1843 * This hence defines a simple default qgroup setup for
1844 * subvolumes, as long as this function is invoked on each
1845 * created subvolume: each subvolume is always accounting
1846 * together with its immediate parents. Optionally, if
1847 * insert_intermediary_qgroup is true, it will also get a
1848 * qgroup that then includes all its own child subvolumes.
1851 if (subvol_id
== 0) {
1852 r
= btrfs_is_subvol(fd
);
1858 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1863 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
1866 if (n
> 0) /* already parent qgroups set up, let's bail */
1869 r
= btrfs_subvol_get_parent(fd
, subvol_id
, &parent_subvol
);
1873 qgroups
= mfree(qgroups
);
1874 n
= btrfs_qgroup_find_parents(fd
, parent_subvol
, &qgroups
);
1878 if (insert_intermediary_qgroup
) {
1879 uint64_t lowest
= 256, new_qgroupid
;
1880 bool created
= false;
1883 /* Determine the lowest qgroup that the parent
1884 * subvolume is assigned to. */
1886 for (i
= 0; i
< n
; i
++) {
1889 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, NULL
);
1897 if (lowest
<= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1900 r
= btrfs_qgroupid_make(lowest
- 1, subvol_id
, &new_qgroupid
);
1904 /* Create the new intermediary group, unless it already exists */
1905 r
= btrfs_qgroup_create(fd
, new_qgroupid
);
1906 if (r
< 0 && r
!= -EEXIST
)
1909 changed
= created
= true;
1911 for (i
= 0; i
< n
; i
++) {
1912 r
= btrfs_qgroup_assign(fd
, new_qgroupid
, qgroups
[i
]);
1913 if (r
< 0 && r
!= -EEXIST
) {
1915 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1923 r
= btrfs_qgroup_assign(fd
, subvol_id
, new_qgroupid
);
1924 if (r
< 0 && r
!= -EEXIST
) {
1926 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1935 /* Assign our subvolume to all the same qgroups as the parent */
1937 for (i
= 0; i
< n
; i
++) {
1938 r
= btrfs_qgroup_assign(fd
, subvol_id
, qgroups
[i
]);
1939 if (r
< 0 && r
!= -EEXIST
)
1949 int btrfs_subvol_auto_qgroup(const char *path
, uint64_t subvol_id
, bool create_intermediary_qgroup
) {
1950 _cleanup_close_
int fd
= -1;
1952 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1956 return btrfs_subvol_auto_qgroup_fd(fd
, subvol_id
, create_intermediary_qgroup
);
1959 int btrfs_subvol_get_parent(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
1961 struct btrfs_ioctl_search_args args
= {
1962 /* Tree of tree roots */
1963 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1965 /* Look precisely for the subvolume items */
1966 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1967 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1969 /* No restrictions on the other components */
1970 .key
.min_offset
= 0,
1971 .key
.max_offset
= (uint64_t) -1,
1973 .key
.min_transid
= 0,
1974 .key
.max_transid
= (uint64_t) -1,
1981 if (subvol_id
== 0) {
1982 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1986 r
= btrfs_is_filesystem(fd
);
1993 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
1995 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1996 const struct btrfs_ioctl_search_header
*sh
;
1999 args
.key
.nr_items
= 256;
2000 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
2003 if (args
.key
.nr_items
<= 0)
2006 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
2008 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
2010 if (sh
->objectid
!= subvol_id
)