11 #include <sys/ioctl.h>
13 #include <sys/sysmacros.h>
14 #include <sys/types.h>
18 #include <uuid/uuid.h>
20 #include "libbcachefs.h"
21 #include "libbcachefs/bcachefs_ioctl.h"
22 #include "linux/sort.h"
23 #include "tools-util.h"
24 #include "libbcachefs/util.h"
26 void die(const char *fmt, ...)
31 vfprintf(stderr, fmt, args);
38 char *mprintf(const char *fmt, ...)
45 ret = vasprintf(&str, fmt, args);
49 die("insufficient memory");
54 void *xcalloc(size_t count, size_t size)
56 void *p = calloc(count, size);
59 die("insufficient memory");
64 void *xmalloc(size_t size)
66 void *p = malloc(size);
69 die("insufficient memory");
75 void *xrealloc(void *p, size_t size)
79 die("insufficient memory");
84 void xpread(int fd, void *buf, size_t count, off_t offset)
87 ssize_t r = pread(fd, buf, count, offset);
90 die("read error: %m");
92 die("pread error: unexpected eof");
98 void xpwrite(int fd, const void *buf, size_t count, off_t offset, const char *msg)
100 ssize_t r = pwrite(fd, buf, count, offset);
103 die("error writing %s (ret %zi err %m)", msg, r);
106 struct stat xfstatat(int dirfd, const char *path, int flags)
109 if (fstatat(dirfd, path, &stat, flags))
110 die("stat error: %m");
114 struct stat xfstat(int fd)
117 if (fstat(fd, &stat))
118 die("stat error: %m");
122 struct stat xstat(const char *path)
125 if (stat(path, &statbuf))
126 die("stat error statting %s: %m", path);
130 /* File parsing (i.e. sysfs) */
132 void write_file_str(int dirfd, const char *path, const char *str)
134 int fd = xopenat(dirfd, path, O_WRONLY);
135 ssize_t wrote, len = strlen(str);
137 wrote = write(fd, str, len);
139 die("read error: %m");
143 char *read_file_str(int dirfd, const char *path)
145 int fd = xopenat(dirfd, path, O_RDONLY);
146 ssize_t len = xfstat(fd).st_size;
148 char *buf = xmalloc(len + 1);
150 len = read(fd, buf, len);
152 die("read error: %m");
155 if (len && buf[len - 1] == '\n')
167 u64 read_file_u64(int dirfd, const char *path)
169 char *buf = read_file_str(dirfd, path);
171 if (bch2_strtou64_h(buf, &v))
172 die("read_file_u64: error parsing %s (got %s)", path, buf);
177 /* String list options: */
179 ssize_t read_string_list_or_die(const char *opt, const char * const list[],
182 ssize_t v = match_string(list, -1, opt);
184 die("Bad %s %s", msg, opt);
189 /* Returns size of file or block device: */
192 struct stat statbuf = xfstat(fd);
194 if (!S_ISBLK(statbuf.st_mode))
195 return statbuf.st_size;
198 xioctl(fd, BLKGETSIZE64, &ret);
202 /* Returns blocksize, in bytes: */
203 unsigned get_blocksize(int fd)
205 struct stat statbuf = xfstat(fd);
207 if (!S_ISBLK(statbuf.st_mode))
208 return statbuf.st_blksize;
211 xioctl(fd, BLKPBSZGET, &ret);
215 /* Open a block device, do magic blkid stuff to probe for existing filesystems: */
216 int open_for_format(struct dev_opts *dev, bool force)
219 const char *fs_type = NULL, *fs_label = NULL;
220 size_t fs_type_len, fs_label_len;
222 dev->bdev = blkdev_get_by_path(dev->path, BLK_OPEN_READ|BLK_OPEN_WRITE|BLK_OPEN_EXCL,
224 int ret = PTR_ERR_OR_ZERO(dev->bdev);
226 die("Error opening device to format %s: %s", dev->path, strerror(-ret));
231 if (!(pr = blkid_new_probe()))
232 die("blkid error 1");
233 if (blkid_probe_set_device(pr, dev->bdev->bd_buffered_fd, 0, 0))
234 die("blkid error 2");
235 if (blkid_probe_enable_partitions(pr, true))
236 die("blkid error 3");
237 if (blkid_do_fullprobe(pr) < 0)
238 die("blkid error 4");
240 blkid_probe_lookup_value(pr, "TYPE", &fs_type, &fs_type_len);
241 blkid_probe_lookup_value(pr, "LABEL", &fs_label, &fs_label_len);
245 printf("%s contains a %s filesystem labelled '%s'\n",
246 dev->path, fs_type, fs_label);
248 printf("%s contains a %s filesystem\n",
250 fputs("Proceed anyway?", stdout);
253 while (blkid_do_probe(pr) == 0)
254 blkid_do_wipe(pr, 0);
257 blkid_free_probe(pr);
263 const char *short_yes = "yY";
268 fputs(" (y,n) ", stdout);
271 if (getline(&buf, &buflen, stdin) < 0)
272 die("error reading from standard input");
274 ret = strchr(short_yes, buf[0]);
279 static int range_cmp(const void *_l, const void *_r)
281 const struct range *l = _l, *r = _r;
283 if (l->start < r->start)
285 if (l->start > r->start)
290 void ranges_sort_merge(ranges *r)
295 sort(r->data, r->nr, sizeof(r->data[0]), range_cmp, NULL);
297 /* Merge contiguous ranges: */
298 darray_for_each(*r, i) {
299 t = tmp.nr ? &tmp.data[tmp.nr - 1] : NULL;
301 if (t && t->end >= i->start)
302 t->end = max(t->end, i->end);
304 darray_push(&tmp, *i);
311 void ranges_roundup(ranges *r, unsigned block_size)
315 darray_for_each(*r, i) {
316 i->start = round_down(i->start, block_size);
317 i->end = round_up(i->end, block_size);
321 void ranges_rounddown(ranges *r, unsigned block_size)
325 darray_for_each(*r, i) {
326 i->start = round_up(i->start, block_size);
327 i->end = round_down(i->end, block_size);
328 i->end = max(i->end, i->start);
332 struct fiemap_extent fiemap_iter_next(struct fiemap_iter *iter)
334 struct fiemap_extent e;
336 BUG_ON(iter->idx > iter->f->fm_mapped_extents);
338 if (iter->idx == iter->f->fm_mapped_extents) {
339 xioctl(iter->fd, FS_IOC_FIEMAP, iter->f);
341 if (!iter->f->fm_mapped_extents)
342 return (struct fiemap_extent) { .fe_length = 0 };
347 e = iter->f->fm_extents[iter->idx++];
348 BUG_ON(!e.fe_length);
350 iter->f->fm_start = e.fe_logical + e.fe_length;
355 char *strcmp_prefix(char *a, const char *a_prefix)
357 while (*a_prefix && *a == *a_prefix) {
361 return *a_prefix ? NULL : a;
366 static u32 crc32c_default(u32 crc, const void *buf, size_t size)
368 static const u32 crc32c_tab[] = {
369 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
370 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
371 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
372 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
373 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
374 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
375 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
376 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
377 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
378 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
379 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
380 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
381 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
382 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
383 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
384 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
385 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
386 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
387 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
388 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
389 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
390 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
391 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
392 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
393 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
394 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
395 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
396 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
397 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
398 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
399 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
400 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
401 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
402 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
403 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
404 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
405 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
406 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
407 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
408 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
409 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
410 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
411 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
412 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
413 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
414 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
415 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
416 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
417 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
418 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
419 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
420 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
421 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
422 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
423 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
424 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
425 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
426 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
427 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
428 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
429 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
430 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
431 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
432 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
437 crc = crc32c_tab[(crc ^ *p++) & 0xFFL] ^ (crc >> 8);
442 #include <linux/compiler.h>
447 #define REX_PRE "0x48, "
452 static u32 crc32c_sse42(u32 crc, const void *buf, size_t size)
454 while (size >= sizeof(long)) {
455 const unsigned long *d = buf;
457 __asm__ __volatile__(
458 ".byte 0xf2, " REX_PRE "0xf, 0x38, 0xf1, 0xf1;"
463 size -= sizeof(long);
469 __asm__ __volatile__(
470 ".byte 0xf2, 0xf, 0x38, 0xf0, 0xf1"
483 static void *resolve_crc32c(void)
486 if (__builtin_cpu_supports("sse4.2"))
489 return crc32c_default;
493 * ifunc is buggy and I don't know what breaks it (LTO?)
495 #ifdef HAVE_WORKING_IFUNC
497 static void *ifunc_resolve_crc32c(void)
499 __builtin_cpu_init();
501 return resolve_crc32c
504 u32 crc32c(u32, const void *, size_t)
505 __attribute__((ifunc("ifunc_resolve_crc32c")));
509 u32 crc32c(u32 crc, const void *buf, size_t size)
511 static u32 (*real_crc32c)(u32, const void *, size_t);
513 if (unlikely(!real_crc32c))
514 real_crc32c = resolve_crc32c();
516 return real_crc32c(crc, buf, size);
519 #endif /* HAVE_WORKING_IFUNC */
521 char *dev_to_name(dev_t dev)
523 char *line = NULL, *name = NULL;
526 FILE *f = fopen("/proc/partitions", "r");
528 die("error opening /proc/partitions: %m");
530 while (getline(&line, &n, f) != -1) {
534 name = realloc(name, n + 1);
536 if (sscanf(line, " %u %u %llu %s", &ma, &mi, §ors, name) == 4 &&
537 ma == major(dev) && mi == minor(dev))
549 char *dev_to_path(dev_t dev)
551 char *name = dev_to_name(dev);
555 char *path = mprintf("/dev/%s", name);
561 struct mntent *dev_to_mount(char *dev)
563 struct mntent *mnt, *ret = NULL;
564 FILE *f = setmntent("/proc/mounts", "r");
566 die("error opening /proc/mounts: %m");
568 struct stat d1 = xstat(dev);
570 while ((mnt = getmntent(f))) {
571 char *d, *p = mnt->mnt_fsname;
573 while ((d = strsep(&p, ":"))) {
579 if (S_ISBLK(d1.st_mode) != S_ISBLK(d2.st_mode))
582 if (S_ISBLK(d1.st_mode)) {
583 if (d1.st_rdev != d2.st_rdev)
586 if (d1.st_dev != d2.st_dev ||
587 d1.st_ino != d2.st_ino)
600 int dev_mounted(char *dev)
602 struct mntent *mnt = dev_to_mount(dev);
606 if (hasmntopt(mnt, "ro"))
611 static int kstrtoull_symbolic(const char *s, unsigned int base, unsigned long long *res)
613 if (!strcmp(s, "U64_MAX")) {
618 if (!strcmp(s, "U32_MAX")) {
623 return kstrtoull(s, base, res);
626 static int kstrtouint_symbolic(const char *s, unsigned int base, unsigned *res)
628 unsigned long long tmp;
631 rv = kstrtoull_symbolic(s, base, &tmp);
634 if (tmp != (unsigned long long)(unsigned int)tmp)
640 struct bpos bpos_parse(char *buf)
642 char *orig = strdup(buf);
645 char *inode_s = strsep(&s, ":");
646 char *offset_s = strsep(&s, ":");
647 char *snapshot_s = strsep(&s, ":");
649 if (!inode_s || !offset_s || s)
650 die("invalid bpos %s", orig);
653 u64 inode_v = 0, offset_v = 0;
655 if (kstrtoull_symbolic(inode_s, 10, &inode_v))
656 die("invalid bpos.inode %s", inode_s);
658 if (kstrtoull_symbolic(offset_s, 10, &offset_v))
659 die("invalid bpos.offset %s", offset_s);
662 kstrtouint_symbolic(snapshot_s, 10, &snapshot_v))
663 die("invalid bpos.snapshot %s", snapshot_s);
665 return (struct bpos) { .inode = inode_v, .offset = offset_v, .snapshot = snapshot_v };
668 struct bbpos bbpos_parse(char *buf)
670 char *s = buf, *field;
673 if (!(field = strsep(&s, ":")))
674 die("invalid bbpos %s", buf);
676 ret.btree = read_string_list_or_die(field, bch2_btree_ids, "btree id");
679 die("invalid bbpos %s", buf);
681 ret.pos = bpos_parse(s);