From patchwork Tue Sep 17 15:30:52 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Holton X-Patchwork-Id: 2902901 Return-Path: X-Original-To: patchwork-linux-btrfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id C7C1C9F1E3 for ; Tue, 17 Sep 2013 15:31:06 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C624C202DD for ; Tue, 17 Sep 2013 15:31:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2BC912016A for ; Tue, 17 Sep 2013 15:31:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753343Ab3IQPaz (ORCPT ); Tue, 17 Sep 2013 11:30:55 -0400 Received: from mail-ve0-f177.google.com ([209.85.128.177]:57755 "EHLO mail-ve0-f177.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753238Ab3IQPax (ORCPT ); Tue, 17 Sep 2013 11:30:53 -0400 Received: by mail-ve0-f177.google.com with SMTP id db12so4226860veb.22 for ; Tue, 17 Sep 2013 08:30:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=UzsO/8PDxEExK4w2W8np5PiiAXRFSeSyhP8Y//Fv5vo=; b=hrL6PgbcXeRtOZCTUMLBI8rgE6PbEjWYJILQav3lCyU5Sxh+1uKFzXyHQl9QQgMYZf kiACu0PNeNDBG4eRtlK+MQnjdRSC4mRmu5Q8pcAuHNOMqM+TKBfjfLVRoi9jVPibLDyW 4mogBntvlnF7WnaNL3cVT/Y6deyczVhb/gON8rOEa/pekPXljPobpwCtv0xDCOu+1Gmc chqDAZNXeCc11XS/laqYGXXfYHQVUkkKIssm9kKVYxfYzv95qrbilENLgn75wLKt1EDl vuzHnVsJr33ini3Q9u7BqcaPyLR5cHUqQB4MvHKEFh7FtWq47m+EhemzJMbpkwMA7PQF kBfw== MIME-Version: 1.0 X-Received: by 10.221.53.74 with SMTP id vp10mr80044vcb.54.1379431852764; Tue, 17 Sep 2013 08:30:52 -0700 (PDT) Received: by 10.58.208.137 with HTTP; Tue, 17 Sep 2013 08:30:52 -0700 (PDT) Date: Tue, 17 Sep 2013 11:30:52 -0400 Message-ID: Subject: Re: [RFC v2] btrfs-progs: Add recursive defrag using -r option From: Frank Holton To: dsterba@suse.cz, Frank Holton , linux-btrfs@vger.kernel.org Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Spam-Status: No, score=-7.4 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Thanks for that hint to use ftw. I've updated the code to use it and tried to make sure that I caught all of the styling errors. Since the ftw callback doesn't take any additional options I had to add several global variables to pass the fancy_ioctl and range parameters. Should I replace all of the uses of those variables with the globals or just copy into the globals like I did in the code below. It does not attempt to defrag directories anymore in the recursive mode, however, the non recursive mode will still attempt to defrag directories. I figured since that only works when you run as root that it is acceptable for now. Thanks again for looking over it. - Frank --- cmds-filesystem.c | 119 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 96 insertions(+), 23 deletions(-) int fd; @@ -349,7 +403,8 @@ static int cmd_defrag(int argc, char **argv) u64 len = (u64)-1; u32 thresh = 0; int i; - int errors = 0; + int recursive = 0; + global_errors = 0; int ret = 0; int verbose = 0; int fancy_ioctl = 0; @@ -359,7 +414,7 @@ static int cmd_defrag(int argc, char **argv) optind = 1; while(1) { - int c = getopt(argc, argv, "vc::fs:l:t:"); + int c = getopt(argc, argv, "vrc::fs:l:t:"); if (c < 0) break; @@ -389,6 +444,9 @@ static int cmd_defrag(int argc, char **argv) thresh = parse_size(optarg); fancy_ioctl = 1; break; + case 'r': + recursive = 1; + break; default: usage(cmd_defrag_usage); } @@ -407,47 +465,62 @@ static int cmd_defrag(int argc, char **argv) } if (flush) range.flags |= BTRFS_DEFRAG_RANGE_START_IO; + + memcpy(&global_range, &range, sizeof(range)); + global_verbose = verbose; + global_fancy_ioctl = fancy_ioctl; for (i = optind; i < argc; i++) { - if (verbose) - printf("%s\n", argv[i]); fd = open_file_or_dir(argv[i]); if (fd < 0) { - fprintf(stderr, "failed to open %s\n", argv[i]); + fprintf(stderr, "ERROR: failed to open %s\n", argv[i]); perror("open:"); - errors++; + global_errors++; continue; } - if (!fancy_ioctl) { - ret = ioctl(fd, BTRFS_IOC_DEFRAG, NULL); - e=errno; - } else { - ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &range); - if (ret && errno == ENOTTY) { - fprintf(stderr, "ERROR: defrag range ioctl not " - "supported in this kernel, please try " - "without any options.\n"); - errors++; - close(fd); - break; + if (recursive) { + struct stat st; + fstat(fd, &st); + if (S_ISDIR(st.st_mode)) { + ret = ftw(argv[i], defrag_callback, 10); + if (ret == ENOTTY) + exit(1); + /* errors are handled in the callback */ + ret = 0; + } else { + if (verbose) + printf("%s\n", argv[i]); + ret = do_defrag(fd, fancy_ioctl, &range); + e = errno; } + } else { + if (verbose) + printf("%s\n", argv[i]); + ret = do_defrag(fd, fancy_ioctl, &range); e = errno; } + close(fd); + if (ret && e == ENOTTY) { + fprintf(stderr, "ERROR: defrag range ioctl not " + "supported in this kernel, please try " + "without any options.\n"); + global_errors++; + break; + } if (ret) { fprintf(stderr, "ERROR: defrag failed on %s - %s\n", argv[i], strerror(e)); - errors++; + global_errors++; } - close(fd); } if (verbose) printf("%s\n", BTRFS_BUILD_VERSION); - if (errors) { - fprintf(stderr, "total %d failures\n", errors); + if (global_errors) { + fprintf(stderr, "total %d failures\n", global_errors); exit(1); } - return errors; + return 0; } static const char * const cmd_resize_usage[] = { diff --git a/cmds-filesystem.c b/cmds-filesystem.c index f41a72a..9635066 100644 --- a/cmds-filesystem.c +++ b/cmds-filesystem.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "kerncompat.h" #include "ctree.h" @@ -333,6 +335,7 @@ static const char * const cmd_defrag_usage[] = { "Defragment a file or a directory", "", "-v be verbose", + "-r defragment files recursively", "-c[zlib,lzo] compress the file while defragmenting", "-f flush data to disk immediately after defragmenting", "-s start defragment only from byte onward", @@ -341,6 +344,57 @@ static const char * const cmd_defrag_usage[] = { NULL }; +static int do_defrag(int fd, int fancy_ioctl, + struct btrfs_ioctl_defrag_range_args *range) +{ + int ret; + + if (!fancy_ioctl) { + ret = ioctl(fd, BTRFS_IOC_DEFRAG, NULL); + } else { + ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, range); + } + return ret; +} + +static int global_fancy_ioctl; +static struct btrfs_ioctl_defrag_range_args global_range; +static int global_verbose; +static int global_errors; +static int defrag_callback(const char *fpath, const struct stat *sb, int typeflag) +{ + int ret = 0; + int e = 0; + int fd = 0; + + if (typeflag == FTW_F) { + if (global_verbose) + printf("%s\n", fpath); + fd = open(fpath,O_RDWR); + e = errno; + if (fd < 0) + goto error; + ret = do_defrag(fd, global_fancy_ioctl, &global_range); + e = errno; + close(fd); + if (ret && e == ENOTTY) { + fprintf(stderr, "ERROR: defrag range ioctl not " + "supported in this kernel, please try " + "without any options.\n"); + global_errors++; + return ENOTTY; + } + if (ret) + goto error; + } + return 0; + +error: + fprintf(stderr, "ERROR: defrag failed on %s - %s\n", fpath, strerror(e)); + global_errors++; + return 0; +} + static int cmd_defrag(int argc, char **argv) {