>From f66209859385759510d1a5aa3fe1dadadc913b17 Mon Sep 17 00:00:00 2001 From: Ondrej Oprala Date: Tue, 22 Jan 2013 14:21:23 +0100 Subject: [PATCH] dd: Postpone buffer allocations if possible. * src/dd.c (dd_copy): Move and split the code for buffer allocations to separate functions and call them conditionally. (alloc_ibuf): Allocate memory for the input buffer. (alloc_obuf): Allocate memory for the output buffer. * tests/dd/no-allocate.sh: New test. * tests/local.mk: Add the test. --- src/dd.c | 88 +++++++++++++++++++++++++++++-------------------- tests/dd/no-allocate.sh | 28 ++++++++++++++++ tests/local.mk | 1 + 3 files changed, 82 insertions(+), 35 deletions(-) create mode 100755 tests/dd/no-allocate.sh diff --git a/src/dd.c b/src/dd.c index ef5664b..0a3bede 100644 --- a/src/dd.c +++ b/src/dd.c @@ -236,6 +236,9 @@ static uintmax_t r_truncate = 0; static char newline_character = '\n'; static char space_character = ' '; +/* Input buffer. */ +static char *ibuf; + /* Output buffer. */ static char *obuf; @@ -1833,16 +1836,49 @@ human_size (size_t n) return human_readable (n, hbuf, human_opts, 1, 1); } +static void +alloc_ibuf (void) +{ + char *real_buf = malloc (input_blocksize + INPUT_BLOCK_SLOP); + if (!real_buf) + error (EXIT_FAILURE, 0, + _("memory exhausted by input buffer of size %zu bytes (%s)"), + input_blocksize, human_size (input_blocksize)); + + real_buf += SWAB_ALIGN_OFFSET; /* allow space for swab */ + + ibuf = ptr_align (real_buf, page_size); +} + +static void +alloc_obuf (void) +{ + if (conversions_mask & C_TWOBUFS) + { + /* Page-align the output buffer, too. */ + char *real_obuf = malloc (output_blocksize + OUTPUT_BLOCK_SLOP); + if (!real_obuf) + error (EXIT_FAILURE, 0, + _("memory exhausted by output buffer of size %zu bytes (%s)"), + output_blocksize, human_size (output_blocksize)); + obuf = ptr_align (real_obuf, page_size); + } + else + obuf = ibuf; + + /* Write a sentinel to the slop after the buffer, + to allow efficient checking for NUL blocks. */ + assert (sizeof (uintptr_t) <= OUTPUT_BLOCK_SLOP); + if (obuf) + memset (obuf + output_blocksize, 1, sizeof (uintptr_t)); +} + /* The main loop. */ static int dd_copy (void) { - char *ibuf, *bufstart; /* Input buffer. */ - /* These are declared static so that even though we don't free the - buffers, valgrind will recognize that there is no "real" leak. */ - static char *real_buf; /* real buffer address before alignment */ - static char *real_obuf; + char *bufstart; /* Input buffer. */ ssize_t nread; /* Bytes read in the current block. */ /* If nonzero, then the previously read block was partial and @@ -1869,37 +1905,14 @@ dd_copy (void) It is necessary when accessing raw (i.e. character special) disk devices on Unixware or other SVR4-derived system. */ - real_buf = malloc (input_blocksize + INPUT_BLOCK_SLOP); - if (!real_buf) - error (EXIT_FAILURE, 0, - _("memory exhausted by input buffer of size %zu bytes (%s)"), - input_blocksize, human_size (input_blocksize)); - - ibuf = real_buf; - ibuf += SWAB_ALIGN_OFFSET; /* allow space for swab */ - - ibuf = ptr_align (ibuf, page_size); - - if (conversions_mask & C_TWOBUFS) - { - /* Page-align the output buffer, too. */ - real_obuf = malloc (output_blocksize + OUTPUT_BLOCK_SLOP); - if (!real_obuf) - error (EXIT_FAILURE, 0, - _("memory exhausted by output buffer of size %zu bytes (%s)"), - output_blocksize, human_size (output_blocksize)); - obuf = ptr_align (real_obuf, page_size); - } - else - { - real_obuf = NULL; - obuf = ibuf; - } + /* Delay buffer allocation if possible*/ + if ((skip_records > OFF_T_MAX / input_blocksize) + || 0 > skip_via_lseek (input_file, STDIN_FILENO, 0, SEEK_CUR)) + alloc_ibuf (); - /* Write a sentinel to the slop after the buffer, - to allow efficient checking for NUL blocks. */ - assert (sizeof (uintptr_t) <= OUTPUT_BLOCK_SLOP); - memset (obuf + output_blocksize, 1, sizeof (uintptr_t)); + if ((seek_records > OFF_T_MAX / output_blocksize) + || 0 > skip_via_lseek (output_file, STDOUT_FILENO, 0, SEEK_CUR)) + alloc_obuf (); if (skip_records != 0 || skip_bytes != 0) { @@ -1955,6 +1968,11 @@ dd_copy (void) if (max_records == 0 && max_bytes == 0) return exit_status; + if (!ibuf) + alloc_ibuf (); + if (!obuf) + alloc_obuf (); + while (1) { if (r_partial + r_full >= max_records + !!max_bytes) diff --git a/tests/dd/no-allocate.sh b/tests/dd/no-allocate.sh new file mode 100755 index 0000000..e992280 --- /dev/null +++ b/tests/dd/no-allocate.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# make sure that dd doesn't allocate memory unnecessarily + +# Copyright (C) 2013 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ dd + +#count and skip is zero, we don't need to allocate memory for input block +(ulimit -v 10000;dd if=/dev/zero of=x bs=10M count=0) || fail=1 + +#non-skippable input, we need to allocate input block size (and we should fail) +(ulimit -v 10000; echo "abcde" | dd of=x bs=10M seek=1 skip=1 count=0) && fail=1 + +Exit $fail diff --git a/tests/local.mk b/tests/local.mk index 82daee5..e011fdf 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -462,6 +462,7 @@ all_tests = \ tests/df/skip-rootfs.sh \ tests/dd/direct.sh \ tests/dd/misc.sh \ + tests/dd/no-allocate.sh \ tests/dd/nocache.sh \ tests/dd/not-rewound.sh \ tests/dd/reblock.sh \ -- 1.7.11.7