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