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