X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=lib%2Futils_loop.c;h=9b316031bc524ff14687424468f533781a565208;hb=6497abd1df88001eb1f45f7348534911b33d05b5;hp=9e680725fda4ee45102a9585ba3c199aab24d77c;hpb=f7fc3bb4e50cce23dd95111b246b6e034537e2cf;p=platform%2Fupstream%2Fcryptsetup.git diff --git a/lib/utils_loop.c b/lib/utils_loop.c index 9e68072..9b31603 100644 --- a/lib/utils_loop.c +++ b/lib/utils_loop.c @@ -1,8 +1,8 @@ /* * loopback block device utilities * - * Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved. - * Copyright (C) 2009-2021 Milan Broz + * Copyright (C) 2009-2023 Red Hat, Inc. All rights reserved. + * Copyright (C) 2009-2023 Milan Broz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,13 +28,14 @@ #include #include #include -#include #ifdef HAVE_SYS_SYSMACROS_H # include /* for major, minor */ #endif +#include #include #include "utils_loop.h" +#include "libcryptsetup_macros.h" #define LOOP_DEV_MAJOR 7 @@ -50,9 +51,23 @@ #define LOOP_SET_CAPACITY 0x4C07 #endif +#ifndef LOOP_SET_BLOCK_SIZE +#define LOOP_SET_BLOCK_SIZE 0x4C09 +#endif + +#ifndef LOOP_CONFIGURE +#define LOOP_CONFIGURE 0x4C0A +struct loop_config { + __u32 fd; + __u32 block_size; + struct loop_info64 info; + __u64 __reserved[8]; +}; +#endif + static char *crypt_loop_get_device_old(void) { - char dev[20]; + char dev[64]; int i, loop_fd; struct loop_info64 lo64 = {0}; @@ -101,11 +116,12 @@ static char *crypt_loop_get_device(void) } int crypt_loop_attach(char **loop, const char *file, int offset, - int autoclear, int *readonly) + int autoclear, int *readonly, size_t blocksize) { - struct loop_info64 lo64 = {0}; + struct loop_config config = {0}; char *lo_file_name; int loop_fd = -1, file_fd = -1, r = 1; + int fallback = 0; *loop = NULL; @@ -117,7 +133,18 @@ int crypt_loop_attach(char **loop, const char *file, int offset, if (file_fd < 0) goto out; - while (loop_fd < 0) { + config.fd = file_fd; + + lo_file_name = (char*)config.info.lo_file_name; + lo_file_name[LO_NAME_SIZE-1] = '\0'; + strncpy(lo_file_name, file, LO_NAME_SIZE-1); + config.info.lo_offset = offset; + if (autoclear) + config.info.lo_flags |= LO_FLAGS_AUTOCLEAR; + if (blocksize > SECTOR_SIZE) + config.block_size = blocksize; + + while (loop_fd < 0) { *loop = crypt_loop_get_device(); if (!*loop) goto out; @@ -125,8 +152,18 @@ int crypt_loop_attach(char **loop, const char *file, int offset, loop_fd = open(*loop, *readonly ? O_RDONLY : O_RDWR); if (loop_fd < 0) goto out; - - if (ioctl(loop_fd, LOOP_SET_FD, file_fd) < 0) { + if (ioctl(loop_fd, LOOP_CONFIGURE, &config) < 0) { + if (errno == EINVAL || errno == ENOTTY) { + free(*loop); + *loop = NULL; + + close(loop_fd); + loop_fd = -1; + + /* kernel doesn't support LOOP_CONFIGURE */ + fallback = 1; + break; + } if (errno != EBUSY) goto out; free(*loop); @@ -137,23 +174,40 @@ int crypt_loop_attach(char **loop, const char *file, int offset, } } - lo_file_name = (char*)lo64.lo_file_name; - lo_file_name[LO_NAME_SIZE-1] = '\0'; - strncpy(lo_file_name, file, LO_NAME_SIZE-1); - lo64.lo_offset = offset; - if (autoclear) - lo64.lo_flags |= LO_FLAGS_AUTOCLEAR; + if (fallback) { + while (loop_fd < 0) { + *loop = crypt_loop_get_device(); + if (!*loop) + goto out; - if (ioctl(loop_fd, LOOP_SET_STATUS64, &lo64) < 0) { - (void)ioctl(loop_fd, LOOP_CLR_FD, 0); - goto out; + loop_fd = open(*loop, *readonly ? O_RDONLY : O_RDWR); + if (loop_fd < 0) + goto out; + if (ioctl(loop_fd, LOOP_SET_FD, file_fd) < 0) { + if (errno != EBUSY) + goto out; + free(*loop); + *loop = NULL; + + close(loop_fd); + loop_fd = -1; + } + } + + if (blocksize > SECTOR_SIZE) + (void)ioctl(loop_fd, LOOP_SET_BLOCK_SIZE, (unsigned long)blocksize); + + if (ioctl(loop_fd, LOOP_SET_STATUS64, &config.info) < 0) { + (void)ioctl(loop_fd, LOOP_CLR_FD, 0); + goto out; + } } /* Verify that autoclear is really set */ if (autoclear) { - memset(&lo64, 0, sizeof(lo64)); - if (ioctl(loop_fd, LOOP_GET_STATUS64, &lo64) < 0 || - !(lo64.lo_flags & LO_FLAGS_AUTOCLEAR)) { + memset(&config.info, 0, sizeof(config.info)); + if (ioctl(loop_fd, LOOP_GET_STATUS64, &config.info) < 0 || + !(config.info.lo_flags & LO_FLAGS_AUTOCLEAR)) { (void)ioctl(loop_fd, LOOP_CLR_FD, 0); goto out; }