btrfs-util.c revision 1c7dd82563ff2e71a067aea20d2acb2d0553644b
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/***
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2014 Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering***/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
8bdbb8d9cbe1d35708385573d70984ab4533812dLennart Poettering#include <stdlib.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <sys/vfs.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <sys/stat.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#ifdef HAVE_LINUX_BTRFS_H
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <linux/btrfs.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#endif
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering#include "missing.h"
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering#include "util.h"
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering#include "path-util.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "macro.h"
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen#include "strv.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "copy.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "selinux-util.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "smack-util.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "btrfs-ctree.h"
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen#include "btrfs-util.h"
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int validate_subvolume_name(const char *name) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (!filename_is_valid(name))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EINVAL;
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (strlen(name) > BTRFS_SUBVOL_NAME_MAX)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return -E2BIG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int open_parent(const char *path, int flags) {
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen _cleanup_free_ char *parent = NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r, fd;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering assert(path);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = path_get_parent(path, &parent);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fd = open(parent, flags);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (fd < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return fd;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int extract_subvolume_name(const char *path, const char **subvolume) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen const char *fn;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(path);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(subvolume);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fn = basename(path);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = validate_subvolume_name(fn);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (r < 0)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return r;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen *subvolume = fn;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return 0;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen}
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenint btrfs_is_snapshot(int fd) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen struct stat st;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct statfs sfs;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* On btrfs subvolumes always have the inode 256 */
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen if (fstat(fd, &st) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (fstatfs(fd, &sfs) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poetteringint btrfs_subvol_snapshot(const char *old_path, const char *new_path, bool read_only, bool fallback_copy) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen struct btrfs_ioctl_vol_args_v2 args = {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen .flags = read_only ? BTRFS_SUBVOL_RDONLY : 0,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen };
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering _cleanup_close_ int old_fd = -1, new_fd = -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *subvolume;
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen int r;
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(old_path);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering old_fd = open(old_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (old_fd < 0)
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return -errno;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = btrfs_is_snapshot(old_fd);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (r < 0)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return r;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (r == 0) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (fallback_copy) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering r = btrfs_subvol_make(new_path);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (r < 0)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return r;
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering r = copy_directory_fd(old_fd, new_path, true);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (r < 0) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering btrfs_subvol_remove(new_path);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return r;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering if (read_only) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering r = btrfs_subvol_set_read_only(new_path, true);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (r < 0) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering btrfs_subvol_remove(new_path);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return r;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering }
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering return 0;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering }
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return -EISDIR;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering r = extract_subvolume_name(new_path, &subvolume);
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering if (r < 0)
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering return r;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering new_fd = open_parent(new_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering if (new_fd < 0)
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering return new_fd;
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering strncpy(args.name, subvolume, sizeof(args.name)-1);
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering args.fd = old_fd;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (ioctl(new_fd, BTRFS_IOC_SNAP_CREATE_V2, &args) < 0)
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return -errno;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return 0;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering}
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringint btrfs_subvol_make(const char *path) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering struct btrfs_ioctl_vol_args args = {};
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering _cleanup_close_ int fd = -1;
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering const char *subvolume;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering int r;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering assert(path);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering r = extract_subvolume_name(path, &subvolume);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (r < 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return r;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (fd < 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return fd;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering strncpy(args.name, subvolume, sizeof(args.name)-1);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args) < 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return -errno;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return 0;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering}
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringint btrfs_subvol_make_label(const char *path) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering int r;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering assert(path);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering r = mac_selinux_create_file_prepare(path, S_IFDIR);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (r < 0)
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering return r;
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering r = btrfs_subvol_make(path);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering mac_selinux_create_file_clear();
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (r < 0)
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering return r;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return mac_smack_fix(path, false, false);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering}
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringint btrfs_subvol_remove(const char *path) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering struct btrfs_ioctl_vol_args args = {};
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering _cleanup_close_ int fd = -1;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering const char *subvolume;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering int r;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering assert(path);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering r = extract_subvolume_name(path, &subvolume);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (r < 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return r;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (fd < 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return fd;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering strncpy(args.name, subvolume, sizeof(args.name)-1);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args) < 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return -errno;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return 0;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering}
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringint btrfs_subvol_set_read_only(const char *path, bool b) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering _cleanup_close_ int fd = -1;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering uint64_t flags, nflags;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (fd < 0)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return -errno;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return -errno;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (b)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering nflags = flags | BTRFS_SUBVOL_RDONLY;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering else
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering nflags = flags & ~BTRFS_SUBVOL_RDONLY;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (flags == nflags)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return 0;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &nflags) < 0)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return -errno;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return 0;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering}
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poetteringint btrfs_subvol_get_read_only_fd(int fd) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering uint64_t flags;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return -errno;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return !!(flags & BTRFS_SUBVOL_RDONLY);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering}
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poetteringint btrfs_reflink(int infd, int outfd) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering int r;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering assert(infd >= 0);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering assert(outfd >= 0);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering r = ioctl(outfd, BTRFS_IOC_CLONE, infd);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (r < 0)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return -errno;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sieversint btrfs_clone_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, uint64_t sz) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers struct btrfs_ioctl_clone_range_args args = {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering .src_fd = infd,
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers .src_offset = in_offset,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering .src_length = sz,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering .dest_offset = out_offset,
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering };
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(infd >= 0);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen assert(outfd >= 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(sz > 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering r = ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint btrfs_get_block_device(const char *path, dev_t *dev) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct btrfs_ioctl_fs_info_args fsi = {};
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering _cleanup_close_ int fd = -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint64_t id;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(path);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(dev);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (fd < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* We won't do this for btrfs RAID */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (fsi.num_devices != 1)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (id = 1; id <= fsi.max_id; id++) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct btrfs_ioctl_dev_info_args di = {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering .devid = id,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering };
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct stat st;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (errno == ENODEV)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering continue;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (stat((char*) di.path, &st) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!S_ISBLK(st.st_mode))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENODEV;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (major(st.st_rdev) == 0)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return -ENODEV;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering *dev = st.st_rdev;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return 1;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering }
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return -ENODEV;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering}
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poetteringint btrfs_subvol_get_id_fd(int fd, uint64_t *ret) {
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering struct btrfs_ioctl_ino_lookup_args args = {
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering .objectid = BTRFS_FIRST_FREE_OBJECTID
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering };
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering assert(fd >= 0);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering assert(ret);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return -errno;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering *ret = args.treeid;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return 0;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering}
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringstatic bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args *args) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering assert(args);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering /* the objectid, type, offset together make up the btrfs key,
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering * which is considered a single 136byte integer when
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering * comparing. This call increases the counter by one, dealing
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * with the overflow between the overflows */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (args->key.min_offset < (uint64_t) -1) {
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering args->key.min_offset++;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return true;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering }
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (args->key.min_type < (uint8_t) -1) {
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering args->key.min_type++;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering args->key.min_offset = 0;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return true;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering }
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
e7e9b6bb0b0bc5b1eb256a44f8afec6b634f26efZbigniew Jędrzejewski-Szmek if (args->key.min_objectid < (uint64_t) -1) {
e7e9b6bb0b0bc5b1eb256a44f8afec6b634f26efZbigniew Jędrzejewski-Szmek args->key.min_objectid++;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering args->key.min_offset = 0;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering args->key.min_type = 0;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return true;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering }
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return 0;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering}
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poetteringstatic void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args *args, const struct btrfs_ioctl_search_header *h) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers assert(args);
a6c616024db23fef34152c1432892824a07799ccLennart Poettering assert(h);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering args->key.min_objectid = h->objectid;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering args->key.min_type = h->type;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering args->key.min_offset = h->offset;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering}
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poetteringstatic int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args *args) {
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering assert(args);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering /* Compare min and max */
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (args->key.min_objectid < args->key.max_objectid)
a6c616024db23fef34152c1432892824a07799ccLennart Poettering return -1;
a6c616024db23fef34152c1432892824a07799ccLennart Poettering if (args->key.min_objectid > args->key.max_objectid)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return 1;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (args->key.min_type < args->key.max_type)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (args->key.min_type > args->key.max_type)
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return 1;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (args->key.min_offset < args->key.max_offset)
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return -1;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (args->key.min_offset > args->key.max_offset)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return 1;
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for ((i) = 0, \
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (i) < (args).key.nr_items; \
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers (i)++, \
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers#define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sieversint btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) {
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering struct btrfs_ioctl_search_args args = {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Tree of tree roots */
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Look precisely for the subvolume items */
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers .key.min_type = BTRFS_ROOT_ITEM_KEY,
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers .key.max_type = BTRFS_ROOT_ITEM_KEY,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers .key.min_offset = 0,
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers .key.max_offset = (uint64_t) -1,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers /* No restrictions on the other components */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen .key.min_transid = 0,
27e72d6b22890ba4a8cbc05c49667cd1cccf1461Simon Peeters .key.max_transid = (uint64_t) -1,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen };
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint64_t subvol_id;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering bool found = false;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen assert(fd >= 0);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen assert(ret);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers r = btrfs_subvol_get_id_fd(fd, &subvol_id);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering args.key.min_objectid = args.key.max_objectid = subvol_id;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering while (btrfs_ioctl_search_args_compare(&args) <= 0) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers const struct btrfs_ioctl_search_header *sh;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering unsigned i;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering args.key.nr_items = 256;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return -errno;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (args.key.nr_items <= 0)
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers break;
8c841f21f5042b11acc91cc1b039cb162cbbe8f4Djalal Harouni
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const struct btrfs_root_item *ri;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Make sure we start the next search at least from this entry */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering btrfs_ioctl_search_args_set(&args, sh);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (sh->objectid != subvol_id)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen continue;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (sh->type != BTRFS_ROOT_ITEM_KEY)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen continue;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen /* Older versions of the struct lacked the otime setting */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (sh->len < offsetof(struct btrfs_root_item, otime) + sizeof(struct btrfs_timespec))
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen continue;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen ri = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen ret->otime = (usec_t) le64toh(ri->otime.sec) * USEC_PER_SEC +
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen (usec_t) le32toh(ri->otime.nsec) / NSEC_PER_USEC;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering ret->subvol_id = subvol_id;
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering ret->read_only = !!(le64toh(ri->flags) & BTRFS_ROOT_SUBVOL_RDONLY);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers assert_cc(sizeof(ri->uuid) == sizeof(ret->uuid));
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers memcpy(&ret->uuid, ri->uuid, sizeof(ret->uuid));
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers memcpy(&ret->parent_uuid, ri->parent_uuid, sizeof(ret->parent_uuid));
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering found = true;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto finish;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Increase search key by one, to read the next item, if we can. */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (!btrfs_ioctl_search_args_inc(&args))
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen break;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringfinish:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!found)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENODATA;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen struct btrfs_ioctl_search_args args = {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen /* Tree of quota items */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen /* The object ID is always 0 */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen .key.min_objectid = 0,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen .key.max_objectid = 0,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen /* Look precisely for the quota items */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen .key.min_type = BTRFS_QGROUP_STATUS_KEY,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering .key.max_type = BTRFS_QGROUP_LIMIT_KEY,
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* No restrictions on the other components */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering .key.min_transid = 0,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering .key.max_transid = (uint64_t) -1,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering };
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering uint64_t subvol_id;
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering bool found_info = false, found_limit = false;
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering assert(fd >= 0);
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering assert(ret);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering r = btrfs_subvol_get_id_fd(fd, &subvol_id);
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering if (r < 0)
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering args.key.min_offset = args.key.max_offset = subvol_id;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering while (btrfs_ioctl_search_args_compare(&args) <= 0) {
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering const struct btrfs_ioctl_search_header *sh;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering unsigned i;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering args.key.nr_items = 256;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering return -errno;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering if (args.key.nr_items <= 0)
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering break;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering /* Make sure we start the next search at least from this entry */
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering btrfs_ioctl_search_args_set(&args, sh);
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering if (sh->objectid != 0)
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering continue;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering if (sh->offset != subvol_id)
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering continue;
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering if (sh->type == BTRFS_QGROUP_INFO_KEY) {
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering const struct btrfs_qgroup_info_item *qii = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering ret->referred = le64toh(qii->rfer);
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering ret->exclusive = le64toh(qii->excl);
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering found_info = true;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
3d94f76c99da13e5603831d0b278f8c8c21bcb02Lennart Poettering } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
a4475f577bd0daf762d6c3b4e58bc484e0cb74afLennart Poettering const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering ret->referred_max = le64toh(qli->max_rfer);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering ret->exclusive_max = le64toh(qli->max_excl);
34a6778fb9d1065f3fbb8e2243b9f0f25d1d18f1Zbigniew Jędrzejewski-Szmek
34a6778fb9d1065f3fbb8e2243b9f0f25d1d18f1Zbigniew Jędrzejewski-Szmek if (ret->referred_max == 0)
34a6778fb9d1065f3fbb8e2243b9f0f25d1d18f1Zbigniew Jędrzejewski-Szmek ret->referred_max = (uint64_t) -1;
34a6778fb9d1065f3fbb8e2243b9f0f25d1d18f1Zbigniew Jędrzejewski-Szmek if (ret->exclusive_max == 0)
34a6778fb9d1065f3fbb8e2243b9f0f25d1d18f1Zbigniew Jędrzejewski-Szmek ret->exclusive_max = (uint64_t) -1;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
f69157a66ffe413b4cf8bd79057487fc8921e78bThomas Hindoe Paaboel Andersen found_limit = true;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (found_info && found_limit)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering goto finish;
bc9fd78c7bfc39881e19457e476393635f8b0442Lennart Poettering }
bc9fd78c7bfc39881e19457e476393635f8b0442Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering /* Increase search key by one, to read the next item, if we can. */
bc9fd78c7bfc39881e19457e476393635f8b0442Lennart Poettering if (!btrfs_ioctl_search_args_inc(&args))
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering break;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringfinish:
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (!found_limit && !found_info)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return -ENODATA;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering if (!found_info) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering ret->referred = (uint64_t) -1;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering ret->exclusive = (uint64_t) -1;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (!found_limit) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering ret->referred_max = (uint64_t) -1;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering ret->exclusive_max = (uint64_t) -1;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return 0;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering}
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringint btrfs_defrag_fd(int fd) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(fd >= 0);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (ioctl(fd, BTRFS_IOC_DEFRAG, NULL) < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return -errno;
bc9fd78c7bfc39881e19457e476393635f8b0442Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return 0;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering}
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringint btrfs_defrag(const char *p) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering _cleanup_close_ int fd = -1;
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
fbadf04511389c4a0687ba5e9baf0ecebdbb07f1Lennart Poettering if (fd < 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return -errno;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return btrfs_defrag_fd(fd);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering}
fbadf04511389c4a0687ba5e9baf0ecebdbb07f1Lennart Poettering