xfs
[Top] [All Lists]

[PATCH 1/3] xfs_io: add fiemap command to xfs_io

To: xfs@xxxxxxxxxxx
Subject: [PATCH 1/3] xfs_io: add fiemap command to xfs_io
From: Christoph Hellwig <hch@xxxxxxxxxxxxx>
Date: Fri, 04 Mar 2011 19:22:23 -0500
Cc: josef@xxxxxxxxxx
References: <20110305002222.395571492@xxxxxxxxxxxxxxxxxxxxxx>
User-agent: quilt/0.48-1
Add a fiemap command that works almost exactly like bmap, but works on all
filesystem supporting the FIEMAP ioctl.  It is formatted similarly and
takes similar flags, the only thing thats different is obviously it doesn't
pit out AG info and it doesn't make finding prealloc space optional.

Signed-off-by: Josef Bacik <josef@xxxxxxxxxx>
Signed-off-by: Christoph Hellwig <hch@xxxxxx>

diff --git a/configure.in b/configure.in
index 30907de..16441ce 100644
--- a/configure.in
+++ b/configure.in
@@ -103,6 +103,7 @@ AC_HAVE_SENDFILE
 AC_HAVE_GETMNTENT
 AC_HAVE_GETMNTINFO
 AC_HAVE_FALLOCATE
+AC_HAVE_FIEMAP
 AC_HAVE_BLKID_TOPO($enable_blkid)
 
 AC_TYPE_PSINT
diff --git a/include/builddefs.in b/include/builddefs.in
index 93d1e67..f895ed9 100644
--- a/include/builddefs.in
+++ b/include/builddefs.in
@@ -98,6 +98,7 @@ HAVE_SENDFILE = @have_sendfile@
 HAVE_GETMNTENT = @have_getmntent@
 HAVE_GETMNTINFO = @have_getmntinfo@
 HAVE_FALLOCATE = @have_fallocate@
+HAVE_FIEMAP = @have_fiemap@
 
 GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall 
 #         -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
diff --git a/io/Makefile b/io/Makefile
index fc98166..9d79dca 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -44,6 +44,13 @@ else
 LSRCFILES += sendfile.c
 endif
 
+ifeq ($(HAVE_FIEMAP),yes)
+CFILES += fiemap.c
+LCFLAGS += -DHAVE_FIEMAP
+else
+LSRCFILES += fiemap.c
+endif
+
 ifeq ($(PKG_PLATFORM),irix)
 LSRCFILES += inject.c resblks.c
 else
