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/>.
26 #ifdef HAVE_LINUX_BTRFS_H
27 #include <linux/btrfs.h>
32 #include "path-util.h"
35 #include "selinux-util.h"
36 #include "smack-util.h"
38 #include "btrfs-ctree.h"
39 #include "btrfs-util.h"
41 static int validate_subvolume_name(const char *name) {
43 if (!filename_is_valid(name))
46 if (strlen(name) > BTRFS_SUBVOL_NAME_MAX)
52 static int open_parent(const char *path, int flags) {
53 _cleanup_free_ char *parent = NULL;
58 r = path_get_parent(path, &parent);
62 fd = open(parent, flags);
69 static int extract_subvolume_name(const char *path, const char **subvolume) {
78 r = validate_subvolume_name(fn);
86 int btrfs_is_snapshot(int fd) {
90 /* On btrfs subvolumes always have the inode 256 */
92 if (fstat(fd, &st) < 0)
95 if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
98 if (fstatfs(fd, &sfs) < 0)
101 return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
104 int btrfs_subvol_snapshot(const char *old_path, const char *new_path, bool read_only, bool fallback_copy) {
105 struct btrfs_ioctl_vol_args_v2 args = {
106 .flags = read_only ? BTRFS_SUBVOL_RDONLY : 0,
108 _cleanup_close_ int old_fd = -1, new_fd = -1;
109 const char *subvolume;
114 old_fd = open(old_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
118 r = btrfs_is_snapshot(old_fd);
124 r = btrfs_subvol_make(new_path);
128 r = copy_directory_fd(old_fd, new_path, true);
130 btrfs_subvol_remove(new_path);
135 r = btrfs_subvol_set_read_only(new_path, true);
137 btrfs_subvol_remove(new_path);
148 r = extract_subvolume_name(new_path, &subvolume);
152 new_fd = open_parent(new_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
156 strncpy(args.name, subvolume, sizeof(args.name)-1);
159 if (ioctl(new_fd, BTRFS_IOC_SNAP_CREATE_V2, &args) < 0)
165 int btrfs_subvol_make(const char *path) {
166 struct btrfs_ioctl_vol_args args = {};
167 _cleanup_close_ int fd = -1;
168 const char *subvolume;
173 r = extract_subvolume_name(path, &subvolume);
177 fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
181 strncpy(args.name, subvolume, sizeof(args.name)-1);
183 if (ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args) < 0)
189 int btrfs_subvol_make_label(const char *path) {
194 r = mac_selinux_create_file_prepare(path, S_IFDIR);
198 r = btrfs_subvol_make(path);
199 mac_selinux_create_file_clear();
204 return mac_smack_fix(path, false, false);
207 int btrfs_subvol_remove(const char *path) {
208 struct btrfs_ioctl_vol_args args = {};
209 _cleanup_close_ int fd = -1;
210 const char *subvolume;
215 r = extract_subvolume_name(path, &subvolume);
219 fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
223 strncpy(args.name, subvolume, sizeof(args.name)-1);
225 if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args) < 0)
231 int btrfs_subvol_set_read_only_fd(int fd, bool b) {
232 uint64_t flags, nflags;
237 if (fstat(fd, &st) < 0)
240 if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
243 if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
247 nflags = flags | BTRFS_SUBVOL_RDONLY;
249 nflags = flags & ~BTRFS_SUBVOL_RDONLY;
254 if (ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &nflags) < 0)
260 int btrfs_subvol_set_read_only(const char *path, bool b) {
261 _cleanup_close_ int fd = -1;
263 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
267 return btrfs_subvol_set_read_only_fd(fd, b);
270 int btrfs_subvol_get_read_only_fd(int fd) {
273 if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
276 return !!(flags & BTRFS_SUBVOL_RDONLY);
279 int btrfs_reflink(int infd, int outfd) {
285 r = ioctl(outfd, BTRFS_IOC_CLONE, infd);
292 int btrfs_clone_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, uint64_t sz) {
293 struct btrfs_ioctl_clone_range_args args = {
295 .src_offset = in_offset,
297 .dest_offset = out_offset,
305 r = ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args);
312 int btrfs_get_block_device_fd(int fd, dev_t *dev) {
313 struct btrfs_ioctl_fs_info_args fsi = {};
319 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
322 /* We won't do this for btrfs RAID */
323 if (fsi.num_devices != 1)
326 for (id = 1; id <= fsi.max_id; id++) {
327 struct btrfs_ioctl_dev_info_args di = {
332 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
339 if (stat((char*) di.path, &st) < 0)
342 if (!S_ISBLK(st.st_mode))
345 if (major(st.st_rdev) == 0)
355 int btrfs_get_block_device(const char *path, dev_t *dev) {
356 _cleanup_close_ int fd = -1;
361 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
365 return btrfs_get_block_device_fd(fd, dev);
368 int btrfs_subvol_get_id_fd(int fd, uint64_t *ret) {
369 struct btrfs_ioctl_ino_lookup_args args = {
370 .objectid = BTRFS_FIRST_FREE_OBJECTID
376 if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
383 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args *args) {
386 /* the objectid, type, offset together make up the btrfs key,
387 * which is considered a single 136byte integer when
388 * comparing. This call increases the counter by one, dealing
389 * with the overflow between the overflows */
391 if (args->key.min_offset < (uint64_t) -1) {
392 args->key.min_offset++;
396 if (args->key.min_type < (uint8_t) -1) {
397 args->key.min_type++;
398 args->key.min_offset = 0;
402 if (args->key.min_objectid < (uint64_t) -1) {
403 args->key.min_objectid++;
404 args->key.min_offset = 0;
405 args->key.min_type = 0;
412 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args *args, const struct btrfs_ioctl_search_header *h) {
416 args->key.min_objectid = h->objectid;
417 args->key.min_type = h->type;
418 args->key.min_offset = h->offset;
421 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args *args) {
424 /* Compare min and max */
426 if (args->key.min_objectid < args->key.max_objectid)
428 if (args->key.min_objectid > args->key.max_objectid)
431 if (args->key.min_type < args->key.max_type)
433 if (args->key.min_type > args->key.max_type)
436 if (args->key.min_offset < args->key.max_offset)
438 if (args->key.min_offset > args->key.max_offset)
444 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
446 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
447 (i) < (args).key.nr_items; \
449 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
451 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
452 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
454 int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) {
455 struct btrfs_ioctl_search_args args = {
456 /* Tree of tree roots */
457 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
459 /* Look precisely for the subvolume items */
460 .key.min_type = BTRFS_ROOT_ITEM_KEY,
461 .key.max_type = BTRFS_ROOT_ITEM_KEY,
464 .key.max_offset = (uint64_t) -1,
466 /* No restrictions on the other components */
467 .key.min_transid = 0,
468 .key.max_transid = (uint64_t) -1,
478 r = btrfs_subvol_get_id_fd(fd, &subvol_id);
482 args.key.min_objectid = args.key.max_objectid = subvol_id;
484 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
485 const struct btrfs_ioctl_search_header *sh;
488 args.key.nr_items = 256;
489 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
492 if (args.key.nr_items <= 0)
495 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
497 const struct btrfs_root_item *ri;
499 /* Make sure we start the next search at least from this entry */
500 btrfs_ioctl_search_args_set(&args, sh);
502 if (sh->objectid != subvol_id)
504 if (sh->type != BTRFS_ROOT_ITEM_KEY)
507 /* Older versions of the struct lacked the otime setting */
508 if (sh->len < offsetof(struct btrfs_root_item, otime) + sizeof(struct btrfs_timespec))
511 ri = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
513 ret->otime = (usec_t) le64toh(ri->otime.sec) * USEC_PER_SEC +
514 (usec_t) le32toh(ri->otime.nsec) / NSEC_PER_USEC;
516 ret->subvol_id = subvol_id;
517 ret->read_only = !!(le64toh(ri->flags) & BTRFS_ROOT_SUBVOL_RDONLY);
519 assert_cc(sizeof(ri->uuid) == sizeof(ret->uuid));
520 memcpy(&ret->uuid, ri->uuid, sizeof(ret->uuid));
521 memcpy(&ret->parent_uuid, ri->parent_uuid, sizeof(ret->parent_uuid));
527 /* Increase search key by one, to read the next item, if we can. */
528 if (!btrfs_ioctl_search_args_inc(&args))
539 int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) {
541 struct btrfs_ioctl_search_args args = {
542 /* Tree of quota items */
543 .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
545 /* The object ID is always 0 */
546 .key.min_objectid = 0,
547 .key.max_objectid = 0,
549 /* Look precisely for the quota items */
550 .key.min_type = BTRFS_QGROUP_STATUS_KEY,
551 .key.max_type = BTRFS_QGROUP_LIMIT_KEY,
553 /* No restrictions on the other components */
554 .key.min_transid = 0,
555 .key.max_transid = (uint64_t) -1,
559 bool found_info = false, found_limit = false;
565 r = btrfs_subvol_get_id_fd(fd, &subvol_id);
569 args.key.min_offset = args.key.max_offset = subvol_id;
571 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
572 const struct btrfs_ioctl_search_header *sh;
575 args.key.nr_items = 256;
576 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
579 if (args.key.nr_items <= 0)
582 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
584 /* Make sure we start the next search at least from this entry */
585 btrfs_ioctl_search_args_set(&args, sh);
587 if (sh->objectid != 0)
589 if (sh->offset != subvol_id)
592 if (sh->type == BTRFS_QGROUP_INFO_KEY) {
593 const struct btrfs_qgroup_info_item *qii = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
595 ret->referred = le64toh(qii->rfer);
596 ret->exclusive = le64toh(qii->excl);
600 } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
601 const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
603 ret->referred_max = le64toh(qli->max_rfer);
604 ret->exclusive_max = le64toh(qli->max_excl);
606 if (ret->referred_max == 0)
607 ret->referred_max = (uint64_t) -1;
608 if (ret->exclusive_max == 0)
609 ret->exclusive_max = (uint64_t) -1;
614 if (found_info && found_limit)
618 /* Increase search key by one, to read the next item, if we can. */
619 if (!btrfs_ioctl_search_args_inc(&args))
624 if (!found_limit && !found_info)
628 ret->referred = (uint64_t) -1;
629 ret->exclusive = (uint64_t) -1;
633 ret->referred_max = (uint64_t) -1;
634 ret->exclusive_max = (uint64_t) -1;
640 int btrfs_defrag_fd(int fd) {
643 if (ioctl(fd, BTRFS_IOC_DEFRAG, NULL) < 0)
649 int btrfs_defrag(const char *p) {
650 _cleanup_close_ int fd = -1;
652 fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
656 return btrfs_defrag_fd(fd);
659 int btrfs_quota_enable_fd(int fd, bool b) {
660 struct btrfs_ioctl_quota_ctl_args args = {
661 .cmd = b ? BTRFS_QUOTA_CTL_ENABLE : BTRFS_QUOTA_CTL_DISABLE,
666 if (ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args) < 0)
672 int btrfs_quota_enable(const char *path, bool b) {
673 _cleanup_close_ int fd = -1;
675 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
679 return btrfs_quota_enable_fd(fd, b);
682 int btrfs_quota_limit_fd(int fd, uint64_t referred_max) {
683 struct btrfs_ioctl_qgroup_limit_args args = {
685 referred_max == (uint64_t) -1 ? 0 :
686 referred_max == 0 ? 1 : referred_max,
687 .lim.flags = BTRFS_QGROUP_LIMIT_MAX_RFER,
692 if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0)
698 int btrfs_quota_limit(const char *path, uint64_t referred_max) {
699 _cleanup_close_ int fd = -1;
701 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
705 return btrfs_quota_limit_fd(fd, referred_max);
708 int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
709 struct btrfs_ioctl_vol_args args = {};
710 _cleanup_free_ char *p = NULL, *loop = NULL, *backing = NULL;
711 _cleanup_close_ int loop_fd = -1, backing_fd = -1;
716 /* btrfs cannot handle file systems < 16M, hence use this as minimum */
717 if (new_size < 16*1024*1024)
718 new_size = 16*1024*1024;
720 r = btrfs_get_block_device_fd(fd, &dev);
726 if (asprintf(&p, "/sys/dev/block/%u:%u/loop/backing_file", major(dev), minor(dev)) < 0)
728 r = read_one_line_file(p, &backing);
733 if (isempty(backing) || !path_is_absolute(backing))
736 backing_fd = open(backing, O_RDWR|O_CLOEXEC|O_NOCTTY);
740 if (fstat(backing_fd, &st) < 0)
742 if (!S_ISREG(st.st_mode))
745 if (new_size == (uint64_t) st.st_size)
748 if (grow_only && new_size < (uint64_t) st.st_size)
751 if (asprintf(&loop, "/dev/block/%u:%u", major(dev), minor(dev)) < 0)
753 loop_fd = open(loop, O_RDWR|O_CLOEXEC|O_NOCTTY);
757 if (snprintf(args.name, sizeof(args.name), "%" PRIu64, new_size) >= (int) sizeof(args.name))
760 if (new_size < (uint64_t) st.st_size) {
761 /* Decrease size: first decrease btrfs size, then shorten loopback */
762 if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
766 if (ftruncate(backing_fd, new_size) < 0)
769 if (ioctl(loop_fd, LOOP_SET_CAPACITY, 0) < 0)
772 if (new_size > (uint64_t) st.st_size) {
773 /* Increase size: first enlarge loopback, then increase btrfs size */
774 if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
778 /* Make sure the free disk space is correctly updated for both file systems */
780 (void) fsync(backing_fd);
785 int btrfs_resize_loopback(const char *p, uint64_t new_size, bool grow_only) {
786 _cleanup_close_ int fd = -1;
788 fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
792 return btrfs_resize_loopback_fd(fd, new_size, grow_only);