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"
36 #include "selinux-util.h"
37 #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(const char *path, bool b) {
232 _cleanup_close_ int fd = -1;
233 uint64_t flags, nflags;
235 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
239 if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
243 nflags = flags | BTRFS_SUBVOL_RDONLY;
245 nflags = flags & ~BTRFS_SUBVOL_RDONLY;
250 if (ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &nflags) < 0)
256 int btrfs_subvol_get_read_only_fd(int fd) {
259 if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
262 return !!(flags & BTRFS_SUBVOL_RDONLY);
265 int btrfs_reflink(int infd, int outfd) {
271 r = ioctl(outfd, BTRFS_IOC_CLONE, infd);
278 int btrfs_clone_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, uint64_t sz) {
279 struct btrfs_ioctl_clone_range_args args = {
281 .src_offset = in_offset,
283 .dest_offset = out_offset,
291 r = ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args);
298 int btrfs_get_block_device(const char *path, dev_t *dev) {
299 struct btrfs_ioctl_fs_info_args fsi = {};
300 _cleanup_close_ int fd = -1;
306 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
310 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
313 /* We won't do this for btrfs RAID */
314 if (fsi.num_devices != 1)
317 for (id = 1; id <= fsi.max_id; id++) {
318 struct btrfs_ioctl_dev_info_args di = {
323 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
330 if (stat((char*) di.path, &st) < 0)
333 if (!S_ISBLK(st.st_mode))
336 if (major(st.st_rdev) == 0)
346 int btrfs_subvol_get_id_fd(int fd, uint64_t *ret) {
347 struct btrfs_ioctl_ino_lookup_args args = {
348 .objectid = BTRFS_FIRST_FREE_OBJECTID
354 if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
361 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args *args) {
364 /* the objectid, type, offset together make up the btrfs key,
365 * which is considered a single 136byte integer when
366 * comparing. This call increases the counter by one, dealing
367 * with the overflow between the overflows */
369 if (args->key.min_offset < (uint64_t) -1) {
370 args->key.min_offset++;
374 if (args->key.min_type < (uint8_t) -1) {
375 args->key.min_type++;
376 args->key.min_offset = 0;
380 if (args->key.min_objectid < (uint64_t) -1) {
381 args->key.min_objectid++;
382 args->key.min_offset = 0;
383 args->key.min_type = 0;
390 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args *args, const struct btrfs_ioctl_search_header *h) {
394 args->key.min_objectid = h->objectid;
395 args->key.min_type = h->type;
396 args->key.min_offset = h->offset;
399 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args *args) {
402 /* Compare min and max */
404 if (args->key.min_objectid < args->key.max_objectid)
406 if (args->key.min_objectid > args->key.max_objectid)
409 if (args->key.min_type < args->key.max_type)
411 if (args->key.min_type > args->key.max_type)
414 if (args->key.min_offset < args->key.max_offset)
416 if (args->key.min_offset > args->key.max_offset)
422 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
424 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
425 (i) < (args).key.nr_items; \
427 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
429 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
430 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
432 int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) {
433 struct btrfs_ioctl_search_args args = {
434 /* Tree of tree roots */
435 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
437 /* Look precisely for the subvolume items */
438 .key.min_type = BTRFS_ROOT_ITEM_KEY,
439 .key.max_type = BTRFS_ROOT_ITEM_KEY,
442 .key.max_offset = (uint64_t) -1,
444 /* No restrictions on the other components */
445 .key.min_transid = 0,
446 .key.max_transid = (uint64_t) -1,
456 r = btrfs_subvol_get_id_fd(fd, &subvol_id);
460 args.key.min_objectid = args.key.max_objectid = subvol_id;
462 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
463 const struct btrfs_ioctl_search_header *sh;
466 args.key.nr_items = 256;
467 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
470 if (args.key.nr_items <= 0)
473 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
475 const struct btrfs_root_item *ri;
477 /* Make sure we start the next search at least from this entry */
478 btrfs_ioctl_search_args_set(&args, sh);
480 if (sh->objectid != subvol_id)
482 if (sh->type != BTRFS_ROOT_ITEM_KEY)
485 /* Older versions of the struct lacked the otime setting */
486 if (sh->len < offsetof(struct btrfs_root_item, otime) + sizeof(struct btrfs_timespec))
489 ri = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
491 ret->otime = (usec_t) le64toh(ri->otime.sec) * USEC_PER_SEC +
492 (usec_t) le32toh(ri->otime.nsec) / NSEC_PER_USEC;
494 ret->subvol_id = subvol_id;
495 ret->read_only = !!(le64toh(ri->flags) & BTRFS_ROOT_SUBVOL_RDONLY);
497 assert_cc(sizeof(ri->uuid) == sizeof(ret->uuid));
498 memcpy(&ret->uuid, ri->uuid, sizeof(ret->uuid));
499 memcpy(&ret->parent_uuid, ri->parent_uuid, sizeof(ret->parent_uuid));
505 /* Increase search key by one, to read the next item, if we can. */
506 if (!btrfs_ioctl_search_args_inc(&args))
517 int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) {
519 struct btrfs_ioctl_search_args args = {
520 /* Tree of quota items */
521 .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
523 /* The object ID is always 0 */
524 .key.min_objectid = 0,
525 .key.max_objectid = 0,
527 /* Look precisely for the quota items */
528 .key.min_type = BTRFS_QGROUP_STATUS_KEY,
529 .key.max_type = BTRFS_QGROUP_LIMIT_KEY,
531 /* No restrictions on the other components */
532 .key.min_transid = 0,
533 .key.max_transid = (uint64_t) -1,
537 bool found_info = false, found_limit = false;
543 r = btrfs_subvol_get_id_fd(fd, &subvol_id);
547 args.key.min_offset = args.key.max_offset = subvol_id;
549 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
550 const struct btrfs_ioctl_search_header *sh;
553 args.key.nr_items = 256;
554 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
557 if (args.key.nr_items <= 0)
560 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
562 /* Make sure we start the next search at least from this entry */
563 btrfs_ioctl_search_args_set(&args, sh);
565 if (sh->objectid != 0)
567 if (sh->offset != subvol_id)
570 if (sh->type == BTRFS_QGROUP_INFO_KEY) {
571 const struct btrfs_qgroup_info_item *qii = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
573 ret->referred = le64toh(qii->rfer);
574 ret->exclusive = le64toh(qii->excl);
578 } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
579 const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
581 ret->referred_max = le64toh(qli->max_rfer);
582 ret->exclusive_max = le64toh(qli->max_excl);
584 if (ret->referred_max == 0)
585 ret->referred_max = (uint64_t) -1;
586 if (ret->exclusive_max == 0)
587 ret->exclusive_max = (uint64_t) -1;
592 if (found_info && found_limit)
596 /* Increase search key by one, to read the next item, if we can. */
597 if (!btrfs_ioctl_search_args_inc(&args))
602 if (!found_limit && !found_info)
606 ret->referred = (uint64_t) -1;
607 ret->exclusive = (uint64_t) -1;
611 ret->referred_max = (uint64_t) -1;
612 ret->exclusive_max = (uint64_t) -1;
618 int btrfs_defrag_fd(int fd) {
621 if (ioctl(fd, BTRFS_IOC_DEFRAG, NULL) < 0)
627 int btrfs_defrag(const char *p) {
628 _cleanup_close_ int fd = -1;
630 fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
634 return btrfs_defrag_fd(fd);