diff --git a/io/fiemap.c b/io/fiemap.c
new file mode 100644
index 0000000..fa990cc
--- /dev/null
+++ b/io/fiemap.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2010 Red Hat, Inc.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it would 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, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <xfs/xfs.h>
+#include <xfs/command.h>
+#include <linux/fiemap.h>
+#include <linux/fs.h>
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t fiemap_cmd;
+
+static void
+fiemap_help(void)
+{
+       printf(_(
+"\n"
+" prints the block mapping for a file's data or attribute forks"
+"\n"
+" Example:\n"
+" 'fiemap -v' - tabular format verbose map\n"
+"\n"
+" fiemap prints the map of disk blocks used by the current file.\n"
+" The map lists each extent used by the file, as well as regions in the\n"
+" file that do not have any corresponding blocks (holes).\n"
+" By default, each line of the listing takes the following form:\n"
+"     extent: [startoffset..endoffset]: startblock..endblock\n"
+" Holes are marked by replacing the startblock..endblock with 'hole'.\n"
+" All the file offsets and disk blocks are in units of 512-byte blocks.\n"
+" -a -- prints the attribute fork map instead of the data fork.\n"
+" -l -- also displays the length of each extent in 512-byte blocks.\n"
+" -n -- query n extents.\n"
+" -v -- Verbose information\n"
+"\n"));
+}
+
+static int
+numlen(
+       __u64   val,
+       int     base)
+{
+       __u64   tmp;
+       int     len;
+
+       for (len = 0, tmp = val; tmp > 0; tmp = tmp/base)
+               len++;
+       return (len == 0 ? 1 : len);
+}
+
+static void
+print_verbose(
+       struct fiemap_extent    *extent,
+       int                     blocksize,
+       int                     foff_w,
+       int                     boff_w,
+       int                     tot_w,
+       int                     flg_w,
+       int                     max_extents,
+       int                     *cur_extent,
+       __u64                   *last_logical)
+{
+       __u64                   lstart;
+       __u64                   len;
+       __u64                   block;
+       char                    lbuf[48];
+       char                    bbuf[48];
+       char                    flgbuf[16];
+
+       lstart = extent->fe_logical / blocksize;
+       len = extent->fe_length / blocksize;
+       block = extent->fe_physical / blocksize;
+
+       memset(lbuf, 0, sizeof(lbuf));
+       memset(bbuf, 0, sizeof(bbuf));
+
+       if (lstart != *last_logical) {
+               snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:", *last_logical,
+                        lstart - 1ULL);
+               printf("%4d: %-*s %-*s %*llu\n", *cur_extent, foff_w, lbuf,
+                      boff_w, _("hole"), tot_w, lstart - *last_logical);
+               (*cur_extent)++;
+               memset(lbuf, 0, sizeof(lbuf));
+       }
+
+       if ((*cur_extent + 1) == max_extents)
+               return;
+
+       snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:", lstart,
+                lstart + len - 1ULL);
+       snprintf(bbuf, sizeof(bbuf), "%llu..%llu", block, block + len - 1ULL);
+       snprintf(flgbuf, sizeof(flgbuf), "0x%x", extent->fe_flags);
+       printf("%4d: %-*s %-*s %*llu %*s\n", *cur_extent, foff_w, lbuf,
+              boff_w, bbuf, tot_w, len, flg_w, flgbuf);
+
+       (*cur_extent)++;
+       *last_logical = lstart + len;
+}
+
+static void
+print_plain(
+       struct fiemap_extent    *extent,
+       int                     lflag,
+       int                     blocksize,
+       int                     max_extents,
+       int                     *cur_extent,
+       __u64                   *last_logical)
+{
+       __u64                   lstart;
+       __u64                   block;
+       __u64                   len;
+
+       lstart = extent->fe_logical / blocksize;
+       len = extent->fe_length / blocksize;
+       block = extent->fe_physical / blocksize;
+
+       if (lstart != *last_logical) {
+               printf("\t%d: [%llu..%llu]: hole", *cur_extent,
+                      *last_logical, lstart - 1ULL);
+               if (lflag)
+                       printf(_(" %llu blocks\n"),
+                              lstart - *last_logical);
+               else
+                       printf("\n");
+               (*cur_extent)++;
+       }
+
+       if ((*cur_extent + 1) == max_extents)
+               return;
+
+       printf("\t%d: [%llu..%llu]: %llu..%llu", *cur_extent,
+              lstart, lstart + len - 1ULL, block,
+              block + len - 1ULL);
+
+       if (lflag)
+               printf(_(" %llu blocks\n"), len);
+       else
+               printf("\n");
+       (*cur_extent)++;
+       *last_logical = lstart + len;
+}
+
+int
+fiemap_f(
+       int             argc,
+       char            **argv)
+{
+       struct fiemap   *fiemap;
+       int             max_extents = 0;
+       int             num_extents = 32;
+       int             last = 0;
+       int             nflag = 0;
+       int             lflag = 0;
+       int             vflag = 0;
+       int             fiemap_flags = FIEMAP_FLAG_SYNC;
+       int             c;
+       int             i;
+       int             map_size;
+       int             ret;
+       int             cur_extent = 0;
+       int             foff_w = 16;    /* 16 just for a good minimum range */
+       int             boff_w = 16;
+       int             tot_w = 5;      /* 5 since its just one number */
+       int             flg_w = 5;
+       __u64           blocksize = 512;
+       __u64           last_logical = 0;
+       struct stat     st;
+
+       while ((c = getopt(argc, argv, "aln:v")) != EOF) {
+               switch (c) {
+               case 'a':
+                       fiemap_flags |= FIEMAP_FLAG_XATTR;
+                       break;
+               case 'l':
+                       lflag = 1;
+                       break;
+               case 'n':
+                       max_extents = atoi(optarg);
+                       nflag = 1;
+                       break;
+               case 'v':
+                       vflag++;
+                       break;
+               default:
+                       return command_usage(&fiemap_cmd);
+               }
+       }
+
+       if (max_extents)
+               num_extents = min(num_extents, max_extents);
+       map_size = sizeof(struct fiemap) +
+               (num_extents * sizeof(struct fiemap_extent));
+       fiemap = malloc(map_size);
+       if (!fiemap) {
+               fprintf(stderr, _("%s: malloc of %d bytes failed.\n"),
+                       progname, map_size);
+               exitcode = 1;
+               return 0;
+       }
+
+       printf("%s:\n", file->name);
+
+       if (vflag) {
+               for (i = 0; i < fiemap->fm_mapped_extents; i++) {
+                       char                    lbuf[32];
+                       char                    bbuf[32];
+                       __u64                   logical;
+                       __u64                   block;
+                       __u64                   len;
+                       struct fiemap_extent    *extent;
+
+                       extent = &fiemap->fm_extents[i];
+                       logical = extent->fe_logical / blocksize;
+                       len = extent->fe_length / blocksize;
+                       block = extent->fe_physical / blocksize;
+
+                       snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]", logical,
+                                logical + len - 1);
+                       snprintf(bbuf, sizeof(bbuf), "%llu..%llu", block,
+                                block + len - 1);
+                       foff_w = max(foff_w, strlen(lbuf));
+                       boff_w = max(boff_w, strlen(bbuf));
+                       tot_w = max(tot_w, numlen(len, 10));
+                       flg_w = max(flg_w, numlen(extent->fe_flags, 16));
+                       if (extent->fe_flags & FIEMAP_EXTENT_LAST)
+                               break;
+               }
+               printf("%4s: %-*s %-*s %*s %*s\n", _("EXT"),
+                      foff_w, _("FILE-OFFSET"),
+                      boff_w, _("BLOCK-RANGE"),
+                      tot_w, _("TOTAL"),
+                      flg_w, _("FLAGS"));
+       }
+
+       while (!last && ((cur_extent + 1) != max_extents)) {
+               if (max_extents)
+                       num_extents = min(num_extents,
+                                         max_extents - (cur_extent + 1));
+
+               memset(fiemap, 0, map_size);
+               fiemap->fm_flags = fiemap_flags;
+               fiemap->fm_start = last_logical;
+               fiemap->fm_length = -1;
+               fiemap->fm_extent_count = num_extents;
+
+               ret = ioctl(file->fd, FS_IOC_FIEMAP, (unsigned long)fiemap);
+               if (ret < 0) {
+                       fprintf(stderr, "%s: ioctl(FS_IOC_FIEMAP) [\"%s\"]: "
+                               "%s\n", progname, file->name, strerror(errno));
+                       free(fiemap);
+                       exitcode = 1;
+                       return 0;
+               }
+
+               /* No more extents to map, exit */
+               if (!fiemap->fm_mapped_extents)
+                       break;
+
+               for (i = 0; i < fiemap->fm_mapped_extents; i++) {
+                       struct fiemap_extent    *extent;
+
+                       extent = &fiemap->fm_extents[i];
+                       if (vflag)
+                               print_verbose(extent, blocksize, foff_w,
+                                             boff_w, tot_w, flg_w,
+                                             max_extents, &cur_extent,
+                                             &last_logical);
+                       else
+                               print_plain(extent, lflag, blocksize,
+                                           max_extents, &cur_extent,
+                                           &last_logical);
+                       if (extent->fe_flags & FIEMAP_EXTENT_LAST) {
+                               last = 1;
+                               break;
+                       }
+
+                       if ((cur_extent + 1) == max_extents)
+                               break;
+               }
+       }
+
+       if ((cur_extent + 1) == max_extents)
+               goto out;
+
+       memset(&st, 0, sizeof(st));
+       if (fstat(file->fd, &st)) {
+               fprintf(stderr, "%s: fstat failed: %s\n", progname,
+                       strerror(errno));
+               free(fiemap);
+               exitcode = 1;
+               return 0;
+       }
+
+       if (cur_extent && last_logical < (st.st_size / blocksize)) {
+               char    lbuf[32];
+
+               snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:",
+                        last_logical, (st.st_size / blocksize) - 1);
+               if (vflag) {
+                       printf("%4d: %-*s %-*s %*llu\n", cur_extent,
+                              foff_w, lbuf, boff_w, _("hole"), tot_w,
+                              (st.st_size / blocksize) - last_logical);
+               } else {
+                       printf("\t%d: %s %s", cur_extent, lbuf,
+                              _("hole"));
+                       if (lflag)
+                               printf(_(" %llu blocks\n"),
+                                      (st.st_size / blocksize) -
+                                      last_logical);
+                       else
+                               printf("\n");
+               }
+       }
+
+out:
+       free(fiemap);
+       return 0;
+}
+
+void
+fiemap_init(void)
+{
+       fiemap_cmd.name = "fiemap";
+       fiemap_cmd.cfunc = fiemap_f;
+       fiemap_cmd.argmin = 0;
+       fiemap_cmd.argmax = -1;
+       fiemap_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
+       fiemap_cmd.args = _("[-alv] [-n nx]");
+       fiemap_cmd.oneline = _("print block mapping for a file");
+       fiemap_cmd.help = fiemap_help;
+
+       add_command(&fiemap_cmd);
+}
diff --git a/io/init.c b/io/init.c
index f8fc25d..a166ad1 100644
--- a/io/init.c
+++ b/io/init.c
@@ -71,6 +71,7 @@ init_commands(void)
        parent_init();
        pread_init();
        prealloc_init();
