Skip to content

Commit

Permalink
cmd_fsck: Create loopback device for kernel fsck when necessary
Browse files Browse the repository at this point in the history
fstests generic/648 now passes

Signed-off-by: Kent Overstreet <[email protected]>
  • Loading branch information
Kent Overstreet committed Oct 12, 2024
1 parent 282331d commit 4f9293b
Showing 1 changed file with 60 additions and 5 deletions.
65 changes: 60 additions & 5 deletions c_src/cmd_fsck.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = {
Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit 4f9293b

Please sign in to comment.