chiark / gitweb /
sd-bus: handle ppid=0 more gracefully (which happens for pid=1)
[elogind.git] / src / shared / 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/vfs.h>
24 #include <sys/stat.h>
25
26 #ifdef HAVE_LINUX_BTRFS_H
27 #include <linux/btrfs.h>
28 #endif
29
30 #include "missing.h"
31 #include "util.h"
32 #include "path-util.h"
33 #include "macro.h"
34 #include "copy.h"
35 #include "selinux-util.h"
36 #include "smack-util.h"
37 #include "fileio.h"
38 #include "btrfs-ctree.h"
39 #include "btrfs-util.h"
40
41 /* WARNING: Be careful with file system ioctls! When we get an fd, we
42  * need to make sure it either refers to only a regular file or
43  * directory, or that it is located on btrfs, before invoking any
44  * btrfs ioctls. The ioctl numbers are reused by some device drivers
45  * (such as DRM), and hence might have bad effects when invoked on
46  * device nodes (that reference drivers) rather than fds to normal
47  * files or directories. */
48
49 static int validate_subvolume_name(const char *name) {
50
51         if (!filename_is_valid(name))
52                 return -EINVAL;
53
54         if (strlen(name) > BTRFS_SUBVOL_NAME_MAX)
55                 return -E2BIG;
56
57         return 0;
58 }
59
60 static int open_parent(const char *path, int flags) {
61         _cleanup_free_ char *parent = NULL;
62         int r, fd;
63
64         assert(path);
65
66         r = path_get_parent(path, &parent);
67         if (r < 0)
68                 return r;
69
70         fd = open(parent, flags);
71         if (fd < 0)
72                 return -errno;
73
74         return fd;
75 }
76
77 static int extract_subvolume_name(const char *path, const char **subvolume) {
78         const char *fn;
79         int r;
80
81         assert(path);
82         assert(subvolume);
83
84         fn = basename(path);
85
86         r = validate_subvolume_name(fn);
87         if (r < 0)
88                 return r;
89
90         *subvolume = fn;
91         return 0;
92 }
93
94 int btrfs_is_filesystem(int fd) {
95         struct statfs sfs;
96
97         assert(fd >= 0);
98
99         if (fstatfs(fd, &sfs) < 0)
100                 return -errno;
101
102         return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
103 }
104
105 int btrfs_is_subvol(int fd) {
106         struct stat st;
107
108         assert(fd >= 0);
109
110         /* On btrfs subvolumes always have the inode 256 */
111
112         if (fstat(fd, &st) < 0)
113                 return -errno;
114
115         if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
116                 return 0;
117
118         return btrfs_is_filesystem(fd);
119 }
120
121 int btrfs_subvol_make(const char *path) {
122         struct btrfs_ioctl_vol_args args = {};
123         _cleanup_close_ int fd = -1;
124         const char *subvolume;
125         int r;
126
127         assert(path);
128
129         r = extract_subvolume_name(path, &subvolume);
130         if (r < 0)
131                 return r;
132
133         fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
134         if (fd < 0)
135                 return fd;
136
137         strncpy(args.name, subvolume, sizeof(args.name)-1);
138
139         if (ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args) < 0)
140                 return -errno;
141
142         return 0;
143 }
144
145 int btrfs_subvol_make_label(const char *path) {
146         int r;
147
148         assert(path);
149
150         r = mac_selinux_create_file_prepare(path, S_IFDIR);
151         if (r < 0)
152                 return r;
153
154         r = btrfs_subvol_make(path);
155         mac_selinux_create_file_clear();
156
157         if (r < 0)
158                 return r;
159
160         return mac_smack_fix(path, false, false);
161 }
162
163 int btrfs_subvol_set_read_only_fd(int fd, bool b) {
164         uint64_t flags, nflags;
165         struct stat st;
166
167         assert(fd >= 0);
168
169         if (fstat(fd, &st) < 0)
170                 return -errno;
171
172         if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
173                 return -EINVAL;
174
175         if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
176                 return -errno;
177
178         if (b)
179                 nflags = flags | BTRFS_SUBVOL_RDONLY;
180         else
181                 nflags = flags & ~BTRFS_SUBVOL_RDONLY;
182
183         if (flags == nflags)
184                 return 0;
185
186         if (ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &nflags) < 0)
187                 return -errno;
188
189         return 0;
190 }
191
192 int btrfs_subvol_set_read_only(const char *path, bool b) {
193         _cleanup_close_ int fd = -1;
194
195         fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
196         if (fd < 0)
197                 return -errno;
198
199         return btrfs_subvol_set_read_only_fd(fd, b);
200 }
201
202 int btrfs_subvol_get_read_only_fd(int fd) {
203         uint64_t flags;
204         struct stat st;
205
206         assert(fd >= 0);
207
208         if (fstat(fd, &st) < 0)
209                 return -errno;
210
211         if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
212                 return -EINVAL;
213
214         if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
215                 return -errno;
216
217         return !!(flags & BTRFS_SUBVOL_RDONLY);
218 }
219
220 int btrfs_reflink(int infd, int outfd) {
221         struct stat st;
222         int r;
223
224         assert(infd >= 0);
225         assert(outfd >= 0);
226
227         /* Make sure we invoke the ioctl on a regular file, so that no
228          * device driver accidentally gets it. */
229
230         if (fstat(outfd, &st) < 0)
231                 return -errno;
232
233         if (!S_ISREG(st.st_mode))
234                 return -EINVAL;
235
236         r = ioctl(outfd, BTRFS_IOC_CLONE, infd);
237         if (r < 0)
238                 return -errno;
239
240         return 0;
241 }
242
243 int btrfs_clone_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, uint64_t sz) {
244         struct btrfs_ioctl_clone_range_args args = {
245                 .src_fd = infd,
246                 .src_offset = in_offset,
247                 .src_length = sz,
248                 .dest_offset = out_offset,
249         };
250         struct stat st;
251         int r;
252
253         assert(infd >= 0);
254         assert(outfd >= 0);
255         assert(sz > 0);
256
257         if (fstat(outfd, &st) < 0)
258                 return -errno;
259
260         if (!S_ISREG(st.st_mode))
261                 return -EINVAL;
262
263         r = ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args);
264         if (r < 0)
265                 return -errno;
266
267         return 0;
268 }
269
270 int btrfs_get_block_device_fd(int fd, dev_t *dev) {
271         struct btrfs_ioctl_fs_info_args fsi = {};
272         uint64_t id;
273         int r;
274
275         assert(fd >= 0);
276         assert(dev);
277
278         r = btrfs_is_filesystem(fd);
279         if (r < 0)
280                 return r;
281         if (!r)
282                 return -ENOTTY;
283
284         if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
285                 return -errno;
286
287         /* We won't do this for btrfs RAID */
288         if (fsi.num_devices != 1)
289                 return 0;
290
291         for (id = 1; id <= fsi.max_id; id++) {
292                 struct btrfs_ioctl_dev_info_args di = {
293                         .devid = id,
294                 };
295                 struct stat st;
296
297                 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
298                         if (errno == ENODEV)
299                                 continue;
300
301                         return -errno;
302                 }
303
304                 if (stat((char*) di.path, &st) < 0)
305                         return -errno;
306
307                 if (!S_ISBLK(st.st_mode))
308                         return -ENODEV;
309
310                 if (major(st.st_rdev) == 0)
311                         return -ENODEV;
312
313                 *dev = st.st_rdev;
314                 return 1;
315         }
316
317         return -ENODEV;
318 }
319
320 int btrfs_get_block_device(const char *path, dev_t *dev) {
321         _cleanup_close_ int fd = -1;
322
323         assert(path);
324         assert(dev);
325
326         fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
327         if (fd < 0)
328                 return -errno;
329
330         return btrfs_get_block_device_fd(fd, dev);
331 }
332
333 int btrfs_subvol_get_id_fd(int fd, uint64_t *ret) {
334         struct btrfs_ioctl_ino_lookup_args args = {
335                 .objectid = BTRFS_FIRST_FREE_OBJECTID
336         };
337         int r;
338
339         assert(fd >= 0);
340         assert(ret);
341
342         r = btrfs_is_filesystem(fd);
343         if (r < 0)
344                 return r;
345         if (!r)
346                 return -ENOTTY;
347
348         if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
349                 return -errno;
350
351         *ret = args.treeid;
352         return 0;
353 }
354
355 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args *args) {
356         assert(args);
357
358         /* the objectid, type, offset together make up the btrfs key,
359          * which is considered a single 136byte integer when
360          * comparing. This call increases the counter by one, dealing
361          * with the overflow between the overflows */
362
363         if (args->key.min_offset < (uint64_t) -1) {
364                 args->key.min_offset++;
365                 return true;
366         }
367
368         if (args->key.min_type < (uint8_t) -1) {
369                 args->key.min_type++;
370                 args->key.min_offset = 0;
371                 return true;
372         }
373
374         if (args->key.min_objectid < (uint64_t) -1) {
375                 args->key.min_objectid++;
376                 args->key.min_offset = 0;
377                 args->key.min_type = 0;
378                 return true;
379         }
380
381         return 0;
382 }
383
384 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args *args, const struct btrfs_ioctl_search_header *h) {
385         assert(args);
386         assert(h);
387
388         args->key.min_objectid = h->objectid;
389         args->key.min_type = h->type;
390         args->key.min_offset = h->offset;
391 }
392
393 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args *args) {
394         assert(args);
395
396         /* Compare min and max */
397
398         if (args->key.min_objectid < args->key.max_objectid)
399                 return -1;
400         if (args->key.min_objectid > args->key.max_objectid)
401                 return 1;
402
403         if (args->key.min_type < args->key.max_type)
404                 return -1;
405         if (args->key.min_type > args->key.max_type)
406                 return 1;
407
408         if (args->key.min_offset < args->key.max_offset)
409                 return -1;
410         if (args->key.min_offset > args->key.max_offset)
411                 return 1;
412
413         return 0;
414 }
415
416 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args)                  \
417         for ((i) = 0,                                                   \
418              (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
419              (i) < (args).key.nr_items;                                 \
420              (i)++,                                                     \
421              (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
422
423 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh)                              \
424         ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
425
426 int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) {
427         struct btrfs_ioctl_search_args args = {
428                 /* Tree of tree roots */
429                 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
430
431                 /* Look precisely for the subvolume items */
432                 .key.min_type = BTRFS_ROOT_ITEM_KEY,
433                 .key.max_type = BTRFS_ROOT_ITEM_KEY,
434
435                 .key.min_offset = 0,
436                 .key.max_offset = (uint64_t) -1,
437
438                 /* No restrictions on the other components */
439                 .key.min_transid = 0,
440                 .key.max_transid = (uint64_t) -1,
441         };
442
443         uint64_t subvol_id;
444         bool found = false;
445         int r;
446
447         assert(fd >= 0);
448         assert(ret);
449
450         r = btrfs_subvol_get_id_fd(fd, &subvol_id);
451         if (r < 0)
452                 return r;
453
454         args.key.min_objectid = args.key.max_objectid = subvol_id;
455
456         while (btrfs_ioctl_search_args_compare(&args) <= 0) {
457                 const struct btrfs_ioctl_search_header *sh;
458                 unsigned i;
459
460                 args.key.nr_items = 256;
461                 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
462                         return -errno;
463
464                 if (args.key.nr_items <= 0)
465                         break;
466
467                 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
468
469                         const struct btrfs_root_item *ri;
470
471                         /* Make sure we start the next search at least from this entry */
472                         btrfs_ioctl_search_args_set(&args, sh);
473
474                         if (sh->objectid != subvol_id)
475                                 continue;
476                         if (sh->type != BTRFS_ROOT_ITEM_KEY)
477                                 continue;
478
479                         /* Older versions of the struct lacked the otime setting */
480                         if (sh->len < offsetof(struct btrfs_root_item, otime) + sizeof(struct btrfs_timespec))
481                                 continue;
482
483                         ri = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
484
485                         ret->otime = (usec_t) le64toh(ri->otime.sec) * USEC_PER_SEC +
486                                 (usec_t) le32toh(ri->otime.nsec) / NSEC_PER_USEC;
487
488                         ret->subvol_id = subvol_id;
489                         ret->read_only = !!(le64toh(ri->flags) & BTRFS_ROOT_SUBVOL_RDONLY);
490
491                         assert_cc(sizeof(ri->uuid) == sizeof(ret->uuid));
492                         memcpy(&ret->uuid, ri->uuid, sizeof(ret->uuid));
493                         memcpy(&ret->parent_uuid, ri->parent_uuid, sizeof(ret->parent_uuid));
494
495                         found = true;
496                         goto finish;
497                 }
498
499                 /* Increase search key by one, to read the next item, if we can. */
500                 if (!btrfs_ioctl_search_args_inc(&args))
501                         break;
502         }
503
504 finish:
505         if (!found)
506                 return -ENODATA;
507
508         return 0;
509 }
510
511 int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) {
512
513         struct btrfs_ioctl_search_args args = {
514                 /* Tree of quota items */
515                 .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
516
517                 /* The object ID is always 0 */
518                 .key.min_objectid = 0,
519                 .key.max_objectid = 0,
520
521                 /* Look precisely for the quota items */
522                 .key.min_type = BTRFS_QGROUP_STATUS_KEY,
523                 .key.max_type = BTRFS_QGROUP_LIMIT_KEY,
524
525                 /* No restrictions on the other components */
526                 .key.min_transid = 0,
527                 .key.max_transid = (uint64_t) -1,
528         };
529
530         uint64_t subvol_id;
531         bool found_info = false, found_limit = false;
532         int r;
533
534         assert(fd >= 0);
535         assert(ret);
536
537         r = btrfs_subvol_get_id_fd(fd, &subvol_id);
538         if (r < 0)
539                 return r;
540
541         args.key.min_offset = args.key.max_offset = subvol_id;
542
543         while (btrfs_ioctl_search_args_compare(&args) <= 0) {
544                 const struct btrfs_ioctl_search_header *sh;
545                 unsigned i;
546
547                 args.key.nr_items = 256;
548                 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
549                         return -errno;
550
551                 if (args.key.nr_items <= 0)
552                         break;
553
554                 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
555
556                         /* Make sure we start the next search at least from this entry */
557                         btrfs_ioctl_search_args_set(&args, sh);
558
559                         if (sh->objectid != 0)
560                                 continue;
561                         if (sh->offset != subvol_id)
562                                 continue;
563
564                         if (sh->type == BTRFS_QGROUP_INFO_KEY) {
565                                 const struct btrfs_qgroup_info_item *qii = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
566
567                                 ret->referenced = le64toh(qii->rfer);
568                                 ret->exclusive = le64toh(qii->excl);
569
570                                 found_info = true;
571
572                         } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
573                                 const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
574
575                                 ret->referenced_max = le64toh(qli->max_rfer);
576                                 ret->exclusive_max = le64toh(qli->max_excl);
577
578                                 if (ret->referenced_max == 0)
579                                         ret->referenced_max = (uint64_t) -1;
580                                 if (ret->exclusive_max == 0)
581                                         ret->exclusive_max = (uint64_t) -1;
582
583                                 found_limit = true;
584                         }
585
586                         if (found_info && found_limit)
587                                 goto finish;
588                 }
589
590                 /* Increase search key by one, to read the next item, if we can. */
591                 if (!btrfs_ioctl_search_args_inc(&args))
592                         break;
593         }
594
595 finish:
596         if (!found_limit && !found_info)
597                 return -ENODATA;
598
599         if (!found_info) {
600                 ret->referenced = (uint64_t) -1;
601                 ret->exclusive = (uint64_t) -1;
602         }
603
604         if (!found_limit) {
605                 ret->referenced_max = (uint64_t) -1;
606                 ret->exclusive_max = (uint64_t) -1;
607         }
608
609         return 0;
610 }
611
612 int btrfs_defrag_fd(int fd) {
613         struct stat st;
614
615         assert(fd >= 0);
616
617         if (fstat(fd, &st) < 0)
618                 return -errno;
619
620         if (!S_ISREG(st.st_mode))
621                 return -EINVAL;
622
623         if (ioctl(fd, BTRFS_IOC_DEFRAG, NULL) < 0)
624                 return -errno;
625
626         return 0;
627 }
628
629 int btrfs_defrag(const char *p) {
630         _cleanup_close_ int fd = -1;
631
632         fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
633         if (fd < 0)
634                 return -errno;
635
636         return btrfs_defrag_fd(fd);
637 }
638
639 int btrfs_quota_enable_fd(int fd, bool b) {
640         struct btrfs_ioctl_quota_ctl_args args = {
641                 .cmd = b ? BTRFS_QUOTA_CTL_ENABLE : BTRFS_QUOTA_CTL_DISABLE,
642         };
643         int r;
644
645         assert(fd >= 0);
646
647         r = btrfs_is_filesystem(fd);
648         if (r < 0)
649                 return r;
650         if (!r)
651                 return -ENOTTY;
652
653         if (ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args) < 0)
654                 return -errno;
655
656         return 0;
657 }
658
659 int btrfs_quota_enable(const char *path, bool b) {
660         _cleanup_close_ int fd = -1;
661
662         fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
663         if (fd < 0)
664                 return -errno;
665
666         return btrfs_quota_enable_fd(fd, b);
667 }
668
669 int btrfs_quota_limit_fd(int fd, uint64_t referenced_max) {
670         struct btrfs_ioctl_qgroup_limit_args args = {
671                 .lim.max_rfer =
672                         referenced_max == (uint64_t) -1 ? 0 :
673                         referenced_max == 0 ? 1 : referenced_max,
674                 .lim.flags = BTRFS_QGROUP_LIMIT_MAX_RFER,
675         };
676         int r;
677
678         assert(fd >= 0);
679
680         r = btrfs_is_filesystem(fd);
681         if (r < 0)
682                 return r;
683         if (!r)
684                 return -ENOTTY;
685
686         if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0)
687                 return -errno;
688
689         return 0;
690 }
691
692 int btrfs_quota_limit(const char *path, uint64_t referenced_max) {
693         _cleanup_close_ int fd = -1;
694
695         fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
696         if (fd < 0)
697                 return -errno;
698
699         return btrfs_quota_limit_fd(fd, referenced_max);
700 }
701
702 int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
703         struct btrfs_ioctl_vol_args args = {};
704         _cleanup_free_ char *p = NULL, *loop = NULL, *backing = NULL;
705         _cleanup_close_ int loop_fd = -1, backing_fd = -1;
706         struct stat st;
707         dev_t dev = 0;
708         int r;
709
710         /* btrfs cannot handle file systems < 16M, hence use this as minimum */
711         if (new_size < 16*1024*1024)
712                 new_size = 16*1024*1024;
713
714         r = btrfs_get_block_device_fd(fd, &dev);
715         if (r < 0)
716                 return r;
717         if (r == 0)
718                 return -ENODEV;
719
720         if (asprintf(&p, "/sys/dev/block/%u:%u/loop/backing_file", major(dev), minor(dev)) < 0)
721                 return -ENOMEM;
722         r = read_one_line_file(p, &backing);
723         if (r == -ENOENT)
724                 return -ENODEV;
725         if (r < 0)
726                 return r;
727         if (isempty(backing) || !path_is_absolute(backing))
728                 return -ENODEV;
729
730         backing_fd = open(backing, O_RDWR|O_CLOEXEC|O_NOCTTY);
731         if (backing_fd < 0)
732                 return -errno;
733
734         if (fstat(backing_fd, &st) < 0)
735                 return -errno;
736         if (!S_ISREG(st.st_mode))
737                 return -ENODEV;
738
739         if (new_size == (uint64_t) st.st_size)
740                 return 0;
741
742         if (grow_only && new_size < (uint64_t) st.st_size)
743                 return -EINVAL;
744
745         if (asprintf(&loop, "/dev/block/%u:%u", major(dev), minor(dev)) < 0)
746                 return -ENOMEM;
747         loop_fd = open(loop, O_RDWR|O_CLOEXEC|O_NOCTTY);
748         if (loop_fd < 0)
749                 return -errno;
750
751         if (snprintf(args.name, sizeof(args.name), "%" PRIu64, new_size) >= (int) sizeof(args.name))
752                 return -EINVAL;
753
754         if (new_size < (uint64_t) st.st_size) {
755                 /* Decrease size: first decrease btrfs size, then shorten loopback */
756                 if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
757                         return -errno;
758         }
759
760         if (ftruncate(backing_fd, new_size) < 0)
761                 return -errno;
762
763         if (ioctl(loop_fd, LOOP_SET_CAPACITY, 0) < 0)
764                 return -errno;
765
766         if (new_size > (uint64_t) st.st_size) {
767                 /* Increase size: first enlarge loopback, then increase btrfs size */
768                 if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
769                         return -errno;
770         }
771
772         /* Make sure the free disk space is correctly updated for both file systems */
773         (void) fsync(fd);
774         (void) fsync(backing_fd);
775
776         return 1;
777 }
778
779 int btrfs_resize_loopback(const char *p, uint64_t new_size, bool grow_only) {
780         _cleanup_close_ int fd = -1;
781
782         fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
783         if (fd < 0)
784                 return -errno;
785
786         return btrfs_resize_loopback_fd(fd, new_size, grow_only);
787 }
788
789 static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol_id, bool recursive) {
790         struct btrfs_ioctl_search_args args = {
791                 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
792
793                 .key.min_objectid = BTRFS_FIRST_FREE_OBJECTID,
794                 .key.max_objectid = BTRFS_LAST_FREE_OBJECTID,
795
796                 .key.min_type = BTRFS_ROOT_BACKREF_KEY,
797                 .key.max_type = BTRFS_ROOT_BACKREF_KEY,
798
799                 .key.min_transid = 0,
800                 .key.max_transid = (uint64_t) -1,
801         };
802
803         struct btrfs_ioctl_vol_args vol_args = {};
804         _cleanup_close_ int subvol_fd = -1;
805         struct stat st;
806         int r;
807
808         assert(fd >= 0);
809         assert(subvolume);
810
811         if (fstat(fd, &st) < 0)
812                 return -errno;
813
814         if (!S_ISDIR(st.st_mode))
815                 return -EINVAL;
816
817         /* First, try to remove the subvolume. If it happens to be
818          * already empty, this will just work. */
819         strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
820         if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) >= 0)
821                 return 0;
822         if (!recursive || errno != ENOTEMPTY)
823                 return -errno;
824
825         /* OK, the subvolume is not empty, let's look for child
826          * subvolumes, and remove them, first */
827         subvol_fd = openat(fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
828         if (subvol_fd < 0)
829                 return -errno;
830
831         if (subvol_id == 0) {
832                 r = btrfs_subvol_get_id_fd(subvol_fd, &subvol_id);
833                 if (r < 0)
834                         return r;
835         }
836
837         args.key.min_offset = args.key.max_offset = subvol_id;
838
839         while (btrfs_ioctl_search_args_compare(&args) <= 0) {
840                 const struct btrfs_ioctl_search_header *sh;
841                 unsigned i;
842
843                 args.key.nr_items = 256;
844                 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
845                         return -errno;
846
847                 if (args.key.nr_items <= 0)
848                         break;
849
850                 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
851                         _cleanup_free_ char *p = NULL;
852                         const struct btrfs_root_ref *ref;
853                         struct btrfs_ioctl_ino_lookup_args ino_args;
854
855                         btrfs_ioctl_search_args_set(&args, sh);
856
857                         if (sh->type != BTRFS_ROOT_BACKREF_KEY)
858                                 continue;
859                         if (sh->offset != subvol_id)
860                                 continue;
861
862                         ref = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
863
864                         p = strndup((char*) ref + sizeof(struct btrfs_root_ref), le64toh(ref->name_len));
865                         if (!p)
866                                 return -ENOMEM;
867
868                         zero(ino_args);
869                         ino_args.treeid = subvol_id;
870                         ino_args.objectid = htole64(ref->dirid);
871
872                         if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args) < 0)
873                                 return -errno;
874
875                         if (isempty(ino_args.name))
876                                 /* Subvolume is in the top-level
877                                  * directory of the subvolume. */
878                                 r = subvol_remove_children(subvol_fd, p, sh->objectid, recursive);
879                         else {
880                                 _cleanup_close_ int child_fd = -1;
881
882                                 /* Subvolume is somewhere further down,
883                                  * hence we need to open the
884                                  * containing directory first */
885
886                                 child_fd = openat(subvol_fd, ino_args.name, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
887                                 if (child_fd < 0)
888                                         return -errno;
889
890                                 r = subvol_remove_children(child_fd, p, sh->objectid, recursive);
891                         }
892                         if (r < 0)
893                                 return r;
894                 }
895
896                 /* Increase search key by one, to read the next item, if we can. */
897                 if (!btrfs_ioctl_search_args_inc(&args))
898                         break;
899         }
900
901         /* OK, the child subvolumes should all be gone now, let's try
902          * again to remove the subvolume */
903         if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) < 0)
904                 return -errno;
905
906         return 0;
907 }
908
909 int btrfs_subvol_remove(const char *path, bool recursive) {
910         _cleanup_close_ int fd = -1;
911         const char *subvolume;
912         int r;
913
914         assert(path);
915
916         r = extract_subvolume_name(path, &subvolume);
917         if (r < 0)
918                 return r;
919
920         fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
921         if (fd < 0)
922                 return fd;
923
924         return subvol_remove_children(fd, subvolume, 0, recursive);
925 }
926
927 int btrfs_subvol_remove_fd(int fd, const char *subvolume, bool recursive) {
928         return subvol_remove_children(fd, subvolume, 0, recursive);
929 }
930
931 static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolume, uint64_t subvol_id, BtrfsSnapshotFlags flags) {
932
933         struct btrfs_ioctl_search_args args = {
934                 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
935
936                 .key.min_objectid = BTRFS_FIRST_FREE_OBJECTID,
937                 .key.max_objectid = BTRFS_LAST_FREE_OBJECTID,
938
939                 .key.min_type = BTRFS_ROOT_BACKREF_KEY,
940                 .key.max_type = BTRFS_ROOT_BACKREF_KEY,
941
942                 .key.min_transid = 0,
943                 .key.max_transid = (uint64_t) -1,
944         };
945
946         struct btrfs_ioctl_vol_args_v2 vol_args = {
947                 .flags = flags & BTRFS_SNAPSHOT_READ_ONLY ? BTRFS_SUBVOL_RDONLY : 0,
948                 .fd = old_fd,
949         };
950         int r;
951
952         assert(old_fd >= 0);
953         assert(new_fd >= 0);
954         assert(subvolume);
955
956         strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
957         vol_args.fd = old_fd;
958
959         if (ioctl(new_fd, BTRFS_IOC_SNAP_CREATE_V2, &vol_args) < 0)
960                 return -errno;
961
962         if (!(flags & BTRFS_SNAPSHOT_RECURSIVE))
963                 return 0;
964
965         if (subvol_id == 0) {
966                 r = btrfs_subvol_get_id_fd(old_fd, &subvol_id);
967                 if (r < 0)
968                         return r;
969         }
970
971         args.key.min_offset = args.key.max_offset = subvol_id;
972
973         while (btrfs_ioctl_search_args_compare(&args) <= 0) {
974                 const struct btrfs_ioctl_search_header *sh;
975                 unsigned i;
976
977                 args.key.nr_items = 256;
978                 if (ioctl(old_fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
979                         return -errno;
980
981                 if (args.key.nr_items <= 0)
982                         break;
983
984                 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
985                         _cleanup_free_ char *p = NULL, *c = NULL, *np = NULL;
986                         struct btrfs_ioctl_ino_lookup_args ino_args;
987                         const struct btrfs_root_ref *ref;
988                         _cleanup_close_ int old_child_fd = -1, new_child_fd = -1;
989
990                         btrfs_ioctl_search_args_set(&args, sh);
991
992                         if (sh->type != BTRFS_ROOT_BACKREF_KEY)
993                                 continue;
994                         if (sh->offset != subvol_id)
995                                 continue;
996
997                         ref = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
998
999                         p = strndup((char*) ref + sizeof(struct btrfs_root_ref), le64toh(ref->name_len));
1000                         if (!p)
1001                                 return -ENOMEM;
1002
1003                         zero(ino_args);
1004                         ino_args.treeid = subvol_id;
1005                         ino_args.objectid = htole64(ref->dirid);
1006
1007                         if (ioctl(old_fd, BTRFS_IOC_INO_LOOKUP, &ino_args) < 0)
1008                                 return -errno;
1009
1010                         /* The kernel returns an empty name if the
1011                          * subvolume is in the top-level directory,
1012                          * and otherwise appends a slash, so that we
1013                          * can just concatenate easily here, without
1014                          * adding a slash. */
1015                         c = strappend(ino_args.name, p);
1016                         if (!c)
1017                                 return -ENOMEM;
1018
1019                         old_child_fd = openat(old_fd, c, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1020                         if (old_child_fd < 0)
1021                                 return -errno;
1022
1023                         np = strjoin(subvolume, "/", ino_args.name, NULL);
1024                         if (!np)
1025                                 return -ENOMEM;
1026
1027                         new_child_fd = openat(new_fd, np, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1028                         if (new_child_fd < 0)
1029                                 return -errno;
1030
1031                         /* When btrfs clones the subvolumes, child
1032                          * subvolumes appear as directories. Remove
1033                          * them, so that we can create a new snapshot
1034                          * in their place */
1035                         if (unlinkat(new_child_fd, p, AT_REMOVEDIR) < 0)
1036                                 return -errno;
1037
1038                         r = subvol_snapshot_children(old_child_fd, new_child_fd, p, sh->objectid, flags & ~BTRFS_SNAPSHOT_FALLBACK_COPY);
1039                         if (r < 0)
1040                                 return r;
1041                 }
1042
1043                 /* Increase search key by one, to read the next item, if we can. */
1044                 if (!btrfs_ioctl_search_args_inc(&args))
1045                         break;
1046         }
1047
1048         return 0;
1049 }
1050
1051 int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags) {
1052         _cleanup_close_ int new_fd = -1;
1053         const char *subvolume;
1054         int r;
1055
1056         assert(old_fd >= 0);
1057         assert(new_path);
1058
1059         r = btrfs_is_subvol(old_fd);
1060         if (r < 0)
1061                 return r;
1062         if (r == 0) {
1063                 if (!(flags & BTRFS_SNAPSHOT_FALLBACK_COPY))
1064                         return -EISDIR;
1065
1066                 r = btrfs_subvol_make(new_path);
1067                 if (r < 0)
1068                         return r;
1069
1070                 r = copy_directory_fd(old_fd, new_path, true);
1071                 if (r < 0) {
1072                         btrfs_subvol_remove(new_path, false);
1073                         return r;
1074                 }
1075
1076                 if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
1077                         r = btrfs_subvol_set_read_only(new_path, true);
1078                         if (r < 0) {
1079                                 btrfs_subvol_remove(new_path, false);
1080                                 return r;
1081                         }
1082                 }
1083
1084                 return 0;
1085         }
1086
1087         r = extract_subvolume_name(new_path, &subvolume);
1088         if (r < 0)
1089                 return r;
1090
1091         new_fd = open_parent(new_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1092         if (new_fd < 0)
1093                 return new_fd;
1094
1095         return subvol_snapshot_children(old_fd, new_fd, subvolume, 0, flags);
1096 }
1097
1098 int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags) {
1099         _cleanup_close_ int old_fd = -1;
1100
1101         assert(old_path);
1102         assert(new_path);
1103
1104         old_fd = open(old_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1105         if (old_fd < 0)
1106                 return -errno;
1107
1108         return btrfs_subvol_snapshot_fd(old_fd, new_path, flags);
1109 }