losetup: directly set dio instead of afterwards

This avoids an extra syscall, and allows the kernel to automatically set
block size [0], avoiding unnecessary failure with 4096-byte devices.

This changes the observable behavior of losetup --direct-io in the case
where DIO is not supported to fully fail, instead of creating a
non-direct-io device. If the user explicitly specifies --direct-io, then
they should get either a DIO loopdev or no loopdev, not a non-DIO
loopdev and a misleading error.

Additionally, loopcxt_setup_device now uses O_CLOEXEC in the read-only
fallback.

[0] 85560117d0
This commit is contained in:
Alex Xu (Hello71) 2021-09-09 09:55:03 -04:00
parent 78001b7af3
commit d53346ed08
2 changed files with 9 additions and 6 deletions

View File

@ -1290,7 +1290,8 @@ static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd)
*/
int loopcxt_setup_device(struct loopdev_cxt *lc)
{
int file_fd, dev_fd, mode = O_RDWR, rc = -1, cnt = 0, err, again;
int file_fd, dev_fd, mode = O_RDWR, flags = O_CLOEXEC;
int rc = -1, cnt = 0, err, again;
int errsv = 0;
int fallback = 0;
@ -1305,9 +1306,12 @@ int loopcxt_setup_device(struct loopdev_cxt *lc)
if (lc->config.info.lo_flags & LO_FLAGS_READ_ONLY)
mode = O_RDONLY;
if ((file_fd = open(lc->filename, mode | O_CLOEXEC)) < 0) {
if (lc->config.info.lo_flags & LO_FLAGS_DIRECT_IO)
flags |= O_DIRECT;
if ((file_fd = open(lc->filename, mode | flags)) < 0) {
if (mode != O_RDONLY && (errno == EROFS || errno == EACCES))
file_fd = open(lc->filename, mode = O_RDONLY);
file_fd = open(lc->filename, (mode = O_RDONLY) | flags);
if (file_fd < 0) {
DBG(SETUP, ul_debugobj(lc, "open backing file failed: %m"));

View File

@ -728,6 +728,8 @@ int main(int argc, char **argv)
use_dio = set_dio = 1;
if (optarg)
use_dio = parse_switch(optarg, _("argument error"), "on", "off", NULL);
if (use_dio)
lo_flags |= LO_FLAGS_DIRECT_IO;
break;
case 'v':
break;
@ -847,8 +849,6 @@ int main(int argc, char **argv)
if (showdev)
printf("%s\n", loopcxt_get_device(&lc));
warn_size(file, sizelimit, offset, flags);
if (set_dio)
goto lo_set_dio;
}
break;
case A_DELETE:
@ -901,7 +901,6 @@ int main(int argc, char **argv)
loopcxt_get_device(&lc));
break;
case A_SET_DIRECT_IO:
lo_set_dio:
res = loopcxt_ioctl_dio(&lc, use_dio);
if (res)
warn(_("%s: set direct io failed"),