11 #include <sys/ioctl.h>
13 #include <sys/sysmacros.h>
14 #include <sys/types.h>
18 #include <uuid/uuid.h>
20 #include "libbcachefs/bcachefs_ioctl.h"
21 #include "linux/sort.h"
22 #include "tools-util.h"
23 #include "libbcachefs/util.h"
25 void die(const char *fmt, ...)
30 vfprintf(stderr, fmt, args);
37 char *mprintf(const char *fmt, ...)
44 ret = vasprintf(&str, fmt, args);
48 die("insufficient memory");
53 void *xcalloc(size_t count, size_t size)
55 void *p = calloc(count, size);
58 die("insufficient memory");
63 void *xmalloc(size_t size)
65 void *p = malloc(size);
68 die("insufficient memory");
74 void *xrealloc(void *p, size_t size)
78 die("insufficient memory");
83 void xpread(int fd, void *buf, size_t count, off_t offset)
86 ssize_t r = pread(fd, buf, count, offset);
89 die("read error: %m");
91 die("pread error: unexpected eof");
97 void xpwrite(int fd, const void *buf, size_t count, off_t offset, const char *msg)
99 ssize_t r = pwrite(fd, buf, count, offset);
102 die("error writing %s (ret %zi err %m)", msg, r);
105 struct stat xfstatat(int dirfd, const char *path, int flags)
108 if (fstatat(dirfd, path, &stat, flags))
109 die("stat error: %m");
113 struct stat xfstat(int fd)
116 if (fstat(fd, &stat))
117 die("stat error: %m");
121 struct stat xstat(const char *path)
124 if (stat(path, &statbuf))
125 die("stat error statting %s: %m", path);
129 /* File parsing (i.e. sysfs) */
131 char *read_file_str(int dirfd, const char *path)
133 int fd = xopenat(dirfd, path, O_RDONLY);
134 ssize_t len = xfstat(fd).st_size;
136 char *buf = xmalloc(len + 1);
138 len = read(fd, buf, len);
140 die("read error: %m");
143 if (len && buf[len - 1] == '\n')
155 u64 read_file_u64(int dirfd, const char *path)
157 char *buf = read_file_str(dirfd, path);
159 if (bch2_strtou64_h(buf, &v))
160 die("read_file_u64: error parsing %s (got %s)", path, buf);
165 /* String list options: */
167 ssize_t read_string_list_or_die(const char *opt, const char * const list[],
170 ssize_t v = match_string(list, -1, opt);
172 die("Bad %s %s", msg, opt);
177 /* Returns size of file or block device: */
178 u64 get_size(const char *path, int fd)
180 struct stat statbuf = xfstat(fd);
182 if (!S_ISBLK(statbuf.st_mode))
183 return statbuf.st_size;
186 xioctl(fd, BLKGETSIZE64, &ret);
190 /* Returns blocksize, in bytes: */
191 unsigned get_blocksize(const char *path, int fd)
193 struct stat statbuf = xfstat(fd);
195 if (!S_ISBLK(statbuf.st_mode))
196 return statbuf.st_blksize;
199 xioctl(fd, BLKPBSZGET, &ret);
203 /* Open a block device, do magic blkid stuff to probe for existing filesystems: */
204 int open_for_format(const char *dev, bool force)
207 const char *fs_type = NULL, *fs_label = NULL;
208 size_t fs_type_len, fs_label_len;
210 int fd = open(dev, O_RDWR|O_EXCL);
212 die("Error opening device to format %s: %m", dev);
217 if (!(pr = blkid_new_probe()))
218 die("blkid error 1");
219 if (blkid_probe_set_device(pr, fd, 0, 0))
220 die("blkid error 2");
221 if (blkid_probe_enable_partitions(pr, true))
222 die("blkid error 3");
223 if (blkid_do_fullprobe(pr) < 0)
224 die("blkid error 4");
226 blkid_probe_lookup_value(pr, "TYPE", &fs_type, &fs_type_len);
227 blkid_probe_lookup_value(pr, "LABEL", &fs_label, &fs_label_len);
231 printf("%s contains a %s filesystem labelled '%s'\n",
232 dev, fs_type, fs_label);
234 printf("%s contains a %s filesystem\n",
236 fputs("Proceed anyway?", stdout);
239 while (blkid_do_probe(pr) == 0)
240 blkid_do_wipe(pr, 0);
243 blkid_free_probe(pr);
249 const char *short_yes = "yY";
254 fputs(" (y,n) ", stdout);
257 if (getline(&buf, &buflen, stdin) < 0)
258 die("error reading from standard input");
260 ret = strchr(short_yes, buf[0]);
265 static int range_cmp(const void *_l, const void *_r)
267 const struct range *l = _l, *r = _r;
269 if (l->start < r->start)
271 if (l->start > r->start)
276 void ranges_sort_merge(ranges *r)
281 sort(r->data, r->nr, sizeof(r->data[0]), range_cmp, NULL);
283 /* Merge contiguous ranges: */
284 darray_for_each(*r, i) {
285 t = tmp.nr ? &tmp.data[tmp.nr - 1] : NULL;
287 if (t && t->end >= i->start)
288 t->end = max(t->end, i->end);
290 darray_push(&tmp, *i);
297 void ranges_roundup(ranges *r, unsigned block_size)
301 darray_for_each(*r, i) {
302 i->start = round_down(i->start, block_size);
303 i->end = round_up(i->end, block_size);
307 void ranges_rounddown(ranges *r, unsigned block_size)
311 darray_for_each(*r, i) {
312 i->start = round_up(i->start, block_size);
313 i->end = round_down(i->end, block_size);
314 i->end = max(i->end, i->start);
318 struct fiemap_extent fiemap_iter_next(struct fiemap_iter *iter)
320 struct fiemap_extent e;
322 BUG_ON(iter->idx > iter->f.fm_mapped_extents);
324 if (iter->idx == iter->f.fm_mapped_extents) {
325 xioctl(iter->fd, FS_IOC_FIEMAP, &iter->f);
327 if (!iter->f.fm_mapped_extents)
328 return (struct fiemap_extent) { .fe_length = 0 };
333 e = iter->f.fm_extents[iter->idx++];
334 BUG_ON(!e.fe_length);
336 iter->f.fm_start = e.fe_logical + e.fe_length;
341 char *strcmp_prefix(char *a, const char *a_prefix)
343 while (*a_prefix && *a == *a_prefix) {
347 return *a_prefix ? NULL : a;
352 static u32 crc32c_default(u32 crc, const void *buf, size_t size)
354 static const u32 crc32c_tab[] = {
355 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
356 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
357 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
358 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
359 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
360 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
361 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
362 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
363 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
364 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
365 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
366 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
367 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
368 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
369 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
370 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
371 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
372 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
373 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
374 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
375 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
376 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
377 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
378 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
379 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
380 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
381 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
382 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
383 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
384 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
385 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
386 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
387 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
388 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
389 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
390 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
391 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
392 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
393 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
394 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
395 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
396 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
397 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
398 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
399 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
400 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
401 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
402 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
403 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
404 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
405 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
406 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
407 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
408 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
409 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
410 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
411 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
412 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
413 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
414 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
415 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
416 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
417 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
418 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
423 crc = crc32c_tab[(crc ^ *p++) & 0xFFL] ^ (crc >> 8);
428 #include <linux/compiler.h>
433 #define REX_PRE "0x48, "
438 static u32 crc32c_sse42(u32 crc, const void *buf, size_t size)
440 while (size >= sizeof(long)) {
441 const unsigned long *d = buf;
443 __asm__ __volatile__(
444 ".byte 0xf2, " REX_PRE "0xf, 0x38, 0xf1, 0xf1;"
449 size -= sizeof(long);
455 __asm__ __volatile__(
456 ".byte 0xf2, 0xf, 0x38, 0xf0, 0xf1"
469 static void *resolve_crc32c(void)
472 if (__builtin_cpu_supports("sse4.2"))
475 return crc32c_default;
479 * ifunc is buggy and I don't know what breaks it (LTO?)
481 #ifdef HAVE_WORKING_IFUNC
483 static void *ifunc_resolve_crc32c(void)
485 __builtin_cpu_init();
487 return resolve_crc32c
490 u32 crc32c(u32, const void *, size_t)
491 __attribute__((ifunc("ifunc_resolve_crc32c")));
495 u32 crc32c(u32 crc, const void *buf, size_t size)
497 static u32 (*real_crc32c)(u32, const void *, size_t);
499 if (unlikely(!real_crc32c))
500 real_crc32c = resolve_crc32c();
502 return real_crc32c(crc, buf, size);
505 #endif /* HAVE_WORKING_IFUNC */
507 char *dev_to_name(dev_t dev)
509 char *line = NULL, *name = NULL;
512 FILE *f = fopen("/proc/partitions", "r");
514 die("error opening /proc/partitions: %m");
516 while (getline(&line, &n, f) != -1) {
520 name = realloc(name, n + 1);
522 if (sscanf(line, " %u %u %llu %s", &ma, &mi, §ors, name) == 4 &&
523 ma == major(dev) && mi == minor(dev))
535 char *dev_to_path(dev_t dev)
537 char *name = dev_to_name(dev);
541 char *path = mprintf("/dev/%s", name);
547 struct mntent *dev_to_mount(char *dev)
549 struct mntent *mnt, *ret = NULL;
550 FILE *f = setmntent("/proc/mounts", "r");
552 die("error opening /proc/mounts: %m");
554 struct stat d1 = xstat(dev);
556 while ((mnt = getmntent(f))) {
557 char *d, *p = mnt->mnt_fsname;
559 while ((d = strsep(&p, ":"))) {
565 if (S_ISBLK(d1.st_mode) != S_ISBLK(d2.st_mode))
568 if (S_ISBLK(d1.st_mode)) {
569 if (d1.st_rdev != d2.st_rdev)
572 if (d1.st_dev != d2.st_dev ||
573 d1.st_ino != d2.st_ino)
586 int dev_mounted(char *dev)
588 struct mntent *mnt = dev_to_mount(dev);
592 if (hasmntopt(mnt, "ro"))
597 struct bpos bpos_parse(char *buf)
599 char *s = buf, *field;
600 u64 inode_v = 0, offset_v = 0;
602 if (!(field = strsep(&s, ":")) ||
603 kstrtoull(field, 10, &inode_v))
604 die("invalid bpos %s", buf);
606 if ((field = strsep(&s, ":")) &&
607 kstrtoull(field, 10, &offset_v))
608 die("invalid bpos %s", buf);
611 die("invalid bpos %s", buf);
613 return (struct bpos) { .inode = inode_v, .offset = offset_v };