chiark / gitweb /
qcow2: when dissecting qcow2, use btrfs clone ioctls for reflinking blocks to target
[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 "strv.h"
35 #include "copy.h"
36 #include "selinux-util.h"
37 #include "smack-util.h"
38 #include "btrfs-ctree.h"
39 #include "btrfs-util.h"
40
41 static int validate_subvolume_name(const char *name) {
42
43         if (!filename_is_valid(name))
44                 return -EINVAL;
45
46         if (strlen(name) > BTRFS_SUBVOL_NAME_MAX)
47                 return -E2BIG;
48
49         return 0;
50 }
51
52 static int open_parent(const char *path, int flags) {
53         _cleanup_free_ char *parent = NULL;
54         int r, fd;
55
56         assert(path);
57
58         r = path_get_parent(path, &parent);
59         if (r < 0)
60                 return r;
61
62         fd = open(parent, flags);
63         if (fd < 0)
64                 return -errno;
65
66         return fd;
67 }
68
69 static int extract_subvolume_name(const char *path, const char **subvolume) {
70         const char *fn;
71         int r;
72
73         assert(path);
74         assert(subvolume);
75
76         fn = basename(path);
77
78         r = validate_subvolume_name(fn);
79         if (r < 0)
80                 return r;
81
82         *subvolume = fn;
83         return 0;
84 }
85
86 int btrfs_is_snapshot(int fd) {
87         struct stat st;
88         struct statfs sfs;
89
90         /* On btrfs subvolumes always have the inode 256 */
91
92         if (fstat(fd, &st) < 0)
93                 return -errno;
94
95         if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
96                 return 0;
97
98         if (fstatfs(fd, &sfs) < 0)
99                 return -errno;
100
101         return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
102 }
103
104 int btrfs_subvol_snapshot(const char *old_path, const char *new_path, bool read_only, bool fallback_copy) {
105         struct btrfs_ioctl_vol_args_v2 args = {
106                 .flags = read_only ? BTRFS_SUBVOL_RDONLY : 0,
107         };
108         _cleanup_close_ int old_fd = -1, new_fd = -1;
109         const char *subvolume;
110         int r;
111
112         assert(old_path);
113
114         old_fd = open(old_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
115         if (old_fd < 0)
116                 return -errno;
117
118         r = btrfs_is_snapshot(old_fd);
119         if (r < 0)
120                 return r;
121         if (r == 0) {
122
123                 if (fallback_copy) {
124                         r = btrfs_subvol_make(new_path);
125                         if (r < 0)
126                                 return r;
127
128                         r = copy_directory_fd(old_fd, new_path, true);
129                         if (r < 0) {
130                                 btrfs_subvol_remove(new_path);
131                                 return r;
132                         }
133
134                         if (read_only) {
135                                 r = btrfs_subvol_set_read_only(new_path, true);
136                                 if (r < 0) {
137                                         btrfs_subvol_remove(new_path);
138                                         return r;
139                                 }
140                         }
141
142                         return 0;
143                 }
144
145                 return -EISDIR;
146         }
147
148         r = extract_subvolume_name(new_path, &subvolume);
149         if (r < 0)
150                 return r;
151
152         new_fd = open_parent(new_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
153         if (new_fd < 0)
154                 return new_fd;
155
156         strncpy(args.name, subvolume, sizeof(args.name)-1);
157         args.fd = old_fd;
158
159         if (ioctl(new_fd, BTRFS_IOC_SNAP_CREATE_V2, &args) < 0)
160                 return -errno;
161
162         return 0;
163 }
164
165 int btrfs_subvol_make(const char *path) {
166         struct btrfs_ioctl_vol_args args = {};
167         _cleanup_close_ int fd = -1;
168         const char *subvolume;
169         int r;
170
171         assert(path);
172
173         r = extract_subvolume_name(path, &subvolume);
174         if (r < 0)
175                 return r;
176
177         fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
178         if (fd < 0)
179                 return fd;
180
181         strncpy(args.name, subvolume, sizeof(args.name)-1);
182
183         if (ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args) < 0)
184                 return -errno;
185
186         return 0;
187 }
188
189 int btrfs_subvol_make_label(const char *path) {
190         int r;
191
192         assert(path);
193
194         r = mac_selinux_create_file_prepare(path, S_IFDIR);
195         if (r < 0)
196                 return r;
197
198         r = btrfs_subvol_make(path);
199         mac_selinux_create_file_clear();
200
201         if (r < 0)
202                 return r;
203
204         return mac_smack_fix(path, false, false);
205 }
206
207 int btrfs_subvol_remove(const char *path) {
208         struct btrfs_ioctl_vol_args args = {};
209         _cleanup_close_ int fd = -1;
210         const char *subvolume;
211         int r;
212
213         assert(path);
214
215         r = extract_subvolume_name(path, &subvolume);
216         if (r < 0)
217                 return r;
218
219         fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
220         if (fd < 0)
221                 return fd;
222
223         strncpy(args.name, subvolume, sizeof(args.name)-1);
224
225         if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args) < 0)
226                 return -errno;
227
228         return 0;
229 }
230
231 int btrfs_subvol_set_read_only(const char *path, bool b) {
232         _cleanup_close_ int fd = -1;
233         uint64_t flags, nflags;
234
235         fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
236         if (fd < 0)
237                 return -errno;
238
239         if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
240                 return -errno;
241
242         if (b)
243                 nflags = flags | BTRFS_SUBVOL_RDONLY;
244         else
245                 nflags = flags & ~BTRFS_SUBVOL_RDONLY;
246
247         if (flags == nflags)
248                 return 0;
249
250         if (ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &nflags) < 0)
251                 return -errno;
252
253         return 0;
254 }
255
256 int btrfs_subvol_get_read_only_fd(int fd) {
257         uint64_t flags;
258
259         if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
260                 return -errno;
261
262         return !!(flags & BTRFS_SUBVOL_RDONLY);
263 }
264
265 int btrfs_reflink(int infd, int outfd) {
266         int r;
267
268         assert(infd >= 0);
269         assert(outfd >= 0);
270
271         r = ioctl(outfd, BTRFS_IOC_CLONE, infd);
272         if (r < 0)
273                 return -errno;
274
275         return 0;
276 }
277
278 int btrfs_clone_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, uint64_t sz) {
279         struct btrfs_ioctl_clone_range_args args = {
280                 .src_fd = infd,
281                 .src_offset = in_offset,
282                 .src_length = sz,
283                 .dest_offset = out_offset,
284         };
285         int r;
286
287         assert(infd >= 0);
288         assert(outfd >= 0);
289         assert(sz > 0);
290
291         r = ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args);
292         if (r < 0)
293                 return -errno;
294
295         return 0;
296 }
297
298 int btrfs_get_block_device(const char *path, dev_t *dev) {
299         struct btrfs_ioctl_fs_info_args fsi = {};
300         _cleanup_close_ int fd = -1;
301         uint64_t id;
302
303         assert(path);
304         assert(dev);
305
306         fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
307         if (fd < 0)
308                 return -errno;
309
310         if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
311                 return -errno;
312
313         /* We won't do this for btrfs RAID */
314         if (fsi.num_devices != 1)
315                 return 0;
316
317         for (id = 1; id <= fsi.max_id; id++) {
318                 struct btrfs_ioctl_dev_info_args di = {
319                         .devid = id,
320                 };
321                 struct stat st;
322
323                 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
324                         if (errno == ENODEV)
325                                 continue;
326
327                         return -errno;
328                 }
329
330                 if (stat((char*) di.path, &st) < 0)
331                         return -errno;
332
333                 if (!S_ISBLK(st.st_mode))
334                         return -ENODEV;
335
336                 if (major(st.st_rdev) == 0)
337                         return -ENODEV;
338
339                 *dev = st.st_rdev;
340                 return 1;
341         }
342
343         return -ENODEV;
344 }
345
346 int btrfs_subvol_get_id_fd(int fd, uint64_t *ret) {
347         struct btrfs_ioctl_ino_lookup_args args = {
348                 .objectid = BTRFS_FIRST_FREE_OBJECTID
349         };
350
351         assert(fd >= 0);
352         assert(ret);
353
354         if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
355                 return -errno;
356
357         *ret = args.treeid;
358         return 0;
359 }
360
361 static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args *args) {
362         assert(args);
363
364         /* the objectid, type, offset together make up the btrfs key,
365          * which is considered a single 136byte integer when
366          * comparing. This call increases the counter by one, dealing
367          * with the overflow between the overflows */
368
369         if (args->key.min_offset < (uint64_t) -1) {
370                 args->key.min_offset++;
371                 return true;
372         }
373
374         if (args->key.min_type < (uint8_t) -1) {
375                 args->key.min_type++;
376                 args->key.min_offset = 0;
377                 return true;
378         }
379
380         if (args->key.min_objectid < (uint64_t) -1) {
381                 args->key.min_objectid++;
382                 args->key.min_offset = 0;
383                 args->key.min_type = 0;
384                 return true;
385         }
386
387         return 0;
388 }
389
390 static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args *args, const struct btrfs_ioctl_search_header *h) {
391         assert(args);
392         assert(h);
393
394         args->key.min_objectid = h->objectid;
395         args->key.min_type = h->type;
396         args->key.min_offset = h->offset;
397 }
398
399 static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args *args) {
400         assert(args);
401
402         /* Compare min and max */
403
404         if (args->key.min_objectid < args->key.max_objectid)
405                 return -1;
406         if (args->key.min_objectid > args->key.max_objectid)
407                 return 1;
408
409         if (args->key.min_type < args->key.max_type)
410                 return -1;
411         if (args->key.min_type > args->key.max_type)
412                 return 1;
413
414         if (args->key.min_offset < args->key.max_offset)
415                 return -1;
416         if (args->key.min_offset > args->key.max_offset)
417                 return 1;
418
419         return 0;
420 }
421
422 #define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args)                  \
423         for ((i) = 0,                                                   \
424              (sh) = (const struct btrfs_ioctl_search_header*) (args).buf; \
425              (i) < (args).key.nr_items;                                 \
426              (i)++,                                                     \
427              (sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
428
429 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh)                              \
430         ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
431
432 int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) {
433         struct btrfs_ioctl_search_args args = {
434                 /* Tree of tree roots */
435                 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
436
437                 /* Look precisely for the subvolume items */
438                 .key.min_type = BTRFS_ROOT_ITEM_KEY,
439                 .key.max_type = BTRFS_ROOT_ITEM_KEY,
440
441                 .key.min_offset = 0,
442                 .key.max_offset = (uint64_t) -1,
443
444                 /* No restrictions on the other components */
445                 .key.min_transid = 0,
446                 .key.max_transid = (uint64_t) -1,
447         };
448
449         uint64_t subvol_id;
450         bool found = false;
451         int r;
452
453         assert(fd >= 0);
454         assert(ret);
455
456         r = btrfs_subvol_get_id_fd(fd, &subvol_id);
457         if (r < 0)
458                 return r;
459
460         args.key.min_objectid = args.key.max_objectid = subvol_id;
461
462         while (btrfs_ioctl_search_args_compare(&args) <= 0) {
463                 const struct btrfs_ioctl_search_header *sh;
464                 unsigned i;
465
466                 args.key.nr_items = 256;
467                 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
468                         return -errno;
469
470                 if (args.key.nr_items <= 0)
471                         break;
472
473                 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
474
475                         const struct btrfs_root_item *ri;
476
477                         /* Make sure we start the next search at least from this entry */
478                         btrfs_ioctl_search_args_set(&args, sh);
479
480                         if (sh->objectid != subvol_id)
481                                 continue;
482                         if (sh->type != BTRFS_ROOT_ITEM_KEY)
483                                 continue;
484
485                         /* Older versions of the struct lacked the otime setting */
486                         if (sh->len < offsetof(struct btrfs_root_item, otime) + sizeof(struct btrfs_timespec))
487                                 continue;
488
489                         ri = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
490
491                         ret->otime = (usec_t) le64toh(ri->otime.sec) * USEC_PER_SEC +
492                                 (usec_t) le32toh(ri->otime.nsec) / NSEC_PER_USEC;
493
494                         ret->subvol_id = subvol_id;
495                         ret->read_only = !!(le64toh(ri->flags) & BTRFS_ROOT_SUBVOL_RDONLY);
496
497                         assert_cc(sizeof(ri->uuid) == sizeof(ret->uuid));
498                         memcpy(&ret->uuid, ri->uuid, sizeof(ret->uuid));
499                         memcpy(&ret->parent_uuid, ri->parent_uuid, sizeof(ret->parent_uuid));
500
501                         found = true;
502                         goto finish;
503                 }
504
505                 /* Increase search key by one, to read the next item, if we can. */
506                 if (!btrfs_ioctl_search_args_inc(&args))
507                         break;
508         }
509
510 finish:
511         if (!found)
512                 return -ENODATA;
513
514         return 0;
515 }
516
517 int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) {
518
519         struct btrfs_ioctl_search_args args = {
520                 /* Tree of quota items */
521                 .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
522
523                 /* The object ID is always 0 */
524                 .key.min_objectid = 0,
525                 .key.max_objectid = 0,
526
527                 /* Look precisely for the quota items */
528                 .key.min_type = BTRFS_QGROUP_STATUS_KEY,
529                 .key.max_type = BTRFS_QGROUP_LIMIT_KEY,
530
531                 /* No restrictions on the other components */
532                 .key.min_transid = 0,
533                 .key.max_transid = (uint64_t) -1,
534         };
535
536         uint64_t subvol_id;
537         bool found_info = false, found_limit = false;
538         int r;
539
540         assert(fd >= 0);
541         assert(ret);
542
543         r = btrfs_subvol_get_id_fd(fd, &subvol_id);
544         if (r < 0)
545                 return r;
546
547         args.key.min_offset = args.key.max_offset = subvol_id;
548
549         while (btrfs_ioctl_search_args_compare(&args) <= 0) {
550                 const struct btrfs_ioctl_search_header *sh;
551                 unsigned i;
552
553                 args.key.nr_items = 256;
554                 if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
555                         return -errno;
556
557                 if (args.key.nr_items <= 0)
558                         break;
559
560                 FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
561
562                         /* Make sure we start the next search at least from this entry */
563                         btrfs_ioctl_search_args_set(&args, sh);
564
565                         if (sh->objectid != 0)
566                                 continue;
567                         if (sh->offset != subvol_id)
568                                 continue;
569
570                         if (sh->type == BTRFS_QGROUP_INFO_KEY) {
571                                 const struct btrfs_qgroup_info_item *qii = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
572
573                                 ret->referred = le64toh(qii->rfer);
574                                 ret->exclusive = le64toh(qii->excl);
575
576                                 found_info = true;
577
578                         } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
579                                 const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
580
581                                 ret->referred_max = le64toh(qli->max_rfer);
582                                 ret->exclusive_max = le64toh(qli->max_excl);
583
584                                 if (ret->referred_max == 0)
585                                         ret->referred_max = (uint64_t) -1;
586                                 if (ret->exclusive_max == 0)
587                                         ret->exclusive_max = (uint64_t) -1;
588
589                                 found_limit = true;
590                         }
591
592                         if (found_info && found_limit)
593                                 goto finish;
594                 }
595
596                 /* Increase search key by one, to read the next item, if we can. */
597                 if (!btrfs_ioctl_search_args_inc(&args))
598                         break;
599         }
600
601 finish:
602         if (!found_limit && !found_info)
603                 return -ENODATA;
604
605         if (!found_info) {
606                 ret->referred = (uint64_t) -1;
607                 ret->exclusive = (uint64_t) -1;
608         }
609
610         if (!found_limit) {
611                 ret->referred_max = (uint64_t) -1;
612                 ret->exclusive_max = (uint64_t) -1;
613         }
614
615         return 0;
616 }
617
618 int btrfs_defrag_fd(int fd) {
619         assert(fd >= 0);
620
621         if (ioctl(fd, BTRFS_IOC_DEFRAG, NULL) < 0)
622                 return -errno;
623
624         return 0;
625 }
626
627 int btrfs_defrag(const char *p) {
628         _cleanup_close_ int fd = -1;
629
630         fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
631         if (fd < 0)
632                 return -errno;
633
634         return btrfs_defrag_fd(fd);
635 }