diff options
Diffstat (limited to 'src/utils/lib/loopdev.c')
-rw-r--r-- | src/utils/lib/loopdev.c | 133 |
1 files changed, 85 insertions, 48 deletions
diff --git a/src/utils/lib/loopdev.c b/src/utils/lib/loopdev.c index be4e486..194daf9 100644 --- a/src/utils/lib/loopdev.c +++ b/src/utils/lib/loopdev.c @@ -100,7 +100,7 @@ int loopcxt_set_device(struct loopdev_cxt *lc, const char *device) lc->has_info = 0; lc->info_failed = 0; *lc->device = '\0'; - memset(&lc->info, 0, sizeof(lc->info)); + memset(&lc->config, 0, sizeof(lc->config)); /* set new */ if (device) { @@ -659,17 +659,17 @@ struct loop_info64 *loopcxt_get_info(struct loopdev_cxt *lc) } errno = 0; if (lc->has_info) - return &lc->info; + return &lc->config.info; fd = loopcxt_get_fd(lc); if (fd < 0) return NULL; - if (ioctl(fd, LOOP_GET_STATUS64, &lc->info) == 0) { + if (ioctl(fd, LOOP_GET_STATUS64, &lc->config.info) == 0) { lc->has_info = 1; lc->info_failed = 0; DBG(CXT, ul_debugobj(lc, "reading loop_info64 OK")); - return &lc->info; + return &lc->config.info; } lc->info_failed = 1; @@ -1156,7 +1156,7 @@ int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset) { if (!lc) return -EINVAL; - lc->info.lo_offset = offset; + lc->config.info.lo_offset = offset; DBG(CXT, ul_debugobj(lc, "set offset=%jd", offset)); return 0; @@ -1169,7 +1169,7 @@ int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit) { if (!lc) return -EINVAL; - lc->info.lo_sizelimit = sizelimit; + lc->config.info.lo_sizelimit = sizelimit; DBG(CXT, ul_debugobj(lc, "set sizelimit=%jd", sizelimit)); return 0; @@ -1202,7 +1202,7 @@ int loopcxt_set_blocksize(struct loopdev_cxt *lc, uint64_t blocksize) int loopcxt_set_file_fmt_type(struct loopdev_cxt *lc, uint32_t file_fmt_type) { if (!lc) return -EINVAL; - lc->info.lo_file_fmt_type = file_fmt_type; + lc->config.info.lo_file_fmt_type = file_fmt_type; DBG(CXT, ul_debugobj(lc, "set file_fmt_type=%u", (unsigned) file_fmt_type)); return 0; @@ -1220,7 +1220,7 @@ int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags) { if (!lc) return -EINVAL; - lc->info.lo_flags = flags; + lc->config.info.lo_flags = flags; DBG(CXT, ul_debugobj(lc, "set flags=%u", (unsigned) flags)); return 0; @@ -1243,9 +1243,9 @@ int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename) if (!lc->filename) return -errno; - xstrncpy((char *)lc->info.lo_file_name, lc->filename, LO_NAME_SIZE); + xstrncpy((char *)lc->config.info.lo_file_name, lc->filename, LO_NAME_SIZE); - DBG(CXT, ul_debugobj(lc, "set backing file=%s", lc->info.lo_file_name)); + DBG(CXT, ul_debugobj(lc, "set backing file=%s", lc->config.info.lo_file_name)); return 0; } @@ -1268,7 +1268,7 @@ static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd) int dev_fd; struct stat st; - if (!lc->info.lo_offset && !lc->info.lo_sizelimit) + if (!lc->config.info.lo_offset && !lc->config.info.lo_sizelimit) return 0; if (fstat(file_fd, &st)) { @@ -1284,16 +1284,16 @@ static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd) } else expected_size = st.st_size; - if (expected_size == 0 || expected_size <= lc->info.lo_offset) { + if (expected_size == 0 || expected_size <= lc->config.info.lo_offset) { DBG(CXT, ul_debugobj(lc, "failed to determine expected size")); return 0; /* ignore this error */ } - if (lc->info.lo_offset > 0) - expected_size -= lc->info.lo_offset; + if (lc->config.info.lo_offset > 0) + expected_size -= lc->config.info.lo_offset; - if (lc->info.lo_sizelimit > 0 && lc->info.lo_sizelimit < expected_size) - expected_size = lc->info.lo_sizelimit; + if (lc->config.info.lo_sizelimit > 0 && lc->config.info.lo_sizelimit < expected_size) + expected_size = lc->config.info.lo_sizelimit; dev_fd = loopcxt_get_fd(lc); if (dev_fd < 0) { @@ -1361,6 +1361,7 @@ int loopcxt_setup_device(struct loopdev_cxt *lc) { int file_fd, dev_fd, mode = O_RDWR, rc = -1, cnt = 0, err, again; int errsv = 0; + int fallback = 0; if (!lc || !*lc->device || !lc->filename) return -EINVAL; @@ -1370,7 +1371,7 @@ int loopcxt_setup_device(struct loopdev_cxt *lc) /* * Open backing file and device */ - if (lc->info.lo_flags & LO_FLAGS_READ_ONLY) + if (lc->config.info.lo_flags & LO_FLAGS_READ_ONLY) mode = O_RDONLY; if ((file_fd = open(lc->filename, mode | O_CLOEXEC)) < 0) { @@ -1393,10 +1394,10 @@ int loopcxt_setup_device(struct loopdev_cxt *lc) if (mode == O_RDONLY) { lc->flags |= LOOPDEV_FL_RDONLY; /* open() mode */ - lc->info.lo_flags |= LO_FLAGS_READ_ONLY; /* kernel loopdev mode */ + lc->config.info.lo_flags |= LO_FLAGS_READ_ONLY; /* kernel loopdev mode */ } else { lc->flags |= LOOPDEV_FL_RDWR; /* open() mode */ - lc->info.lo_flags &= ~LO_FLAGS_READ_ONLY; + lc->config.info.lo_flags &= ~LO_FLAGS_READ_ONLY; lc->flags &= ~LOOPDEV_FL_RDONLY; } @@ -1407,8 +1408,8 @@ int loopcxt_setup_device(struct loopdev_cxt *lc) break; if (errno != EACCES && errno != ENOENT) break; - /* We have permissions to open /dev/xloop-control, but open - * /dev/xloopN failed with EACCES, it's probably because udevd + /* We have permissions to open /dev/loop-control, but open + * /dev/loopN failed with EACCES, it's probably because udevd * does not applied chown yet. Let's wait a moment. */ xusleep(25000); } while (cnt++ < 16); @@ -1421,44 +1422,70 @@ int loopcxt_setup_device(struct loopdev_cxt *lc) DBG(SETUP, ul_debugobj(lc, "device open: OK")); /* - * Set FD + * Atomic way to configure all by one ioctl call + * -- since Linux v5.8-rc1, commit 3448914e8cc550ba792d4ccc74471d1ca4293aae */ - if (ioctl(dev_fd, LOOP_SET_FD, file_fd) < 0) { + lc->config.fd = file_fd; + if (ioctl(dev_fd, LOOP_CONFIGURE, &lc->config) < 0) { rc = -errno; errsv = errno; - DBG(SETUP, ul_debugobj(lc, "LOOP_SET_FD failed: %m")); - goto err; + if (errno != EINVAL) { + DBG(SETUP, ul_debugobj(lc, "LOOP_CONFIGURE failed: %m")); + goto err; + } + fallback = 1; + } else { + if (lc->blocksize > 0 + && (rc = loopcxt_ioctl_blocksize(lc, lc->blocksize)) < 0) { + errsv = -rc; + goto err; + } + DBG(SETUP, ul_debugobj(lc, "LOOP_CONFIGURE: OK")); } - DBG(SETUP, ul_debugobj(lc, "LOOP_SET_FD: OK")); + /* + * Old deprecated way; first assign backing file FD and then in the + * second step set loop device properties. + */ + if (fallback) { + if (ioctl(dev_fd, LOOP_SET_FD, file_fd) < 0) { + rc = -errno; + errsv = errno; + DBG(SETUP, ul_debugobj(lc, "LOOP_SET_FD failed: %m")); + goto err; + } - if (lc->blocksize > 0 - && (rc = loopcxt_ioctl_blocksize(lc, lc->blocksize)) < 0) { - errsv = -rc; - goto err; - } + DBG(SETUP, ul_debugobj(lc, "LOOP_SET_FD: OK")); - do { - err = ioctl(dev_fd, LOOP_SET_STATUS64, &lc->info); - again = err && errno == EAGAIN; - if (again) - xusleep(250000); - } while (again); - if (err) { - rc = -errno; - errsv = errno; - DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64 failed: %m")); - goto err; - } + if (lc->blocksize > 0 + && (rc = loopcxt_ioctl_blocksize(lc, lc->blocksize)) < 0) { + errsv = -rc; + goto err; + } - DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64: OK")); + do { + err = ioctl(dev_fd, LOOP_SET_STATUS64, &lc->config.info); + again = err && errno == EAGAIN; + if (again) + xusleep(250000); + } while (again); + + if (err) { + rc = -errno; + errsv = errno; + DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64 failed: %m")); + goto err; + } + + DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64: OK")); + } if ((rc = loopcxt_check_size(lc, file_fd))) goto err; close(file_fd); - memset(&lc->info, 0, sizeof(lc->info)); + memset(&lc->config, 0, sizeof(lc->config)); lc->has_info = 0; lc->info_failed = 0; @@ -1501,7 +1528,7 @@ int loopcxt_ioctl_status(struct loopdev_cxt *lc) DBG(SETUP, ul_debugobj(lc, "device open: OK")); do { - err = ioctl(dev_fd, LOOP_SET_STATUS64, &lc->info); + err = ioctl(dev_fd, LOOP_SET_STATUS64, &lc->config.info); again = err && errno == EAGAIN; if (again) xusleep(250000); @@ -1654,7 +1681,7 @@ int loopcxt_find_unused(struct loopdev_cxt *lc) } if (rc < 0) { - DBG(CXT, ul_debugobj(lc, "using loop scan")); + DBG(CXT, ul_debugobj(lc, "using xloop scan")); rc = loopcxt_init_iterator(lc, LOOPITER_FL_FREE); if (rc) return rc; @@ -1705,6 +1732,17 @@ char *loopdev_get_backing_file(const char *device) return res; } +int loopdev_has_backing_file(const char *device) +{ + char *tmp = loopdev_get_backing_file(device); + + if (tmp) { + free(tmp); + return 1; + } + return 0; +} + /* * Returns: TRUE/FALSE */ @@ -1911,4 +1949,3 @@ int loopdev_count_by_backing_file(const char *filename, char **loopdev) } return count; } - |