]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/btrfs-util.c
Merge pull request #1828 from fbuihuu/set-property-on-inactive-unit
[thirdparty/systemd.git] / src / basic / btrfs-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <stdlib.h>
23 #include <sys/stat.h>
24 #include <sys/vfs.h>
25 #ifdef HAVE_LINUX_BTRFS_H
26 #include <linux/btrfs.h>
27 #endif
28
29 #include "alloc-util.h"
30 #include "btrfs-ctree.h"
31 #include "btrfs-util.h"
32 #include "copy.h"
33 #include "fd-util.h"
34 #include "fileio.h"
35 #include "macro.h"
36 #include "missing.h"
37 #include "path-util.h"
38 #include "selinux-util.h"
39 #include "smack-util.h"
40 #include "stat-util.h"
41 #include "string-util.h"
42 #include "util.h"
43
44 /* WARNING: Be careful with file system ioctls! When we get an fd, we
45 * need to make sure it either refers to only a regular file or
46 * directory, or that it is located on btrfs, before invoking any
47 * btrfs ioctls. The ioctl numbers are reused by some device drivers
48 * (such as DRM), and hence might have bad effects when invoked on
49 * device nodes (that reference drivers) rather than fds to normal
50 * files or directories. */
51
52 static int validate_subvolume_name(const char *name) {
53
54 if (!filename_is_valid(name))
55 return -EINVAL;
56
57 if (strlen(name) > BTRFS_SUBVOL_NAME_MAX)
58 return -E2BIG;
59
60 return 0;
61 }
62
63 static int open_parent(const char *path, int flags) {
64 _cleanup_free_ char *parent = NULL;
65 int fd;
66
67 assert(path);
68
69 parent = dirname_malloc(path);
70 if (!parent)
71 return -ENOMEM;
72
73 fd = open(parent, flags);
74 if (fd < 0)
75 return -errno;
76
77 return fd;
78 }
79
80 static int extract_subvolume_name(const char *path, const char **subvolume) {
81 const char *fn;
82 int r;
83
84 assert(path);
85 assert(subvolume);
86
87 fn = basename(path);
88
89 r = validate_subvolume_name(fn);
90 if (r < 0)
91 return r;
92
93 *subvolume = fn;
94 return 0;
95 }
96
97 int btrfs_is_filesystem(int fd) {
98 struct statfs sfs;
99
100 assert(fd >= 0);
101
102 if (fstatfs(fd, &sfs) < 0)
103 return -errno;
104
105 return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
106 }
107
108 int btrfs_is_subvol_fd(int fd) {
109 struct stat st;
110
111 assert(fd >= 0);
112
113 /* On btrfs subvolumes always have the inode 256 */
114
115 if (fstat(fd, &st) < 0)
116 return -errno;
117
118 if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
119 return 0;
120
121 return btrfs_is_filesystem(fd);
122 }
123
124 int btrfs_is_subvol(const char *path) {
125 _cleanup_close_ int fd = -1;
126
127 assert(path);
128
129 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
130 if (fd < 0)
131 return -errno;
132
133 return btrfs_is_subvol_fd(fd);
134 }
135
136 int btrfs_subvol_make(const char *path) {
137 struct btrfs_ioctl_vol_args args = {};
138 _cleanup_close_ int fd = -1;
139 const char *subvolume;
140 int r;
141
142 assert(path);
143
144 r = extract_subvolume_name(path, &subvolume);
145 if (r < 0)
146 return r;
147
148 fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
149 if (fd < 0)
150 return fd;
151
152 strncpy(args.name, subvolume, sizeof(args.name)-1);
153
154 if (ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args) < 0)
155 return -errno;
156
157 return 0;
158 }
159
160 int btrfs_subvol_make_label(const char *path) {
161 int r;
162
163 assert(path);
164
165 r = mac_selinux_create_file_prepare(path, S_IFDIR);
166 if (r < 0)
167 return r;
168
169 r = btrfs_subvol_make(path);
170 mac_selinux_create_file_clear();
171
172 if (r < 0)
173 return r;
174
175 return mac_smack_fix(path, false, false);
176 }
177
178 int btrfs_subvol_set_read_only_fd(int fd, bool b) {
179 uint64_t flags, nflags;
180 struct stat st;
181
182 assert(fd >= 0);
183
184 if (fstat(fd, &st) < 0)
185 return -errno;
186
187 if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
188 return -EINVAL;
189
190 if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
191 return -errno;
192
193 if (b)
194 nflags = flags | BTRFS_SUBVOL_RDONLY;
195 else
196 nflags = flags & ~BTRFS_SUBVOL_RDONLY;
197
198 if (flags == nflags)
199 return 0;
200
201 if (ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &nflags) < 0)
202 return -errno;
203
204 return 0;
205 }
206
207 int btrfs_subvol_set_read_only(const char *path, bool b) {
208 _cleanup_close_ int fd = -1;
209
210 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
211 if (fd < 0)
212 return -errno;
213
214 return btrfs_subvol_set_read_only_fd(fd, b);
215 }
216
217 int btrfs_subvol_get_read_only_fd(int fd) {
218 uint64_t flags;
219 struct stat st;
220
221 assert(fd >= 0);
222
223 if (fstat(fd, &st) < 0)
224 return -errno;
225
226 if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
227 return -EINVAL;
228
229 if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
230 return -errno;
231
232 return !!(flags & BTRFS_SUBVOL_RDONLY);
233 }
234
235 int btrfs_reflink(int infd, int outfd) {
236 struct stat st;
237 int r;
238
239 assert(infd >= 0);
240 assert(outfd >= 0);
241
242 /* Make sure we invoke the ioctl on a regular file, so that no
243 * device driver accidentally gets it. */
244
245 if (fstat(outfd, &st) < 0)
246 return -errno;
247
248 if (!S_ISREG(st.st_mode))
249 return -EINVAL;
250
251 r = ioctl(outfd, BTRFS_IOC_CLONE, infd);
252 if (r < 0)
253 return -errno;
254
255 return 0;
256 }
257
258 int btrfs_clone_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, uint64_t sz) {
259 struct btrfs_ioctl_clone_range_args args = {
260 .src_fd = infd,
261 .src_offset = in_offset,
262 .src_length = sz,
263 .dest_offset = out_offset,
264 };
265 struct stat st;
266 int r;
267
268 assert(infd >= 0);
269 assert(outfd >= 0);
270 assert(sz > 0);
271
272 if (fstat(outfd, &st) < 0)
273 return -errno;
274
275 if (!S_ISREG(st.st_mode))
276 return -EINVAL;
277
278 r = ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args);
279 if (r < 0)
280 return -errno;
281
282 return 0;
283 }
284
285 int btrfs_get_block_device_fd(int fd, dev_t *dev) {
286 struct btrfs_ioctl_fs_info_args fsi = {};
287 uint64_t id;
288 int r;
289
290 assert(fd >= 0);
291 assert(dev);
292
293 r = btrfs_is_filesystem(fd);
294 if (r < 0)
295 return r;
296 if (!r)
297 return -ENOTTY;
298
299 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
300 return -errno;
301
302 /* We won't do this for btrfs RAID */
303 if (fsi.num_devices != 1)
304 return 0;
305
306 for (id = 1; id <= fsi.max_id; id++) {
307 struct btrfs_ioctl_dev_info_args di = {
308 .devid = id,
309 };
310 struct stat st;
311
312 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
313 if (errno == ENODEV)
314 continue;
315
316 return -errno;
317 }
318
319 if (stat((char*) di.path, &st) < 0)
320 return -errno;
321
322 if (!S_ISBLK(st.st_mode))
323 return -ENODEV;
324
325 if (major(st.st_rdev) == 0)
326 return -ENODEV;
327
328 *dev = st.st_rdev;
329 return 1;
330 }
331
332 return -ENODEV;
333 }
334
335 int btrfs_get_block_device(const char *path, dev_t *dev) {
336 _cleanup_close_ int fd = -1;
337
338 assert(path);
339 assert(dev);
340
341 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
342 if (fd < 0)
343 return -errno;
344
345 return btrfs_get_block_device_fd(fd, dev);
346 }
347
348 int btrfs_subvol_get_id_fd(int fd, uint64_t *ret) {
349 struct btrfs_ioctl_ino_lookup_args args = {
350 .objectid = BTRFS_FIRST_FREE_OBJECTID
351 };
352 int r;
353
354 assert(fd >= 0);
355 assert(ret);
356
357 r = btrfs_is_filesystem(fd);
358 if (r < 0)
359 return r;
360 if (!r)
361 return -ENOTTY;
362
363 if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
364 return -errno;
365
366 *ret = args.treeid;
367 return 0;
368 }
369
370 int btrfs_subvol_get_id(int fd, const char *subvol, uint64_t *ret) {
371 _cleanup_close_ int subvol_fd = -1;
372
373 assert(fd >= 0);
374 assert(ret);
375
376 subvol_fd = openat(fd, subvol, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
377 if (subvol_fd < 0)
378 return -errno;
379
380 return btrfs_subvol_get_id_fd(subvol_fd, ret);
381 }
382
383 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args *args) {
384 assert(args);
385
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 */
390
391 if (args->key.min_offset < (uint64_t) -1) {
392 args->key.min_offset++;
393 return true;
394 }
395
396 if (args->key.min_type < (uint8_t) -1) {
397 args->key.min_type++;
398 args->key.min_offset = 0;
399 return true;
400 }
401
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;
406 return true;
407 }
408
409 return 0;
410 }
411
412 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args *args, const struct btrfs_ioctl_search_header *h) {
413 assert(args);
414 assert(h);
415
416 args->key.min_objectid = h->objectid;
417 args->key.min_type = h->type;
418 args->key.min_offset = h->offset;
419 }
420
421 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args *args) {
422 assert(args);
423
424 /* Compare min and max */
425
426 if (args->key.min_objectid < args->key.max_objectid)
427 return -1;
428 if (args->key.min_objectid > args->key.max_objectid)
429 return 1;
430
431 if (args->key.min_type < args->key.max_type)
432 return -1;
433 if (args->key.min_type > args->key.max_type)
434 return 1;
435
436 if (args->key.min_offset < args->key.max_offset)
437 return -1;
438 if (args->key.min_offset > args->key.max_offset)
439 return 1;
440
441 return 0;
442 }
443
444 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) \
445 for ((i) = 0, \
446 (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
447 (i) < (args).key.nr_items; \
448 (i)++, \
449 (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
450
451 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
452 ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
453
454 int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *ret) {
455 struct btrfs_ioctl_search_args args = {
456 /* Tree of tree roots */
457 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
458
459 /* Look precisely for the subvolume items */
460 .key.min_type = BTRFS_ROOT_ITEM_KEY,
461 .key.max_type = BTRFS_ROOT_ITEM_KEY,
462
463 .key.min_offset = 0,
464 .key.max_offset = (uint64_t) -1,
465
466 /* No restrictions on the other components */
467 .key.min_transid = 0,
468 .key.max_transid = (uint64_t) -1,
469 };
470
471 bool found = false;
472 int r;
473
474 assert(fd >= 0);
475 assert(ret);
476
477 if (subvol_id == 0) {
478 r = btrfs_subvol_get_id_fd(fd, &subvol_id);
479 if (r < 0)
480 return r;
481 } else {
482 r = btrfs_is_filesystem(fd);
483 if (r < 0)
484 return r;
485 if (!r)
486 return -ENOTTY;
487 }
488
489 args.key.min_objectid = args.key.max_objectid = subvol_id;
490
491 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
492 const struct btrfs_ioctl_search_header *sh;
493 unsigned i;
494
495 args.key.nr_items = 256;
496 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
497 return -errno;
498
499 if (args.key.nr_items <= 0)
500 break;
501
502 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
503
504 const struct btrfs_root_item *ri;
505
506 /* Make sure we start the next search at least from this entry */
507 btrfs_ioctl_search_args_set(&args, sh);
508
509 if (sh->objectid != subvol_id)
510 continue;
511 if (sh->type != BTRFS_ROOT_ITEM_KEY)
512 continue;
513
514 /* Older versions of the struct lacked the otime setting */
515 if (sh->len < offsetof(struct btrfs_root_item, otime) + sizeof(struct btrfs_timespec))
516 continue;
517
518 ri = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
519
520 ret->otime = (usec_t) le64toh(ri->otime.sec) * USEC_PER_SEC +
521 (usec_t) le32toh(ri->otime.nsec) / NSEC_PER_USEC;
522
523 ret->subvol_id = subvol_id;
524 ret->read_only = !!(le64toh(ri->flags) & BTRFS_ROOT_SUBVOL_RDONLY);
525
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));
529
530 found = true;
531 goto finish;
532 }
533
534 /* Increase search key by one, to read the next item, if we can. */
535 if (!btrfs_ioctl_search_args_inc(&args))
536 break;
537 }
538
539 finish:
540 if (!found)
541 return -ENODATA;
542
543 return 0;
544 }
545
546 int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *ret) {
547
548 struct btrfs_ioctl_search_args args = {
549 /* Tree of quota items */
550 .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
551
552 /* The object ID is always 0 */
553 .key.min_objectid = 0,
554 .key.max_objectid = 0,
555
556 /* Look precisely for the quota items */
557 .key.min_type = BTRFS_QGROUP_STATUS_KEY,
558 .key.max_type = BTRFS_QGROUP_LIMIT_KEY,
559
560 /* No restrictions on the other components */
561 .key.min_transid = 0,
562 .key.max_transid = (uint64_t) -1,
563 };
564
565 bool found_info = false, found_limit = false;
566 int r;
567
568 assert(fd >= 0);
569 assert(ret);
570
571 if (qgroupid == 0) {
572 r = btrfs_subvol_get_id_fd(fd, &qgroupid);
573 if (r < 0)
574 return r;
575 } else {
576 r = btrfs_is_filesystem(fd);
577 if (r < 0)
578 return r;
579 if (!r)
580 return -ENOTTY;
581 }
582
583 args.key.min_offset = args.key.max_offset = qgroupid;
584
585 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
586 const struct btrfs_ioctl_search_header *sh;
587 unsigned i;
588
589 args.key.nr_items = 256;
590 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) {
591 if (errno == ENOENT) /* quota tree is missing: quota disabled */
592 break;
593
594 return -errno;
595 }
596
597 if (args.key.nr_items <= 0)
598 break;
599
600 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
601
602 /* Make sure we start the next search at least from this entry */
603 btrfs_ioctl_search_args_set(&args, sh);
604
605 if (sh->objectid != 0)
606 continue;
607 if (sh->offset != qgroupid)
608 continue;
609
610 if (sh->type == BTRFS_QGROUP_INFO_KEY) {
611 const struct btrfs_qgroup_info_item *qii = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
612
613 ret->referenced = le64toh(qii->rfer);
614 ret->exclusive = le64toh(qii->excl);
615
616 found_info = true;
617
618 } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
619 const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
620
621 if (le64toh(qli->flags) & BTRFS_QGROUP_LIMIT_MAX_RFER)
622 ret->referenced_max = le64toh(qli->max_rfer);
623 else
624 ret->referenced_max = (uint64_t) -1;
625
626 if (le64toh(qli->flags) & BTRFS_QGROUP_LIMIT_MAX_EXCL)
627 ret->exclusive_max = le64toh(qli->max_excl);
628 else
629 ret->exclusive_max = (uint64_t) -1;
630
631 found_limit = true;
632 }
633
634 if (found_info && found_limit)
635 goto finish;
636 }
637
638 /* Increase search key by one, to read the next item, if we can. */
639 if (!btrfs_ioctl_search_args_inc(&args))
640 break;
641 }
642
643 finish:
644 if (!found_limit && !found_info)
645 return -ENODATA;
646
647 if (!found_info) {
648 ret->referenced = (uint64_t) -1;
649 ret->exclusive = (uint64_t) -1;
650 }
651
652 if (!found_limit) {
653 ret->referenced_max = (uint64_t) -1;
654 ret->exclusive_max = (uint64_t) -1;
655 }
656
657 return 0;
658 }
659
660 int btrfs_qgroup_get_quota(const char *path, uint64_t qgroupid, BtrfsQuotaInfo *ret) {
661 _cleanup_close_ int fd = -1;
662
663 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
664 if (fd < 0)
665 return -errno;
666
667 return btrfs_qgroup_get_quota_fd(fd, qgroupid, ret);
668 }
669
670 int btrfs_subvol_find_subtree_qgroup(int fd, uint64_t subvol_id, uint64_t *ret) {
671 uint64_t level, lowest = (uint64_t) -1, lowest_qgroupid = 0;
672 _cleanup_free_ uint64_t *qgroups = NULL;
673 int r, n, i;
674
675 assert(fd >= 0);
676 assert(ret);
677
678 /* This finds the "subtree" qgroup for a specific
679 * subvolume. This only works for subvolumes that have been
680 * prepared with btrfs_subvol_auto_qgroup_fd() with
681 * insert_intermediary_qgroup=true (or equivalent). For others
682 * it will return the leaf qgroup instead. The two cases may
683 * be distuingished via the return value, which is 1 in case
684 * an appropriate "subtree" qgroup was found, and 0
685 * otherwise. */
686
687 if (subvol_id == 0) {
688 r = btrfs_subvol_get_id_fd(fd, &subvol_id);
689 if (r < 0)
690 return r;
691 }
692
693 r = btrfs_qgroupid_split(subvol_id, &level, NULL);
694 if (r < 0)
695 return r;
696 if (level != 0) /* Input must be a leaf qgroup */
697 return -EINVAL;
698
699 n = btrfs_qgroup_find_parents(fd, subvol_id, &qgroups);
700 if (n < 0)
701 return n;
702
703 for (i = 0; i < n; i++) {
704 uint64_t id;
705
706 r = btrfs_qgroupid_split(qgroups[i], &level, &id);
707 if (r < 0)
708 return r;
709
710 if (id != subvol_id)
711 continue;
712
713 if (lowest == (uint64_t) -1 || level < lowest) {
714 lowest_qgroupid = qgroups[i];
715 lowest = level;
716 }
717 }
718
719 if (lowest == (uint64_t) -1) {
720 /* No suitable higher-level qgroup found, let's return
721 * the leaf qgroup instead, and indicate that with the
722 * return value. */
723
724 *ret = subvol_id;
725 return 0;
726 }
727
728 *ret = lowest_qgroupid;
729 return 1;
730 }
731
732 int btrfs_subvol_get_subtree_quota_fd(int fd, uint64_t subvol_id, BtrfsQuotaInfo *ret) {
733 uint64_t qgroupid;
734 int r;
735
736 assert(fd >= 0);
737 assert(ret);
738
739 /* This determines the quota data of the qgroup with the
740 * lowest level, that shares the id part with the specified
741 * subvolume. This is useful for determining the quota data
742 * for entire subvolume subtrees, as long as the subtrees have
743 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
744 * compatible way */
745
746 r = btrfs_subvol_find_subtree_qgroup(fd, subvol_id, &qgroupid);
747 if (r < 0)
748 return r;
749
750 return btrfs_qgroup_get_quota_fd(fd, qgroupid, ret);
751 }
752
753 int btrfs_subvol_get_subtree_quota(const char *path, uint64_t subvol_id, BtrfsQuotaInfo *ret) {
754 _cleanup_close_ int fd = -1;
755
756 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
757 if (fd < 0)
758 return -errno;
759
760 return btrfs_subvol_get_subtree_quota_fd(fd, subvol_id, ret);
761 }
762
763 int btrfs_defrag_fd(int fd) {
764 struct stat st;
765
766 assert(fd >= 0);
767
768 if (fstat(fd, &st) < 0)
769 return -errno;
770
771 if (!S_ISREG(st.st_mode))
772 return -EINVAL;
773
774 if (ioctl(fd, BTRFS_IOC_DEFRAG, NULL) < 0)
775 return -errno;
776
777 return 0;
778 }
779
780 int btrfs_defrag(const char *p) {
781 _cleanup_close_ int fd = -1;
782
783 fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
784 if (fd < 0)
785 return -errno;
786
787 return btrfs_defrag_fd(fd);
788 }
789
790 int btrfs_quota_enable_fd(int fd, bool b) {
791 struct btrfs_ioctl_quota_ctl_args args = {
792 .cmd = b ? BTRFS_QUOTA_CTL_ENABLE : BTRFS_QUOTA_CTL_DISABLE,
793 };
794 int r;
795
796 assert(fd >= 0);
797
798 r = btrfs_is_filesystem(fd);
799 if (r < 0)
800 return r;
801 if (!r)
802 return -ENOTTY;
803
804 if (ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args) < 0)
805 return -errno;
806
807 return 0;
808 }
809
810 int btrfs_quota_enable(const char *path, bool b) {
811 _cleanup_close_ int fd = -1;
812
813 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
814 if (fd < 0)
815 return -errno;
816
817 return btrfs_quota_enable_fd(fd, b);
818 }
819
820 int btrfs_qgroup_set_limit_fd(int fd, uint64_t qgroupid, uint64_t referenced_max) {
821
822 struct btrfs_ioctl_qgroup_limit_args args = {
823 .lim.max_rfer = referenced_max,
824 .lim.flags = BTRFS_QGROUP_LIMIT_MAX_RFER,
825 };
826 unsigned c;
827 int r;
828
829 assert(fd >= 0);
830
831 if (qgroupid == 0) {
832 r = btrfs_subvol_get_id_fd(fd, &qgroupid);
833 if (r < 0)
834 return r;
835 } else {
836 r = btrfs_is_filesystem(fd);
837 if (r < 0)
838 return r;
839 if (!r)
840 return -ENOTTY;
841 }
842
843 args.qgroupid = qgroupid;
844
845 for (c = 0;; c++) {
846 if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0) {
847
848 if (errno == EBUSY && c < 10) {
849 (void) btrfs_quota_scan_wait(fd);
850 continue;
851 }
852
853 return -errno;
854 }
855
856 break;
857 }
858
859 return 0;
860 }
861
862 int btrfs_qgroup_set_limit(const char *path, uint64_t qgroupid, uint64_t referenced_max) {
863 _cleanup_close_ int fd = -1;
864
865 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
866 if (fd < 0)
867 return -errno;
868
869 return btrfs_qgroup_set_limit_fd(fd, qgroupid, referenced_max);
870 }
871
872 int btrfs_subvol_set_subtree_quota_limit_fd(int fd, uint64_t subvol_id, uint64_t referenced_max) {
873 uint64_t qgroupid;
874 int r;
875
876 assert(fd >= 0);
877
878 r = btrfs_subvol_find_subtree_qgroup(fd, subvol_id, &qgroupid);
879 if (r < 0)
880 return r;
881
882 return btrfs_qgroup_set_limit_fd(fd, qgroupid, referenced_max);
883 }
884
885 int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, uint64_t referenced_max) {
886 _cleanup_close_ int fd = -1;
887
888 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
889 if (fd < 0)
890 return -errno;
891
892 return btrfs_subvol_set_subtree_quota_limit_fd(fd, subvol_id, referenced_max);
893 }
894
895 int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
896 struct btrfs_ioctl_vol_args args = {};
897 _cleanup_free_ char *p = NULL, *loop = NULL, *backing = NULL;
898 _cleanup_close_ int loop_fd = -1, backing_fd = -1;
899 struct stat st;
900 dev_t dev = 0;
901 int r;
902
903 /* btrfs cannot handle file systems < 16M, hence use this as minimum */
904 if (new_size < 16*1024*1024)
905 new_size = 16*1024*1024;
906
907 r = btrfs_get_block_device_fd(fd, &dev);
908 if (r < 0)
909 return r;
910 if (r == 0)
911 return -ENODEV;
912
913 if (asprintf(&p, "/sys/dev/block/%u:%u/loop/backing_file", major(dev), minor(dev)) < 0)
914 return -ENOMEM;
915 r = read_one_line_file(p, &backing);
916 if (r == -ENOENT)
917 return -ENODEV;
918 if (r < 0)
919 return r;
920 if (isempty(backing) || !path_is_absolute(backing))
921 return -ENODEV;
922
923 backing_fd = open(backing, O_RDWR|O_CLOEXEC|O_NOCTTY);
924 if (backing_fd < 0)
925 return -errno;
926
927 if (fstat(backing_fd, &st) < 0)
928 return -errno;
929 if (!S_ISREG(st.st_mode))
930 return -ENODEV;
931
932 if (new_size == (uint64_t) st.st_size)
933 return 0;
934
935 if (grow_only && new_size < (uint64_t) st.st_size)
936 return -EINVAL;
937
938 if (asprintf(&loop, "/dev/block/%u:%u", major(dev), minor(dev)) < 0)
939 return -ENOMEM;
940 loop_fd = open(loop, O_RDWR|O_CLOEXEC|O_NOCTTY);
941 if (loop_fd < 0)
942 return -errno;
943
944 if (snprintf(args.name, sizeof(args.name), "%" PRIu64, new_size) >= (int) sizeof(args.name))
945 return -EINVAL;
946
947 if (new_size < (uint64_t) st.st_size) {
948 /* Decrease size: first decrease btrfs size, then shorten loopback */
949 if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
950 return -errno;
951 }
952
953 if (ftruncate(backing_fd, new_size) < 0)
954 return -errno;
955
956 if (ioctl(loop_fd, LOOP_SET_CAPACITY, 0) < 0)
957 return -errno;
958
959 if (new_size > (uint64_t) st.st_size) {
960 /* Increase size: first enlarge loopback, then increase btrfs size */
961 if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
962 return -errno;
963 }
964
965 /* Make sure the free disk space is correctly updated for both file systems */
966 (void) fsync(fd);
967 (void) fsync(backing_fd);
968
969 return 1;
970 }
971
972 int btrfs_resize_loopback(const char *p, uint64_t new_size, bool grow_only) {
973 _cleanup_close_ int fd = -1;
974
975 fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
976 if (fd < 0)
977 return -errno;
978
979 return btrfs_resize_loopback_fd(fd, new_size, grow_only);
980 }
981
982 int btrfs_qgroupid_make(uint64_t level, uint64_t id, uint64_t *ret) {
983 assert(ret);
984
985 if (level >= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT)))
986 return -EINVAL;
987
988 if (id >= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT))
989 return -EINVAL;
990
991 *ret = (level << BTRFS_QGROUP_LEVEL_SHIFT) | id;
992 return 0;
993 }
994
995 int btrfs_qgroupid_split(uint64_t qgroupid, uint64_t *level, uint64_t *id) {
996 assert(level || id);
997
998 if (level)
999 *level = qgroupid >> BTRFS_QGROUP_LEVEL_SHIFT;
1000
1001 if (id)
1002 *id = qgroupid & ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT) - 1);
1003
1004 return 0;
1005 }
1006
1007 static int qgroup_create_or_destroy(int fd, bool b, uint64_t qgroupid) {
1008
1009 struct btrfs_ioctl_qgroup_create_args args = {
1010 .create = b,
1011 .qgroupid = qgroupid,
1012 };
1013 unsigned c;
1014 int r;
1015
1016 r = btrfs_is_filesystem(fd);
1017 if (r < 0)
1018 return r;
1019 if (r == 0)
1020 return -ENOTTY;
1021
1022 for (c = 0;; c++) {
1023 if (ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args) < 0) {
1024
1025 /* If quota is not enabled, we get EINVAL. Turn this into a recognizable error */
1026 if (errno == EINVAL)
1027 return -ENOPROTOOPT;
1028
1029 if (errno == EBUSY && c < 10) {
1030 (void) btrfs_quota_scan_wait(fd);
1031 continue;
1032 }
1033
1034 return -errno;
1035 }
1036
1037 break;
1038 }
1039
1040 return 0;
1041 }
1042
1043 int btrfs_qgroup_create(int fd, uint64_t qgroupid) {
1044 return qgroup_create_or_destroy(fd, true, qgroupid);
1045 }
1046
1047 int btrfs_qgroup_destroy(int fd, uint64_t qgroupid) {
1048 return qgroup_create_or_destroy(fd, false, qgroupid);
1049 }
1050
1051 int btrfs_qgroup_destroy_recursive(int fd, uint64_t qgroupid) {
1052 _cleanup_free_ uint64_t *qgroups = NULL;
1053 uint64_t subvol_id;
1054 int i, n, r;
1055
1056 /* Destroys the specified qgroup, but unassigns it from all
1057 * its parents first. Also, it recursively destroys all
1058 * qgroups it is assgined to that have the same id part of the
1059 * qgroupid as the specified group. */
1060
1061 r = btrfs_qgroupid_split(qgroupid, NULL, &subvol_id);
1062 if (r < 0)
1063 return r;
1064
1065 n = btrfs_qgroup_find_parents(fd, qgroupid, &qgroups);
1066 if (n < 0)
1067 return n;
1068
1069 for (i = 0; i < n; i++) {
1070 uint64_t id;
1071
1072 r = btrfs_qgroupid_split(qgroups[i], NULL, &id);
1073 if (r < 0)
1074 return r;
1075
1076 r = btrfs_qgroup_unassign(fd, qgroupid, qgroups[i]);
1077 if (r < 0)
1078 return r;
1079
1080 if (id != subvol_id)
1081 continue;
1082
1083 /* The parent qgroupid shares the same id part with
1084 * us? If so, destroy it too. */
1085
1086 (void) btrfs_qgroup_destroy_recursive(fd, qgroups[i]);
1087 }
1088
1089 return btrfs_qgroup_destroy(fd, qgroupid);
1090 }
1091
1092 int btrfs_quota_scan_start(int fd) {
1093 struct btrfs_ioctl_quota_rescan_args args = {};
1094
1095 assert(fd >= 0);
1096
1097 if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN, &args) < 0)
1098 return -errno;
1099
1100 return 0;
1101 }
1102
1103 int btrfs_quota_scan_wait(int fd) {
1104 assert(fd >= 0);
1105
1106 if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_WAIT) < 0)
1107 return -errno;
1108
1109 return 0;
1110 }
1111
1112 int btrfs_quota_scan_ongoing(int fd) {
1113 struct btrfs_ioctl_quota_rescan_args args = {};
1114
1115 assert(fd >= 0);
1116
1117 if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_STATUS, &args) < 0)
1118 return -errno;
1119
1120 return !!args.flags;
1121 }
1122
1123 static int qgroup_assign_or_unassign(int fd, bool b, uint64_t child, uint64_t parent) {
1124 struct btrfs_ioctl_qgroup_assign_args args = {
1125 .assign = b,
1126 .src = child,
1127 .dst = parent,
1128 };
1129 unsigned c;
1130 int r;
1131
1132 r = btrfs_is_filesystem(fd);
1133 if (r < 0)
1134 return r;
1135 if (r == 0)
1136 return -ENOTTY;
1137
1138 for (c = 0;; c++) {
1139 r = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args);
1140 if (r < 0) {
1141 if (errno == EBUSY && c < 10) {
1142 (void) btrfs_quota_scan_wait(fd);
1143 continue;
1144 }
1145
1146 return -errno;
1147 }
1148
1149 if (r == 0)
1150 return 0;
1151
1152 /* If the return value is > 0, we need to request a rescan */
1153
1154 (void) btrfs_quota_scan_start(fd);
1155 return 1;
1156 }
1157 }
1158
1159 int btrfs_qgroup_assign(int fd, uint64_t child, uint64_t parent) {
1160 return qgroup_assign_or_unassign(fd, true, child, parent);
1161 }
1162
1163 int btrfs_qgroup_unassign(int fd, uint64_t child, uint64_t parent) {
1164 return qgroup_assign_or_unassign(fd, false, child, parent);
1165 }
1166
1167 static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol_id, BtrfsRemoveFlags flags) {
1168 struct btrfs_ioctl_search_args args = {
1169 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
1170
1171 .key.min_objectid = BTRFS_FIRST_FREE_OBJECTID,
1172 .key.max_objectid = BTRFS_LAST_FREE_OBJECTID,
1173
1174 .key.min_type = BTRFS_ROOT_BACKREF_KEY,
1175 .key.max_type = BTRFS_ROOT_BACKREF_KEY,
1176
1177 .key.min_transid = 0,
1178 .key.max_transid = (uint64_t) -1,
1179 };
1180
1181 struct btrfs_ioctl_vol_args vol_args = {};
1182 _cleanup_close_ int subvol_fd = -1;
1183 struct stat st;
1184 bool made_writable = false;
1185 int r;
1186
1187 assert(fd >= 0);
1188 assert(subvolume);
1189
1190 if (fstat(fd, &st) < 0)
1191 return -errno;
1192
1193 if (!S_ISDIR(st.st_mode))
1194 return -EINVAL;
1195
1196 subvol_fd = openat(fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1197 if (subvol_fd < 0)
1198 return -errno;
1199
1200 if (subvol_id == 0) {
1201 r = btrfs_subvol_get_id_fd(subvol_fd, &subvol_id);
1202 if (r < 0)
1203 return r;
1204 }
1205
1206 /* First, try to remove the subvolume. If it happens to be
1207 * already empty, this will just work. */
1208 strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
1209 if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) >= 0) {
1210 (void) btrfs_qgroup_destroy_recursive(fd, subvol_id); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1211 return 0;
1212 }
1213 if (!(flags & BTRFS_REMOVE_RECURSIVE) || errno != ENOTEMPTY)
1214 return -errno;
1215
1216 /* OK, the subvolume is not empty, let's look for child
1217 * subvolumes, and remove them, first */
1218
1219 args.key.min_offset = args.key.max_offset = subvol_id;
1220
1221 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
1222 const struct btrfs_ioctl_search_header *sh;
1223 unsigned i;
1224
1225 args.key.nr_items = 256;
1226 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
1227 return -errno;
1228
1229 if (args.key.nr_items <= 0)
1230 break;
1231
1232 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
1233 _cleanup_free_ char *p = NULL;
1234 const struct btrfs_root_ref *ref;
1235 struct btrfs_ioctl_ino_lookup_args ino_args;
1236
1237 btrfs_ioctl_search_args_set(&args, sh);
1238
1239 if (sh->type != BTRFS_ROOT_BACKREF_KEY)
1240 continue;
1241 if (sh->offset != subvol_id)
1242 continue;
1243
1244 ref = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
1245
1246 p = strndup((char*) ref + sizeof(struct btrfs_root_ref), le64toh(ref->name_len));
1247 if (!p)
1248 return -ENOMEM;
1249
1250 zero(ino_args);
1251 ino_args.treeid = subvol_id;
1252 ino_args.objectid = htole64(ref->dirid);
1253
1254 if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args) < 0)
1255 return -errno;
1256
1257 if (!made_writable) {
1258 r = btrfs_subvol_set_read_only_fd(subvol_fd, false);
1259 if (r < 0)
1260 return r;
1261
1262 made_writable = true;
1263 }
1264
1265 if (isempty(ino_args.name))
1266 /* Subvolume is in the top-level
1267 * directory of the subvolume. */
1268 r = subvol_remove_children(subvol_fd, p, sh->objectid, flags);
1269 else {
1270 _cleanup_close_ int child_fd = -1;
1271
1272 /* Subvolume is somewhere further down,
1273 * hence we need to open the
1274 * containing directory first */
1275
1276 child_fd = openat(subvol_fd, ino_args.name, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1277 if (child_fd < 0)
1278 return -errno;
1279
1280 r = subvol_remove_children(child_fd, p, sh->objectid, flags);
1281 }
1282 if (r < 0)
1283 return r;
1284 }
1285
1286 /* Increase search key by one, to read the next item, if we can. */
1287 if (!btrfs_ioctl_search_args_inc(&args))
1288 break;
1289 }
1290
1291 /* OK, the child subvolumes should all be gone now, let's try
1292 * again to remove the subvolume */
1293 if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) < 0)
1294 return -errno;
1295
1296 (void) btrfs_qgroup_destroy_recursive(fd, subvol_id);
1297 return 0;
1298 }
1299
1300 int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags) {
1301 _cleanup_close_ int fd = -1;
1302 const char *subvolume;
1303 int r;
1304
1305 assert(path);
1306
1307 r = extract_subvolume_name(path, &subvolume);
1308 if (r < 0)
1309 return r;
1310
1311 fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1312 if (fd < 0)
1313 return fd;
1314
1315 return subvol_remove_children(fd, subvolume, 0, flags);
1316 }
1317
1318 int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags) {
1319 return subvol_remove_children(fd, subvolume, 0, flags);
1320 }
1321
1322 int btrfs_qgroup_copy_limits(int fd, uint64_t old_qgroupid, uint64_t new_qgroupid) {
1323
1324 struct btrfs_ioctl_search_args args = {
1325 /* Tree of quota items */
1326 .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
1327
1328 /* The object ID is always 0 */
1329 .key.min_objectid = 0,
1330 .key.max_objectid = 0,
1331
1332 /* Look precisely for the quota items */
1333 .key.min_type = BTRFS_QGROUP_LIMIT_KEY,
1334 .key.max_type = BTRFS_QGROUP_LIMIT_KEY,
1335
1336 /* For our qgroup */
1337 .key.min_offset = old_qgroupid,
1338 .key.max_offset = old_qgroupid,
1339
1340 /* No restrictions on the other components */
1341 .key.min_transid = 0,
1342 .key.max_transid = (uint64_t) -1,
1343 };
1344
1345 int r;
1346
1347 r = btrfs_is_filesystem(fd);
1348 if (r < 0)
1349 return r;
1350 if (!r)
1351 return -ENOTTY;
1352
1353 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
1354 const struct btrfs_ioctl_search_header *sh;
1355 unsigned i;
1356
1357 args.key.nr_items = 256;
1358 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) {
1359 if (errno == ENOENT) /* quota tree missing: quota is not enabled, hence nothing to copy */
1360 break;
1361
1362 return -errno;
1363 }
1364
1365 if (args.key.nr_items <= 0)
1366 break;
1367
1368 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
1369 const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
1370 struct btrfs_ioctl_qgroup_limit_args qargs;
1371 unsigned c;
1372
1373 /* Make sure we start the next search at least from this entry */
1374 btrfs_ioctl_search_args_set(&args, sh);
1375
1376 if (sh->objectid != 0)
1377 continue;
1378 if (sh->type != BTRFS_QGROUP_LIMIT_KEY)
1379 continue;
1380 if (sh->offset != old_qgroupid)
1381 continue;
1382
1383 /* We found the entry, now copy things over. */
1384
1385 qargs = (struct btrfs_ioctl_qgroup_limit_args) {
1386 .qgroupid = new_qgroupid,
1387
1388 .lim.max_rfer = le64toh(qli->max_rfer),
1389 .lim.max_excl = le64toh(qli->max_excl),
1390 .lim.rsv_rfer = le64toh(qli->rsv_rfer),
1391 .lim.rsv_excl = le64toh(qli->rsv_excl),
1392
1393 .lim.flags = le64toh(qli->flags) & (BTRFS_QGROUP_LIMIT_MAX_RFER|
1394 BTRFS_QGROUP_LIMIT_MAX_EXCL|
1395 BTRFS_QGROUP_LIMIT_RSV_RFER|
1396 BTRFS_QGROUP_LIMIT_RSV_EXCL),
1397 };
1398
1399 for (c = 0;; c++) {
1400 if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &qargs) < 0) {
1401 if (errno == EBUSY && c < 10) {
1402 (void) btrfs_quota_scan_wait(fd);
1403 continue;
1404 }
1405 return -errno;
1406 }
1407
1408 break;
1409 }
1410
1411 return 1;
1412 }
1413
1414 /* Increase search key by one, to read the next item, if we can. */
1415 if (!btrfs_ioctl_search_args_inc(&args))
1416 break;
1417 }
1418
1419 return 0;
1420 }
1421
1422 static int copy_quota_hierarchy(int fd, uint64_t old_subvol_id, uint64_t new_subvol_id) {
1423 _cleanup_free_ uint64_t *old_qgroups = NULL, *old_parent_qgroups = NULL;
1424 bool copy_from_parent = false, insert_intermediary_qgroup = false;
1425 int n_old_qgroups, n_old_parent_qgroups, r, i;
1426 uint64_t old_parent_id;
1427
1428 assert(fd >= 0);
1429
1430 /* Copies a reduced form of quota information from the old to
1431 * the new subvolume. */
1432
1433 n_old_qgroups = btrfs_qgroup_find_parents(fd, old_subvol_id, &old_qgroups);
1434 if (n_old_qgroups <= 0) /* Nothing to copy */
1435 return n_old_qgroups;
1436
1437 r = btrfs_subvol_get_parent(fd, old_subvol_id, &old_parent_id);
1438 if (r == -ENXIO)
1439 /* We have no parent, hence nothing to copy. */
1440 n_old_parent_qgroups = 0;
1441 else if (r < 0)
1442 return r;
1443 else {
1444 n_old_parent_qgroups = btrfs_qgroup_find_parents(fd, old_parent_id, &old_parent_qgroups);
1445 if (n_old_parent_qgroups < 0)
1446 return n_old_parent_qgroups;
1447 }
1448
1449 for (i = 0; i < n_old_qgroups; i++) {
1450 uint64_t id;
1451 int j;
1452
1453 r = btrfs_qgroupid_split(old_qgroups[i], NULL, &id);
1454 if (r < 0)
1455 return r;
1456
1457 if (id == old_subvol_id) {
1458 /* The old subvolume was member of a qgroup
1459 * that had the same id, but a different level
1460 * as it self. Let's set up something similar
1461 * in the destination. */
1462 insert_intermediary_qgroup = true;
1463 break;
1464 }
1465
1466 for (j = 0; j < n_old_parent_qgroups; j++)
1467 if (old_parent_qgroups[j] == old_qgroups[i]) {
1468 /* The old subvolume shared a common
1469 * parent qgroup with its parent
1470 * subvolume. Let's set up something
1471 * similar in the destination. */
1472 copy_from_parent = true;
1473 }
1474 }
1475
1476 if (!insert_intermediary_qgroup && !copy_from_parent)
1477 return 0;
1478
1479 return btrfs_subvol_auto_qgroup_fd(fd, new_subvol_id, insert_intermediary_qgroup);
1480 }
1481
1482 static int copy_subtree_quota_limits(int fd, uint64_t old_subvol, uint64_t new_subvol) {
1483 uint64_t old_subtree_qgroup, new_subtree_qgroup;
1484 bool changed;
1485 int r;
1486
1487 /* First copy the leaf limits */
1488 r = btrfs_qgroup_copy_limits(fd, old_subvol, new_subvol);
1489 if (r < 0)
1490 return r;
1491 changed = r > 0;
1492
1493 /* Then, try to copy the subtree limits, if there are any. */
1494 r = btrfs_subvol_find_subtree_qgroup(fd, old_subvol, &old_subtree_qgroup);
1495 if (r < 0)
1496 return r;
1497 if (r == 0)
1498 return changed;
1499
1500 r = btrfs_subvol_find_subtree_qgroup(fd, new_subvol, &new_subtree_qgroup);
1501 if (r < 0)
1502 return r;
1503 if (r == 0)
1504 return changed;
1505
1506 r = btrfs_qgroup_copy_limits(fd, old_subtree_qgroup, new_subtree_qgroup);
1507 if (r != 0)
1508 return r;
1509
1510 return changed;
1511 }
1512
1513 static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolume, uint64_t old_subvol_id, BtrfsSnapshotFlags flags) {
1514
1515 struct btrfs_ioctl_search_args args = {
1516 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
1517
1518 .key.min_objectid = BTRFS_FIRST_FREE_OBJECTID,
1519 .key.max_objectid = BTRFS_LAST_FREE_OBJECTID,
1520
1521 .key.min_type = BTRFS_ROOT_BACKREF_KEY,
1522 .key.max_type = BTRFS_ROOT_BACKREF_KEY,
1523
1524 .key.min_transid = 0,
1525 .key.max_transid = (uint64_t) -1,
1526 };
1527
1528 struct btrfs_ioctl_vol_args_v2 vol_args = {
1529 .flags = flags & BTRFS_SNAPSHOT_READ_ONLY ? BTRFS_SUBVOL_RDONLY : 0,
1530 .fd = old_fd,
1531 };
1532 _cleanup_close_ int subvolume_fd = -1;
1533 uint64_t new_subvol_id;
1534 int r;
1535
1536 assert(old_fd >= 0);
1537 assert(new_fd >= 0);
1538 assert(subvolume);
1539
1540 strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
1541
1542 if (ioctl(new_fd, BTRFS_IOC_SNAP_CREATE_V2, &vol_args) < 0)
1543 return -errno;
1544
1545 if (!(flags & BTRFS_SNAPSHOT_RECURSIVE) &&
1546 !(flags & BTRFS_SNAPSHOT_QUOTA))
1547 return 0;
1548
1549 if (old_subvol_id == 0) {
1550 r = btrfs_subvol_get_id_fd(old_fd, &old_subvol_id);
1551 if (r < 0)
1552 return r;
1553 }
1554
1555 r = btrfs_subvol_get_id(new_fd, vol_args.name, &new_subvol_id);
1556 if (r < 0)
1557 return r;
1558
1559 if (flags & BTRFS_SNAPSHOT_QUOTA)
1560 (void) copy_quota_hierarchy(new_fd, old_subvol_id, new_subvol_id);
1561
1562 if (!(flags & BTRFS_SNAPSHOT_RECURSIVE)) {
1563
1564 if (flags & BTRFS_SNAPSHOT_QUOTA)
1565 (void) copy_subtree_quota_limits(new_fd, old_subvol_id, new_subvol_id);
1566
1567 return 0;
1568 }
1569
1570 args.key.min_offset = args.key.max_offset = old_subvol_id;
1571
1572 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
1573 const struct btrfs_ioctl_search_header *sh;
1574 unsigned i;
1575
1576 args.key.nr_items = 256;
1577 if (ioctl(old_fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
1578 return -errno;
1579
1580 if (args.key.nr_items <= 0)
1581 break;
1582
1583 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
1584 _cleanup_free_ char *p = NULL, *c = NULL, *np = NULL;
1585 struct btrfs_ioctl_ino_lookup_args ino_args;
1586 const struct btrfs_root_ref *ref;
1587 _cleanup_close_ int old_child_fd = -1, new_child_fd = -1;
1588
1589 btrfs_ioctl_search_args_set(&args, sh);
1590
1591 if (sh->type != BTRFS_ROOT_BACKREF_KEY)
1592 continue;
1593
1594 /* Avoid finding the source subvolume a second
1595 * time */
1596 if (sh->offset != old_subvol_id)
1597 continue;
1598
1599 /* Avoid running into loops if the new
1600 * subvolume is below the old one. */
1601 if (sh->objectid == new_subvol_id)
1602 continue;
1603
1604 ref = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
1605 p = strndup((char*) ref + sizeof(struct btrfs_root_ref), le64toh(ref->name_len));
1606 if (!p)
1607 return -ENOMEM;
1608
1609 zero(ino_args);
1610 ino_args.treeid = old_subvol_id;
1611 ino_args.objectid = htole64(ref->dirid);
1612
1613 if (ioctl(old_fd, BTRFS_IOC_INO_LOOKUP, &ino_args) < 0)
1614 return -errno;
1615
1616 /* The kernel returns an empty name if the
1617 * subvolume is in the top-level directory,
1618 * and otherwise appends a slash, so that we
1619 * can just concatenate easily here, without
1620 * adding a slash. */
1621 c = strappend(ino_args.name, p);
1622 if (!c)
1623 return -ENOMEM;
1624
1625 old_child_fd = openat(old_fd, c, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1626 if (old_child_fd < 0)
1627 return -errno;
1628
1629 np = strjoin(subvolume, "/", ino_args.name, NULL);
1630 if (!np)
1631 return -ENOMEM;
1632
1633 new_child_fd = openat(new_fd, np, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1634 if (new_child_fd < 0)
1635 return -errno;
1636
1637 if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
1638 /* If the snapshot is read-only we
1639 * need to mark it writable
1640 * temporarily, to put the subsnapshot
1641 * into place. */
1642
1643 if (subvolume_fd < 0) {
1644 subvolume_fd = openat(new_fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1645 if (subvolume_fd < 0)
1646 return -errno;
1647 }
1648
1649 r = btrfs_subvol_set_read_only_fd(subvolume_fd, false);
1650 if (r < 0)
1651 return r;
1652 }
1653
1654 /* When btrfs clones the subvolumes, child
1655 * subvolumes appear as empty directories. Remove
1656 * them, so that we can create a new snapshot
1657 * in their place */
1658 if (unlinkat(new_child_fd, p, AT_REMOVEDIR) < 0) {
1659 int k = -errno;
1660
1661 if (flags & BTRFS_SNAPSHOT_READ_ONLY)
1662 (void) btrfs_subvol_set_read_only_fd(subvolume_fd, true);
1663
1664 return k;
1665 }
1666
1667 r = subvol_snapshot_children(old_child_fd, new_child_fd, p, sh->objectid, flags & ~BTRFS_SNAPSHOT_FALLBACK_COPY);
1668
1669 /* Restore the readonly flag */
1670 if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
1671 int k;
1672
1673 k = btrfs_subvol_set_read_only_fd(subvolume_fd, true);
1674 if (r >= 0 && k < 0)
1675 return k;
1676 }
1677
1678 if (r < 0)
1679 return r;
1680 }
1681
1682 /* Increase search key by one, to read the next item, if we can. */
1683 if (!btrfs_ioctl_search_args_inc(&args))
1684 break;
1685 }
1686
1687 if (flags & BTRFS_SNAPSHOT_QUOTA)
1688 (void) copy_subtree_quota_limits(new_fd, old_subvol_id, new_subvol_id);
1689
1690 return 0;
1691 }
1692
1693 int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags) {
1694 _cleanup_close_ int new_fd = -1;
1695 const char *subvolume;
1696 int r;
1697
1698 assert(old_fd >= 0);
1699 assert(new_path);
1700
1701 r = btrfs_is_subvol_fd(old_fd);
1702 if (r < 0)
1703 return r;
1704 if (r == 0) {
1705 if (!(flags & BTRFS_SNAPSHOT_FALLBACK_COPY))
1706 return -EISDIR;
1707
1708 r = btrfs_subvol_make(new_path);
1709 if (r < 0)
1710 return r;
1711
1712 r = copy_directory_fd(old_fd, new_path, true);
1713 if (r < 0) {
1714 (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA);
1715 return r;
1716 }
1717
1718 if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
1719 r = btrfs_subvol_set_read_only(new_path, true);
1720 if (r < 0) {
1721 (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA);
1722 return r;
1723 }
1724 }
1725
1726 return 0;
1727 }
1728
1729 r = extract_subvolume_name(new_path, &subvolume);
1730 if (r < 0)
1731 return r;
1732
1733 new_fd = open_parent(new_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1734 if (new_fd < 0)
1735 return new_fd;
1736
1737 return subvol_snapshot_children(old_fd, new_fd, subvolume, 0, flags);
1738 }
1739
1740 int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags) {
1741 _cleanup_close_ int old_fd = -1;
1742
1743 assert(old_path);
1744 assert(new_path);
1745
1746 old_fd = open(old_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1747 if (old_fd < 0)
1748 return -errno;
1749
1750 return btrfs_subvol_snapshot_fd(old_fd, new_path, flags);
1751 }
1752
1753 int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) {
1754
1755 struct btrfs_ioctl_search_args args = {
1756 /* Tree of quota items */
1757 .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
1758
1759 /* Look precisely for the quota relation items */
1760 .key.min_type = BTRFS_QGROUP_RELATION_KEY,
1761 .key.max_type = BTRFS_QGROUP_RELATION_KEY,
1762
1763 /* No restrictions on the other components */
1764 .key.min_offset = 0,
1765 .key.max_offset = (uint64_t) -1,
1766
1767 .key.min_transid = 0,
1768 .key.max_transid = (uint64_t) -1,
1769 };
1770
1771 _cleanup_free_ uint64_t *items = NULL;
1772 size_t n_items = 0, n_allocated = 0;
1773 int r;
1774
1775 assert(fd >= 0);
1776 assert(ret);
1777
1778 if (qgroupid == 0) {
1779 r = btrfs_subvol_get_id_fd(fd, &qgroupid);
1780 if (r < 0)
1781 return r;
1782 } else {
1783 r = btrfs_is_filesystem(fd);
1784 if (r < 0)
1785 return r;
1786 if (!r)
1787 return -ENOTTY;
1788 }
1789
1790 args.key.min_objectid = args.key.max_objectid = qgroupid;
1791
1792 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
1793 const struct btrfs_ioctl_search_header *sh;
1794 unsigned i;
1795
1796 args.key.nr_items = 256;
1797 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) {
1798 if (errno == ENOENT) /* quota tree missing: quota is disabled */
1799 break;
1800
1801 return -errno;
1802 }
1803
1804 if (args.key.nr_items <= 0)
1805 break;
1806
1807 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
1808
1809 /* Make sure we start the next search at least from this entry */
1810 btrfs_ioctl_search_args_set(&args, sh);
1811
1812 if (sh->type != BTRFS_QGROUP_RELATION_KEY)
1813 continue;
1814 if (sh->offset < sh->objectid)
1815 continue;
1816 if (sh->objectid != qgroupid)
1817 continue;
1818
1819 if (!GREEDY_REALLOC(items, n_allocated, n_items+1))
1820 return -ENOMEM;
1821
1822 items[n_items++] = sh->offset;
1823 }
1824
1825 /* Increase search key by one, to read the next item, if we can. */
1826 if (!btrfs_ioctl_search_args_inc(&args))
1827 break;
1828 }
1829
1830 if (n_items <= 0) {
1831 *ret = NULL;
1832 return 0;
1833 }
1834
1835 *ret = items;
1836 items = NULL;
1837
1838 return (int) n_items;
1839 }
1840
1841 int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermediary_qgroup) {
1842 _cleanup_free_ uint64_t *qgroups = NULL;
1843 uint64_t parent_subvol;
1844 bool changed = false;
1845 int n = 0, r;
1846
1847 assert(fd >= 0);
1848
1849 /*
1850 * Sets up the specified subvolume's qgroup automatically in
1851 * one of two ways:
1852 *
1853 * If insert_intermediary_qgroup is false, the subvolume's
1854 * leaf qgroup will be assigned to the same parent qgroups as
1855 * the subvolume's parent subvolume.
1856 *
1857 * If insert_intermediary_qgroup is true a new intermediary
1858 * higher-level qgroup is created, with a higher level number,
1859 * but reusing the id of the subvolume. The level number is
1860 * picked as one smaller than the lowest level qgroup the
1861 * parent subvolume is a member of. If the parent subvolume's
1862 * leaf qgroup is assigned to no higher-level qgroup a new
1863 * qgroup of level 255 is created instead. Either way, the new
1864 * qgroup is then assigned to the parent's higher-level
1865 * qgroup, and the subvolume itself is assigned to it.
1866 *
1867 * If the subvolume is already assigned to a higher level
1868 * qgroup, no operation is executed.
1869 *
1870 * Effectively this means: regardless if
1871 * insert_intermediary_qgroup is true or not, after this
1872 * function is invoked the subvolume will be accounted within
1873 * the same qgroups as the parent. However, if it is true, it
1874 * will also get its own higher-level qgroup, which may in
1875 * turn be used by subvolumes created beneath this subvolume
1876 * later on.
1877 *
1878 * This hence defines a simple default qgroup setup for
1879 * subvolumes, as long as this function is invoked on each
1880 * created subvolume: each subvolume is always accounting
1881 * together with its immediate parents. Optionally, if
1882 * insert_intermediary_qgroup is true, it will also get a
1883 * qgroup that then includes all its own child subvolumes.
1884 */
1885
1886 if (subvol_id == 0) {
1887 r = btrfs_is_subvol_fd(fd);
1888 if (r < 0)
1889 return r;
1890 if (!r)
1891 return -ENOTTY;
1892
1893 r = btrfs_subvol_get_id_fd(fd, &subvol_id);
1894 if (r < 0)
1895 return r;
1896 }
1897
1898 n = btrfs_qgroup_find_parents(fd, subvol_id, &qgroups);
1899 if (n < 0)
1900 return n;
1901 if (n > 0) /* already parent qgroups set up, let's bail */
1902 return 0;
1903
1904 qgroups = mfree(qgroups);
1905
1906 r = btrfs_subvol_get_parent(fd, subvol_id, &parent_subvol);
1907 if (r == -ENXIO)
1908 /* No parent, hence no qgroup memberships */
1909 n = 0;
1910 else if (r < 0)
1911 return r;
1912 else {
1913 n = btrfs_qgroup_find_parents(fd, parent_subvol, &qgroups);
1914 if (n < 0)
1915 return n;
1916 }
1917
1918 if (insert_intermediary_qgroup) {
1919 uint64_t lowest = 256, new_qgroupid;
1920 bool created = false;
1921 int i;
1922
1923 /* Determine the lowest qgroup that the parent
1924 * subvolume is assigned to. */
1925
1926 for (i = 0; i < n; i++) {
1927 uint64_t level;
1928
1929 r = btrfs_qgroupid_split(qgroups[i], &level, NULL);
1930 if (r < 0)
1931 return r;
1932
1933 if (level < lowest)
1934 lowest = level;
1935 }
1936
1937 if (lowest <= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1938 return -EBUSY;
1939
1940 r = btrfs_qgroupid_make(lowest - 1, subvol_id, &new_qgroupid);
1941 if (r < 0)
1942 return r;
1943
1944 /* Create the new intermediary group, unless it already exists */
1945 r = btrfs_qgroup_create(fd, new_qgroupid);
1946 if (r < 0 && r != -EEXIST)
1947 return r;
1948 if (r >= 0)
1949 changed = created = true;
1950
1951 for (i = 0; i < n; i++) {
1952 r = btrfs_qgroup_assign(fd, new_qgroupid, qgroups[i]);
1953 if (r < 0 && r != -EEXIST) {
1954 if (created)
1955 (void) btrfs_qgroup_destroy_recursive(fd, new_qgroupid);
1956
1957 return r;
1958 }
1959 if (r >= 0)
1960 changed = true;
1961 }
1962
1963 r = btrfs_qgroup_assign(fd, subvol_id, new_qgroupid);
1964 if (r < 0 && r != -EEXIST) {
1965 if (created)
1966 (void) btrfs_qgroup_destroy_recursive(fd, new_qgroupid);
1967 return r;
1968 }
1969 if (r >= 0)
1970 changed = true;
1971
1972 } else {
1973 int i;
1974
1975 /* Assign our subvolume to all the same qgroups as the parent */
1976
1977 for (i = 0; i < n; i++) {
1978 r = btrfs_qgroup_assign(fd, subvol_id, qgroups[i]);
1979 if (r < 0 && r != -EEXIST)
1980 return r;
1981 if (r >= 0)
1982 changed = true;
1983 }
1984 }
1985
1986 return changed;
1987 }
1988
1989 int btrfs_subvol_auto_qgroup(const char *path, uint64_t subvol_id, bool create_intermediary_qgroup) {
1990 _cleanup_close_ int fd = -1;
1991
1992 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1993 if (fd < 0)
1994 return -errno;
1995
1996 return btrfs_subvol_auto_qgroup_fd(fd, subvol_id, create_intermediary_qgroup);
1997 }
1998
1999 int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret) {
2000
2001 struct btrfs_ioctl_search_args args = {
2002 /* Tree of tree roots */
2003 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
2004
2005 /* Look precisely for the subvolume items */
2006 .key.min_type = BTRFS_ROOT_BACKREF_KEY,
2007 .key.max_type = BTRFS_ROOT_BACKREF_KEY,
2008
2009 /* No restrictions on the other components */
2010 .key.min_offset = 0,
2011 .key.max_offset = (uint64_t) -1,
2012
2013 .key.min_transid = 0,
2014 .key.max_transid = (uint64_t) -1,
2015 };
2016 int r;
2017
2018 assert(fd >= 0);
2019 assert(ret);
2020
2021 if (subvol_id == 0) {
2022 r = btrfs_subvol_get_id_fd(fd, &subvol_id);
2023 if (r < 0)
2024 return r;
2025 } else {
2026 r = btrfs_is_filesystem(fd);
2027 if (r < 0)
2028 return r;
2029 if (!r)
2030 return -ENOTTY;
2031 }
2032
2033 args.key.min_objectid = args.key.max_objectid = subvol_id;
2034
2035 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
2036 const struct btrfs_ioctl_search_header *sh;
2037 unsigned i;
2038
2039 args.key.nr_items = 256;
2040 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
2041 return -errno;
2042
2043 if (args.key.nr_items <= 0)
2044 break;
2045
2046 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
2047
2048 if (sh->type != BTRFS_ROOT_BACKREF_KEY)
2049 continue;
2050 if (sh->objectid != subvol_id)
2051 continue;
2052
2053 *ret = sh->offset;
2054 return 0;
2055 }
2056 }
2057
2058 return -ENXIO;
2059 }