1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include <linux/loop.h>
30 #include <sys/ioctl.h>
32 #include <sys/statfs.h>
33 #include <sys/sysmacros.h>
36 #if HAVE_LINUX_BTRFS_H
37 #include <linux/btrfs.h>
40 #include "alloc-util.h"
41 #include "blockdev-util.h"
42 #include "btrfs-ctree.h"
43 #include "btrfs-util.h"
44 #include "chattr-util.h"
46 #include "device-nodes.h"
52 #include "path-util.h"
54 #include "smack-util.h"
55 #include "sparse-endian.h"
56 #include "stat-util.h"
57 #include "string-util.h"
58 #include "time-util.h"
61 /* WARNING: Be careful with file system ioctls! When we get an fd, we
62 * need to make sure it either refers to only a regular file or
63 * directory, or that it is located on btrfs, before invoking any
64 * btrfs ioctls. The ioctl numbers are reused by some device drivers
65 * (such as DRM), and hence might have bad effects when invoked on
66 * device nodes (that reference drivers) rather than fds to normal
67 * files or directories. */
69 static int validate_subvolume_name(const char *name
) {
71 if (!filename_is_valid(name
))
74 if (strlen(name
) > BTRFS_SUBVOL_NAME_MAX
)
80 static int open_parent(const char *path
, int flags
) {
81 _cleanup_free_
char *parent
= NULL
;
86 parent
= dirname_malloc(path
);
90 fd
= open(parent
, flags
);
97 static int extract_subvolume_name(const char *path
, const char **subvolume
) {
106 r
= validate_subvolume_name(fn
);
114 int btrfs_is_filesystem(int fd
) {
119 if (fstatfs(fd
, &sfs
) < 0)
122 return F_TYPE_EQUAL(sfs
.f_type
, BTRFS_SUPER_MAGIC
);
125 int btrfs_is_subvol_fd(int fd
) {
130 /* On btrfs subvolumes always have the inode 256 */
132 if (fstat(fd
, &st
) < 0)
135 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
138 return btrfs_is_filesystem(fd
);
141 int btrfs_is_subvol(const char *path
) {
142 _cleanup_close_
int fd
= -1;
146 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
150 return btrfs_is_subvol_fd(fd
);
153 int btrfs_subvol_make(const char *path
) {
154 struct btrfs_ioctl_vol_args args
= {};
155 _cleanup_close_
int fd
= -1;
156 const char *subvolume
;
161 r
= extract_subvolume_name(path
, &subvolume
);
165 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
169 strncpy(args
.name
, subvolume
, sizeof(args
.name
)-1);
171 if (ioctl(fd
, BTRFS_IOC_SUBVOL_CREATE
, &args
) < 0)
177 int btrfs_subvol_set_read_only_fd(int fd
, bool b
) {
178 uint64_t flags
, nflags
;
183 if (fstat(fd
, &st
) < 0)
186 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
189 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
193 nflags
= flags
| BTRFS_SUBVOL_RDONLY
;
195 nflags
= flags
& ~BTRFS_SUBVOL_RDONLY
;
200 if (ioctl(fd
, BTRFS_IOC_SUBVOL_SETFLAGS
, &nflags
) < 0)
206 int btrfs_subvol_set_read_only(const char *path
, bool b
) {
207 _cleanup_close_
int fd
= -1;
209 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
213 return btrfs_subvol_set_read_only_fd(fd
, b
);
216 int btrfs_subvol_get_read_only_fd(int fd
) {
222 if (fstat(fd
, &st
) < 0)
225 if (!S_ISDIR(st
.st_mode
) || st
.st_ino
!= 256)
228 if (ioctl(fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
) < 0)
231 return !!(flags
& BTRFS_SUBVOL_RDONLY
);
234 int btrfs_reflink(int infd
, int outfd
) {
240 /* Make sure we invoke the ioctl on a regular file, so that no device driver accidentally gets it. */
242 r
= fd_verify_regular(outfd
);
246 if (ioctl(outfd
, BTRFS_IOC_CLONE
, infd
) < 0)
252 int btrfs_clone_range(int infd
, uint64_t in_offset
, int outfd
, uint64_t out_offset
, uint64_t sz
) {
253 struct btrfs_ioctl_clone_range_args args
= {
255 .src_offset
= in_offset
,
257 .dest_offset
= out_offset
,
265 r
= fd_verify_regular(outfd
);
269 if (ioctl(outfd
, BTRFS_IOC_CLONE_RANGE
, &args
) < 0)
275 int btrfs_get_block_device_fd(int fd
, dev_t
*dev
) {
276 struct btrfs_ioctl_fs_info_args fsi
= {};
283 r
= btrfs_is_filesystem(fd
);
289 if (ioctl(fd
, BTRFS_IOC_FS_INFO
, &fsi
) < 0)
292 /* We won't do this for btrfs RAID */
293 if (fsi
.num_devices
!= 1)
296 for (id
= 1; id
<= fsi
.max_id
; id
++) {
297 struct btrfs_ioctl_dev_info_args di
= {
302 if (ioctl(fd
, BTRFS_IOC_DEV_INFO
, &di
) < 0) {
309 if (stat((char*) di
.path
, &st
) < 0)
312 if (!S_ISBLK(st
.st_mode
))
315 if (major(st
.st_rdev
) == 0)
325 int btrfs_get_block_device(const char *path
, dev_t
*dev
) {
326 _cleanup_close_
int fd
= -1;
331 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
335 return btrfs_get_block_device_fd(fd
, dev
);
338 int btrfs_subvol_get_id_fd(int fd
, uint64_t *ret
) {
339 struct btrfs_ioctl_ino_lookup_args args
= {
340 .objectid
= BTRFS_FIRST_FREE_OBJECTID
347 r
= btrfs_is_filesystem(fd
);
353 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
) < 0)
360 int btrfs_subvol_get_id(int fd
, const char *subvol
, uint64_t *ret
) {
361 _cleanup_close_
int subvol_fd
= -1;
366 subvol_fd
= openat(fd
, subvol
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
370 return btrfs_subvol_get_id_fd(subvol_fd
, ret
);
373 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args
*args
) {
376 /* the objectid, type, offset together make up the btrfs key,
377 * which is considered a single 136byte integer when
378 * comparing. This call increases the counter by one, dealing
379 * with the overflow between the overflows */
381 if (args
->key
.min_offset
< (uint64_t) -1) {
382 args
->key
.min_offset
++;
386 if (args
->key
.min_type
< (uint8_t) -1) {
387 args
->key
.min_type
++;
388 args
->key
.min_offset
= 0;
392 if (args
->key
.min_objectid
< (uint64_t) -1) {
393 args
->key
.min_objectid
++;
394 args
->key
.min_offset
= 0;
395 args
->key
.min_type
= 0;
402 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args
*args
, const struct btrfs_ioctl_search_header
*h
) {
406 args
->key
.min_objectid
= h
->objectid
;
407 args
->key
.min_type
= h
->type
;
408 args
->key
.min_offset
= h
->offset
;
411 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
*args
) {
414 /* Compare min and max */
416 if (args
->key
.min_objectid
< args
->key
.max_objectid
)
418 if (args
->key
.min_objectid
> args
->key
.max_objectid
)
421 if (args
->key
.min_type
< args
->key
.max_type
)
423 if (args
->key
.min_type
> args
->key
.max_type
)
426 if (args
->key
.min_offset
< args
->key
.max_offset
)
428 if (args
->key
.min_offset
> args
->key
.max_offset
)
434 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
436 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
437 (i) < (args).key.nr_items; \
439 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
441 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
442 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
444 int btrfs_subvol_get_info_fd(int fd
, uint64_t subvol_id
, BtrfsSubvolInfo
*ret
) {
445 struct btrfs_ioctl_search_args args
= {
446 /* Tree of tree roots */
447 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
449 /* Look precisely for the subvolume items */
450 .key
.min_type
= BTRFS_ROOT_ITEM_KEY
,
451 .key
.max_type
= BTRFS_ROOT_ITEM_KEY
,
454 .key
.max_offset
= (uint64_t) -1,
456 /* No restrictions on the other components */
457 .key
.min_transid
= 0,
458 .key
.max_transid
= (uint64_t) -1,
467 if (subvol_id
== 0) {
468 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
472 r
= btrfs_is_filesystem(fd
);
479 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
481 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
482 const struct btrfs_ioctl_search_header
*sh
;
485 args
.key
.nr_items
= 256;
486 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
489 if (args
.key
.nr_items
<= 0)
492 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
494 const struct btrfs_root_item
*ri
;
496 /* Make sure we start the next search at least from this entry */
497 btrfs_ioctl_search_args_set(&args
, sh
);
499 if (sh
->objectid
!= subvol_id
)
501 if (sh
->type
!= BTRFS_ROOT_ITEM_KEY
)
504 /* Older versions of the struct lacked the otime setting */
505 if (sh
->len
< offsetof(struct btrfs_root_item
, otime
) + sizeof(struct btrfs_timespec
))
508 ri
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
510 ret
->otime
= (usec_t
) le64toh(ri
->otime
.sec
) * USEC_PER_SEC
+
511 (usec_t
) le32toh(ri
->otime
.nsec
) / NSEC_PER_USEC
;
513 ret
->subvol_id
= subvol_id
;
514 ret
->read_only
= !!(le64toh(ri
->flags
) & BTRFS_ROOT_SUBVOL_RDONLY
);
516 assert_cc(sizeof(ri
->uuid
) == sizeof(ret
->uuid
));
517 memcpy(&ret
->uuid
, ri
->uuid
, sizeof(ret
->uuid
));
518 memcpy(&ret
->parent_uuid
, ri
->parent_uuid
, sizeof(ret
->parent_uuid
));
524 /* Increase search key by one, to read the next item, if we can. */
525 if (!btrfs_ioctl_search_args_inc(&args
))
536 int btrfs_qgroup_get_quota_fd(int fd
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
538 struct btrfs_ioctl_search_args args
= {
539 /* Tree of quota items */
540 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
542 /* The object ID is always 0 */
543 .key
.min_objectid
= 0,
544 .key
.max_objectid
= 0,
546 /* Look precisely for the quota items */
547 .key
.min_type
= BTRFS_QGROUP_STATUS_KEY
,
548 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
550 /* No restrictions on the other components */
551 .key
.min_transid
= 0,
552 .key
.max_transid
= (uint64_t) -1,
555 bool found_info
= false, found_limit
= false;
562 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
566 r
= btrfs_is_filesystem(fd
);
573 args
.key
.min_offset
= args
.key
.max_offset
= qgroupid
;
575 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
576 const struct btrfs_ioctl_search_header
*sh
;
579 args
.key
.nr_items
= 256;
580 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
581 if (errno
== ENOENT
) /* quota tree is missing: quota disabled */
587 if (args
.key
.nr_items
<= 0)
590 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
592 /* Make sure we start the next search at least from this entry */
593 btrfs_ioctl_search_args_set(&args
, sh
);
595 if (sh
->objectid
!= 0)
597 if (sh
->offset
!= qgroupid
)
600 if (sh
->type
== BTRFS_QGROUP_INFO_KEY
) {
601 const struct btrfs_qgroup_info_item
*qii
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
603 ret
->referenced
= le64toh(qii
->rfer
);
604 ret
->exclusive
= le64toh(qii
->excl
);
608 } else if (sh
->type
== BTRFS_QGROUP_LIMIT_KEY
) {
609 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
611 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_RFER
)
612 ret
->referenced_max
= le64toh(qli
->max_rfer
);
614 ret
->referenced_max
= (uint64_t) -1;
616 if (le64toh(qli
->flags
) & BTRFS_QGROUP_LIMIT_MAX_EXCL
)
617 ret
->exclusive_max
= le64toh(qli
->max_excl
);
619 ret
->exclusive_max
= (uint64_t) -1;
624 if (found_info
&& found_limit
)
628 /* Increase search key by one, to read the next item, if we can. */
629 if (!btrfs_ioctl_search_args_inc(&args
))
634 if (!found_limit
&& !found_info
)
638 ret
->referenced
= (uint64_t) -1;
639 ret
->exclusive
= (uint64_t) -1;
643 ret
->referenced_max
= (uint64_t) -1;
644 ret
->exclusive_max
= (uint64_t) -1;
650 int btrfs_qgroup_get_quota(const char *path
, uint64_t qgroupid
, BtrfsQuotaInfo
*ret
) {
651 _cleanup_close_
int fd
= -1;
653 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
657 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
660 int btrfs_subvol_find_subtree_qgroup(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
661 uint64_t level
, lowest
= (uint64_t) -1, lowest_qgroupid
= 0;
662 _cleanup_free_
uint64_t *qgroups
= NULL
;
668 /* This finds the "subtree" qgroup for a specific
669 * subvolume. This only works for subvolumes that have been
670 * prepared with btrfs_subvol_auto_qgroup_fd() with
671 * insert_intermediary_qgroup=true (or equivalent). For others
672 * it will return the leaf qgroup instead. The two cases may
673 * be distuingished via the return value, which is 1 in case
674 * an appropriate "subtree" qgroup was found, and 0
677 if (subvol_id
== 0) {
678 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
683 r
= btrfs_qgroupid_split(subvol_id
, &level
, NULL
);
686 if (level
!= 0) /* Input must be a leaf qgroup */
689 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
693 for (i
= 0; i
< n
; i
++) {
696 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, &id
);
703 if (lowest
== (uint64_t) -1 || level
< lowest
) {
704 lowest_qgroupid
= qgroups
[i
];
709 if (lowest
== (uint64_t) -1) {
710 /* No suitable higher-level qgroup found, let's return
711 * the leaf qgroup instead, and indicate that with the
718 *ret
= lowest_qgroupid
;
722 int btrfs_subvol_get_subtree_quota_fd(int fd
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
729 /* This determines the quota data of the qgroup with the
730 * lowest level, that shares the id part with the specified
731 * subvolume. This is useful for determining the quota data
732 * for entire subvolume subtrees, as long as the subtrees have
733 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
736 r
= btrfs_subvol_find_subtree_qgroup(fd
, subvol_id
, &qgroupid
);
740 return btrfs_qgroup_get_quota_fd(fd
, qgroupid
, ret
);
743 int btrfs_subvol_get_subtree_quota(const char *path
, uint64_t subvol_id
, BtrfsQuotaInfo
*ret
) {
744 _cleanup_close_
int fd
= -1;
746 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
750 return btrfs_subvol_get_subtree_quota_fd(fd
, subvol_id
, ret
);
753 int btrfs_defrag_fd(int fd
) {
758 r
= fd_verify_regular(fd
);
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 char p
[SYS_BLOCK_PATH_MAX("/loop/backing_file")];
886 _cleanup_free_
char *backing
= NULL
;
887 _cleanup_close_
int loop_fd
= -1, backing_fd
= -1;
892 /* In contrast to btrfs quota ioctls ftruncate() cannot make sense of "infinity" or file sizes > 2^31 */
893 if (!FILE_SIZE_VALID(new_size
))
896 /* btrfs cannot handle file systems < 16M, hence use this as minimum */
897 if (new_size
< 16*1024*1024)
898 new_size
= 16*1024*1024;
900 r
= btrfs_get_block_device_fd(fd
, &dev
);
906 xsprintf_sys_block_path(p
, "/loop/backing_file", dev
);
907 r
= read_one_line_file(p
, &backing
);
912 if (isempty(backing
) || !path_is_absolute(backing
))
915 backing_fd
= open(backing
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
919 if (fstat(backing_fd
, &st
) < 0)
921 if (!S_ISREG(st
.st_mode
))
924 if (new_size
== (uint64_t) st
.st_size
)
927 if (grow_only
&& new_size
< (uint64_t) st
.st_size
)
930 xsprintf_sys_block_path(p
, NULL
, dev
);
931 loop_fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
);
935 if (snprintf(args
.name
, sizeof(args
.name
), "%" PRIu64
, new_size
) >= (int) sizeof(args
.name
))
938 if (new_size
< (uint64_t) st
.st_size
) {
939 /* Decrease size: first decrease btrfs size, then shorten loopback */
940 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
944 if (ftruncate(backing_fd
, new_size
) < 0)
947 if (ioctl(loop_fd
, LOOP_SET_CAPACITY
, 0) < 0)
950 if (new_size
> (uint64_t) st
.st_size
) {
951 /* Increase size: first enlarge loopback, then increase btrfs size */
952 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
956 /* Make sure the free disk space is correctly updated for both file systems */
958 (void) fsync(backing_fd
);
963 int btrfs_resize_loopback(const char *p
, uint64_t new_size
, bool grow_only
) {
964 _cleanup_close_
int fd
= -1;
966 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
970 return btrfs_resize_loopback_fd(fd
, new_size
, grow_only
);
973 int btrfs_qgroupid_make(uint64_t level
, uint64_t id
, uint64_t *ret
) {
976 if (level
>= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT
)))
979 if (id
>= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
))
982 *ret
= (level
<< BTRFS_QGROUP_LEVEL_SHIFT
) | id
;
986 int btrfs_qgroupid_split(uint64_t qgroupid
, uint64_t *level
, uint64_t *id
) {
990 *level
= qgroupid
>> BTRFS_QGROUP_LEVEL_SHIFT
;
993 *id
= qgroupid
& ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT
) - 1);
998 static int qgroup_create_or_destroy(int fd
, bool b
, uint64_t qgroupid
) {
1000 struct btrfs_ioctl_qgroup_create_args args
= {
1002 .qgroupid
= qgroupid
,
1007 r
= btrfs_is_filesystem(fd
);
1014 if (ioctl(fd
, BTRFS_IOC_QGROUP_CREATE
, &args
) < 0) {
1016 /* If quota is not enabled, we get EINVAL. Turn this into a recognizable error */
1017 if (errno
== EINVAL
)
1018 return -ENOPROTOOPT
;
1020 if (errno
== EBUSY
&& c
< 10) {
1021 (void) btrfs_quota_scan_wait(fd
);
1034 int btrfs_qgroup_create(int fd
, uint64_t qgroupid
) {
1035 return qgroup_create_or_destroy(fd
, true, qgroupid
);
1038 int btrfs_qgroup_destroy(int fd
, uint64_t qgroupid
) {
1039 return qgroup_create_or_destroy(fd
, false, qgroupid
);
1042 int btrfs_qgroup_destroy_recursive(int fd
, uint64_t qgroupid
) {
1043 _cleanup_free_
uint64_t *qgroups
= NULL
;
1047 /* Destroys the specified qgroup, but unassigns it from all
1048 * its parents first. Also, it recursively destroys all
1049 * qgroups it is assgined to that have the same id part of the
1050 * qgroupid as the specified group. */
1052 r
= btrfs_qgroupid_split(qgroupid
, NULL
, &subvol_id
);
1056 n
= btrfs_qgroup_find_parents(fd
, qgroupid
, &qgroups
);
1060 for (i
= 0; i
< n
; i
++) {
1063 r
= btrfs_qgroupid_split(qgroups
[i
], NULL
, &id
);
1067 r
= btrfs_qgroup_unassign(fd
, qgroupid
, qgroups
[i
]);
1071 if (id
!= subvol_id
)
1074 /* The parent qgroupid shares the same id part with
1075 * us? If so, destroy it too. */
1077 (void) btrfs_qgroup_destroy_recursive(fd
, qgroups
[i
]);
1080 return btrfs_qgroup_destroy(fd
, qgroupid
);
1083 int btrfs_quota_scan_start(int fd
) {
1084 struct btrfs_ioctl_quota_rescan_args args
= {};
1088 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN
, &args
) < 0)
1094 int btrfs_quota_scan_wait(int fd
) {
1097 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_WAIT
) < 0)
1103 int btrfs_quota_scan_ongoing(int fd
) {
1104 struct btrfs_ioctl_quota_rescan_args args
= {};
1108 if (ioctl(fd
, BTRFS_IOC_QUOTA_RESCAN_STATUS
, &args
) < 0)
1111 return !!args
.flags
;
1114 static int qgroup_assign_or_unassign(int fd
, bool b
, uint64_t child
, uint64_t parent
) {
1115 struct btrfs_ioctl_qgroup_assign_args args
= {
1123 r
= btrfs_is_filesystem(fd
);
1130 r
= ioctl(fd
, BTRFS_IOC_QGROUP_ASSIGN
, &args
);
1132 if (errno
== EBUSY
&& c
< 10) {
1133 (void) btrfs_quota_scan_wait(fd
);
1143 /* If the return value is > 0, we need to request a rescan */
1145 (void) btrfs_quota_scan_start(fd
);
1150 int btrfs_qgroup_assign(int fd
, uint64_t child
, uint64_t parent
) {
1151 return qgroup_assign_or_unassign(fd
, true, child
, parent
);
1154 int btrfs_qgroup_unassign(int fd
, uint64_t child
, uint64_t parent
) {
1155 return qgroup_assign_or_unassign(fd
, false, child
, parent
);
1158 static int subvol_remove_children(int fd
, const char *subvolume
, uint64_t subvol_id
, BtrfsRemoveFlags flags
) {
1159 struct btrfs_ioctl_search_args args
= {
1160 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1162 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1163 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1165 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1166 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1168 .key
.min_transid
= 0,
1169 .key
.max_transid
= (uint64_t) -1,
1172 struct btrfs_ioctl_vol_args vol_args
= {};
1173 _cleanup_close_
int subvol_fd
= -1;
1175 bool made_writable
= false;
1181 if (fstat(fd
, &st
) < 0)
1184 if (!S_ISDIR(st
.st_mode
))
1187 subvol_fd
= openat(fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1191 if (subvol_id
== 0) {
1192 r
= btrfs_subvol_get_id_fd(subvol_fd
, &subvol_id
);
1197 /* First, try to remove the subvolume. If it happens to be
1198 * already empty, this will just work. */
1199 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1200 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) >= 0) {
1201 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1204 if (!(flags
& BTRFS_REMOVE_RECURSIVE
) || errno
!= ENOTEMPTY
)
1207 /* OK, the subvolume is not empty, let's look for child
1208 * subvolumes, and remove them, first */
1210 args
.key
.min_offset
= args
.key
.max_offset
= subvol_id
;
1212 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1213 const struct btrfs_ioctl_search_header
*sh
;
1216 args
.key
.nr_items
= 256;
1217 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1220 if (args
.key
.nr_items
<= 0)
1223 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1224 _cleanup_free_
char *p
= NULL
;
1225 const struct btrfs_root_ref
*ref
;
1226 struct btrfs_ioctl_ino_lookup_args ino_args
;
1228 btrfs_ioctl_search_args_set(&args
, sh
);
1230 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1232 if (sh
->offset
!= subvol_id
)
1235 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1237 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1242 ino_args
.treeid
= subvol_id
;
1243 ino_args
.objectid
= htole64(ref
->dirid
);
1245 if (ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1248 if (!made_writable
) {
1249 r
= btrfs_subvol_set_read_only_fd(subvol_fd
, false);
1253 made_writable
= true;
1256 if (isempty(ino_args
.name
))
1257 /* Subvolume is in the top-level
1258 * directory of the subvolume. */
1259 r
= subvol_remove_children(subvol_fd
, p
, sh
->objectid
, flags
);
1261 _cleanup_close_
int child_fd
= -1;
1263 /* Subvolume is somewhere further down,
1264 * hence we need to open the
1265 * containing directory first */
1267 child_fd
= openat(subvol_fd
, ino_args
.name
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1271 r
= subvol_remove_children(child_fd
, p
, sh
->objectid
, flags
);
1277 /* Increase search key by one, to read the next item, if we can. */
1278 if (!btrfs_ioctl_search_args_inc(&args
))
1282 /* OK, the child subvolumes should all be gone now, let's try
1283 * again to remove the subvolume */
1284 if (ioctl(fd
, BTRFS_IOC_SNAP_DESTROY
, &vol_args
) < 0)
1287 (void) btrfs_qgroup_destroy_recursive(fd
, subvol_id
);
1291 int btrfs_subvol_remove(const char *path
, BtrfsRemoveFlags flags
) {
1292 _cleanup_close_
int fd
= -1;
1293 const char *subvolume
;
1298 r
= extract_subvolume_name(path
, &subvolume
);
1302 fd
= open_parent(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1306 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1309 int btrfs_subvol_remove_fd(int fd
, const char *subvolume
, BtrfsRemoveFlags flags
) {
1310 return subvol_remove_children(fd
, subvolume
, 0, flags
);
1313 int btrfs_qgroup_copy_limits(int fd
, uint64_t old_qgroupid
, uint64_t new_qgroupid
) {
1315 struct btrfs_ioctl_search_args args
= {
1316 /* Tree of quota items */
1317 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1319 /* The object ID is always 0 */
1320 .key
.min_objectid
= 0,
1321 .key
.max_objectid
= 0,
1323 /* Look precisely for the quota items */
1324 .key
.min_type
= BTRFS_QGROUP_LIMIT_KEY
,
1325 .key
.max_type
= BTRFS_QGROUP_LIMIT_KEY
,
1327 /* For our qgroup */
1328 .key
.min_offset
= old_qgroupid
,
1329 .key
.max_offset
= old_qgroupid
,
1331 /* No restrictions on the other components */
1332 .key
.min_transid
= 0,
1333 .key
.max_transid
= (uint64_t) -1,
1338 r
= btrfs_is_filesystem(fd
);
1344 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1345 const struct btrfs_ioctl_search_header
*sh
;
1348 args
.key
.nr_items
= 256;
1349 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1350 if (errno
== ENOENT
) /* quota tree missing: quota is not enabled, hence nothing to copy */
1356 if (args
.key
.nr_items
<= 0)
1359 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1360 const struct btrfs_qgroup_limit_item
*qli
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1361 struct btrfs_ioctl_qgroup_limit_args qargs
;
1364 /* Make sure we start the next search at least from this entry */
1365 btrfs_ioctl_search_args_set(&args
, sh
);
1367 if (sh
->objectid
!= 0)
1369 if (sh
->type
!= BTRFS_QGROUP_LIMIT_KEY
)
1371 if (sh
->offset
!= old_qgroupid
)
1374 /* We found the entry, now copy things over. */
1376 qargs
= (struct btrfs_ioctl_qgroup_limit_args
) {
1377 .qgroupid
= new_qgroupid
,
1379 .lim
.max_rfer
= le64toh(qli
->max_rfer
),
1380 .lim
.max_excl
= le64toh(qli
->max_excl
),
1381 .lim
.rsv_rfer
= le64toh(qli
->rsv_rfer
),
1382 .lim
.rsv_excl
= le64toh(qli
->rsv_excl
),
1384 .lim
.flags
= le64toh(qli
->flags
) & (BTRFS_QGROUP_LIMIT_MAX_RFER
|
1385 BTRFS_QGROUP_LIMIT_MAX_EXCL
|
1386 BTRFS_QGROUP_LIMIT_RSV_RFER
|
1387 BTRFS_QGROUP_LIMIT_RSV_EXCL
),
1391 if (ioctl(fd
, BTRFS_IOC_QGROUP_LIMIT
, &qargs
) < 0) {
1392 if (errno
== EBUSY
&& c
< 10) {
1393 (void) btrfs_quota_scan_wait(fd
);
1405 /* Increase search key by one, to read the next item, if we can. */
1406 if (!btrfs_ioctl_search_args_inc(&args
))
1413 static int copy_quota_hierarchy(int fd
, uint64_t old_subvol_id
, uint64_t new_subvol_id
) {
1414 _cleanup_free_
uint64_t *old_qgroups
= NULL
, *old_parent_qgroups
= NULL
;
1415 bool copy_from_parent
= false, insert_intermediary_qgroup
= false;
1416 int n_old_qgroups
, n_old_parent_qgroups
, r
, i
;
1417 uint64_t old_parent_id
;
1421 /* Copies a reduced form of quota information from the old to
1422 * the new subvolume. */
1424 n_old_qgroups
= btrfs_qgroup_find_parents(fd
, old_subvol_id
, &old_qgroups
);
1425 if (n_old_qgroups
<= 0) /* Nothing to copy */
1426 return n_old_qgroups
;
1428 r
= btrfs_subvol_get_parent(fd
, old_subvol_id
, &old_parent_id
);
1430 /* We have no parent, hence nothing to copy. */
1431 n_old_parent_qgroups
= 0;
1435 n_old_parent_qgroups
= btrfs_qgroup_find_parents(fd
, old_parent_id
, &old_parent_qgroups
);
1436 if (n_old_parent_qgroups
< 0)
1437 return n_old_parent_qgroups
;
1440 for (i
= 0; i
< n_old_qgroups
; i
++) {
1444 r
= btrfs_qgroupid_split(old_qgroups
[i
], NULL
, &id
);
1448 if (id
== old_subvol_id
) {
1449 /* The old subvolume was member of a qgroup
1450 * that had the same id, but a different level
1451 * as it self. Let's set up something similar
1452 * in the destination. */
1453 insert_intermediary_qgroup
= true;
1457 for (j
= 0; j
< n_old_parent_qgroups
; j
++)
1458 if (old_parent_qgroups
[j
] == old_qgroups
[i
]) {
1459 /* The old subvolume shared a common
1460 * parent qgroup with its parent
1461 * subvolume. Let's set up something
1462 * similar in the destination. */
1463 copy_from_parent
= true;
1467 if (!insert_intermediary_qgroup
&& !copy_from_parent
)
1470 return btrfs_subvol_auto_qgroup_fd(fd
, new_subvol_id
, insert_intermediary_qgroup
);
1473 static int copy_subtree_quota_limits(int fd
, uint64_t old_subvol
, uint64_t new_subvol
) {
1474 uint64_t old_subtree_qgroup
, new_subtree_qgroup
;
1478 /* First copy the leaf limits */
1479 r
= btrfs_qgroup_copy_limits(fd
, old_subvol
, new_subvol
);
1484 /* Then, try to copy the subtree limits, if there are any. */
1485 r
= btrfs_subvol_find_subtree_qgroup(fd
, old_subvol
, &old_subtree_qgroup
);
1491 r
= btrfs_subvol_find_subtree_qgroup(fd
, new_subvol
, &new_subtree_qgroup
);
1497 r
= btrfs_qgroup_copy_limits(fd
, old_subtree_qgroup
, new_subtree_qgroup
);
1504 static int subvol_snapshot_children(int old_fd
, int new_fd
, const char *subvolume
, uint64_t old_subvol_id
, BtrfsSnapshotFlags flags
) {
1506 struct btrfs_ioctl_search_args args
= {
1507 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
1509 .key
.min_objectid
= BTRFS_FIRST_FREE_OBJECTID
,
1510 .key
.max_objectid
= BTRFS_LAST_FREE_OBJECTID
,
1512 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
1513 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
1515 .key
.min_transid
= 0,
1516 .key
.max_transid
= (uint64_t) -1,
1519 struct btrfs_ioctl_vol_args_v2 vol_args
= {
1520 .flags
= flags
& BTRFS_SNAPSHOT_READ_ONLY
? BTRFS_SUBVOL_RDONLY
: 0,
1523 _cleanup_close_
int subvolume_fd
= -1;
1524 uint64_t new_subvol_id
;
1527 assert(old_fd
>= 0);
1528 assert(new_fd
>= 0);
1531 strncpy(vol_args
.name
, subvolume
, sizeof(vol_args
.name
)-1);
1533 if (ioctl(new_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &vol_args
) < 0)
1536 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
) &&
1537 !(flags
& BTRFS_SNAPSHOT_QUOTA
))
1540 if (old_subvol_id
== 0) {
1541 r
= btrfs_subvol_get_id_fd(old_fd
, &old_subvol_id
);
1546 r
= btrfs_subvol_get_id(new_fd
, vol_args
.name
, &new_subvol_id
);
1550 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1551 (void) copy_quota_hierarchy(new_fd
, old_subvol_id
, new_subvol_id
);
1553 if (!(flags
& BTRFS_SNAPSHOT_RECURSIVE
)) {
1555 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1556 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1561 args
.key
.min_offset
= args
.key
.max_offset
= old_subvol_id
;
1563 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1564 const struct btrfs_ioctl_search_header
*sh
;
1567 args
.key
.nr_items
= 256;
1568 if (ioctl(old_fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
1571 if (args
.key
.nr_items
<= 0)
1574 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1575 _cleanup_free_
char *p
= NULL
, *c
= NULL
, *np
= NULL
;
1576 struct btrfs_ioctl_ino_lookup_args ino_args
;
1577 const struct btrfs_root_ref
*ref
;
1578 _cleanup_close_
int old_child_fd
= -1, new_child_fd
= -1;
1580 btrfs_ioctl_search_args_set(&args
, sh
);
1582 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
1585 /* Avoid finding the source subvolume a second
1587 if (sh
->offset
!= old_subvol_id
)
1590 /* Avoid running into loops if the new
1591 * subvolume is below the old one. */
1592 if (sh
->objectid
== new_subvol_id
)
1595 ref
= BTRFS_IOCTL_SEARCH_HEADER_BODY(sh
);
1596 p
= strndup((char*) ref
+ sizeof(struct btrfs_root_ref
), le64toh(ref
->name_len
));
1601 ino_args
.treeid
= old_subvol_id
;
1602 ino_args
.objectid
= htole64(ref
->dirid
);
1604 if (ioctl(old_fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
) < 0)
1607 /* The kernel returns an empty name if the
1608 * subvolume is in the top-level directory,
1609 * and otherwise appends a slash, so that we
1610 * can just concatenate easily here, without
1611 * adding a slash. */
1612 c
= strappend(ino_args
.name
, p
);
1616 old_child_fd
= openat(old_fd
, c
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1617 if (old_child_fd
< 0)
1620 np
= strjoin(subvolume
, "/", ino_args
.name
);
1624 new_child_fd
= openat(new_fd
, np
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1625 if (new_child_fd
< 0)
1628 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1629 /* If the snapshot is read-only we
1630 * need to mark it writable
1631 * temporarily, to put the subsnapshot
1634 if (subvolume_fd
< 0) {
1635 subvolume_fd
= openat(new_fd
, subvolume
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
1636 if (subvolume_fd
< 0)
1640 r
= btrfs_subvol_set_read_only_fd(subvolume_fd
, false);
1645 /* When btrfs clones the subvolumes, child
1646 * subvolumes appear as empty directories. Remove
1647 * them, so that we can create a new snapshot
1649 if (unlinkat(new_child_fd
, p
, AT_REMOVEDIR
) < 0) {
1652 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
)
1653 (void) btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1658 r
= subvol_snapshot_children(old_child_fd
, new_child_fd
, p
, sh
->objectid
, flags
& ~BTRFS_SNAPSHOT_FALLBACK_COPY
);
1660 /* Restore the readonly flag */
1661 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1664 k
= btrfs_subvol_set_read_only_fd(subvolume_fd
, true);
1665 if (r
>= 0 && k
< 0)
1673 /* Increase search key by one, to read the next item, if we can. */
1674 if (!btrfs_ioctl_search_args_inc(&args
))
1678 if (flags
& BTRFS_SNAPSHOT_QUOTA
)
1679 (void) copy_subtree_quota_limits(new_fd
, old_subvol_id
, new_subvol_id
);
1684 int btrfs_subvol_snapshot_fd(int old_fd
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1685 _cleanup_close_
int new_fd
= -1;
1686 const char *subvolume
;
1689 assert(old_fd
>= 0);
1692 r
= btrfs_is_subvol_fd(old_fd
);
1696 bool plain_directory
= false;
1698 /* If the source isn't a proper subvolume, fail unless fallback is requested */
1699 if (!(flags
& BTRFS_SNAPSHOT_FALLBACK_COPY
))
1702 r
= btrfs_subvol_make(new_path
);
1703 if (r
== -ENOTTY
&& (flags
& BTRFS_SNAPSHOT_FALLBACK_DIRECTORY
)) {
1704 /* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */
1705 if (mkdir(new_path
, 0755) < 0)
1708 plain_directory
= true;
1712 r
= copy_directory_fd(old_fd
, new_path
, COPY_MERGE
|COPY_REFLINK
);
1716 if (flags
& BTRFS_SNAPSHOT_READ_ONLY
) {
1718 if (plain_directory
) {
1719 /* Plain directories have no recursive read-only flag, but something pretty close to
1720 * it: the IMMUTABLE bit. Let's use this here, if this is requested. */
1722 if (flags
& BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE
)
1723 (void) chattr_path(new_path
, FS_IMMUTABLE_FL
, FS_IMMUTABLE_FL
);
1725 r
= btrfs_subvol_set_read_only(new_path
, true);
1734 (void) rm_rf(new_path
, REMOVE_ROOT
|REMOVE_PHYSICAL
|REMOVE_SUBVOLUME
);
1738 r
= extract_subvolume_name(new_path
, &subvolume
);
1742 new_fd
= open_parent(new_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1746 return subvol_snapshot_children(old_fd
, new_fd
, subvolume
, 0, flags
);
1749 int btrfs_subvol_snapshot(const char *old_path
, const char *new_path
, BtrfsSnapshotFlags flags
) {
1750 _cleanup_close_
int old_fd
= -1;
1755 old_fd
= open(old_path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1759 return btrfs_subvol_snapshot_fd(old_fd
, new_path
, flags
);
1762 int btrfs_qgroup_find_parents(int fd
, uint64_t qgroupid
, uint64_t **ret
) {
1764 struct btrfs_ioctl_search_args args
= {
1765 /* Tree of quota items */
1766 .key
.tree_id
= BTRFS_QUOTA_TREE_OBJECTID
,
1768 /* Look precisely for the quota relation items */
1769 .key
.min_type
= BTRFS_QGROUP_RELATION_KEY
,
1770 .key
.max_type
= BTRFS_QGROUP_RELATION_KEY
,
1772 /* No restrictions on the other components */
1773 .key
.min_offset
= 0,
1774 .key
.max_offset
= (uint64_t) -1,
1776 .key
.min_transid
= 0,
1777 .key
.max_transid
= (uint64_t) -1,
1780 _cleanup_free_
uint64_t *items
= NULL
;
1781 size_t n_items
= 0, n_allocated
= 0;
1787 if (qgroupid
== 0) {
1788 r
= btrfs_subvol_get_id_fd(fd
, &qgroupid
);
1792 r
= btrfs_is_filesystem(fd
);
1799 args
.key
.min_objectid
= args
.key
.max_objectid
= qgroupid
;
1801 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
1802 const struct btrfs_ioctl_search_header
*sh
;
1805 args
.key
.nr_items
= 256;
1806 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0) {
1807 if (errno
== ENOENT
) /* quota tree missing: quota is disabled */
1813 if (args
.key
.nr_items
<= 0)
1816 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
1818 /* Make sure we start the next search at least from this entry */
1819 btrfs_ioctl_search_args_set(&args
, sh
);
1821 if (sh
->type
!= BTRFS_QGROUP_RELATION_KEY
)
1823 if (sh
->offset
< sh
->objectid
)
1825 if (sh
->objectid
!= qgroupid
)
1828 if (!GREEDY_REALLOC(items
, n_allocated
, n_items
+1))
1831 items
[n_items
++] = sh
->offset
;
1834 /* Increase search key by one, to read the next item, if we can. */
1835 if (!btrfs_ioctl_search_args_inc(&args
))
1847 return (int) n_items
;
1850 int btrfs_subvol_auto_qgroup_fd(int fd
, uint64_t subvol_id
, bool insert_intermediary_qgroup
) {
1851 _cleanup_free_
uint64_t *qgroups
= NULL
;
1852 uint64_t parent_subvol
;
1853 bool changed
= false;
1859 * Sets up the specified subvolume's qgroup automatically in
1862 * If insert_intermediary_qgroup is false, the subvolume's
1863 * leaf qgroup will be assigned to the same parent qgroups as
1864 * the subvolume's parent subvolume.
1866 * If insert_intermediary_qgroup is true a new intermediary
1867 * higher-level qgroup is created, with a higher level number,
1868 * but reusing the id of the subvolume. The level number is
1869 * picked as one smaller than the lowest level qgroup the
1870 * parent subvolume is a member of. If the parent subvolume's
1871 * leaf qgroup is assigned to no higher-level qgroup a new
1872 * qgroup of level 255 is created instead. Either way, the new
1873 * qgroup is then assigned to the parent's higher-level
1874 * qgroup, and the subvolume itself is assigned to it.
1876 * If the subvolume is already assigned to a higher level
1877 * qgroup, no operation is executed.
1879 * Effectively this means: regardless if
1880 * insert_intermediary_qgroup is true or not, after this
1881 * function is invoked the subvolume will be accounted within
1882 * the same qgroups as the parent. However, if it is true, it
1883 * will also get its own higher-level qgroup, which may in
1884 * turn be used by subvolumes created beneath this subvolume
1887 * This hence defines a simple default qgroup setup for
1888 * subvolumes, as long as this function is invoked on each
1889 * created subvolume: each subvolume is always accounting
1890 * together with its immediate parents. Optionally, if
1891 * insert_intermediary_qgroup is true, it will also get a
1892 * qgroup that then includes all its own child subvolumes.
1895 if (subvol_id
== 0) {
1896 r
= btrfs_is_subvol_fd(fd
);
1902 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
1907 n
= btrfs_qgroup_find_parents(fd
, subvol_id
, &qgroups
);
1910 if (n
> 0) /* already parent qgroups set up, let's bail */
1913 qgroups
= mfree(qgroups
);
1915 r
= btrfs_subvol_get_parent(fd
, subvol_id
, &parent_subvol
);
1917 /* No parent, hence no qgroup memberships */
1922 n
= btrfs_qgroup_find_parents(fd
, parent_subvol
, &qgroups
);
1927 if (insert_intermediary_qgroup
) {
1928 uint64_t lowest
= 256, new_qgroupid
;
1929 bool created
= false;
1932 /* Determine the lowest qgroup that the parent
1933 * subvolume is assigned to. */
1935 for (i
= 0; i
< n
; i
++) {
1938 r
= btrfs_qgroupid_split(qgroups
[i
], &level
, NULL
);
1946 if (lowest
<= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1949 r
= btrfs_qgroupid_make(lowest
- 1, subvol_id
, &new_qgroupid
);
1953 /* Create the new intermediary group, unless it already exists */
1954 r
= btrfs_qgroup_create(fd
, new_qgroupid
);
1955 if (r
< 0 && r
!= -EEXIST
)
1958 changed
= created
= true;
1960 for (i
= 0; i
< n
; i
++) {
1961 r
= btrfs_qgroup_assign(fd
, new_qgroupid
, qgroups
[i
]);
1962 if (r
< 0 && r
!= -EEXIST
) {
1964 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1972 r
= btrfs_qgroup_assign(fd
, subvol_id
, new_qgroupid
);
1973 if (r
< 0 && r
!= -EEXIST
) {
1975 (void) btrfs_qgroup_destroy_recursive(fd
, new_qgroupid
);
1984 /* Assign our subvolume to all the same qgroups as the parent */
1986 for (i
= 0; i
< n
; i
++) {
1987 r
= btrfs_qgroup_assign(fd
, subvol_id
, qgroups
[i
]);
1988 if (r
< 0 && r
!= -EEXIST
)
1998 int btrfs_subvol_auto_qgroup(const char *path
, uint64_t subvol_id
, bool create_intermediary_qgroup
) {
1999 _cleanup_close_
int fd
= -1;
2001 fd
= open(path
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
2005 return btrfs_subvol_auto_qgroup_fd(fd
, subvol_id
, create_intermediary_qgroup
);
2008 int btrfs_subvol_get_parent(int fd
, uint64_t subvol_id
, uint64_t *ret
) {
2010 struct btrfs_ioctl_search_args args
= {
2011 /* Tree of tree roots */
2012 .key
.tree_id
= BTRFS_ROOT_TREE_OBJECTID
,
2014 /* Look precisely for the subvolume items */
2015 .key
.min_type
= BTRFS_ROOT_BACKREF_KEY
,
2016 .key
.max_type
= BTRFS_ROOT_BACKREF_KEY
,
2018 /* No restrictions on the other components */
2019 .key
.min_offset
= 0,
2020 .key
.max_offset
= (uint64_t) -1,
2022 .key
.min_transid
= 0,
2023 .key
.max_transid
= (uint64_t) -1,
2030 if (subvol_id
== 0) {
2031 r
= btrfs_subvol_get_id_fd(fd
, &subvol_id
);
2035 r
= btrfs_is_filesystem(fd
);
2042 args
.key
.min_objectid
= args
.key
.max_objectid
= subvol_id
;
2044 while (btrfs_ioctl_search_args_compare(&args
) <= 0) {
2045 const struct btrfs_ioctl_search_header
*sh
;
2048 args
.key
.nr_items
= 256;
2049 if (ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
) < 0)
2050 return negative_errno();
2052 if (args
.key
.nr_items
<= 0)
2055 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i
, sh
, args
) {
2057 if (sh
->type
!= BTRFS_ROOT_BACKREF_KEY
)
2059 if (sh
->objectid
!= subvol_id
)