]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - tools-util.c
Update bcachefs sources to 44ac32df8e0c bcachefs: Split brain detection
[bcachefs-tools-debian] / tools-util.c
index baf24ae57eb6bf5c6198befb0598c3a351e045bb..5f0b9ba4fd5f7c279763c3f7df9a9da1d0ca0f59 100644 (file)
@@ -17,6 +17,7 @@
 #include <blkid.h>
 #include <uuid/uuid.h>
 
+#include "libbcachefs.h"
 #include "libbcachefs/bcachefs_ioctl.h"
 #include "linux/sort.h"
 #include "tools-util.h"
@@ -50,36 +51,6 @@ char *mprintf(const char *fmt, ...)
        return str;
 }
 
-void *xcalloc(size_t count, size_t size)
-{
-       void *p = calloc(count, size);
-
-       if (!p)
-               die("insufficient memory");
-
-       return p;
-}
-
-void *xmalloc(size_t size)
-{
-       void *p = malloc(size);
-
-       if (!p)
-               die("insufficient memory");
-
-       memset(p, 0, size);
-       return p;
-}
-
-void *xrealloc(void *p, size_t size)
-{
-       p = realloc(p, size);
-       if (!p)
-               die("insufficient memory");
-
-       return p;
-}
-
 void xpread(int fd, void *buf, size_t count, off_t offset)
 {
        while (count) {
@@ -128,6 +99,17 @@ struct stat xstat(const char *path)
 
 /* File parsing (i.e. sysfs) */
 
+void write_file_str(int dirfd, const char *path, const char *str)
+{
+       int fd = xopenat(dirfd, path, O_WRONLY);
+       ssize_t wrote, len = strlen(str);
+
+       wrote = write(fd, str, len);
+       if (wrote != len)
+               die("read error: %m");
+       close(fd);
+}
+
 char *read_file_str(int dirfd, const char *path)
 {
        int fd = xopenat(dirfd, path, O_RDONLY);
@@ -175,7 +157,7 @@ ssize_t read_string_list_or_die(const char *opt, const char * const list[],
 }
 
 /* Returns size of file or block device: */
-u64 get_size(const char *path, int fd)
+u64 get_size(int fd)
 {
        struct stat statbuf = xfstat(fd);
 
@@ -188,7 +170,7 @@ u64 get_size(const char *path, int fd)
 }
 
 /* Returns blocksize, in bytes: */
-unsigned get_blocksize(const char *path, int fd)
+unsigned get_blocksize(int fd)
 {
        struct stat statbuf = xfstat(fd);
 
@@ -201,24 +183,26 @@ unsigned get_blocksize(const char *path, int fd)
 }
 
 /* Open a block device, do magic blkid stuff to probe for existing filesystems: */
-int open_for_format(const char *dev, bool force)
+int open_for_format(struct dev_opts *dev, bool force)
 {
        blkid_probe pr;
        const char *fs_type = NULL, *fs_label = NULL;
        size_t fs_type_len, fs_label_len;
 
-       int fd = open(dev, O_RDWR|O_EXCL);
-       if (fd < 0)
-               die("Error opening device to format %s: %m", dev);
-
-       if (force)
-               return fd;
+       dev->bdev = blkdev_get_by_path(dev->path, BLK_OPEN_READ|BLK_OPEN_WRITE|BLK_OPEN_EXCL,
+                                      dev, NULL);
+       int ret = PTR_ERR_OR_ZERO(dev->bdev);
+       if (ret < 0)
+               die("Error opening device to format %s: %s", dev->path, strerror(-ret));
 
        if (!(pr = blkid_new_probe()))
                die("blkid error 1");
-       if (blkid_probe_set_device(pr, fd, 0, 0))
+       if (blkid_probe_set_device(pr, dev->bdev->bd_buffered_fd, 0, 0))
                die("blkid error 2");
-       if (blkid_probe_enable_partitions(pr, true))
+       if (blkid_probe_enable_partitions(pr, true) ||
+           blkid_probe_enable_superblocks(pr, true) ||
+           blkid_probe_set_superblocks_flags(pr,
+                       BLKID_SUBLKS_LABEL|BLKID_SUBLKS_TYPE|BLKID_SUBLKS_MAGIC))
                die("blkid error 3");
        if (blkid_do_fullprobe(pr) < 0)
                die("blkid error 4");
@@ -229,19 +213,23 @@ int open_for_format(const char *dev, bool force)
        if (fs_type) {
                if (fs_label)
                        printf("%s contains a %s filesystem labelled '%s'\n",
-                              dev, fs_type, fs_label);
+                              dev->path, fs_type, fs_label);
                else
                        printf("%s contains a %s filesystem\n",
-                              dev, fs_type);
-               fputs("Proceed anyway?", stdout);
-               if (!ask_yn())
-                       exit(EXIT_FAILURE);
-               while (blkid_do_probe(pr) == 0)
-                       blkid_do_wipe(pr, 0);
+                              dev->path, fs_type);
+               if (!force) {
+                       fputs("Proceed anyway?", stdout);
+                       if (!ask_yn())
+                               exit(EXIT_FAILURE);
+               }
+               while (blkid_do_probe(pr) == 0) {
+                       if (blkid_do_wipe(pr, 0))
+                               die("Failed to wipe preexisting metadata.");
+               }
        }
 
        blkid_free_probe(pr);
-       return fd;
+       return ret;
 }
 
 bool ask_yn(void)
@@ -275,14 +263,13 @@ static int range_cmp(const void *_l, const void *_r)
 
 void ranges_sort_merge(ranges *r)
 {
-       struct range *t, *i;
        ranges tmp = { 0 };
 
        sort(r->data, r->nr, sizeof(r->data[0]), range_cmp, NULL);
 
        /* Merge contiguous ranges: */
        darray_for_each(*r, i) {
-               t = tmp.nr ?  &tmp.data[tmp.nr - 1] : NULL;
+               struct range *t = tmp.nr ?  &tmp.data[tmp.nr - 1] : NULL;
 
                if (t && t->end >= i->start)
                        t->end = max(t->end, i->end);
@@ -296,8 +283,6 @@ void ranges_sort_merge(ranges *r)
 
 void ranges_roundup(ranges *r, unsigned block_size)
 {
-       struct range *i;
-
        darray_for_each(*r, i) {
                i->start = round_down(i->start, block_size);
                i->end  = round_up(i->end, block_size);
@@ -306,8 +291,6 @@ void ranges_roundup(ranges *r, unsigned block_size)
 
 void ranges_rounddown(ranges *r, unsigned block_size)
 {
-       struct range *i;
-
        darray_for_each(*r, i) {
                i->start = round_up(i->start, block_size);
                i->end  = round_down(i->end, block_size);
@@ -319,21 +302,21 @@ struct fiemap_extent fiemap_iter_next(struct fiemap_iter *iter)
 {
        struct fiemap_extent e;
 
-       BUG_ON(iter->idx > iter->f.fm_mapped_extents);
+       BUG_ON(iter->idx > iter->f->fm_mapped_extents);
 
-       if (iter->idx == iter->f.fm_mapped_extents) {
-               xioctl(iter->fd, FS_IOC_FIEMAP, &iter->f);
+       if (iter->idx == iter->f->fm_mapped_extents) {
+               xioctl(iter->fd, FS_IOC_FIEMAP, iter->f);
 
-               if (!iter->f.fm_mapped_extents)
+               if (!iter->f->fm_mapped_extents)
                        return (struct fiemap_extent) { .fe_length = 0 };
 
                iter->idx = 0;
        }
 
-       e = iter->f.fm_extents[iter->idx++];
+       e = iter->f->fm_extents[iter->idx++];
        BUG_ON(!e.fe_length);
 
-       iter->f.fm_start = e.fe_logical + e.fe_length;
+       iter->f->fm_start = e.fe_logical + e.fe_length;
 
        return e;
 }
@@ -594,21 +577,90 @@ int dev_mounted(char *dev)
        return 2;
 }
 
+static int kstrtoull_symbolic(const char *s, unsigned int base, unsigned long long *res)
+{
+       if (!strcmp(s, "U64_MAX")) {
+               *res = U64_MAX;
+               return 0;
+       }
+
+       if (!strcmp(s, "U32_MAX")) {
+               *res = U32_MAX;
+               return 0;
+       }
+
+       return kstrtoull(s, base, res);
+}
+
+static int kstrtouint_symbolic(const char *s, unsigned int base, unsigned *res)
+{
+       unsigned long long tmp;
+       int rv;
+
+       rv = kstrtoull_symbolic(s, base, &tmp);
+       if (rv < 0)
+               return rv;
+       if (tmp != (unsigned long long)(unsigned int)tmp)
+               return -ERANGE;
+       *res = tmp;
+       return 0;
+}
+
 struct bpos bpos_parse(char *buf)
 {
-       char *s = buf, *field;
+       char *orig = strdup(buf);
+       char *s = buf;
+
+       char *inode_s   = strsep(&s, ":");
+       char *offset_s  = strsep(&s, ":");
+       char *snapshot_s = strsep(&s, ":");
+
+       if (!inode_s || !offset_s || s)
+               die("invalid bpos %s", orig);
+       free(orig);
+
        u64 inode_v = 0, offset_v = 0;
+       u32 snapshot_v = 0;
+       if (kstrtoull_symbolic(inode_s, 10, &inode_v))
+               die("invalid bpos.inode %s", inode_s);
 
-       if (!(field = strsep(&s, ":")) ||
-           kstrtoull(field, 10, &inode_v))
-               die("invalid bpos %s", buf);
+       if (kstrtoull_symbolic(offset_s, 10, &offset_v))
+               die("invalid bpos.offset %s", offset_s);
 
-       if ((field = strsep(&s, ":")) &&
-           kstrtoull(field, 10, &offset_v))
-               die("invalid bpos %s", buf);
+       if (snapshot_s &&
+           kstrtouint_symbolic(snapshot_s, 10, &snapshot_v))
+               die("invalid bpos.snapshot %s", snapshot_s);
 
-       if (s)
-               die("invalid bpos %s", buf);
+       return (struct bpos) { .inode = inode_v, .offset = offset_v, .snapshot = snapshot_v };
+}
+
+struct bbpos bbpos_parse(char *buf)
+{
+       char *s = buf, *field;
+       struct bbpos ret;
 
-       return (struct bpos) { .inode = inode_v, .offset = offset_v };
+       if (!(field = strsep(&s, ":")))
+               die("invalid bbpos %s", buf);
+
+       ret.btree = read_string_list_or_die(field, __bch2_btree_ids, "btree id");
+
+       if (!s)
+               die("invalid bbpos %s", buf);
+
+       ret.pos = bpos_parse(s);
+       return ret;
+}
+
+darray_str get_or_split_cmdline_devs(int argc, char *argv[])
+{
+       darray_str ret = {};
+
+       if (argc == 1) {
+               bch2_split_devs(argv[0], &ret);
+       } else {
+               for (unsigned i = 0; i < argc; i++)
+                       darray_push(&ret, strdup(argv[i]));
+       }
+
+       return ret;
 }