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