]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/btrfs-util.c
Merge pull request #1886 from poettering/tasks-max
[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 if (errno == ENOENT) /* quota tree is missing: quota disabled */
580 break;
581
582 return -errno;
583 }
584
585 if (args.key.nr_items <= 0)
586 break;
587
588 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
589
590 /* Make sure we start the next search at least from this entry */
591 btrfs_ioctl_search_args_set(&args, sh);
592
593 if (sh->objectid != 0)
594 continue;
595 if (sh->offset != qgroupid)
596 continue;
597
598 if (sh->type == BTRFS_QGROUP_INFO_KEY) {
599 const struct btrfs_qgroup_info_item *qii = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
600
601 ret->referenced = le64toh(qii->rfer);
602 ret->exclusive = le64toh(qii->excl);
603
604 found_info = true;
605
606 } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
607 const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
608
609 if (le64toh(qli->flags) & BTRFS_QGROUP_LIMIT_MAX_RFER)
610 ret->referenced_max = le64toh(qli->max_rfer);
611 else
612 ret->referenced_max = (uint64_t) -1;
613
614 if (le64toh(qli->flags) & BTRFS_QGROUP_LIMIT_MAX_EXCL)
615 ret->exclusive_max = le64toh(qli->max_excl);
616 else
617 ret->exclusive_max = (uint64_t) -1;
618
619 found_limit = true;
620 }
621
622 if (found_info && found_limit)
623 goto finish;
624 }
625
626 /* Increase search key by one, to read the next item, if we can. */
627 if (!btrfs_ioctl_search_args_inc(&args))
628 break;
629 }
630
631 finish:
632 if (!found_limit && !found_info)
633 return -ENODATA;
634
635 if (!found_info) {
636 ret->referenced = (uint64_t) -1;
637 ret->exclusive = (uint64_t) -1;
638 }
639
640 if (!found_limit) {
641 ret->referenced_max = (uint64_t) -1;
642 ret->exclusive_max = (uint64_t) -1;
643 }
644
645 return 0;
646 }
647
648 int btrfs_qgroup_get_quota(const char *path, uint64_t qgroupid, BtrfsQuotaInfo *ret) {
649 _cleanup_close_ int fd = -1;
650
651 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
652 if (fd < 0)
653 return -errno;
654
655 return btrfs_qgroup_get_quota_fd(fd, qgroupid, ret);
656 }
657
658 int btrfs_subvol_find_subtree_qgroup(int fd, uint64_t subvol_id, uint64_t *ret) {
659 uint64_t level, lowest = (uint64_t) -1, lowest_qgroupid = 0;
660 _cleanup_free_ uint64_t *qgroups = NULL;
661 int r, n, i;
662
663 assert(fd >= 0);
664 assert(ret);
665
666 /* This finds the "subtree" qgroup for a specific
667 * subvolume. This only works for subvolumes that have been
668 * prepared with btrfs_subvol_auto_qgroup_fd() with
669 * insert_intermediary_qgroup=true (or equivalent). For others
670 * it will return the leaf qgroup instead. The two cases may
671 * be distuingished via the return value, which is 1 in case
672 * an appropriate "subtree" qgroup was found, and 0
673 * otherwise. */
674
675 if (subvol_id == 0) {
676 r = btrfs_subvol_get_id_fd(fd, &subvol_id);
677 if (r < 0)
678 return r;
679 }
680
681 r = btrfs_qgroupid_split(subvol_id, &level, NULL);
682 if (r < 0)
683 return r;
684 if (level != 0) /* Input must be a leaf qgroup */
685 return -EINVAL;
686
687 n = btrfs_qgroup_find_parents(fd, subvol_id, &qgroups);
688 if (n < 0)
689 return n;
690
691 for (i = 0; i < n; i++) {
692 uint64_t id;
693
694 r = btrfs_qgroupid_split(qgroups[i], &level, &id);
695 if (r < 0)
696 return r;
697
698 if (id != subvol_id)
699 continue;
700
701 if (lowest == (uint64_t) -1 || level < lowest) {
702 lowest_qgroupid = qgroups[i];
703 lowest = level;
704 }
705 }
706
707 if (lowest == (uint64_t) -1) {
708 /* No suitable higher-level qgroup found, let's return
709 * the leaf qgroup instead, and indicate that with the
710 * return value. */
711
712 *ret = subvol_id;
713 return 0;
714 }
715
716 *ret = lowest_qgroupid;
717 return 1;
718 }
719
720 int btrfs_subvol_get_subtree_quota_fd(int fd, uint64_t subvol_id, BtrfsQuotaInfo *ret) {
721 uint64_t qgroupid;
722 int r;
723
724 assert(fd >= 0);
725 assert(ret);
726
727 /* This determines the quota data of the qgroup with the
728 * lowest level, that shares the id part with the specified
729 * subvolume. This is useful for determining the quota data
730 * for entire subvolume subtrees, as long as the subtrees have
731 * been set up with btrfs_qgroup_subvol_auto_fd() or in a
732 * compatible way */
733
734 r = btrfs_subvol_find_subtree_qgroup(fd, subvol_id, &qgroupid);
735 if (r < 0)
736 return r;
737
738 return btrfs_qgroup_get_quota_fd(fd, qgroupid, ret);
739 }
740
741 int btrfs_subvol_get_subtree_quota(const char *path, uint64_t subvol_id, BtrfsQuotaInfo *ret) {
742 _cleanup_close_ int fd = -1;
743
744 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
745 if (fd < 0)
746 return -errno;
747
748 return btrfs_subvol_get_subtree_quota_fd(fd, subvol_id, ret);
749 }
750
751 int btrfs_defrag_fd(int fd) {
752 struct stat st;
753
754 assert(fd >= 0);
755
756 if (fstat(fd, &st) < 0)
757 return -errno;
758
759 if (!S_ISREG(st.st_mode))
760 return -EINVAL;
761
762 if (ioctl(fd, BTRFS_IOC_DEFRAG, NULL) < 0)
763 return -errno;
764
765 return 0;
766 }
767
768 int btrfs_defrag(const char *p) {
769 _cleanup_close_ int fd = -1;
770
771 fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
772 if (fd < 0)
773 return -errno;
774
775 return btrfs_defrag_fd(fd);
776 }
777
778 int btrfs_quota_enable_fd(int fd, bool b) {
779 struct btrfs_ioctl_quota_ctl_args args = {
780 .cmd = b ? BTRFS_QUOTA_CTL_ENABLE : BTRFS_QUOTA_CTL_DISABLE,
781 };
782 int r;
783
784 assert(fd >= 0);
785
786 r = btrfs_is_filesystem(fd);
787 if (r < 0)
788 return r;
789 if (!r)
790 return -ENOTTY;
791
792 if (ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args) < 0)
793 return -errno;
794
795 return 0;
796 }
797
798 int btrfs_quota_enable(const char *path, bool b) {
799 _cleanup_close_ int fd = -1;
800
801 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
802 if (fd < 0)
803 return -errno;
804
805 return btrfs_quota_enable_fd(fd, b);
806 }
807
808 int btrfs_qgroup_set_limit_fd(int fd, uint64_t qgroupid, uint64_t referenced_max) {
809
810 struct btrfs_ioctl_qgroup_limit_args args = {
811 .lim.max_rfer = referenced_max,
812 .lim.flags = BTRFS_QGROUP_LIMIT_MAX_RFER,
813 };
814 unsigned c;
815 int r;
816
817 assert(fd >= 0);
818
819 if (qgroupid == 0) {
820 r = btrfs_subvol_get_id_fd(fd, &qgroupid);
821 if (r < 0)
822 return r;
823 } else {
824 r = btrfs_is_filesystem(fd);
825 if (r < 0)
826 return r;
827 if (!r)
828 return -ENOTTY;
829 }
830
831 args.qgroupid = qgroupid;
832
833 for (c = 0;; c++) {
834 if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0) {
835
836 if (errno == EBUSY && c < 10) {
837 (void) btrfs_quota_scan_wait(fd);
838 continue;
839 }
840
841 return -errno;
842 }
843
844 break;
845 }
846
847 return 0;
848 }
849
850 int btrfs_qgroup_set_limit(const char *path, uint64_t qgroupid, uint64_t referenced_max) {
851 _cleanup_close_ int fd = -1;
852
853 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
854 if (fd < 0)
855 return -errno;
856
857 return btrfs_qgroup_set_limit_fd(fd, qgroupid, referenced_max);
858 }
859
860 int btrfs_subvol_set_subtree_quota_limit_fd(int fd, uint64_t subvol_id, uint64_t referenced_max) {
861 uint64_t qgroupid;
862 int r;
863
864 assert(fd >= 0);
865
866 r = btrfs_subvol_find_subtree_qgroup(fd, subvol_id, &qgroupid);
867 if (r < 0)
868 return r;
869
870 return btrfs_qgroup_set_limit_fd(fd, qgroupid, referenced_max);
871 }
872
873 int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, uint64_t referenced_max) {
874 _cleanup_close_ int fd = -1;
875
876 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
877 if (fd < 0)
878 return -errno;
879
880 return btrfs_subvol_set_subtree_quota_limit_fd(fd, subvol_id, referenced_max);
881 }
882
883 int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
884 struct btrfs_ioctl_vol_args args = {};
885 _cleanup_free_ char *p = NULL, *loop = NULL, *backing = NULL;
886 _cleanup_close_ int loop_fd = -1, backing_fd = -1;
887 struct stat st;
888 dev_t dev = 0;
889 int r;
890
891 /* btrfs cannot handle file systems < 16M, hence use this as minimum */
892 if (new_size < 16*1024*1024)
893 new_size = 16*1024*1024;
894
895 r = btrfs_get_block_device_fd(fd, &dev);
896 if (r < 0)
897 return r;
898 if (r == 0)
899 return -ENODEV;
900
901 if (asprintf(&p, "/sys/dev/block/%u:%u/loop/backing_file", major(dev), minor(dev)) < 0)
902 return -ENOMEM;
903 r = read_one_line_file(p, &backing);
904 if (r == -ENOENT)
905 return -ENODEV;
906 if (r < 0)
907 return r;
908 if (isempty(backing) || !path_is_absolute(backing))
909 return -ENODEV;
910
911 backing_fd = open(backing, O_RDWR|O_CLOEXEC|O_NOCTTY);
912 if (backing_fd < 0)
913 return -errno;
914
915 if (fstat(backing_fd, &st) < 0)
916 return -errno;
917 if (!S_ISREG(st.st_mode))
918 return -ENODEV;
919
920 if (new_size == (uint64_t) st.st_size)
921 return 0;
922
923 if (grow_only && new_size < (uint64_t) st.st_size)
924 return -EINVAL;
925
926 if (asprintf(&loop, "/dev/block/%u:%u", major(dev), minor(dev)) < 0)
927 return -ENOMEM;
928 loop_fd = open(loop, O_RDWR|O_CLOEXEC|O_NOCTTY);
929 if (loop_fd < 0)
930 return -errno;
931
932 if (snprintf(args.name, sizeof(args.name), "%" PRIu64, new_size) >= (int) sizeof(args.name))
933 return -EINVAL;
934
935 if (new_size < (uint64_t) st.st_size) {
936 /* Decrease size: first decrease btrfs size, then shorten loopback */
937 if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
938 return -errno;
939 }
940
941 if (ftruncate(backing_fd, new_size) < 0)
942 return -errno;
943
944 if (ioctl(loop_fd, LOOP_SET_CAPACITY, 0) < 0)
945 return -errno;
946
947 if (new_size > (uint64_t) st.st_size) {
948 /* Increase size: first enlarge loopback, then increase btrfs size */
949 if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
950 return -errno;
951 }
952
953 /* Make sure the free disk space is correctly updated for both file systems */
954 (void) fsync(fd);
955 (void) fsync(backing_fd);
956
957 return 1;
958 }
959
960 int btrfs_resize_loopback(const char *p, uint64_t new_size, bool grow_only) {
961 _cleanup_close_ int fd = -1;
962
963 fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
964 if (fd < 0)
965 return -errno;
966
967 return btrfs_resize_loopback_fd(fd, new_size, grow_only);
968 }
969
970 int btrfs_qgroupid_make(uint64_t level, uint64_t id, uint64_t *ret) {
971 assert(ret);
972
973 if (level >= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT)))
974 return -EINVAL;
975
976 if (id >= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT))
977 return -EINVAL;
978
979 *ret = (level << BTRFS_QGROUP_LEVEL_SHIFT) | id;
980 return 0;
981 }
982
983 int btrfs_qgroupid_split(uint64_t qgroupid, uint64_t *level, uint64_t *id) {
984 assert(level || id);
985
986 if (level)
987 *level = qgroupid >> BTRFS_QGROUP_LEVEL_SHIFT;
988
989 if (id)
990 *id = qgroupid & ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT) - 1);
991
992 return 0;
993 }
994
995 static int qgroup_create_or_destroy(int fd, bool b, uint64_t qgroupid) {
996
997 struct btrfs_ioctl_qgroup_create_args args = {
998 .create = b,
999 .qgroupid = qgroupid,
1000 };
1001 unsigned c;
1002 int r;
1003
1004 r = btrfs_is_filesystem(fd);
1005 if (r < 0)
1006 return r;
1007 if (r == 0)
1008 return -ENOTTY;
1009
1010 for (c = 0;; c++) {
1011 if (ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args) < 0) {
1012
1013 /* If quota is not enabled, we get EINVAL. Turn this into a recognizable error */
1014 if (errno == EINVAL)
1015 return -ENOPROTOOPT;
1016
1017 if (errno == EBUSY && c < 10) {
1018 (void) btrfs_quota_scan_wait(fd);
1019 continue;
1020 }
1021
1022 return -errno;
1023 }
1024
1025 break;
1026 }
1027
1028 return 0;
1029 }
1030
1031 int btrfs_qgroup_create(int fd, uint64_t qgroupid) {
1032 return qgroup_create_or_destroy(fd, true, qgroupid);
1033 }
1034
1035 int btrfs_qgroup_destroy(int fd, uint64_t qgroupid) {
1036 return qgroup_create_or_destroy(fd, false, qgroupid);
1037 }
1038
1039 int btrfs_qgroup_destroy_recursive(int fd, uint64_t qgroupid) {
1040 _cleanup_free_ uint64_t *qgroups = NULL;
1041 uint64_t subvol_id;
1042 int i, n, r;
1043
1044 /* Destroys the specified qgroup, but unassigns it from all
1045 * its parents first. Also, it recursively destroys all
1046 * qgroups it is assgined to that have the same id part of the
1047 * qgroupid as the specified group. */
1048
1049 r = btrfs_qgroupid_split(qgroupid, NULL, &subvol_id);
1050 if (r < 0)
1051 return r;
1052
1053 n = btrfs_qgroup_find_parents(fd, qgroupid, &qgroups);
1054 if (n < 0)
1055 return n;
1056
1057 for (i = 0; i < n; i++) {
1058 uint64_t id;
1059
1060 r = btrfs_qgroupid_split(qgroups[i], NULL, &id);
1061 if (r < 0)
1062 return r;
1063
1064 r = btrfs_qgroup_unassign(fd, qgroupid, qgroups[i]);
1065 if (r < 0)
1066 return r;
1067
1068 if (id != subvol_id)
1069 continue;
1070
1071 /* The parent qgroupid shares the same id part with
1072 * us? If so, destroy it too. */
1073
1074 (void) btrfs_qgroup_destroy_recursive(fd, qgroups[i]);
1075 }
1076
1077 return btrfs_qgroup_destroy(fd, qgroupid);
1078 }
1079
1080 int btrfs_quota_scan_start(int fd) {
1081 struct btrfs_ioctl_quota_rescan_args args = {};
1082
1083 assert(fd >= 0);
1084
1085 if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN, &args) < 0)
1086 return -errno;
1087
1088 return 0;
1089 }
1090
1091 int btrfs_quota_scan_wait(int fd) {
1092 assert(fd >= 0);
1093
1094 if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_WAIT) < 0)
1095 return -errno;
1096
1097 return 0;
1098 }
1099
1100 int btrfs_quota_scan_ongoing(int fd) {
1101 struct btrfs_ioctl_quota_rescan_args args = {};
1102
1103 assert(fd >= 0);
1104
1105 if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_STATUS, &args) < 0)
1106 return -errno;
1107
1108 return !!args.flags;
1109 }
1110
1111 static int qgroup_assign_or_unassign(int fd, bool b, uint64_t child, uint64_t parent) {
1112 struct btrfs_ioctl_qgroup_assign_args args = {
1113 .assign = b,
1114 .src = child,
1115 .dst = parent,
1116 };
1117 unsigned c;
1118 int r;
1119
1120 r = btrfs_is_filesystem(fd);
1121 if (r < 0)
1122 return r;
1123 if (r == 0)
1124 return -ENOTTY;
1125
1126 for (c = 0;; c++) {
1127 r = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args);
1128 if (r < 0) {
1129 if (errno == EBUSY && c < 10) {
1130 (void) btrfs_quota_scan_wait(fd);
1131 continue;
1132 }
1133
1134 return -errno;
1135 }
1136
1137 if (r == 0)
1138 return 0;
1139
1140 /* If the return value is > 0, we need to request a rescan */
1141
1142 (void) btrfs_quota_scan_start(fd);
1143 return 1;
1144 }
1145 }
1146
1147 int btrfs_qgroup_assign(int fd, uint64_t child, uint64_t parent) {
1148 return qgroup_assign_or_unassign(fd, true, child, parent);
1149 }
1150
1151 int btrfs_qgroup_unassign(int fd, uint64_t child, uint64_t parent) {
1152 return qgroup_assign_or_unassign(fd, false, child, parent);
1153 }
1154
1155 static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol_id, BtrfsRemoveFlags flags) {
1156 struct btrfs_ioctl_search_args args = {
1157 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
1158
1159 .key.min_objectid = BTRFS_FIRST_FREE_OBJECTID,
1160 .key.max_objectid = BTRFS_LAST_FREE_OBJECTID,
1161
1162 .key.min_type = BTRFS_ROOT_BACKREF_KEY,
1163 .key.max_type = BTRFS_ROOT_BACKREF_KEY,
1164
1165 .key.min_transid = 0,
1166 .key.max_transid = (uint64_t) -1,
1167 };
1168
1169 struct btrfs_ioctl_vol_args vol_args = {};
1170 _cleanup_close_ int subvol_fd = -1;
1171 struct stat st;
1172 bool made_writable = false;
1173 int r;
1174
1175 assert(fd >= 0);
1176 assert(subvolume);
1177
1178 if (fstat(fd, &st) < 0)
1179 return -errno;
1180
1181 if (!S_ISDIR(st.st_mode))
1182 return -EINVAL;
1183
1184 subvol_fd = openat(fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1185 if (subvol_fd < 0)
1186 return -errno;
1187
1188 if (subvol_id == 0) {
1189 r = btrfs_subvol_get_id_fd(subvol_fd, &subvol_id);
1190 if (r < 0)
1191 return r;
1192 }
1193
1194 /* First, try to remove the subvolume. If it happens to be
1195 * already empty, this will just work. */
1196 strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
1197 if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) >= 0) {
1198 (void) btrfs_qgroup_destroy_recursive(fd, subvol_id); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1199 return 0;
1200 }
1201 if (!(flags & BTRFS_REMOVE_RECURSIVE) || errno != ENOTEMPTY)
1202 return -errno;
1203
1204 /* OK, the subvolume is not empty, let's look for child
1205 * subvolumes, and remove them, first */
1206
1207 args.key.min_offset = args.key.max_offset = subvol_id;
1208
1209 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
1210 const struct btrfs_ioctl_search_header *sh;
1211 unsigned i;
1212
1213 args.key.nr_items = 256;
1214 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
1215 return -errno;
1216
1217 if (args.key.nr_items <= 0)
1218 break;
1219
1220 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
1221 _cleanup_free_ char *p = NULL;
1222 const struct btrfs_root_ref *ref;
1223 struct btrfs_ioctl_ino_lookup_args ino_args;
1224
1225 btrfs_ioctl_search_args_set(&args, sh);
1226
1227 if (sh->type != BTRFS_ROOT_BACKREF_KEY)
1228 continue;
1229 if (sh->offset != subvol_id)
1230 continue;
1231
1232 ref = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
1233
1234 p = strndup((char*) ref + sizeof(struct btrfs_root_ref), le64toh(ref->name_len));
1235 if (!p)
1236 return -ENOMEM;
1237
1238 zero(ino_args);
1239 ino_args.treeid = subvol_id;
1240 ino_args.objectid = htole64(ref->dirid);
1241
1242 if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args) < 0)
1243 return -errno;
1244
1245 if (!made_writable) {
1246 r = btrfs_subvol_set_read_only_fd(subvol_fd, false);
1247 if (r < 0)
1248 return r;
1249
1250 made_writable = true;
1251 }
1252
1253 if (isempty(ino_args.name))
1254 /* Subvolume is in the top-level
1255 * directory of the subvolume. */
1256 r = subvol_remove_children(subvol_fd, p, sh->objectid, flags);
1257 else {
1258 _cleanup_close_ int child_fd = -1;
1259
1260 /* Subvolume is somewhere further down,
1261 * hence we need to open the
1262 * containing directory first */
1263
1264 child_fd = openat(subvol_fd, ino_args.name, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1265 if (child_fd < 0)
1266 return -errno;
1267
1268 r = subvol_remove_children(child_fd, p, sh->objectid, flags);
1269 }
1270 if (r < 0)
1271 return r;
1272 }
1273
1274 /* Increase search key by one, to read the next item, if we can. */
1275 if (!btrfs_ioctl_search_args_inc(&args))
1276 break;
1277 }
1278
1279 /* OK, the child subvolumes should all be gone now, let's try
1280 * again to remove the subvolume */
1281 if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) < 0)
1282 return -errno;
1283
1284 (void) btrfs_qgroup_destroy_recursive(fd, subvol_id);
1285 return 0;
1286 }
1287
1288 int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags) {
1289 _cleanup_close_ int fd = -1;
1290 const char *subvolume;
1291 int r;
1292
1293 assert(path);
1294
1295 r = extract_subvolume_name(path, &subvolume);
1296 if (r < 0)
1297 return r;
1298
1299 fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1300 if (fd < 0)
1301 return fd;
1302
1303 return subvol_remove_children(fd, subvolume, 0, flags);
1304 }
1305
1306 int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags) {
1307 return subvol_remove_children(fd, subvolume, 0, flags);
1308 }
1309
1310 int btrfs_qgroup_copy_limits(int fd, uint64_t old_qgroupid, uint64_t new_qgroupid) {
1311
1312 struct btrfs_ioctl_search_args args = {
1313 /* Tree of quota items */
1314 .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
1315
1316 /* The object ID is always 0 */
1317 .key.min_objectid = 0,
1318 .key.max_objectid = 0,
1319
1320 /* Look precisely for the quota items */
1321 .key.min_type = BTRFS_QGROUP_LIMIT_KEY,
1322 .key.max_type = BTRFS_QGROUP_LIMIT_KEY,
1323
1324 /* For our qgroup */
1325 .key.min_offset = old_qgroupid,
1326 .key.max_offset = old_qgroupid,
1327
1328 /* No restrictions on the other components */
1329 .key.min_transid = 0,
1330 .key.max_transid = (uint64_t) -1,
1331 };
1332
1333 int r;
1334
1335 r = btrfs_is_filesystem(fd);
1336 if (r < 0)
1337 return r;
1338 if (!r)
1339 return -ENOTTY;
1340
1341 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
1342 const struct btrfs_ioctl_search_header *sh;
1343 unsigned i;
1344
1345 args.key.nr_items = 256;
1346 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) {
1347 if (errno == ENOENT) /* quota tree missing: quota is not enabled, hence nothing to copy */
1348 break;
1349
1350 return -errno;
1351 }
1352
1353 if (args.key.nr_items <= 0)
1354 break;
1355
1356 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
1357 const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
1358 struct btrfs_ioctl_qgroup_limit_args qargs;
1359 unsigned c;
1360
1361 /* Make sure we start the next search at least from this entry */
1362 btrfs_ioctl_search_args_set(&args, sh);
1363
1364 if (sh->objectid != 0)
1365 continue;
1366 if (sh->type != BTRFS_QGROUP_LIMIT_KEY)
1367 continue;
1368 if (sh->offset != old_qgroupid)
1369 continue;
1370
1371 /* We found the entry, now copy things over. */
1372
1373 qargs = (struct btrfs_ioctl_qgroup_limit_args) {
1374 .qgroupid = new_qgroupid,
1375
1376 .lim.max_rfer = le64toh(qli->max_rfer),
1377 .lim.max_excl = le64toh(qli->max_excl),
1378 .lim.rsv_rfer = le64toh(qli->rsv_rfer),
1379 .lim.rsv_excl = le64toh(qli->rsv_excl),
1380
1381 .lim.flags = le64toh(qli->flags) & (BTRFS_QGROUP_LIMIT_MAX_RFER|
1382 BTRFS_QGROUP_LIMIT_MAX_EXCL|
1383 BTRFS_QGROUP_LIMIT_RSV_RFER|
1384 BTRFS_QGROUP_LIMIT_RSV_EXCL),
1385 };
1386
1387 for (c = 0;; c++) {
1388 if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &qargs) < 0) {
1389 if (errno == EBUSY && c < 10) {
1390 (void) btrfs_quota_scan_wait(fd);
1391 continue;
1392 }
1393 return -errno;
1394 }
1395
1396 break;
1397 }
1398
1399 return 1;
1400 }
1401
1402 /* Increase search key by one, to read the next item, if we can. */
1403 if (!btrfs_ioctl_search_args_inc(&args))
1404 break;
1405 }
1406
1407 return 0;
1408 }
1409
1410 static int copy_quota_hierarchy(int fd, uint64_t old_subvol_id, uint64_t new_subvol_id) {
1411 _cleanup_free_ uint64_t *old_qgroups = NULL, *old_parent_qgroups = NULL;
1412 bool copy_from_parent = false, insert_intermediary_qgroup = false;
1413 int n_old_qgroups, n_old_parent_qgroups, r, i;
1414 uint64_t old_parent_id;
1415
1416 assert(fd >= 0);
1417
1418 /* Copies a reduced form of quota information from the old to
1419 * the new subvolume. */
1420
1421 n_old_qgroups = btrfs_qgroup_find_parents(fd, old_subvol_id, &old_qgroups);
1422 if (n_old_qgroups <= 0) /* Nothing to copy */
1423 return n_old_qgroups;
1424
1425 r = btrfs_subvol_get_parent(fd, old_subvol_id, &old_parent_id);
1426 if (r == -ENXIO)
1427 /* We have no parent, hence nothing to copy. */
1428 n_old_parent_qgroups = 0;
1429 else if (r < 0)
1430 return r;
1431 else {
1432 n_old_parent_qgroups = btrfs_qgroup_find_parents(fd, old_parent_id, &old_parent_qgroups);
1433 if (n_old_parent_qgroups < 0)
1434 return n_old_parent_qgroups;
1435 }
1436
1437 for (i = 0; i < n_old_qgroups; i++) {
1438 uint64_t id;
1439 int j;
1440
1441 r = btrfs_qgroupid_split(old_qgroups[i], NULL, &id);
1442 if (r < 0)
1443 return r;
1444
1445 if (id == old_subvol_id) {
1446 /* The old subvolume was member of a qgroup
1447 * that had the same id, but a different level
1448 * as it self. Let's set up something similar
1449 * in the destination. */
1450 insert_intermediary_qgroup = true;
1451 break;
1452 }
1453
1454 for (j = 0; j < n_old_parent_qgroups; j++)
1455 if (old_parent_qgroups[j] == old_qgroups[i]) {
1456 /* The old subvolume shared a common
1457 * parent qgroup with its parent
1458 * subvolume. Let's set up something
1459 * similar in the destination. */
1460 copy_from_parent = true;
1461 }
1462 }
1463
1464 if (!insert_intermediary_qgroup && !copy_from_parent)
1465 return 0;
1466
1467 return btrfs_subvol_auto_qgroup_fd(fd, new_subvol_id, insert_intermediary_qgroup);
1468 }
1469
1470 static int copy_subtree_quota_limits(int fd, uint64_t old_subvol, uint64_t new_subvol) {
1471 uint64_t old_subtree_qgroup, new_subtree_qgroup;
1472 bool changed;
1473 int r;
1474
1475 /* First copy the leaf limits */
1476 r = btrfs_qgroup_copy_limits(fd, old_subvol, new_subvol);
1477 if (r < 0)
1478 return r;
1479 changed = r > 0;
1480
1481 /* Then, try to copy the subtree limits, if there are any. */
1482 r = btrfs_subvol_find_subtree_qgroup(fd, old_subvol, &old_subtree_qgroup);
1483 if (r < 0)
1484 return r;
1485 if (r == 0)
1486 return changed;
1487
1488 r = btrfs_subvol_find_subtree_qgroup(fd, new_subvol, &new_subtree_qgroup);
1489 if (r < 0)
1490 return r;
1491 if (r == 0)
1492 return changed;
1493
1494 r = btrfs_qgroup_copy_limits(fd, old_subtree_qgroup, new_subtree_qgroup);
1495 if (r != 0)
1496 return r;
1497
1498 return changed;
1499 }
1500
1501 static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolume, uint64_t old_subvol_id, BtrfsSnapshotFlags flags) {
1502
1503 struct btrfs_ioctl_search_args args = {
1504 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
1505
1506 .key.min_objectid = BTRFS_FIRST_FREE_OBJECTID,
1507 .key.max_objectid = BTRFS_LAST_FREE_OBJECTID,
1508
1509 .key.min_type = BTRFS_ROOT_BACKREF_KEY,
1510 .key.max_type = BTRFS_ROOT_BACKREF_KEY,
1511
1512 .key.min_transid = 0,
1513 .key.max_transid = (uint64_t) -1,
1514 };
1515
1516 struct btrfs_ioctl_vol_args_v2 vol_args = {
1517 .flags = flags & BTRFS_SNAPSHOT_READ_ONLY ? BTRFS_SUBVOL_RDONLY : 0,
1518 .fd = old_fd,
1519 };
1520 _cleanup_close_ int subvolume_fd = -1;
1521 uint64_t new_subvol_id;
1522 int r;
1523
1524 assert(old_fd >= 0);
1525 assert(new_fd >= 0);
1526 assert(subvolume);
1527
1528 strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
1529
1530 if (ioctl(new_fd, BTRFS_IOC_SNAP_CREATE_V2, &vol_args) < 0)
1531 return -errno;
1532
1533 if (!(flags & BTRFS_SNAPSHOT_RECURSIVE) &&
1534 !(flags & BTRFS_SNAPSHOT_QUOTA))
1535 return 0;
1536
1537 if (old_subvol_id == 0) {
1538 r = btrfs_subvol_get_id_fd(old_fd, &old_subvol_id);
1539 if (r < 0)
1540 return r;
1541 }
1542
1543 r = btrfs_subvol_get_id(new_fd, vol_args.name, &new_subvol_id);
1544 if (r < 0)
1545 return r;
1546
1547 if (flags & BTRFS_SNAPSHOT_QUOTA)
1548 (void) copy_quota_hierarchy(new_fd, old_subvol_id, new_subvol_id);
1549
1550 if (!(flags & BTRFS_SNAPSHOT_RECURSIVE)) {
1551
1552 if (flags & BTRFS_SNAPSHOT_QUOTA)
1553 (void) copy_subtree_quota_limits(new_fd, old_subvol_id, new_subvol_id);
1554
1555 return 0;
1556 }
1557
1558 args.key.min_offset = args.key.max_offset = old_subvol_id;
1559
1560 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
1561 const struct btrfs_ioctl_search_header *sh;
1562 unsigned i;
1563
1564 args.key.nr_items = 256;
1565 if (ioctl(old_fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
1566 return -errno;
1567
1568 if (args.key.nr_items <= 0)
1569 break;
1570
1571 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
1572 _cleanup_free_ char *p = NULL, *c = NULL, *np = NULL;
1573 struct btrfs_ioctl_ino_lookup_args ino_args;
1574 const struct btrfs_root_ref *ref;
1575 _cleanup_close_ int old_child_fd = -1, new_child_fd = -1;
1576
1577 btrfs_ioctl_search_args_set(&args, sh);
1578
1579 if (sh->type != BTRFS_ROOT_BACKREF_KEY)
1580 continue;
1581
1582 /* Avoid finding the source subvolume a second
1583 * time */
1584 if (sh->offset != old_subvol_id)
1585 continue;
1586
1587 /* Avoid running into loops if the new
1588 * subvolume is below the old one. */
1589 if (sh->objectid == new_subvol_id)
1590 continue;
1591
1592 ref = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
1593 p = strndup((char*) ref + sizeof(struct btrfs_root_ref), le64toh(ref->name_len));
1594 if (!p)
1595 return -ENOMEM;
1596
1597 zero(ino_args);
1598 ino_args.treeid = old_subvol_id;
1599 ino_args.objectid = htole64(ref->dirid);
1600
1601 if (ioctl(old_fd, BTRFS_IOC_INO_LOOKUP, &ino_args) < 0)
1602 return -errno;
1603
1604 /* The kernel returns an empty name if the
1605 * subvolume is in the top-level directory,
1606 * and otherwise appends a slash, so that we
1607 * can just concatenate easily here, without
1608 * adding a slash. */
1609 c = strappend(ino_args.name, p);
1610 if (!c)
1611 return -ENOMEM;
1612
1613 old_child_fd = openat(old_fd, c, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1614 if (old_child_fd < 0)
1615 return -errno;
1616
1617 np = strjoin(subvolume, "/", ino_args.name, NULL);
1618 if (!np)
1619 return -ENOMEM;
1620
1621 new_child_fd = openat(new_fd, np, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1622 if (new_child_fd < 0)
1623 return -errno;
1624
1625 if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
1626 /* If the snapshot is read-only we
1627 * need to mark it writable
1628 * temporarily, to put the subsnapshot
1629 * into place. */
1630
1631 if (subvolume_fd < 0) {
1632 subvolume_fd = openat(new_fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1633 if (subvolume_fd < 0)
1634 return -errno;
1635 }
1636
1637 r = btrfs_subvol_set_read_only_fd(subvolume_fd, false);
1638 if (r < 0)
1639 return r;
1640 }
1641
1642 /* When btrfs clones the subvolumes, child
1643 * subvolumes appear as empty directories. Remove
1644 * them, so that we can create a new snapshot
1645 * in their place */
1646 if (unlinkat(new_child_fd, p, AT_REMOVEDIR) < 0) {
1647 int k = -errno;
1648
1649 if (flags & BTRFS_SNAPSHOT_READ_ONLY)
1650 (void) btrfs_subvol_set_read_only_fd(subvolume_fd, true);
1651
1652 return k;
1653 }
1654
1655 r = subvol_snapshot_children(old_child_fd, new_child_fd, p, sh->objectid, flags & ~BTRFS_SNAPSHOT_FALLBACK_COPY);
1656
1657 /* Restore the readonly flag */
1658 if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
1659 int k;
1660
1661 k = btrfs_subvol_set_read_only_fd(subvolume_fd, true);
1662 if (r >= 0 && k < 0)
1663 return k;
1664 }
1665
1666 if (r < 0)
1667 return r;
1668 }
1669
1670 /* Increase search key by one, to read the next item, if we can. */
1671 if (!btrfs_ioctl_search_args_inc(&args))
1672 break;
1673 }
1674
1675 if (flags & BTRFS_SNAPSHOT_QUOTA)
1676 (void) copy_subtree_quota_limits(new_fd, old_subvol_id, new_subvol_id);
1677
1678 return 0;
1679 }
1680
1681 int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags) {
1682 _cleanup_close_ int new_fd = -1;
1683 const char *subvolume;
1684 int r;
1685
1686 assert(old_fd >= 0);
1687 assert(new_path);
1688
1689 r = btrfs_is_subvol(old_fd);
1690 if (r < 0)
1691 return r;
1692 if (r == 0) {
1693 if (!(flags & BTRFS_SNAPSHOT_FALLBACK_COPY))
1694 return -EISDIR;
1695
1696 r = btrfs_subvol_make(new_path);
1697 if (r < 0)
1698 return r;
1699
1700 r = copy_directory_fd(old_fd, new_path, true);
1701 if (r < 0) {
1702 (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA);
1703 return r;
1704 }
1705
1706 if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
1707 r = btrfs_subvol_set_read_only(new_path, true);
1708 if (r < 0) {
1709 (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA);
1710 return r;
1711 }
1712 }
1713
1714 return 0;
1715 }
1716
1717 r = extract_subvolume_name(new_path, &subvolume);
1718 if (r < 0)
1719 return r;
1720
1721 new_fd = open_parent(new_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1722 if (new_fd < 0)
1723 return new_fd;
1724
1725 return subvol_snapshot_children(old_fd, new_fd, subvolume, 0, flags);
1726 }
1727
1728 int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags) {
1729 _cleanup_close_ int old_fd = -1;
1730
1731 assert(old_path);
1732 assert(new_path);
1733
1734 old_fd = open(old_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1735 if (old_fd < 0)
1736 return -errno;
1737
1738 return btrfs_subvol_snapshot_fd(old_fd, new_path, flags);
1739 }
1740
1741 int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) {
1742
1743 struct btrfs_ioctl_search_args args = {
1744 /* Tree of quota items */
1745 .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
1746
1747 /* Look precisely for the quota relation items */
1748 .key.min_type = BTRFS_QGROUP_RELATION_KEY,
1749 .key.max_type = BTRFS_QGROUP_RELATION_KEY,
1750
1751 /* No restrictions on the other components */
1752 .key.min_offset = 0,
1753 .key.max_offset = (uint64_t) -1,
1754
1755 .key.min_transid = 0,
1756 .key.max_transid = (uint64_t) -1,
1757 };
1758
1759 _cleanup_free_ uint64_t *items = NULL;
1760 size_t n_items = 0, n_allocated = 0;
1761 int r;
1762
1763 assert(fd >= 0);
1764 assert(ret);
1765
1766 if (qgroupid == 0) {
1767 r = btrfs_subvol_get_id_fd(fd, &qgroupid);
1768 if (r < 0)
1769 return r;
1770 } else {
1771 r = btrfs_is_filesystem(fd);
1772 if (r < 0)
1773 return r;
1774 if (!r)
1775 return -ENOTTY;
1776 }
1777
1778 args.key.min_objectid = args.key.max_objectid = qgroupid;
1779
1780 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
1781 const struct btrfs_ioctl_search_header *sh;
1782 unsigned i;
1783
1784 args.key.nr_items = 256;
1785 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) {
1786 if (errno == ENOENT) /* quota tree missing: quota is disabled */
1787 break;
1788
1789 return -errno;
1790 }
1791
1792 if (args.key.nr_items <= 0)
1793 break;
1794
1795 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
1796
1797 /* Make sure we start the next search at least from this entry */
1798 btrfs_ioctl_search_args_set(&args, sh);
1799
1800 if (sh->type != BTRFS_QGROUP_RELATION_KEY)
1801 continue;
1802 if (sh->offset < sh->objectid)
1803 continue;
1804 if (sh->objectid != qgroupid)
1805 continue;
1806
1807 if (!GREEDY_REALLOC(items, n_allocated, n_items+1))
1808 return -ENOMEM;
1809
1810 items[n_items++] = sh->offset;
1811 }
1812
1813 /* Increase search key by one, to read the next item, if we can. */
1814 if (!btrfs_ioctl_search_args_inc(&args))
1815 break;
1816 }
1817
1818 if (n_items <= 0) {
1819 *ret = NULL;
1820 return 0;
1821 }
1822
1823 *ret = items;
1824 items = NULL;
1825
1826 return (int) n_items;
1827 }
1828
1829 int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermediary_qgroup) {
1830 _cleanup_free_ uint64_t *qgroups = NULL;
1831 uint64_t parent_subvol;
1832 bool changed = false;
1833 int n = 0, r;
1834
1835 assert(fd >= 0);
1836
1837 /*
1838 * Sets up the specified subvolume's qgroup automatically in
1839 * one of two ways:
1840 *
1841 * If insert_intermediary_qgroup is false, the subvolume's
1842 * leaf qgroup will be assigned to the same parent qgroups as
1843 * the subvolume's parent subvolume.
1844 *
1845 * If insert_intermediary_qgroup is true a new intermediary
1846 * higher-level qgroup is created, with a higher level number,
1847 * but reusing the id of the subvolume. The level number is
1848 * picked as one smaller than the lowest level qgroup the
1849 * parent subvolume is a member of. If the parent subvolume's
1850 * leaf qgroup is assigned to no higher-level qgroup a new
1851 * qgroup of level 255 is created instead. Either way, the new
1852 * qgroup is then assigned to the parent's higher-level
1853 * qgroup, and the subvolume itself is assigned to it.
1854 *
1855 * If the subvolume is already assigned to a higher level
1856 * qgroup, no operation is executed.
1857 *
1858 * Effectively this means: regardless if
1859 * insert_intermediary_qgroup is true or not, after this
1860 * function is invoked the subvolume will be accounted within
1861 * the same qgroups as the parent. However, if it is true, it
1862 * will also get its own higher-level qgroup, which may in
1863 * turn be used by subvolumes created beneath this subvolume
1864 * later on.
1865 *
1866 * This hence defines a simple default qgroup setup for
1867 * subvolumes, as long as this function is invoked on each
1868 * created subvolume: each subvolume is always accounting
1869 * together with its immediate parents. Optionally, if
1870 * insert_intermediary_qgroup is true, it will also get a
1871 * qgroup that then includes all its own child subvolumes.
1872 */
1873
1874 if (subvol_id == 0) {
1875 r = btrfs_is_subvol(fd);
1876 if (r < 0)
1877 return r;
1878 if (!r)
1879 return -ENOTTY;
1880
1881 r = btrfs_subvol_get_id_fd(fd, &subvol_id);
1882 if (r < 0)
1883 return r;
1884 }
1885
1886 n = btrfs_qgroup_find_parents(fd, subvol_id, &qgroups);
1887 if (n < 0)
1888 return n;
1889 if (n > 0) /* already parent qgroups set up, let's bail */
1890 return 0;
1891
1892 qgroups = mfree(qgroups);
1893
1894 r = btrfs_subvol_get_parent(fd, subvol_id, &parent_subvol);
1895 if (r == -ENXIO)
1896 /* No parent, hence no qgroup memberships */
1897 n = 0;
1898 else if (r < 0)
1899 return r;
1900 else {
1901 n = btrfs_qgroup_find_parents(fd, parent_subvol, &qgroups);
1902 if (n < 0)
1903 return n;
1904 }
1905
1906 if (insert_intermediary_qgroup) {
1907 uint64_t lowest = 256, new_qgroupid;
1908 bool created = false;
1909 int i;
1910
1911 /* Determine the lowest qgroup that the parent
1912 * subvolume is assigned to. */
1913
1914 for (i = 0; i < n; i++) {
1915 uint64_t level;
1916
1917 r = btrfs_qgroupid_split(qgroups[i], &level, NULL);
1918 if (r < 0)
1919 return r;
1920
1921 if (level < lowest)
1922 lowest = level;
1923 }
1924
1925 if (lowest <= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1926 return -EBUSY;
1927
1928 r = btrfs_qgroupid_make(lowest - 1, subvol_id, &new_qgroupid);
1929 if (r < 0)
1930 return r;
1931
1932 /* Create the new intermediary group, unless it already exists */
1933 r = btrfs_qgroup_create(fd, new_qgroupid);
1934 if (r < 0 && r != -EEXIST)
1935 return r;
1936 if (r >= 0)
1937 changed = created = true;
1938
1939 for (i = 0; i < n; i++) {
1940 r = btrfs_qgroup_assign(fd, new_qgroupid, qgroups[i]);
1941 if (r < 0 && r != -EEXIST) {
1942 if (created)
1943 (void) btrfs_qgroup_destroy_recursive(fd, new_qgroupid);
1944
1945 return r;
1946 }
1947 if (r >= 0)
1948 changed = true;
1949 }
1950
1951 r = btrfs_qgroup_assign(fd, subvol_id, new_qgroupid);
1952 if (r < 0 && r != -EEXIST) {
1953 if (created)
1954 (void) btrfs_qgroup_destroy_recursive(fd, new_qgroupid);
1955 return r;
1956 }
1957 if (r >= 0)
1958 changed = true;
1959
1960 } else {
1961 int i;
1962
1963 /* Assign our subvolume to all the same qgroups as the parent */
1964
1965 for (i = 0; i < n; i++) {
1966 r = btrfs_qgroup_assign(fd, subvol_id, qgroups[i]);
1967 if (r < 0 && r != -EEXIST)
1968 return r;
1969 if (r >= 0)
1970 changed = true;
1971 }
1972 }
1973
1974 return changed;
1975 }
1976
1977 int btrfs_subvol_auto_qgroup(const char *path, uint64_t subvol_id, bool create_intermediary_qgroup) {
1978 _cleanup_close_ int fd = -1;
1979
1980 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1981 if (fd < 0)
1982 return -errno;
1983
1984 return btrfs_subvol_auto_qgroup_fd(fd, subvol_id, create_intermediary_qgroup);
1985 }
1986
1987 int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret) {
1988
1989 struct btrfs_ioctl_search_args args = {
1990 /* Tree of tree roots */
1991 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
1992
1993 /* Look precisely for the subvolume items */
1994 .key.min_type = BTRFS_ROOT_BACKREF_KEY,
1995 .key.max_type = BTRFS_ROOT_BACKREF_KEY,
1996
1997 /* No restrictions on the other components */
1998 .key.min_offset = 0,
1999 .key.max_offset = (uint64_t) -1,
2000
2001 .key.min_transid = 0,
2002 .key.max_transid = (uint64_t) -1,
2003 };
2004 int r;
2005
2006 assert(fd >= 0);
2007 assert(ret);
2008
2009 if (subvol_id == 0) {
2010 r = btrfs_subvol_get_id_fd(fd, &subvol_id);
2011 if (r < 0)
2012 return r;
2013 } else {
2014 r = btrfs_is_filesystem(fd);
2015 if (r < 0)
2016 return r;
2017 if (!r)
2018 return -ENOTTY;
2019 }
2020
2021 args.key.min_objectid = args.key.max_objectid = subvol_id;
2022
2023 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
2024 const struct btrfs_ioctl_search_header *sh;
2025 unsigned i;
2026
2027 args.key.nr_items = 256;
2028 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
2029 return -errno;
2030
2031 if (args.key.nr_items <= 0)
2032 break;
2033
2034 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
2035
2036 if (sh->type != BTRFS_ROOT_BACKREF_KEY)
2037 continue;
2038 if (sh->objectid != subvol_id)
2039 continue;
2040
2041 *ret = sh->offset;
2042 return 0;
2043 }
2044 }
2045
2046 return -ENXIO;
2047 }