From: Dave Reisner Date: Fri, 24 Aug 2012 21:45:25 +0000 (-0400) Subject: lib/utils_crypt: optimize seek to keyfile-offset X-Git-Tag: upstream/1.6~184 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=961682aa6b22877beb83c148ec157063383d94ee;p=platform%2Fupstream%2Fcryptsetup.git lib/utils_crypt: optimize seek to keyfile-offset Avoid using unbuffered reads when "seeking" to a keyfile offset. This is abysmally slow when the key is hidden at the end of a large device. Instead, try to actually call lseek, falling back on reading in chunks of BUFSIZ bytes until the desired offset is reached. Command line: cryptsetup luksOpen /dev/vdc1 home \ --keyfile /dev/vdd --keyfile-size 4096 --keyfile-offset 123456789 Before: real 0m25.589s user 0m7.030s sys 0m18.479s After: real 0m4.464s user 0m4.253s sys 0m0.157s --- diff --git a/ChangeLog b/ChangeLog index eccb9b4..17b4ceb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2012-08-27 Milan Broz + * Optimize seek to keyfile-offset (Issue #135, thx to dreisner). + 2012-08-12 Milan Broz * Allocate loop device late (only when real block device needed). * Rework underlying device/file access functions. diff --git a/lib/utils_crypt.c b/lib/utils_crypt.c index c2111c7..4433dc7 100644 --- a/lib/utils_crypt.c +++ b/lib/utils_crypt.c @@ -262,6 +262,49 @@ out_err: } /* + * A simple call to lseek(3) might not be possible for some inputs (e.g. + * reading from a pipe), so this function instead reads of up to BUFSIZ bytes + * at a time until the specified number of bytes. It returns -1 on read error + * or when it reaches EOF before the requested number of bytes have been + * discarded. + */ +static int keyfile_seek(int fd, size_t bytes) +{ + char tmp[BUFSIZ]; + size_t next_read; + ssize_t bytes_r; + off_t r; + + r = lseek(fd, bytes, SEEK_CUR); + if (r > 0) + return 0; + if (r < 0 && errno != ESPIPE) + return -1; + + while (bytes > 0) { + /* figure out how much to read */ + next_read = bytes > sizeof(tmp) ? sizeof(tmp) : bytes; + + bytes_r = read(fd, tmp, next_read); + if (bytes_r < 0) { + if (errno == EINTR) + continue; + + /* read error */ + return -1; + } + + if (bytes_r == 0) + /* EOF */ + break; + + bytes -= bytes_r; + } + + return bytes == 0 ? 0 : -1; +} + +/* * Note: --key-file=- is interpreted as a read from a binary file (stdin) * key_size_max == 0 means detect maximum according to input type (tty/file) * timeout and verify options only applies to tty input @@ -274,7 +317,7 @@ int crypt_get_key(const char *prompt, { int fd, regular_file, read_stdin, char_read, unlimited_read = 0; int r = -EINVAL; - char *pass = NULL, tmp; + char *pass = NULL; size_t buflen, i, file_read_size; struct stat st; @@ -342,11 +385,10 @@ int crypt_get_key(const char *prompt, } /* Discard keyfile_offset bytes on input */ - for(i = 0; i < keyfile_offset; i++) - if (read(fd, &tmp, 1) != 1) { - log_err(cd, _("Cannot seek to requested keyfile offset.\n")); - goto out_err; - } + if (keyfile_offset && keyfile_seek(fd, keyfile_offset) < 0) { + log_err(cd, _("Cannot seek to requested keyfile offset.\n")); + goto out_err; + } for(i = 0; i < keyfile_size_max; i++) { if(i == buflen) {