From patchwork Fri Jul 19 02:17:37 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Robert Yang X-Patchwork-Id: 260173 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 74DD32C008F for ; Fri, 19 Jul 2013 12:19:20 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933715Ab3GSCTU (ORCPT ); Thu, 18 Jul 2013 22:19:20 -0400 Received: from mail.windriver.com ([147.11.1.11]:51281 "EHLO mail.windriver.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933638Ab3GSCTT (ORCPT ); Thu, 18 Jul 2013 22:19:19 -0400 Received: from ALA-HCA.corp.ad.wrs.com (ala-hca.corp.ad.wrs.com [147.11.189.40]) by mail.windriver.com (8.14.5/8.14.3) with ESMTP id r6J2JHp2028012 (version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=FAIL); Thu, 18 Jul 2013 19:19:17 -0700 (PDT) Received: from pek-hostel-vm06.wrs.com (128.224.153.176) by ALA-HCA.corp.ad.wrs.com (147.11.189.40) with Microsoft SMTP Server id 14.2.342.3; Thu, 18 Jul 2013 19:19:16 -0700 From: Robert Yang To: , CC: Subject: [PATCH 2/2] debugfs.c: do sparse copy when src is a sparse file Date: Fri, 19 Jul 2013 10:17:37 +0800 Message-ID: <1374200257-2873-3-git-send-email-liezhi.yang@windriver.com> X-Mailer: git-send-email 1.8.1.2 In-Reply-To: <1374200257-2873-1-git-send-email-liezhi.yang@windriver.com> References: <1374200257-2873-1-git-send-email-liezhi.yang@windriver.com> MIME-Version: 1.0 Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org Let debugfs do sparse copy when src is a sparse file, just like "cp --sparse=auto" * For the #define IO_BUFSIZE 32*1024 This is from coreutils-8.13/src/ioblksize.h (GPL V3): /* As of Mar 2009, 32KiB is determined to be the minimium blksize to best minimize system call overhead. This can be tested with this script with the results shown for a 1.7GHz pentium-m with 2GB of 400MHz DDR2 RAM: for i in $(seq 0 10); do size=$((8*1024**3)) #ensure this is big enough bs=$((1024*2**$i)) printf "%7s=" $bs dd bs=$bs if=/dev/zero of=/dev/null count=$(($size/$bs)) 2>&1 | sed -n 's/.* \([0-9.]* [GM]B\/s\)/\1/p' done 1024=734 MB/s 2048=1.3 GB/s 4096=2.4 GB/s 8192=3.5 GB/s 16384=3.9 GB/s 32768=5.2 GB/s 65536=5.3 GB/s 131072=5.5 GB/s 262144=5.7 GB/s 524288=5.7 GB/s 1048576=5.8 GB/s Note that this is to minimize system call overhead. Other values may be appropriate to minimize file system or disk overhead. For example on my current GNU/Linux system the readahead setting is 128KiB which was read using: file="." device=$(df -P --local "$file" | tail -n1 | cut -d' ' -f1) echo $(( $(blockdev --getra $device) * 512 )) However there isn't a portable way to get the above. In the future we could use the above method if available and default to io_blksize() if not. */ enum { IO_BUFSIZE = 32*1024 }; Signed-off-by: Robert Yang Acked-by: Darren Hart --- debugfs/debugfs.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c index b77d0b5..e443703 100644 --- a/debugfs/debugfs.c +++ b/debugfs/debugfs.c @@ -37,6 +37,16 @@ extern char *optarg; #include "../version.h" #include "jfs_user.h" +/* 32KiB is the minimium blksize to best minimize system call overhead. */ +#ifndef IO_BUFSIZE +#define IO_BUFSIZE 32*1024 +#endif + +/* Block size for `st_blocks' */ +#ifndef S_BLKSIZE +#define S_BLKSIZE 512 +#endif + ss_request_table *extra_cmds; const char *debug_prog_name; int sci_idx; @@ -1571,14 +1581,17 @@ void do_find_free_inode(int argc, char *argv[]) } #ifndef READ_ONLY -static errcode_t copy_file(int fd, ext2_ino_t newfile) +static errcode_t copy_file(int fd, ext2_ino_t newfile, int bufsize, + int make_holes, int *zero_written) { ext2_file_t e2_file; errcode_t retval; int got; unsigned int written; - char buf[8192]; + char buf[bufsize]; char *ptr; + char *cp; + int count; retval = ext2fs_file_open(current_fs, newfile, EXT2_FILE_WRITE, &e2_file); @@ -1594,14 +1607,30 @@ static errcode_t copy_file(int fd, ext2_ino_t newfile) goto fail; } ptr = buf; + cp = ptr; + count = got; while (got > 0) { - retval = ext2fs_file_write(e2_file, ptr, - got, &written); - if (retval) - goto fail; - - got -= written; - ptr += written; + if (make_holes) { + /* Check whether all is zero */ + while (count-- && *cp++ == 0) + continue; + if (count < 0) { + /* The whole block is zero, make a hole */ + retval = ext2fs_file_lseek(e2_file, got, EXT2_SEEK_CUR, NULL); + if (retval) + goto fail; + got = 0; + } + } + /* Normal copy */ + if (got > 0) { + *zero_written = 0; + retval = ext2fs_file_write(e2_file, ptr, got, &written); + if (retval) + goto fail; + got -= written; + ptr += written; + } } } retval = ext2fs_file_close(e2_file); @@ -1620,6 +1649,9 @@ void do_write(int argc, char *argv[]) ext2_ino_t newfile; errcode_t retval; struct ext2_inode inode; + int bufsize = IO_BUFSIZE; + int make_holes = 0; + int zero_written = 1; if (common_args_process(argc, argv, 3, 3, "write", " ", CHECK_FS_RW)) @@ -1684,9 +1716,27 @@ void do_write(int argc, char *argv[]) return; } if (LINUX_S_ISREG(inode.i_mode)) { - retval = copy_file(fd, newfile); + if (statbuf.st_blocks < statbuf.st_size / S_BLKSIZE) { + make_holes = 1; + /* + * Use I/O blocksize as buffer size when + * copying sparse files. + */ + bufsize = statbuf.st_blksize; + } + retval = copy_file(fd, newfile, bufsize, make_holes, &zero_written); if (retval) com_err("copy_file", retval, 0); + + if ((inode.i_flags & EXT4_EXTENTS_FL) && zero_written) { + /* + * If no data is copied which indicateds that no write + * happens, we need to turn off the EXT4_EXTENTS_FL. + */ + inode.i_flags &= ~EXT4_EXTENTS_FL; + if (debugfs_write_inode(newfile, &inode, argv[0])) + close(fd); + } } close(fd); }