summaryrefslogtreecommitdiff
path: root/c_src
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2024-10-12 15:13:41 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2024-10-12 17:20:56 -0400
commit4f9293b045cf32dfc629ce300180d311aba8f53a (patch)
tree506a0247bc18f13275afce87828373a38192a696 /c_src
parent282331defa586a03f865efc206d63fd6c03a5077 (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.c65
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;