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