11 #include <sys/ioctl.h>
13 #include <sys/types.h>
17 #include <uuid/uuid.h>
19 #include "bcachefs_ioctl.h"
20 #include "linux/sort.h"
21 #include "tools-util.h"
24 void die(const char *fmt, ...)
29 vfprintf(stderr, fmt, args);
36 char *mprintf(const char *fmt, ...)
43 ret = vasprintf(&str, fmt, args);
47 die("insufficient memory");
52 void *xcalloc(size_t count, size_t size)
54 void *p = calloc(count, size);
57 die("insufficient memory");
62 void *xmalloc(size_t size)
64 void *p = malloc(size);
67 die("insufficient memory");
73 void xpread(int fd, void *buf, size_t count, off_t offset)
75 ssize_t r = pread(fd, buf, count, offset);
78 die("read error (ret %zi)", r);
81 void xpwrite(int fd, const void *buf, size_t count, off_t offset)
83 ssize_t r = pwrite(fd, buf, count, offset);
86 die("write error (ret %zi err %m)", r);
89 struct stat xfstatat(int dirfd, const char *path, int flags)
92 if (fstatat(dirfd, path, &stat, flags))
93 die("stat error: %m");
97 struct stat xfstat(int fd)
100 if (fstat(fd, &stat))
101 die("stat error: %m");
107 struct units_buf __pr_units(u64 v, enum units units)
109 struct units_buf ret;
113 snprintf(ret.b, sizeof(ret.b), "%llu", v << 9);
116 snprintf(ret.b, sizeof(ret.b), "%llu", v);
122 int exp = log(v) / log(1024);
123 snprintf(ret.b, sizeof(ret.b), "%.1f%c",
127 snprintf(ret.b, sizeof(ret.b), "%llu", v);
136 /* Argument parsing stuff: */
138 /* File parsing (i.e. sysfs) */
140 char *read_file_str(int dirfd, const char *path)
142 int fd = xopenat(dirfd, path, O_RDONLY);
143 ssize_t len = xfstat(fd).st_size;
145 char *buf = xmalloc(len + 1);
147 len = read(fd, buf, len);
149 die("read error: %m");
152 if (len && buf[len - 1] == '\n')
160 u64 read_file_u64(int dirfd, const char *path)
162 char *buf = read_file_str(dirfd, path);
164 if (kstrtou64(buf, 10, &v))
165 die("read_file_u64: error parsing %s (got %s)", path, buf);
170 /* String list options: */
172 ssize_t read_string_list_or_die(const char *opt, const char * const list[],
175 ssize_t v = bch2_read_string_list(opt, list);
177 die("Bad %s %s", msg, opt);
182 /* Returns size of file or block device: */
183 u64 get_size(const char *path, int fd)
185 struct stat statbuf = xfstat(fd);
187 if (!S_ISBLK(statbuf.st_mode))
188 return statbuf.st_size;
191 xioctl(fd, BLKGETSIZE64, &ret);
195 /* Returns blocksize in units of 512 byte sectors: */
196 unsigned get_blocksize(const char *path, int fd)
198 struct stat statbuf = xfstat(fd);
200 if (!S_ISBLK(statbuf.st_mode))
201 return statbuf.st_blksize >> 9;
204 xioctl(fd, BLKPBSZGET, &ret);
208 /* Open a block device, do magic blkid stuff to probe for existing filesystems: */
209 int open_for_format(const char *dev, bool force)
212 const char *fs_type = NULL, *fs_label = NULL;
213 size_t fs_type_len, fs_label_len;
215 int fd = xopen(dev, O_RDWR|O_EXCL);
220 if (!(pr = blkid_new_probe()))
221 die("blkid error 1");
222 if (blkid_probe_set_device(pr, fd, 0, 0))
223 die("blkid error 2");
224 if (blkid_probe_enable_partitions(pr, true))
225 die("blkid error 3");
226 if (blkid_do_fullprobe(pr) < 0)
227 die("blkid error 4");
229 blkid_probe_lookup_value(pr, "TYPE", &fs_type, &fs_type_len);
230 blkid_probe_lookup_value(pr, "LABEL", &fs_label, &fs_label_len);
234 printf("%s contains a %s filesystem labelled '%s'\n",
235 dev, fs_type, fs_label);
237 printf("%s contains a %s filesystem\n",
239 fputs("Proceed anyway?", stdout);
244 blkid_free_probe(pr);
248 /* Global control device: */
249 int bcachectl_open(void)
251 return xopen("/dev/bcachefs-ctl", O_RDWR);
254 /* Filesystem handles (ioctl, sysfs dir): */
256 #define SYSFS_BASE "/sys/fs/bcachefs/"
258 struct bcache_handle bcache_fs_open(const char *path)
260 struct bcache_handle ret;
263 if (!uuid_parse(path, tmp)) {
264 /* It's a UUID, look it up in sysfs: */
265 char *sysfs = mprintf("%s%s", SYSFS_BASE, path);
266 ret.sysfs_fd = xopen(sysfs, O_RDONLY);
268 char *minor = read_file_str(ret.sysfs_fd, "minor");
269 char *ctl = mprintf("/dev/bcachefs%s-ctl", minor);
270 ret.ioctl_fd = xopen(ctl, O_RDWR);
277 ret.ioctl_fd = xopen(path, O_RDONLY);
279 struct bch_ioctl_query_uuid uuid;
280 xioctl(ret.ioctl_fd, BCH_IOCTL_QUERY_UUID, &uuid);
283 uuid_unparse(uuid.uuid.b, uuid_str);
285 char *sysfs = mprintf("%s%s", SYSFS_BASE, uuid_str);
286 ret.sysfs_fd = xopen(sysfs, O_RDONLY);
295 const char *short_yes = "yY";
300 fputs(" (y,n) ", stdout);
303 if (getline(&buf, &buflen, stdin) < 0)
304 die("error reading from standard input");
306 ret = strchr(short_yes, buf[0]);
311 static int range_cmp(const void *_l, const void *_r)
313 const struct range *l = _l, *r = _r;
315 if (l->start < r->start)
317 if (l->start > r->start)
322 void ranges_sort_merge(ranges *r)
325 ranges tmp = { NULL };
327 sort(&darray_item(*r, 0), darray_size(*r),
328 sizeof(darray_item(*r, 0)), range_cmp, NULL);
330 /* Merge contiguous ranges: */
331 darray_foreach(i, *r) {
332 t = tmp.size ? &tmp.item[tmp.size - 1] : NULL;
334 if (t && t->end >= i->start)
335 t->end = max(t->end, i->end);
337 darray_append(tmp, *i);
344 void ranges_roundup(ranges *r, unsigned block_size)
348 darray_foreach(i, *r) {
349 i->start = round_down(i->start, block_size);
350 i->end = round_up(i->end, block_size);
354 void ranges_rounddown(ranges *r, unsigned block_size)
358 darray_foreach(i, *r) {
359 i->start = round_up(i->start, block_size);
360 i->end = round_down(i->end, block_size);
361 i->end = max(i->end, i->start);
365 struct fiemap_extent fiemap_iter_next(struct fiemap_iter *iter)
367 struct fiemap_extent e;
369 BUG_ON(iter->idx > iter->f.fm_mapped_extents);
371 if (iter->idx == iter->f.fm_mapped_extents) {
372 xioctl(iter->fd, FS_IOC_FIEMAP, &iter->f);
374 if (!iter->f.fm_mapped_extents)
375 return (struct fiemap_extent) { .fe_length = 0 };
380 e = iter->f.fm_extents[iter->idx++];
381 BUG_ON(!e.fe_length);
383 iter->f.fm_start = e.fe_logical + e.fe_length;
388 const char *strcmp_prefix(const char *a, const char *a_prefix)
390 while (*a_prefix && *a == *a_prefix) {
394 return *a_prefix ? NULL : a;
397 unsigned hatoi_validate(const char *s, const char *msg)
401 if (bch2_strtoull_h(s, &v))
402 die("bad %s %s", msg, s);
407 die("%s too large\n", msg);
410 die("%s too small\n", msg);
417 static u32 crc32c_default(u32 crc, const void *buf, size_t size)
419 static const u32 crc32c_tab[] = {
420 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
421 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
422 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
423 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
424 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
425 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
426 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
427 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
428 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
429 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
430 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
431 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
432 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
433 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
434 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
435 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
436 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
437 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
438 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
439 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
440 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
441 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
442 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
443 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
444 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
445 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
446 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
447 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
448 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
449 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
450 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
451 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
452 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
453 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
454 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
455 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
456 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
457 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
458 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
459 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
460 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
461 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
462 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
463 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
464 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
465 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
466 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
467 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
468 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
469 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
470 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
471 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
472 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
473 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
474 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
475 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
476 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
477 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
478 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
479 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
480 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
481 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
482 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
483 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
488 crc = crc32c_tab[(crc ^ *p++) & 0xFFL] ^ (crc >> 8);
493 #include <linux/compiler.h>
498 #define REX_PRE "0x48, "
503 static u32 crc32c_sse42(u32 crc, const void *buf, size_t size)
505 while (size >= sizeof(long)) {
506 const unsigned long *d = buf;
508 __asm__ __volatile__(
509 ".byte 0xf2, " REX_PRE "0xf, 0x38, 0xf1, 0xf1;"
514 size -= sizeof(long);
520 __asm__ __volatile__(
521 ".byte 0xf2, 0xf, 0x38, 0xf0, 0xf1"
532 static void *resolve_crc32c(void)
534 __builtin_cpu_init();
537 if (__builtin_cpu_supports("sse4.2"))
540 return crc32c_default;
544 * ifunc is buggy and I don't know what breaks it (LTO?)
546 #ifdef HAVE_WORKING_IFUNC
548 u32 crc32c(u32, const void *, size_t)
549 __attribute__((ifunc("resolve_crc32c")));
553 u32 crc32c(u32 crc, const void *buf, size_t size)
555 static u32 (*real_crc32c)(u32, const void *, size_t);
557 if (unlikely(!real_crc32c))
558 real_crc32c = resolve_crc32c();
560 return real_crc32c(crc, buf, size);
563 #endif /* HAVE_WORKING_IFUNC */