]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/btrfs-util.c
btrfs: when querying quota, make sure we don't choke if quota is disabled
[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 (errno == EBUSY && c < 10) {
1014 (void) btrfs_quota_scan_wait(fd);
1015 continue;
1016 }
1017
1018 return -errno;
1019 }
1020
1021 break;
1022 }
1023
1024 return 0;
1025 }
1026
1027 int btrfs_qgroup_create(int fd, uint64_t qgroupid) {
1028 return qgroup_create_or_destroy(fd, true, qgroupid);
1029 }
1030
1031 int btrfs_qgroup_destroy(int fd, uint64_t qgroupid) {
1032 return qgroup_create_or_destroy(fd, false, qgroupid);
1033 }
1034
1035 int btrfs_qgroup_destroy_recursive(int fd, uint64_t qgroupid) {
1036 _cleanup_free_ uint64_t *qgroups = NULL;
1037 uint64_t subvol_id;
1038 int i, n, r;
1039
1040 /* Destroys the specified qgroup, but unassigns it from all
1041 * its parents first. Also, it recursively destroys all
1042 * qgroups it is assgined to that have the same id part of the
1043 * qgroupid as the specified group. */
1044
1045 r = btrfs_qgroupid_split(qgroupid, NULL, &subvol_id);
1046 if (r < 0)
1047 return r;
1048
1049 n = btrfs_qgroup_find_parents(fd, qgroupid, &qgroups);
1050 if (n < 0)
1051 return n;
1052
1053 for (i = 0; i < n; i++) {
1054 uint64_t id;
1055
1056 r = btrfs_qgroupid_split(qgroups[i], NULL, &id);
1057 if (r < 0)
1058 return r;
1059
1060 r = btrfs_qgroup_unassign(fd, qgroupid, qgroups[i]);
1061 if (r < 0)
1062 return r;
1063
1064 if (id != subvol_id)
1065 continue;
1066
1067 /* The parent qgroupid shares the same id part with
1068 * us? If so, destroy it too. */
1069
1070 (void) btrfs_qgroup_destroy_recursive(fd, qgroups[i]);
1071 }
1072
1073 return btrfs_qgroup_destroy(fd, qgroupid);
1074 }
1075
1076 int btrfs_quota_scan_start(int fd) {
1077 struct btrfs_ioctl_quota_rescan_args args = {};
1078
1079 assert(fd >= 0);
1080
1081 if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN, &args) < 0)
1082 return -errno;
1083
1084 return 0;
1085 }
1086
1087 int btrfs_quota_scan_wait(int fd) {
1088 assert(fd >= 0);
1089
1090 if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_WAIT) < 0)
1091 return -errno;
1092
1093 return 0;
1094 }
1095
1096 int btrfs_quota_scan_ongoing(int fd) {
1097 struct btrfs_ioctl_quota_rescan_args args = {};
1098
1099 assert(fd >= 0);
1100
1101 if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_STATUS, &args) < 0)
1102 return -errno;
1103
1104 return !!args.flags;
1105 }
1106
1107 static int qgroup_assign_or_unassign(int fd, bool b, uint64_t child, uint64_t parent) {
1108 struct btrfs_ioctl_qgroup_assign_args args = {
1109 .assign = b,
1110 .src = child,
1111 .dst = parent,
1112 };
1113 unsigned c;
1114 int r;
1115
1116 r = btrfs_is_filesystem(fd);
1117 if (r < 0)
1118 return r;
1119 if (r == 0)
1120 return -ENOTTY;
1121
1122 for (c = 0;; c++) {
1123 r = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args);
1124 if (r < 0) {
1125 if (errno == EBUSY && c < 10) {
1126 (void) btrfs_quota_scan_wait(fd);
1127 continue;
1128 }
1129
1130 return -errno;
1131 }
1132
1133 if (r == 0)
1134 return 0;
1135
1136 /* If the return value is > 0, we need to request a rescan */
1137
1138 (void) btrfs_quota_scan_start(fd);
1139 return 1;
1140 }
1141 }
1142
1143 int btrfs_qgroup_assign(int fd, uint64_t child, uint64_t parent) {
1144 return qgroup_assign_or_unassign(fd, true, child, parent);
1145 }
1146
1147 int btrfs_qgroup_unassign(int fd, uint64_t child, uint64_t parent) {
1148 return qgroup_assign_or_unassign(fd, false, child, parent);
1149 }
1150
1151 static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol_id, BtrfsRemoveFlags flags) {
1152 struct btrfs_ioctl_search_args args = {
1153 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
1154
1155 .key.min_objectid = BTRFS_FIRST_FREE_OBJECTID,
1156 .key.max_objectid = BTRFS_LAST_FREE_OBJECTID,
1157
1158 .key.min_type = BTRFS_ROOT_BACKREF_KEY,
1159 .key.max_type = BTRFS_ROOT_BACKREF_KEY,
1160
1161 .key.min_transid = 0,
1162 .key.max_transid = (uint64_t) -1,
1163 };
1164
1165 struct btrfs_ioctl_vol_args vol_args = {};
1166 _cleanup_close_ int subvol_fd = -1;
1167 struct stat st;
1168 bool made_writable = false;
1169 int r;
1170
1171 assert(fd >= 0);
1172 assert(subvolume);
1173
1174 if (fstat(fd, &st) < 0)
1175 return -errno;
1176
1177 if (!S_ISDIR(st.st_mode))
1178 return -EINVAL;
1179
1180 subvol_fd = openat(fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1181 if (subvol_fd < 0)
1182 return -errno;
1183
1184 if (subvol_id == 0) {
1185 r = btrfs_subvol_get_id_fd(subvol_fd, &subvol_id);
1186 if (r < 0)
1187 return r;
1188 }
1189
1190 /* First, try to remove the subvolume. If it happens to be
1191 * already empty, this will just work. */
1192 strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
1193 if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) >= 0) {
1194 (void) btrfs_qgroup_destroy_recursive(fd, subvol_id); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
1195 return 0;
1196 }
1197 if (!(flags & BTRFS_REMOVE_RECURSIVE) || errno != ENOTEMPTY)
1198 return -errno;
1199
1200 /* OK, the subvolume is not empty, let's look for child
1201 * subvolumes, and remove them, first */
1202
1203 args.key.min_offset = args.key.max_offset = subvol_id;
1204
1205 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
1206 const struct btrfs_ioctl_search_header *sh;
1207 unsigned i;
1208
1209 args.key.nr_items = 256;
1210 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
1211 return -errno;
1212
1213 if (args.key.nr_items <= 0)
1214 break;
1215
1216 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
1217 _cleanup_free_ char *p = NULL;
1218 const struct btrfs_root_ref *ref;
1219 struct btrfs_ioctl_ino_lookup_args ino_args;
1220
1221 btrfs_ioctl_search_args_set(&args, sh);
1222
1223 if (sh->type != BTRFS_ROOT_BACKREF_KEY)
1224 continue;
1225 if (sh->offset != subvol_id)
1226 continue;
1227
1228 ref = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
1229
1230 p = strndup((char*) ref + sizeof(struct btrfs_root_ref), le64toh(ref->name_len));
1231 if (!p)
1232 return -ENOMEM;
1233
1234 zero(ino_args);
1235 ino_args.treeid = subvol_id;
1236 ino_args.objectid = htole64(ref->dirid);
1237
1238 if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args) < 0)
1239 return -errno;
1240
1241 if (!made_writable) {
1242 r = btrfs_subvol_set_read_only_fd(subvol_fd, false);
1243 if (r < 0)
1244 return r;
1245
1246 made_writable = true;
1247 }
1248
1249 if (isempty(ino_args.name))
1250 /* Subvolume is in the top-level
1251 * directory of the subvolume. */
1252 r = subvol_remove_children(subvol_fd, p, sh->objectid, flags);
1253 else {
1254 _cleanup_close_ int child_fd = -1;
1255
1256 /* Subvolume is somewhere further down,
1257 * hence we need to open the
1258 * containing directory first */
1259
1260 child_fd = openat(subvol_fd, ino_args.name, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1261 if (child_fd < 0)
1262 return -errno;
1263
1264 r = subvol_remove_children(child_fd, p, sh->objectid, flags);
1265 }
1266 if (r < 0)
1267 return r;
1268 }
1269
1270 /* Increase search key by one, to read the next item, if we can. */
1271 if (!btrfs_ioctl_search_args_inc(&args))
1272 break;
1273 }
1274
1275 /* OK, the child subvolumes should all be gone now, let's try
1276 * again to remove the subvolume */
1277 if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) < 0)
1278 return -errno;
1279
1280 (void) btrfs_qgroup_destroy_recursive(fd, subvol_id);
1281 return 0;
1282 }
1283
1284 int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags) {
1285 _cleanup_close_ int fd = -1;
1286 const char *subvolume;
1287 int r;
1288
1289 assert(path);
1290
1291 r = extract_subvolume_name(path, &subvolume);
1292 if (r < 0)
1293 return r;
1294
1295 fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1296 if (fd < 0)
1297 return fd;
1298
1299 return subvol_remove_children(fd, subvolume, 0, flags);
1300 }
1301
1302 int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags) {
1303 return subvol_remove_children(fd, subvolume, 0, flags);
1304 }
1305
1306 int btrfs_qgroup_copy_limits(int fd, uint64_t old_qgroupid, uint64_t new_qgroupid) {
1307
1308 struct btrfs_ioctl_search_args args = {
1309 /* Tree of quota items */
1310 .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
1311
1312 /* The object ID is always 0 */
1313 .key.min_objectid = 0,
1314 .key.max_objectid = 0,
1315
1316 /* Look precisely for the quota items */
1317 .key.min_type = BTRFS_QGROUP_LIMIT_KEY,
1318 .key.max_type = BTRFS_QGROUP_LIMIT_KEY,
1319
1320 /* For our qgroup */
1321 .key.min_offset = old_qgroupid,
1322 .key.max_offset = old_qgroupid,
1323
1324 /* No restrictions on the other components */
1325 .key.min_transid = 0,
1326 .key.max_transid = (uint64_t) -1,
1327 };
1328
1329 int r;
1330
1331 r = btrfs_is_filesystem(fd);
1332 if (r < 0)
1333 return r;
1334 if (!r)
1335 return -ENOTTY;
1336
1337 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
1338 const struct btrfs_ioctl_search_header *sh;
1339 unsigned i;
1340
1341 args.key.nr_items = 256;
1342 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) {
1343 if (errno == ENOENT) /* quota tree missing: quota is not enabled, hence nothing to copy */
1344 break;
1345
1346 return -errno;
1347 }
1348
1349 if (args.key.nr_items <= 0)
1350 break;
1351
1352 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
1353 const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
1354 struct btrfs_ioctl_qgroup_limit_args qargs;
1355 unsigned c;
1356
1357 /* Make sure we start the next search at least from this entry */
1358 btrfs_ioctl_search_args_set(&args, sh);
1359
1360 if (sh->objectid != 0)
1361 continue;
1362 if (sh->type != BTRFS_QGROUP_LIMIT_KEY)
1363 continue;
1364 if (sh->offset != old_qgroupid)
1365 continue;
1366
1367 /* We found the entry, now copy things over. */
1368
1369 qargs = (struct btrfs_ioctl_qgroup_limit_args) {
1370 .qgroupid = new_qgroupid,
1371
1372 .lim.max_rfer = le64toh(qli->max_rfer),
1373 .lim.max_excl = le64toh(qli->max_excl),
1374 .lim.rsv_rfer = le64toh(qli->rsv_rfer),
1375 .lim.rsv_excl = le64toh(qli->rsv_excl),
1376
1377 .lim.flags = le64toh(qli->flags) & (BTRFS_QGROUP_LIMIT_MAX_RFER|
1378 BTRFS_QGROUP_LIMIT_MAX_EXCL|
1379 BTRFS_QGROUP_LIMIT_RSV_RFER|
1380 BTRFS_QGROUP_LIMIT_RSV_EXCL),
1381 };
1382
1383 for (c = 0;; c++) {
1384 if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &qargs) < 0) {
1385 if (errno == EBUSY && c < 10) {
1386 (void) btrfs_quota_scan_wait(fd);
1387 continue;
1388 }
1389 return -errno;
1390 }
1391
1392 break;
1393 }
1394
1395 return 1;
1396 }
1397
1398 /* Increase search key by one, to read the next item, if we can. */
1399 if (!btrfs_ioctl_search_args_inc(&args))
1400 break;
1401 }
1402
1403 return 0;
1404 }
1405
1406 static int copy_quota_hierarchy(int fd, uint64_t old_subvol_id, uint64_t new_subvol_id) {
1407 _cleanup_free_ uint64_t *old_qgroups = NULL, *old_parent_qgroups = NULL;
1408 bool copy_from_parent = false, insert_intermediary_qgroup = false;
1409 int n_old_qgroups, n_old_parent_qgroups, r, i;
1410 uint64_t old_parent_id;
1411
1412 assert(fd >= 0);
1413
1414 /* Copies a reduced form of quota information from the old to
1415 * the new subvolume. */
1416
1417 n_old_qgroups = btrfs_qgroup_find_parents(fd, old_subvol_id, &old_qgroups);
1418 if (n_old_qgroups <= 0) /* Nothing to copy */
1419 return n_old_qgroups;
1420
1421 r = btrfs_subvol_get_parent(fd, old_subvol_id, &old_parent_id);
1422 if (r < 0)
1423 return r;
1424
1425 n_old_parent_qgroups = btrfs_qgroup_find_parents(fd, old_parent_id, &old_parent_qgroups);
1426 if (n_old_parent_qgroups < 0)
1427 return n_old_parent_qgroups;
1428
1429 for (i = 0; i < n_old_qgroups; i++) {
1430 uint64_t id;
1431 int j;
1432
1433 r = btrfs_qgroupid_split(old_qgroups[i], NULL, &id);
1434 if (r < 0)
1435 return r;
1436
1437 if (id == old_subvol_id) {
1438 /* The old subvolume was member of a qgroup
1439 * that had the same id, but a different level
1440 * as it self. Let's set up something similar
1441 * in the destination. */
1442 insert_intermediary_qgroup = true;
1443 break;
1444 }
1445
1446 for (j = 0; j < n_old_parent_qgroups; j++)
1447 if (old_parent_qgroups[j] == old_qgroups[i]) {
1448 /* The old subvolume shared a common
1449 * parent qgroup with its parent
1450 * subvolume. Let's set up something
1451 * similar in the destination. */
1452 copy_from_parent = true;
1453 }
1454 }
1455
1456 if (!insert_intermediary_qgroup && !copy_from_parent)
1457 return 0;
1458
1459 return btrfs_subvol_auto_qgroup_fd(fd, new_subvol_id, insert_intermediary_qgroup);
1460 }
1461
1462 static int copy_subtree_quota_limits(int fd, uint64_t old_subvol, uint64_t new_subvol) {
1463 uint64_t old_subtree_qgroup, new_subtree_qgroup;
1464 bool changed;
1465 int r;
1466
1467 /* First copy the leaf limits */
1468 r = btrfs_qgroup_copy_limits(fd, old_subvol, new_subvol);
1469 if (r < 0)
1470 return r;
1471 changed = r > 0;
1472
1473 /* Then, try to copy the subtree limits, if there are any. */
1474 r = btrfs_subvol_find_subtree_qgroup(fd, old_subvol, &old_subtree_qgroup);
1475 if (r < 0)
1476 return r;
1477 if (r == 0)
1478 return changed;
1479
1480 r = btrfs_subvol_find_subtree_qgroup(fd, new_subvol, &new_subtree_qgroup);
1481 if (r < 0)
1482 return r;
1483 if (r == 0)
1484 return changed;
1485
1486 r = btrfs_qgroup_copy_limits(fd, old_subtree_qgroup, new_subtree_qgroup);
1487 if (r != 0)
1488 return r;
1489
1490 return changed;
1491 }
1492
1493 static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolume, uint64_t old_subvol_id, BtrfsSnapshotFlags flags) {
1494
1495 struct btrfs_ioctl_search_args args = {
1496 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
1497
1498 .key.min_objectid = BTRFS_FIRST_FREE_OBJECTID,
1499 .key.max_objectid = BTRFS_LAST_FREE_OBJECTID,
1500
1501 .key.min_type = BTRFS_ROOT_BACKREF_KEY,
1502 .key.max_type = BTRFS_ROOT_BACKREF_KEY,
1503
1504 .key.min_transid = 0,
1505 .key.max_transid = (uint64_t) -1,
1506 };
1507
1508 struct btrfs_ioctl_vol_args_v2 vol_args = {
1509 .flags = flags & BTRFS_SNAPSHOT_READ_ONLY ? BTRFS_SUBVOL_RDONLY : 0,
1510 .fd = old_fd,
1511 };
1512 _cleanup_close_ int subvolume_fd = -1;
1513 uint64_t new_subvol_id;
1514 int r;
1515
1516 assert(old_fd >= 0);
1517 assert(new_fd >= 0);
1518 assert(subvolume);
1519
1520 strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
1521
1522 if (ioctl(new_fd, BTRFS_IOC_SNAP_CREATE_V2, &vol_args) < 0)
1523 return -errno;
1524
1525 if (!(flags & BTRFS_SNAPSHOT_RECURSIVE) &&
1526 !(flags & BTRFS_SNAPSHOT_QUOTA))
1527 return 0;
1528
1529 if (old_subvol_id == 0) {
1530 r = btrfs_subvol_get_id_fd(old_fd, &old_subvol_id);
1531 if (r < 0)
1532 return r;
1533 }
1534
1535 r = btrfs_subvol_get_id(new_fd, vol_args.name, &new_subvol_id);
1536 if (r < 0)
1537 return r;
1538
1539 if (flags & BTRFS_SNAPSHOT_QUOTA)
1540 (void) copy_quota_hierarchy(new_fd, old_subvol_id, new_subvol_id);
1541
1542 if (!(flags & BTRFS_SNAPSHOT_RECURSIVE)) {
1543
1544 if (flags & BTRFS_SNAPSHOT_QUOTA)
1545 (void) copy_subtree_quota_limits(new_fd, old_subvol_id, new_subvol_id);
1546
1547 return 0;
1548 }
1549
1550 args.key.min_offset = args.key.max_offset = old_subvol_id;
1551
1552 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
1553 const struct btrfs_ioctl_search_header *sh;
1554 unsigned i;
1555
1556 args.key.nr_items = 256;
1557 if (ioctl(old_fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
1558 return -errno;
1559
1560 if (args.key.nr_items <= 0)
1561 break;
1562
1563 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
1564 _cleanup_free_ char *p = NULL, *c = NULL, *np = NULL;
1565 struct btrfs_ioctl_ino_lookup_args ino_args;
1566 const struct btrfs_root_ref *ref;
1567 _cleanup_close_ int old_child_fd = -1, new_child_fd = -1;
1568
1569 btrfs_ioctl_search_args_set(&args, sh);
1570
1571 if (sh->type != BTRFS_ROOT_BACKREF_KEY)
1572 continue;
1573
1574 /* Avoid finding the source subvolume a second
1575 * time */
1576 if (sh->offset != old_subvol_id)
1577 continue;
1578
1579 /* Avoid running into loops if the new
1580 * subvolume is below the old one. */
1581 if (sh->objectid == new_subvol_id)
1582 continue;
1583
1584 ref = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
1585 p = strndup((char*) ref + sizeof(struct btrfs_root_ref), le64toh(ref->name_len));
1586 if (!p)
1587 return -ENOMEM;
1588
1589 zero(ino_args);
1590 ino_args.treeid = old_subvol_id;
1591 ino_args.objectid = htole64(ref->dirid);
1592
1593 if (ioctl(old_fd, BTRFS_IOC_INO_LOOKUP, &ino_args) < 0)
1594 return -errno;
1595
1596 /* The kernel returns an empty name if the
1597 * subvolume is in the top-level directory,
1598 * and otherwise appends a slash, so that we
1599 * can just concatenate easily here, without
1600 * adding a slash. */
1601 c = strappend(ino_args.name, p);
1602 if (!c)
1603 return -ENOMEM;
1604
1605 old_child_fd = openat(old_fd, c, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1606 if (old_child_fd < 0)
1607 return -errno;
1608
1609 np = strjoin(subvolume, "/", ino_args.name, NULL);
1610 if (!np)
1611 return -ENOMEM;
1612
1613 new_child_fd = openat(new_fd, np, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1614 if (new_child_fd < 0)
1615 return -errno;
1616
1617 if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
1618 /* If the snapshot is read-only we
1619 * need to mark it writable
1620 * temporarily, to put the subsnapshot
1621 * into place. */
1622
1623 if (subvolume_fd < 0) {
1624 subvolume_fd = openat(new_fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1625 if (subvolume_fd < 0)
1626 return -errno;
1627 }
1628
1629 r = btrfs_subvol_set_read_only_fd(subvolume_fd, false);
1630 if (r < 0)
1631 return r;
1632 }
1633
1634 /* When btrfs clones the subvolumes, child
1635 * subvolumes appear as empty directories. Remove
1636 * them, so that we can create a new snapshot
1637 * in their place */
1638 if (unlinkat(new_child_fd, p, AT_REMOVEDIR) < 0) {
1639 int k = -errno;
1640
1641 if (flags & BTRFS_SNAPSHOT_READ_ONLY)
1642 (void) btrfs_subvol_set_read_only_fd(subvolume_fd, true);
1643
1644 return k;
1645 }
1646
1647 r = subvol_snapshot_children(old_child_fd, new_child_fd, p, sh->objectid, flags & ~BTRFS_SNAPSHOT_FALLBACK_COPY);
1648
1649 /* Restore the readonly flag */
1650 if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
1651 int k;
1652
1653 k = btrfs_subvol_set_read_only_fd(subvolume_fd, true);
1654 if (r >= 0 && k < 0)
1655 return k;
1656 }
1657
1658 if (r < 0)
1659 return r;
1660 }
1661
1662 /* Increase search key by one, to read the next item, if we can. */
1663 if (!btrfs_ioctl_search_args_inc(&args))
1664 break;
1665 }
1666
1667 if (flags & BTRFS_SNAPSHOT_QUOTA)
1668 (void) copy_subtree_quota_limits(new_fd, old_subvol_id, new_subvol_id);
1669
1670 return 0;
1671 }
1672
1673 int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags) {
1674 _cleanup_close_ int new_fd = -1;
1675 const char *subvolume;
1676 int r;
1677
1678 assert(old_fd >= 0);
1679 assert(new_path);
1680
1681 r = btrfs_is_subvol(old_fd);
1682 if (r < 0)
1683 return r;
1684 if (r == 0) {
1685 if (!(flags & BTRFS_SNAPSHOT_FALLBACK_COPY))
1686 return -EISDIR;
1687
1688 r = btrfs_subvol_make(new_path);
1689 if (r < 0)
1690 return r;
1691
1692 r = copy_directory_fd(old_fd, new_path, true);
1693 if (r < 0) {
1694 (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA);
1695 return r;
1696 }
1697
1698 if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
1699 r = btrfs_subvol_set_read_only(new_path, true);
1700 if (r < 0) {
1701 (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA);
1702 return r;
1703 }
1704 }
1705
1706 return 0;
1707 }
1708
1709 r = extract_subvolume_name(new_path, &subvolume);
1710 if (r < 0)
1711 return r;
1712
1713 new_fd = open_parent(new_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1714 if (new_fd < 0)
1715 return new_fd;
1716
1717 return subvol_snapshot_children(old_fd, new_fd, subvolume, 0, flags);
1718 }
1719
1720 int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags) {
1721 _cleanup_close_ int old_fd = -1;
1722
1723 assert(old_path);
1724 assert(new_path);
1725
1726 old_fd = open(old_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1727 if (old_fd < 0)
1728 return -errno;
1729
1730 return btrfs_subvol_snapshot_fd(old_fd, new_path, flags);
1731 }
1732
1733 int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) {
1734
1735 struct btrfs_ioctl_search_args args = {
1736 /* Tree of quota items */
1737 .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
1738
1739 /* Look precisely for the quota relation items */
1740 .key.min_type = BTRFS_QGROUP_RELATION_KEY,
1741 .key.max_type = BTRFS_QGROUP_RELATION_KEY,
1742
1743 /* No restrictions on the other components */
1744 .key.min_offset = 0,
1745 .key.max_offset = (uint64_t) -1,
1746
1747 .key.min_transid = 0,
1748 .key.max_transid = (uint64_t) -1,
1749 };
1750
1751 _cleanup_free_ uint64_t *items = NULL;
1752 size_t n_items = 0, n_allocated = 0;
1753 int r;
1754
1755 assert(fd >= 0);
1756 assert(ret);
1757
1758 if (qgroupid == 0) {
1759 r = btrfs_subvol_get_id_fd(fd, &qgroupid);
1760 if (r < 0)
1761 return r;
1762 } else {
1763 r = btrfs_is_filesystem(fd);
1764 if (r < 0)
1765 return r;
1766 if (!r)
1767 return -ENOTTY;
1768 }
1769
1770 args.key.min_objectid = args.key.max_objectid = qgroupid;
1771
1772 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
1773 const struct btrfs_ioctl_search_header *sh;
1774 unsigned i;
1775
1776 args.key.nr_items = 256;
1777 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) {
1778 if (errno == ENOENT) /* quota tree missing: quota is disabled */
1779 break;
1780
1781 return -errno;
1782 }
1783
1784 if (args.key.nr_items <= 0)
1785 break;
1786
1787 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
1788
1789 /* Make sure we start the next search at least from this entry */
1790 btrfs_ioctl_search_args_set(&args, sh);
1791
1792 if (sh->type != BTRFS_QGROUP_RELATION_KEY)
1793 continue;
1794 if (sh->offset < sh->objectid)
1795 continue;
1796 if (sh->objectid != qgroupid)
1797 continue;
1798
1799 if (!GREEDY_REALLOC(items, n_allocated, n_items+1))
1800 return -ENOMEM;
1801
1802 items[n_items++] = sh->offset;
1803 }
1804
1805 /* Increase search key by one, to read the next item, if we can. */
1806 if (!btrfs_ioctl_search_args_inc(&args))
1807 break;
1808 }
1809
1810 if (n_items <= 0) {
1811 *ret = NULL;
1812 return 0;
1813 }
1814
1815 *ret = items;
1816 items = NULL;
1817
1818 return (int) n_items;
1819 }
1820
1821 int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermediary_qgroup) {
1822 _cleanup_free_ uint64_t *qgroups = NULL;
1823 uint64_t parent_subvol;
1824 bool changed = false;
1825 int n = 0, r;
1826
1827 assert(fd >= 0);
1828
1829 /*
1830 * Sets up the specified subvolume's qgroup automatically in
1831 * one of two ways:
1832 *
1833 * If insert_intermediary_qgroup is false, the subvolume's
1834 * leaf qgroup will be assigned to the same parent qgroups as
1835 * the subvolume's parent subvolume.
1836 *
1837 * If insert_intermediary_qgroup is true a new intermediary
1838 * higher-level qgroup is created, with a higher level number,
1839 * but reusing the id of the subvolume. The level number is
1840 * picked as one smaller than the lowest level qgroup the
1841 * parent subvolume is a member of. If the parent subvolume's
1842 * leaf qgroup is assigned to no higher-level qgroup a new
1843 * qgroup of level 255 is created instead. Either way, the new
1844 * qgroup is then assigned to the parent's higher-level
1845 * qgroup, and the subvolume itself is assigned to it.
1846 *
1847 * If the subvolume is already assigned to a higher level
1848 * qgroup, no operation is executed.
1849 *
1850 * Effectively this means: regardless if
1851 * insert_intermediary_qgroup is true or not, after this
1852 * function is invoked the subvolume will be accounted within
1853 * the same qgroups as the parent. However, if it is true, it
1854 * will also get its own higher-level qgroup, which may in
1855 * turn be used by subvolumes created beneath this subvolume
1856 * later on.
1857 *
1858 * This hence defines a simple default qgroup setup for
1859 * subvolumes, as long as this function is invoked on each
1860 * created subvolume: each subvolume is always accounting
1861 * together with its immediate parents. Optionally, if
1862 * insert_intermediary_qgroup is true, it will also get a
1863 * qgroup that then includes all its own child subvolumes.
1864 */
1865
1866 if (subvol_id == 0) {
1867 r = btrfs_is_subvol(fd);
1868 if (r < 0)
1869 return r;
1870 if (!r)
1871 return -ENOTTY;
1872
1873 r = btrfs_subvol_get_id_fd(fd, &subvol_id);
1874 if (r < 0)
1875 return r;
1876 }
1877
1878 n = btrfs_qgroup_find_parents(fd, subvol_id, &qgroups);
1879 if (n < 0)
1880 return n;
1881 if (n > 0) /* already parent qgroups set up, let's bail */
1882 return 0;
1883
1884 r = btrfs_subvol_get_parent(fd, subvol_id, &parent_subvol);
1885 if (r < 0)
1886 return r;
1887
1888 qgroups = mfree(qgroups);
1889 n = btrfs_qgroup_find_parents(fd, parent_subvol, &qgroups);
1890 if (n < 0)
1891 return n;
1892
1893 if (insert_intermediary_qgroup) {
1894 uint64_t lowest = 256, new_qgroupid;
1895 bool created = false;
1896 int i;
1897
1898 /* Determine the lowest qgroup that the parent
1899 * subvolume is assigned to. */
1900
1901 for (i = 0; i < n; i++) {
1902 uint64_t level;
1903
1904 r = btrfs_qgroupid_split(qgroups[i], &level, NULL);
1905 if (r < 0)
1906 return r;
1907
1908 if (level < lowest)
1909 lowest = level;
1910 }
1911
1912 if (lowest <= 1) /* There are no levels left we could use insert an intermediary qgroup at */
1913 return -EBUSY;
1914
1915 r = btrfs_qgroupid_make(lowest - 1, subvol_id, &new_qgroupid);
1916 if (r < 0)
1917 return r;
1918
1919 /* Create the new intermediary group, unless it already exists */
1920 r = btrfs_qgroup_create(fd, new_qgroupid);
1921 if (r < 0 && r != -EEXIST)
1922 return r;
1923 if (r >= 0)
1924 changed = created = true;
1925
1926 for (i = 0; i < n; i++) {
1927 r = btrfs_qgroup_assign(fd, new_qgroupid, qgroups[i]);
1928 if (r < 0 && r != -EEXIST) {
1929 if (created)
1930 (void) btrfs_qgroup_destroy_recursive(fd, new_qgroupid);
1931
1932 return r;
1933 }
1934 if (r >= 0)
1935 changed = true;
1936 }
1937
1938 r = btrfs_qgroup_assign(fd, subvol_id, new_qgroupid);
1939 if (r < 0 && r != -EEXIST) {
1940 if (created)
1941 (void) btrfs_qgroup_destroy_recursive(fd, new_qgroupid);
1942 return r;
1943 }
1944 if (r >= 0)
1945 changed = true;
1946
1947 } else {
1948 int i;
1949
1950 /* Assign our subvolume to all the same qgroups as the parent */
1951
1952 for (i = 0; i < n; i++) {
1953 r = btrfs_qgroup_assign(fd, subvol_id, qgroups[i]);
1954 if (r < 0 && r != -EEXIST)
1955 return r;
1956 if (r >= 0)
1957 changed = true;
1958 }
1959 }
1960
1961 return changed;
1962 }
1963
1964 int btrfs_subvol_auto_qgroup(const char *path, uint64_t subvol_id, bool create_intermediary_qgroup) {
1965 _cleanup_close_ int fd = -1;
1966
1967 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1968 if (fd < 0)
1969 return -errno;
1970
1971 return btrfs_subvol_auto_qgroup_fd(fd, subvol_id, create_intermediary_qgroup);
1972 }
1973
1974 int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret) {
1975
1976 struct btrfs_ioctl_search_args args = {
1977 /* Tree of tree roots */
1978 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
1979
1980 /* Look precisely for the subvolume items */
1981 .key.min_type = BTRFS_ROOT_BACKREF_KEY,
1982 .key.max_type = BTRFS_ROOT_BACKREF_KEY,
1983
1984 /* No restrictions on the other components */
1985 .key.min_offset = 0,
1986 .key.max_offset = (uint64_t) -1,
1987
1988 .key.min_transid = 0,
1989 .key.max_transid = (uint64_t) -1,
1990 };
1991 int r;
1992
1993 assert(fd >= 0);
1994 assert(ret);
1995
1996 if (subvol_id == 0) {
1997 r = btrfs_subvol_get_id_fd(fd, &subvol_id);
1998 if (r < 0)
1999 return r;
2000 } else {
2001 r = btrfs_is_filesystem(fd);
2002 if (r < 0)
2003 return r;
2004 if (!r)
2005 return -ENOTTY;
2006 }
2007
2008 args.key.min_objectid = args.key.max_objectid = subvol_id;
2009
2010 while (btrfs_ioctl_search_args_compare(&args) <= 0) {
2011 const struct btrfs_ioctl_search_header *sh;
2012 unsigned i;
2013
2014 args.key.nr_items = 256;
2015 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
2016 return -errno;
2017
2018 if (args.key.nr_items <= 0)
2019 break;
2020
2021 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
2022
2023 if (sh->type != BTRFS_ROOT_BACKREF_KEY)
2024 continue;
2025 if (sh->objectid != subvol_id)
2026 continue;
2027
2028 *ret = sh->offset;
2029 return 0;
2030 }
2031 }
2032
2033 return -ENXIO;
2034 }