X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=lib%2Futils_loop.c;h=6e67a6ad9bc5374098538ad088dc8fc149a7b4a5;hb=420ad62f0bb77970a6ba234bde9e1405f7df7789;hp=b5394de06ad06166478405d9e0625ea2871d3f0a;hpb=690c363eb90277fc53a97e3e2367ebe12055937e;p=platform%2Fupstream%2Fcryptsetup.git diff --git a/lib/utils_loop.c b/lib/utils_loop.c index b5394de..6e67a6a 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,16 +28,17 @@ #include #include #include -#include #ifdef HAVE_SYS_SYSMACROS_H # include /* for major, minor */ #endif +#include #include #ifdef HAVE_SYS_SYSMACROS_H #include /* for major, minor */ #endif #include "utils_loop.h" +#include "libcryptsetup_macros.h" #define LOOP_DEV_MAJOR 7 @@ -53,9 +54,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}; @@ -104,11 +119,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; @@ -120,7 +136,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; @@ -128,8 +155,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); @@ -140,23 +177,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; }