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