From d5fd456c88aba4fcf77d35fe38024a8d5c814686 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Wed, 30 Sep 2020 03:28:30 +0000 Subject: [PATCH] loopdev: use LOOP_CONFIG ioctl Prefer to use the new LOOP_CONFIG ioctl. https://lwn.net/Articles/820408/ Signed-off-by: Sinan Kaya --- include/loopdev.h | 12 ++++- lib/loopdev.c | 117 +++++++++++++++++++++++++++----------------- sys-utils/losetup.c | 2 +- 3 files changed, 83 insertions(+), 48 deletions(-) diff --git a/include/loopdev.h b/include/loopdev.h index 65bd579d2..bcc7bfa73 100644 --- a/include/loopdev.h +++ b/include/loopdev.h @@ -66,6 +66,16 @@ struct loop_info64 { uint64_t lo_init[2]; }; +#ifndef LOOP_CONFIGURE +#define LOOP_CONFIGURE 0x4C0A +struct loop_config { + uint32_t fd; + uint32_t block_size; + struct loop_info64 info; + uint64_t __reserved[8]; +}; +#endif + #define LOOPDEV_MAJOR 7 /* loop major number */ #define LOOPDEV_DEFAULT_NNODES 8 /* default number of loop devices */ @@ -105,7 +115,7 @@ struct loopdev_cxt { unsigned int control_ok:1; /* /dev/loop-control success */ struct path_cxt *sysfs; /* pointer to /sys/dev/block// */ - struct loop_info64 info; /* for GET/SET ioctl */ + struct loop_config config; /* for GET/SET ioctl */ struct loopdev_iter iter; /* scans /sys or /dev for used/free devices */ }; diff --git a/lib/loopdev.c b/lib/loopdev.c index c4b492dc5..15264b19c 100644 --- a/lib/loopdev.c +++ b/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; @@ -1087,7 +1087,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; @@ -1100,7 +1100,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; @@ -1134,7 +1134,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; @@ -1157,9 +1157,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; } @@ -1182,7 +1182,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)) { @@ -1198,16 +1198,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) { @@ -1275,6 +1275,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; @@ -1284,7 +1285,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) { @@ -1307,10 +1308,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; } @@ -1334,45 +1335,69 @@ int loopcxt_setup_device(struct loopdev_cxt *lc) DBG(SETUP, ul_debugobj(lc, "device open: OK")); - /* - * Set FD - */ - 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")); + if (fallback) { + /* + * Set FD + */ + 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")); + + if (lc->blocksize > 0 + && (rc = loopcxt_ioctl_blocksize(lc, lc->blocksize)) < 0) { + errsv = -rc; + goto err; + } + + 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")); } - 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; - } - - 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; @@ -1415,7 +1440,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); diff --git a/sys-utils/losetup.c b/sys-utils/losetup.c index 379b95f17..cc4d206b7 100644 --- a/sys-utils/losetup.c +++ b/sys-utils/losetup.c @@ -508,7 +508,7 @@ static int create_loop(struct loopdev_cxt *lc, errx(EXIT_FAILURE, _("%s: overlapping encrypted loop device exists"), file); } - lc->info.lo_flags &= ~LO_FLAGS_AUTOCLEAR; + lc->config.info.lo_flags &= ~LO_FLAGS_AUTOCLEAR; if (loopcxt_ioctl_status(lc)) { loopcxt_deinit(lc); errx(EXIT_FAILURE, _("%s: failed to re-use loop device"), file);