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_fd(int old_fd, 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 new_fd = -1;
109 const char *subvolume;
114 r = btrfs_is_snapshot(old_fd);
121 r = btrfs_subvol_make(new_path);
125 r = copy_directory_fd(old_fd, new_path, true);
127 btrfs_subvol_remove(new_path);
132 r = btrfs_subvol_set_read_only(new_path, true);
134 btrfs_subvol_remove(new_path);
142 r = extract_subvolume_name(new_path, &subvolume);
146 new_fd = open_parent(new_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
150 strncpy(args.name, subvolume, sizeof(args.name)-1);
153 if (ioctl(new_fd, BTRFS_IOC_SNAP_CREATE_V2, &args) < 0)
159 int btrfs_subvol_snapshot(const char *old_path, const char *new_path, bool read_only, bool fallback_copy) {
160 _cleanup_close_ int old_fd = -1;
165 old_fd = open(old_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
169 return btrfs_subvol_snapshot_fd(old_fd, new_path, read_only, fallback_copy);
172 int btrfs_subvol_make(const char *path) {
173 struct btrfs_ioctl_vol_args args = {};
174 _cleanup_close_ int fd = -1;
175 const char *subvolume;
180 r = extract_subvolume_name(path, &subvolume);
184 fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
188 strncpy(args.name, subvolume, sizeof(args.name)-1);
190 if (ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args) < 0)
196 int btrfs_subvol_make_label(const char *path) {
201 r = mac_selinux_create_file_prepare(path, S_IFDIR);
205 r = btrfs_subvol_make(path);
206 mac_selinux_create_file_clear();
211 return mac_smack_fix(path, false, false);
214 int btrfs_subvol_remove(const char *path) {
215 struct btrfs_ioctl_vol_args args = {};
216 _cleanup_close_ int fd = -1;
217 const char *subvolume;
222 r = extract_subvolume_name(path, &subvolume);
226 fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
230 strncpy(args.name, subvolume, sizeof(args.name)-1);
232 if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args) < 0)
238 int btrfs_subvol_set_read_only_fd(int fd, bool b) {
239 uint64_t flags, nflags;
244 if (fstat(fd, &st) < 0)
247 if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
250 if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
254 nflags = flags | BTRFS_SUBVOL_RDONLY;
256 nflags = flags & ~BTRFS_SUBVOL_RDONLY;
261 if (ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &nflags) < 0)
267 int btrfs_subvol_set_read_only(const char *path, bool b) {
268 _cleanup_close_ int fd = -1;
270 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
274 return btrfs_subvol_set_read_only_fd(fd, b);
277 int btrfs_subvol_get_read_only_fd(int fd) {
280 if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
283 return !!(flags & BTRFS_SUBVOL_RDONLY);
286 int btrfs_reflink(int infd, int outfd) {
292 r = ioctl(outfd, BTRFS_IOC_CLONE, infd);
299 int btrfs_clone_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, uint64_t sz) {
300 struct btrfs_ioctl_clone_range_args args = {
302 .src_offset = in_offset,
304 .dest_offset = out_offset,
312 r = ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args);
319 int btrfs_get_block_device_fd(int fd, dev_t *dev) {
320 struct btrfs_ioctl_fs_info_args fsi = {};
326 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
329 /* We won't do this for btrfs RAID */
330 if (fsi.num_devices != 1)
333 for (id = 1; id <= fsi.max_id; id++) {
334 struct btrfs_ioctl_dev_info_args di = {
339 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
346 if (stat((char*) di.path, &st) < 0)
349 if (!S_ISBLK(st.st_mode))
352 if (major(st.st_rdev) == 0)
362 int btrfs_get_block_device(const char *path, dev_t *dev) {
363 _cleanup_close_ int fd = -1;
368 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
372 return btrfs_get_block_device_fd(fd, dev);
375 int btrfs_subvol_get_id_fd(int fd, uint64_t *ret) {
376 struct btrfs_ioctl_ino_lookup_args args = {
377 .objectid = BTRFS_FIRST_FREE_OBJECTID
383 if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
390 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args *args) {
393 /* the objectid, type, offset together make up the btrfs key,
394 * which is considered a single 136byte integer when
395 * comparing. This call increases the counter by one, dealing
396 * with the overflow between the overflows */
398 if (args->key.min_offset < (uint64_t) -1) {
399 args->key.min_offset++;
403 if (args->key.min_type < (uint8_t) -1) {
404 args->key.min_type++;
405 args->key.min_offset = 0;
409 if (args->key.min_objectid < (uint64_t) -1) {
410 args->key.min_objectid++;
411 args->key.min_offset = 0;
412 args->key.min_type = 0;
419 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args *args, const struct btrfs_ioctl_search_header *h) {
423 args->key.min_objectid = h->objectid;
424 args->key.min_type = h->type;
425 args->key.min_offset = h->offset;
428 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args *args) {
431 /* Compare min and max */
433 if (args->key.min_objectid < args->key.max_objectid)
435 if (args->key.min_objectid > args->key.max_objectid)
438 if (args->key.min_type < args->key.max_type)
440 if (args->key.min_type > args->key.max_type)
443 if (args->key.min_offset < args->key.max_offset)
445 if (args->key.min_offset > args->key.max_offset)
451 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
453 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
454 (i) < (args).key.nr_items; \
456 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
458 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
459 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
461 int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) {
462 struct btrfs_ioctl_search_args args = {
463 /* Tree of tree roots */
464 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
466 /* Look precisely for the subvolume items */
467 .key.min_type = BTRFS_ROOT_ITEM_KEY,
468 .key.max_type = BTRFS_ROOT_ITEM_KEY,
471 .key.max_offset = (uint64_t) -1,
473 /* No restrictions on the other components */
474 .key.min_transid = 0,
475 .key.max_transid = (uint64_t) -1,
485 r = btrfs_subvol_get_id_fd(fd, &subvol_id);
489 args.key.min_objectid = args.key.max_objectid = subvol_id;
491 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
492 const struct btrfs_ioctl_search_header *sh;
495 args.key.nr_items = 256;
496 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
499 if (args.key.nr_items <= 0)
502 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
504 const struct btrfs_root_item *ri;
506 /* Make sure we start the next search at least from this entry */
507 btrfs_ioctl_search_args_set(&args, sh);
509 if (sh->objectid != subvol_id)
511 if (sh->type != BTRFS_ROOT_ITEM_KEY)
514 /* Older versions of the struct lacked the otime setting */
515 if (sh->len < offsetof(struct btrfs_root_item, otime) + sizeof(struct btrfs_timespec))
518 ri = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
520 ret->otime = (usec_t) le64toh(ri->otime.sec) * USEC_PER_SEC +
521 (usec_t) le32toh(ri->otime.nsec) / NSEC_PER_USEC;
523 ret->subvol_id = subvol_id;
524 ret->read_only = !!(le64toh(ri->flags) & BTRFS_ROOT_SUBVOL_RDONLY);
526 assert_cc(sizeof(ri->uuid) == sizeof(ret->uuid));
527 memcpy(&ret->uuid, ri->uuid, sizeof(ret->uuid));
528 memcpy(&ret->parent_uuid, ri->parent_uuid, sizeof(ret->parent_uuid));
534 /* Increase search key by one, to read the next item, if we can. */
535 if (!btrfs_ioctl_search_args_inc(&args))
546 int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) {
548 struct btrfs_ioctl_search_args args = {
549 /* Tree of quota items */
550 .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
552 /* The object ID is always 0 */
553 .key.min_objectid = 0,
554 .key.max_objectid = 0,
556 /* Look precisely for the quota items */
557 .key.min_type = BTRFS_QGROUP_STATUS_KEY,
558 .key.max_type = BTRFS_QGROUP_LIMIT_KEY,
560 /* No restrictions on the other components */
561 .key.min_transid = 0,
562 .key.max_transid = (uint64_t) -1,
566 bool found_info = false, found_limit = false;
572 r = btrfs_subvol_get_id_fd(fd, &subvol_id);
576 args.key.min_offset = args.key.max_offset = subvol_id;
578 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
579 const struct btrfs_ioctl_search_header *sh;
582 args.key.nr_items = 256;
583 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
586 if (args.key.nr_items <= 0)
589 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
591 /* Make sure we start the next search at least from this entry */
592 btrfs_ioctl_search_args_set(&args, sh);
594 if (sh->objectid != 0)
596 if (sh->offset != subvol_id)
599 if (sh->type == BTRFS_QGROUP_INFO_KEY) {
600 const struct btrfs_qgroup_info_item *qii = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
602 ret->referenced = le64toh(qii->rfer);
603 ret->exclusive = le64toh(qii->excl);
607 } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
608 const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
610 ret->referenced_max = le64toh(qli->max_rfer);
611 ret->exclusive_max = le64toh(qli->max_excl);
613 if (ret->referenced_max == 0)
614 ret->referenced_max = (uint64_t) -1;
615 if (ret->exclusive_max == 0)
616 ret->exclusive_max = (uint64_t) -1;
621 if (found_info && found_limit)
625 /* Increase search key by one, to read the next item, if we can. */
626 if (!btrfs_ioctl_search_args_inc(&args))
631 if (!found_limit && !found_info)
635 ret->referenced = (uint64_t) -1;
636 ret->exclusive = (uint64_t) -1;
640 ret->referenced_max = (uint64_t) -1;
641 ret->exclusive_max = (uint64_t) -1;
647 int btrfs_defrag_fd(int fd) {
650 if (ioctl(fd, BTRFS_IOC_DEFRAG, NULL) < 0)
656 int btrfs_defrag(const char *p) {
657 _cleanup_close_ int fd = -1;
659 fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
663 return btrfs_defrag_fd(fd);
666 int btrfs_quota_enable_fd(int fd, bool b) {
667 struct btrfs_ioctl_quota_ctl_args args = {
668 .cmd = b ? BTRFS_QUOTA_CTL_ENABLE : BTRFS_QUOTA_CTL_DISABLE,
673 if (ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args) < 0)
679 int btrfs_quota_enable(const char *path, bool b) {
680 _cleanup_close_ int fd = -1;
682 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
686 return btrfs_quota_enable_fd(fd, b);
689 int btrfs_quota_limit_fd(int fd, uint64_t referenced_max) {
690 struct btrfs_ioctl_qgroup_limit_args args = {
692 referenced_max == (uint64_t) -1 ? 0 :
693 referenced_max == 0 ? 1 : referenced_max,
694 .lim.flags = BTRFS_QGROUP_LIMIT_MAX_RFER,
699 if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0)
705 int btrfs_quota_limit(const char *path, uint64_t referenced_max) {
706 _cleanup_close_ int fd = -1;
708 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
712 return btrfs_quota_limit_fd(fd, referenced_max);
715 int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
716 struct btrfs_ioctl_vol_args args = {};
717 _cleanup_free_ char *p = NULL, *loop = NULL, *backing = NULL;
718 _cleanup_close_ int loop_fd = -1, backing_fd = -1;
723 /* btrfs cannot handle file systems < 16M, hence use this as minimum */
724 if (new_size < 16*1024*1024)
725 new_size = 16*1024*1024;
727 r = btrfs_get_block_device_fd(fd, &dev);
733 if (asprintf(&p, "/sys/dev/block/%u:%u/loop/backing_file", major(dev), minor(dev)) < 0)
735 r = read_one_line_file(p, &backing);
740 if (isempty(backing) || !path_is_absolute(backing))
743 backing_fd = open(backing, O_RDWR|O_CLOEXEC|O_NOCTTY);
747 if (fstat(backing_fd, &st) < 0)
749 if (!S_ISREG(st.st_mode))
752 if (new_size == (uint64_t) st.st_size)
755 if (grow_only && new_size < (uint64_t) st.st_size)
758 if (asprintf(&loop, "/dev/block/%u:%u", major(dev), minor(dev)) < 0)
760 loop_fd = open(loop, O_RDWR|O_CLOEXEC|O_NOCTTY);
764 if (snprintf(args.name, sizeof(args.name), "%" PRIu64, new_size) >= (int) sizeof(args.name))
767 if (new_size < (uint64_t) st.st_size) {
768 /* Decrease size: first decrease btrfs size, then shorten loopback */
769 if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
773 if (ftruncate(backing_fd, new_size) < 0)
776 if (ioctl(loop_fd, LOOP_SET_CAPACITY, 0) < 0)
779 if (new_size > (uint64_t) st.st_size) {
780 /* Increase size: first enlarge loopback, then increase btrfs size */
781 if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
785 /* Make sure the free disk space is correctly updated for both file systems */
787 (void) fsync(backing_fd);
792 int btrfs_resize_loopback(const char *p, uint64_t new_size, bool grow_only) {
793 _cleanup_close_ int fd = -1;
795 fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
799 return btrfs_resize_loopback_fd(fd, new_size, grow_only);