diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2024-10-12 15:13:41 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2024-10-12 17:20:56 -0400 |
commit | 4f9293b045cf32dfc629ce300180d311aba8f53a (patch) | |
tree | 506a0247bc18f13275afce87828373a38192a696 /c_src | |
parent | 282331defa586a03f865efc206d63fd6c03a5077 (diff) |
cmd_fsck: Create loopback device for kernel fsck when necessary
fstests generic/648 now passes
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'c_src')
-rw-r--r-- | c_src/cmd_fsck.c | 65 |
1 files changed, 60 insertions, 5 deletions
diff --git a/c_src/cmd_fsck.c b/c_src/cmd_fsck.c index b532de56..0b41fc82 100644 --- a/c_src/cmd_fsck.c +++ b/c_src/cmd_fsck.c @@ -160,6 +160,45 @@ static bool should_use_kernel_fsck(darray_str devs) return ret; } +static bool is_blockdev(const char *path) +{ + struct stat s; + if (stat(path, &s)) + return true; + return S_ISBLK(s.st_mode); +} + +static void loopdev_free(const char *path) +{ + char *cmd = mprintf("losetup -d %s", path); + system(cmd); + free(cmd); +} + +static char *loopdev_alloc(const char *path) +{ + char *cmd = mprintf("losetup --show -f %s", path); + FILE *f = popen(cmd, "r"); + free(cmd); + if (!f) { + fprintf(stderr, "error executing losetup: %m\n"); + return NULL; + } + + char *line = NULL; + size_t n = 0; + getline(&line, &n, f); + int ret = pclose(f); + if (ret) { + fprintf(stderr, "error executing losetup: %i\n", ret); + free(line); + return NULL; + } + + strim(line); + return line; +} + int cmd_fsck(int argc, char *argv[]) { static const struct option longopts[] = { @@ -243,19 +282,35 @@ int cmd_fsck(int argc, char *argv[]) struct printbuf parse_later = PRINTBUF; if (kernel_probed) { + darray_str loopdevs = {}; + int fsck_fd = -1; + printf("Running in-kernel offline fsck\n"); - struct bch_ioctl_fsck_offline *fsck = calloc(sizeof(*fsck) + - sizeof(u64) * devs.nr, 1); + struct bch_ioctl_fsck_offline *fsck = calloc(sizeof(*fsck) + sizeof(u64) * devs.nr, 1); fsck->opts = (unsigned long)opts_str.buf; - darray_for_each(devs, i) - fsck->devs[i - devs.data] = (unsigned long) *i; + darray_for_each(devs, i) { + if (is_blockdev(*i)) { + fsck->devs[i - devs.data] = (unsigned long) *i; + } else { + char *l = loopdev_alloc(*i); + if (!l) + goto kernel_fsck_err; + darray_push(&loopdevs, l); + fsck->devs[i - devs.data] = (unsigned long) l; + } + } fsck->nr_devs = devs.nr; int ctl_fd = bcachectl_open(); - int fsck_fd = ioctl(ctl_fd, BCH_IOCTL_FSCK_OFFLINE, fsck); + fsck_fd = ioctl(ctl_fd, BCH_IOCTL_FSCK_OFFLINE, fsck); +kernel_fsck_err: free(fsck); + darray_for_each(loopdevs, i) + loopdev_free(*i); + darray_exit(&loopdevs); + if (fsck_fd < 0 && kernel < 0) goto userland_fsck; |