+       fiemap_init();
        pwrite_init();
        quit_init();
        resblks_init();
diff --git a/io/io.h b/io/io.h
index 630897d..2923362 100644
--- a/io/io.h
+++ b/io/io.h
@@ -135,3 +135,9 @@ extern void         mincore_init(void);
 #else
 #define mincore_init() do { } while (0)
 #endif
+
+#ifdef HAVE_FIEMAP
+extern void            fiemap_init(void);
+#else
+#define fiemap_init()  do { } while (0)
+#endif
diff --git a/m4/package_libcdev.m4 b/m4/package_libcdev.m4
index 1c1859d..8192181 100644
--- a/m4/package_libcdev.m4
+++ b/m4/package_libcdev.m4
@@ -116,3 +116,11 @@ AC_DEFUN([AC_HAVE_FALLOCATE],
        AC_MSG_RESULT(no))
     AC_SUBST(have_fallocate)
   ])
+
+#
+# Check if we have the fiemap ioctl (Linux)
+#
+AC_DEFUN([AC_HAVE_FIEMAP],
+  [ AC_CHECK_HEADERS([linux/fiemap.h], [ have_fiemap=yes ], [ have_fiemap=no ])
+    AC_SUBST(have_fiemap)
+  ])
-- 
1.6.6.1

_______________________________________________
xfs mailing list
xfs@xxxxxxxxxxx
http://oss.sgi.com/mailman/listinfo/xfs


<Prev in Thread] Current Thread [Next in Thread>