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