On Wed, Jun 21, 2017 at 03:51:24PM -0500, Eric Sandeen wrote: > On 6/15/17 3:36 PM, Darrick J. Wong wrote: > > From: Darrick J. Wong <darrick.wong@xxxxxxxxxx> > > > > Plumb in all the pieces we need to have xfs_io query the GETFSMAP ioctl > > for an arbitrary filesystem. > > > > Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx> > > With minor changes mentioned below which I'll take care of > if you approve, > > Reviewed-by: Eric Sandeen <sandeen@xxxxxxxxxx> > > > --- > > io/Makefile | 7 + > > io/copy_file_range.c | 2 > > io/encrypt.c | 1 > > io/fsmap.c | 588 ++++++++++++++++++++++++++++++++++++++++++++++++++ > > io/init.c | 8 + > > io/io.h | 14 + > > io/open.c | 21 +- > > io/pwrite.c | 2 > > io/reflink.c | 4 > > io/sendfile.c | 2 > > man/man8/xfs_io.8 | 99 ++++++++ > > 11 files changed, 735 insertions(+), 13 deletions(-) > > create mode 100644 io/fsmap.c > > > > > > diff --git a/io/Makefile b/io/Makefile > > index 435ccff..47b0a66 100644 > > --- a/io/Makefile > > +++ b/io/Makefile > > @@ -99,6 +99,13 @@ ifeq ($(HAVE_MREMAP),yes) > > LCFLAGS += -DHAVE_MREMAP > > endif > > > > +# On linux we get fsmap from the system or define it ourselves > > +# so include this based on platform type. If this reverts to only > > +# the autoconf check w/o local definition, change to testing HAVE_GETFSMAP > > +ifeq ($(PKG_PLATFORM),linux) > > +CFILES += fsmap.c > > +endif > > + > > default: depend $(LTCOMMAND) > > > > include $(BUILDRULES) > > diff --git a/io/copy_file_range.c b/io/copy_file_range.c > > index 249c649..d1dfc5a 100644 > > --- a/io/copy_file_range.c > > +++ b/io/copy_file_range.c > > @@ -121,7 +121,7 @@ copy_range_f(int argc, char **argv) > > if (optind != argc - 1) > > return command_usage(©_range_cmd); > > > > - fd = openfile(argv[optind], NULL, IO_READONLY, 0); > > + fd = openfile(argv[optind], NULL, IO_READONLY, 0, NULL); > > if (fd < 0) > > return 0; > > > > diff --git a/io/encrypt.c b/io/encrypt.c > > index d844c5e..26ab97c 100644 > > --- a/io/encrypt.c > > +++ b/io/encrypt.c > > @@ -20,6 +20,7 @@ > > #include "platform_defs.h" > > #include "command.h" > > #include "init.h" > > +#include "path.h" > > #include "io.h" > > > > #ifndef ARRAY_SIZE > > diff --git a/io/fsmap.c b/io/fsmap.c > > new file mode 100644 > > index 0000000..25c0e76 > > --- /dev/null > > +++ b/io/fsmap.c > > @@ -0,0 +1,588 @@ > > +/* > > + * Copyright (C) 2017 Oracle. All Rights Reserved. > > + * > > + * Author: Darrick J. Wong <darrick.wong@xxxxxxxxxx> > > + * > > + * 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 2 > > + * of the License, or (at your option) any later version. > > + * > > + * 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 "platform_defs.h" > > +#include "command.h" > > +#include "init.h" > > +#include "path.h" > > +#include "io.h" > > +#include "input.h" > > + > > +static cmdinfo_t fsmap_cmd; > > +static dev_t xfs_data_dev; > > + > > +static void > > +fsmap_help(void) > > +{ > > + printf(_( > > +"\n" > > +" Prints the block mapping for a filesystem" > > "for the filesystem hosting the current file?" Yes. > > +"\n" > > +" fsmap prints the map of disk blocks used by the whole filesystem.\n" > > +" When possible, owner and offset information will be included in the\n" > > +" sapce report.\n" > > space report Yep. > > +"\n" > > +" By default, each line of the listing takes the following form:\n" > > +" extent: major:minor [startblock..endblock]: owner startoffset..endoffset length\n" > > +" The owner field is either an inode number or a special value.\n" > > +" All the file offsets and disk blocks are in units of 512-byte blocks.\n" > > +" -d -- query only the data device (default).\n" > > +" -l -- query only the log device.\n" > > +" -r -- query only the realtime device.\n" > > +"-m -- machine readable output format.\n" Ugh, did this fall out again? <grugmgajghagh> All looks fine to me. --D > > +" -n -- query n extents at a time.\n" > > +" -v -- Verbose information, show AG and offsets. Show flags legend on 2nd -v\n" > > +"\n")); > > +} > > + > > +#define OWNER_BUF_SZ 32 > > +static const char * > > +special_owner( > > + int64_t owner, > > + char *buf) > > +{ > > + switch (owner) { > > + case XFS_FMR_OWN_FREE: > > + return _("free space"); > > + case XFS_FMR_OWN_UNKNOWN: > > + return _("unknown"); > > + case XFS_FMR_OWN_FS: > > + return _("static fs metadata"); > > + case XFS_FMR_OWN_LOG: > > + return _("journalling log"); > > + case XFS_FMR_OWN_AG: > > + return _("per-AG metadata"); > > + case XFS_FMR_OWN_INOBT: > > + return _("inode btree"); > > + case XFS_FMR_OWN_INODES: > > + return _("inodes"); > > + case XFS_FMR_OWN_REFC: > > + return _("refcount btree"); > > + case XFS_FMR_OWN_COW: > > + return _("cow reservation"); > > + case XFS_FMR_OWN_DEFECTIVE: > > + return _("defective"); > > + default: > > + snprintf(buf, OWNER_BUF_SZ, _("special %u:%u"), > > + FMR_OWNER_TYPE(owner), FMR_OWNER_CODE(owner)); > > + return buf; > > + } > > +} > > + > > +static void > > +dump_map( > > + unsigned long long *nr, > > + struct fsmap_head *head) > > +{ > > + unsigned long long i; > > + struct fsmap *p; > > + char owner[OWNER_BUF_SZ]; > > + char *fork; > > + > > + for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) { > > + printf("\t%llu: %u:%u [%lld..%lld]: ", i + (*nr), > > + major(p->fmr_device), minor(p->fmr_device), > > + (long long)BTOBBT(p->fmr_physical), > > + (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1)); > > + fork = (p->fmr_flags & FMR_OF_ATTR_FORK) ? _("attr") : _("data"); > > + if (p->fmr_flags & FMR_OF_SPECIAL_OWNER) > > + printf("%s", special_owner(p->fmr_owner, owner)); > > + else if (p->fmr_flags & FMR_OF_EXTENT_MAP) > > + printf(_("inode %lld %s extent map"), > > + (long long) p->fmr_owner, fork); > > + else > > + printf(_("inode %lld %s %lld..%lld"), > > + (long long)p->fmr_owner, fork, > > + (long long)BTOBBT(p->fmr_offset), > > + (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1)); > > + printf(_(" %lld\n"), > > + (long long)BTOBBT(p->fmr_length)); > > + } > > + > > + (*nr) += head->fmh_entries; > > +} > > + > > +static void > > +dump_map_machine( > > + unsigned long long *nr, > > + struct fsmap_head *head) > > +{ > > + unsigned long long i; > > + struct fsmap *p; > > + char *fork; > > + > > + printf(_("EXT,MAJOR,MINOR,PSTART,PEND,OWNER,OSTART,OEND,LENGTH\n")); > > + for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) { > > + printf("%llu,%u,%u,%lld,%lld,", i + (*nr), > > + major(p->fmr_device), minor(p->fmr_device), > > + (long long)BTOBBT(p->fmr_physical), > > + (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1)); > > + fork = (p->fmr_flags & FMR_OF_ATTR_FORK) ? "attr" : "data"; > > + if (p->fmr_flags & FMR_OF_SPECIAL_OWNER) > > + printf("special_%u:%u,,,", FMR_OWNER_TYPE(p->fmr_owner), > > + FMR_OWNER_CODE(p->fmr_owner)); > > + else if (p->fmr_flags & FMR_OF_EXTENT_MAP) > > + printf(_("inode_%lld_%s_bmbt,,,"), > > + (long long) p->fmr_owner, fork); > > + else > > + printf(_("inode_%lld_%s,%lld,%lld,"), > > + (long long)p->fmr_owner, fork, > > + (long long)BTOBBT(p->fmr_offset), > > + (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1)); > > + printf("%lld\n", > > + (long long)BTOBBT(p->fmr_length)); > > + } > > + > > + (*nr) += head->fmh_entries; > > +} > > + > > +/* > > + * Verbose mode displays: > > + * extent: major:minor [startblock..endblock]: startoffset..endoffset \ > > + * ag# (agoffset..agendoffset) totalbbs flags > > + */ > > +#define MINRANGE_WIDTH 16 > > +#define MINAG_WIDTH 2 > > +#define MINTOT_WIDTH 5 > > +#define NFLG 7 /* count of flags */ > > +#define FLG_NULL 00000000 /* Null flag */ > > +#define FLG_ATTR_FORK 01000000 /* attribute fork */ > > +#define FLG_SHARED 00100000 /* shared extent */ > > +#define FLG_PRE 00010000 /* Unwritten extent */ > > +#define FLG_BSU 00001000 /* Not on begin of stripe unit */ > > +#define FLG_ESU 00000100 /* Not on end of stripe unit */ > > +#define FLG_BSW 00000010 /* Not on begin of stripe width */ > > +#define FLG_ESW 00000001 /* Not on end of stripe width */ > > +static void > > +dump_map_verbose( > > + unsigned long long *nr, > > + struct fsmap_head *head, > > + bool *dumped_flags, > > + struct xfs_fsop_geom *fsgeo) > > +{ > > + unsigned long long i; > > + struct fsmap *p; > > + int agno; > > + off64_t agoff, bperag; > > + int foff_w, boff_w, aoff_w, tot_w, agno_w, own_w; > > + int nr_w, dev_w; > > + char rbuf[32], bbuf[32], abuf[32], obuf[32]; > > + char nbuf[32], dbuf[32], gbuf[32]; > > + char owner[OWNER_BUF_SZ]; > > + int sunit, swidth; > > + int flg = 0; > > + > > + foff_w = boff_w = aoff_w = own_w = MINRANGE_WIDTH; > > + dev_w = 3; > > + nr_w = 4; > > + tot_w = MINTOT_WIDTH; > > + bperag = (off64_t)fsgeo->agblocks * > > + (off64_t)fsgeo->blocksize; > > + sunit = (fsgeo->sunit * fsgeo->blocksize); > > + swidth = (fsgeo->swidth * fsgeo->blocksize); > > + > > + /* > > + * Go through the extents and figure out the width > > + * needed for all columns. > > + */ > > + for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) { > > + if (p->fmr_flags & FMR_OF_PREALLOC || > > + p->fmr_flags & FMR_OF_ATTR_FORK || > > + p->fmr_flags & FMR_OF_SHARED) > > + flg = 1; > > + if (sunit && > > + (p->fmr_physical % sunit != 0 || > > + ((p->fmr_physical + p->fmr_length) % sunit) != 0 || > > + p->fmr_physical % swidth != 0 || > > + ((p->fmr_physical + p->fmr_length) % swidth) != 0)) > > + flg = 1; > > + if (flg) > > + *dumped_flags = true; > > + snprintf(nbuf, sizeof(nbuf), "%llu", (*nr) + i); > > + nr_w = max(nr_w, strlen(nbuf)); > > + if (head->fmh_oflags & FMH_OF_DEV_T) > > + snprintf(dbuf, sizeof(dbuf), "%u:%u", > > + major(p->fmr_device), > > + minor(p->fmr_device)); > > + else > > + snprintf(dbuf, sizeof(dbuf), "0x%x", p->fmr_device); > > + dev_w = max(dev_w, strlen(dbuf)); > > + snprintf(bbuf, sizeof(bbuf), "[%lld..%lld]:", > > + (long long)BTOBBT(p->fmr_physical), > > + (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1)); > > + boff_w = max(boff_w, strlen(bbuf)); > > + if (p->fmr_flags & FMR_OF_SPECIAL_OWNER) > > + own_w = max(own_w, strlen( > > + special_owner(p->fmr_owner, owner))); > > + else { > > + snprintf(obuf, sizeof(obuf), "%lld", > > + (long long)p->fmr_owner); > > + own_w = max(own_w, strlen(obuf)); > > + } > > + if (p->fmr_flags & FMR_OF_EXTENT_MAP) > > + foff_w = max(foff_w, strlen(_("extent_map"))); > > + else if (p->fmr_flags & FMR_OF_SPECIAL_OWNER) > > + ; > > + else { > > + snprintf(rbuf, sizeof(rbuf), "%lld..%lld", > > + (long long)BTOBBT(p->fmr_offset), > > + (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1)); > > + foff_w = max(foff_w, strlen(rbuf)); > > + } > > + if (p->fmr_device == xfs_data_dev) { > > + agno = p->fmr_physical / bperag; > > + agoff = p->fmr_physical - (agno * bperag); > > + snprintf(abuf, sizeof(abuf), > > + "(%lld..%lld)", > > + (long long)BTOBBT(agoff), > > + (long long)BTOBBT(agoff + p->fmr_length - 1)); > > + } else > > + abuf[0] = 0; > > + aoff_w = max(aoff_w, strlen(abuf)); > > + tot_w = max(tot_w, > > + numlen(BTOBBT(p->fmr_length), 10)); > > + } > > + agno_w = max(MINAG_WIDTH, numlen(fsgeo->agcount, 10)); > > + if (*nr == 0) > > + printf("%*s: %-*s %-*s %-*s %-*s %*s %-*s %*s%s\n", > > + nr_w, _("EXT"), > > + dev_w, _("DEV"), > > + boff_w, _("BLOCK-RANGE"), > > + own_w, _("OWNER"), > > + foff_w, _("FILE-OFFSET"), > > + agno_w, _("AG"), > > + aoff_w, _("AG-OFFSET"), > > + tot_w, _("TOTAL"), > > + flg ? _(" FLAGS") : ""); > > + for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) { > > + flg = FLG_NULL; > > + if (p->fmr_flags & FMR_OF_PREALLOC) > > + flg |= FLG_PRE; > > + if (p->fmr_flags & FMR_OF_ATTR_FORK) > > + flg |= FLG_ATTR_FORK; > > + if (p->fmr_flags & FMR_OF_SHARED) > > + flg |= FLG_SHARED; > > + /* > > + * If striping enabled, determine if extent starts/ends > > + * on a stripe unit boundary. > > + */ > > + if (sunit) { > > + if (p->fmr_physical % sunit != 0) > > + flg |= FLG_BSU; > > + if (((p->fmr_physical + > > + p->fmr_length ) % sunit ) != 0) > > + flg |= FLG_ESU; > > + if (p->fmr_physical % swidth != 0) > > + flg |= FLG_BSW; > > + if (((p->fmr_physical + > > + p->fmr_length ) % swidth ) != 0) > > + flg |= FLG_ESW; > > + } > > + if (head->fmh_oflags & FMH_OF_DEV_T) > > + snprintf(dbuf, sizeof(dbuf), "%u:%u", > > + major(p->fmr_device), > > + minor(p->fmr_device)); > > + else > > + snprintf(dbuf, sizeof(dbuf), "0x%x", p->fmr_device); > > + snprintf(bbuf, sizeof(bbuf), "[%lld..%lld]:", > > + (long long)BTOBBT(p->fmr_physical), > > + (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1)); > > + if (p->fmr_flags & FMR_OF_SPECIAL_OWNER) { > > + snprintf(obuf, sizeof(obuf), "%s", > > + special_owner(p->fmr_owner, owner)); > > + snprintf(rbuf, sizeof(rbuf), " "); > > + } else { > > + snprintf(obuf, sizeof(obuf), "%lld", > > + (long long)p->fmr_owner); > > + snprintf(rbuf, sizeof(rbuf), "%lld..%lld", > > + (long long)BTOBBT(p->fmr_offset), > > + (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1)); > > + } > > + if (p->fmr_device == xfs_data_dev) { > > + agno = p->fmr_physical / bperag; > > + agoff = p->fmr_physical - (agno * bperag); > > + snprintf(abuf, sizeof(abuf), > > + "(%lld..%lld)", > > + (long long)BTOBBT(agoff), > > + (long long)BTOBBT(agoff + p->fmr_length - 1)); > > + snprintf(gbuf, sizeof(gbuf), > > + "%lld", > > + (long long)agno); > > + } else { > > + abuf[0] = 0; > > + gbuf[0] = 0; > > + } > > + if (p->fmr_flags & FMR_OF_EXTENT_MAP) > > + printf("%*llu: %-*s %-*s %-*s %-*s %-*s %-*s %*lld\n", > > + nr_w, (*nr) + i, > > + dev_w, dbuf, > > + boff_w, bbuf, > > + own_w, obuf, > > + foff_w, _("extent map"), > > + agno_w, gbuf, > > + aoff_w, abuf, > > + tot_w, (long long)BTOBBT(p->fmr_length)); > > + else { > > + printf("%*llu: %-*s %-*s %-*s %-*s", nr_w, (*nr) + i, > > + dev_w, dbuf, boff_w, bbuf, own_w, obuf, > > + foff_w, rbuf); > > + printf(" %-*s %-*s", agno_w, gbuf, > > + aoff_w, abuf); > > + printf(" %*lld", tot_w, > > + (long long)BTOBBT(p->fmr_length)); > > + if (flg == FLG_NULL) > > + printf("\n"); > > + else > > + printf(" %-*.*o\n", NFLG, NFLG, flg); > > + } > > + } > > + > > + (*nr) += head->fmh_entries; > > +} > > + > > +static void > > +dump_verbose_key(void) > > +{ > > + printf(_(" FLAG Values:\n")); > > + printf(_(" %*.*o Attribute fork\n"), > > + NFLG+1, NFLG+1, FLG_ATTR_FORK); > > + printf(_(" %*.*o Shared extent\n"), > > + NFLG+1, NFLG+1, FLG_SHARED); > > + printf(_(" %*.*o Unwritten preallocated extent\n"), > > + NFLG+1, NFLG+1, FLG_PRE); > > + printf(_(" %*.*o Doesn't begin on stripe unit\n"), > > + NFLG+1, NFLG+1, FLG_BSU); > > + printf(_(" %*.*o Doesn't end on stripe unit\n"), > > + NFLG+1, NFLG+1, FLG_ESU); > > + printf(_(" %*.*o Doesn't begin on stripe width\n"), > > + NFLG+1, NFLG+1, FLG_BSW); > > + printf(_(" %*.*o Doesn't end on stripe width\n"), > > + NFLG+1, NFLG+1, FLG_ESW); > > +} > > + > > +int > > +fsmap_f( > > + int argc, > > + char **argv) > > +{ > > + struct fsmap *p; > > + struct fsmap_head *nhead; > > + struct fsmap_head *head; > > + struct fsmap *l, *h; > > + struct xfs_fsop_geom fsgeo; > > + long long start = 0; > > + long long end = -1; > > + int nmap_size; > > + int map_size; > > + int nflag = 0; > > + int vflag = 0; > > + int mflag = 0; > > + int i = 0; > > + int c; > > + unsigned long long nr = 0; > > + size_t fsblocksize, fssectsize; > > + struct fs_path *fs; > > + static bool tab_init; > > + bool dumped_flags = false; > > + int dflag, lflag, rflag; > > + > > + init_cvtnum(&fsblocksize, &fssectsize); > > + > > + dflag = lflag = rflag = 0; > > + while ((c = getopt(argc, argv, "dlmn:rv")) != EOF) { > > + switch (c) { > > + case 'd': /* data device */ > > + dflag = 1; > > + break; > > + case 'l': /* log device */ > > + lflag = 1; > > + break; > > + case 'm': /* machine readable format */ > > + mflag++; > > + break; > > + case 'n': /* number of extents specified */ > > + nflag = cvt_u32(optarg, 10); > > + if (errno) > > + return command_usage(&fsmap_cmd); > > + break; > > + case 'r': /* rt device */ > > + rflag = 1; > > + break; > > + case 'v': /* Verbose output */ > > + vflag++; > > + break; > > + default: > > + return command_usage(&fsmap_cmd); > > + } > > + } > > + > > + if ((dflag + lflag + rflag > 1) || (mflag > 0 && vflag > 0) || > > + (argc > optind && dflag + lflag + rflag == 0)) > > + return command_usage(&fsmap_cmd); > > + > > + if (argc > optind) { > > + start = cvtnum(fsblocksize, fssectsize, argv[optind]); > > + if (start < 0) { > > + fprintf(stderr, > > + _("Bad rmap start_bblock %s.\n"), > > + argv[optind]); > > + return 0; > > + } > > + start <<= BBSHIFT; > > + } > > + > > + if (argc > optind + 1) { > > + end = cvtnum(fsblocksize, fssectsize, argv[optind + 1]); > > + if (end < 0) { > > + fprintf(stderr, > > + _("Bad rmap end_bblock %s.\n"), > > + argv[optind + 1]); > > + return 0; > > + } > > + end <<= BBSHIFT; > > + } > > + > > + if (vflag) { > > + c = ioctl(file->fd, XFS_IOC_FSGEOMETRY, &fsgeo); > > + if (c < 0) { > > + fprintf(stderr, > > + _("%s: can't get geometry [\"%s\"]: %s\n"), > > + progname, file->name, strerror(errno)); > > + exitcode = 1; > > + return 0; > > + } > > + } > > + > > + map_size = nflag ? nflag : 131072 / sizeof(struct fsmap); > > + head = malloc(fsmap_sizeof(map_size)); > > + if (head == NULL) { > > + fprintf(stderr, _("%s: malloc of %zu bytes failed.\n"), > > + progname, fsmap_sizeof(map_size)); > > + exitcode = 1; > > + return 0; > > + } > > + > > + memset(head, 0, sizeof(*head)); > > + l = head->fmh_keys; > > + h = head->fmh_keys + 1; > > + if (dflag) { > > + l->fmr_device = h->fmr_device = file->fs_path.fs_datadev; > > + } else if (lflag) { > > + l->fmr_device = h->fmr_device = file->fs_path.fs_logdev; > > + } else if (rflag) { > > + l->fmr_device = h->fmr_device = file->fs_path.fs_rtdev; > > + } else { > > + l->fmr_device = 0; > > + h->fmr_device = UINT_MAX; > > + } > > + l->fmr_physical = start; > > + h->fmr_physical = end; > > + h->fmr_owner = ULLONG_MAX; > > + h->fmr_flags = UINT_MAX; > > + h->fmr_offset = ULLONG_MAX; > > + > > + /* Count mappings */ > > + if (!nflag) { > > + head->fmh_count = 0; > > + i = ioctl(file->fd, FS_IOC_GETFSMAP, head); > > + if (i < 0) { > > + fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETFSMAP)" > > + " iflags=0x%x [\"%s\"]: %s\n"), > > + progname, head->fmh_iflags, file->name, > > + strerror(errno)); > > + free(head); > > + exitcode = 1; > > + return 0; > > + } > > + if (head->fmh_entries > map_size + 2) { > > + map_size = 11ULL * head->fmh_entries / 10; > > + nmap_size = map_size > (1 << 24) ? (1 << 24) : map_size; > > + nhead = realloc(head, fsmap_sizeof(nmap_size)); > > + if (nhead == NULL) { > > + fprintf(stderr, > > + _("%s: cannot realloc %zu bytes\n"), > > + progname, fsmap_sizeof(nmap_size)); > > + } else { > > + head = nhead; > > + map_size = nmap_size; > > + } > > + } > > + } > > + > > + /* > > + * If this is an XFS filesystem, remember the data device. > > + * (We report AG number/block for data device extents on XFS). > > + */ > > + if (!tab_init) { > > + fs_table_initialise(0, NULL, 0, NULL); > > + tab_init = true; > > + } > > + fs = fs_table_lookup(file->name, FS_MOUNT_POINT); > > + xfs_data_dev = fs ? fs->fs_datadev : 0; > > + > > + head->fmh_count = map_size; > > + do { > > + /* Get some extents */ > > + i = ioctl(file->fd, FS_IOC_GETFSMAP, head); > > + if (i < 0) { > > + fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETFSMAP)" > > + " iflags=0x%x [\"%s\"]: %s\n"), > > + progname, head->fmh_iflags, file->name, > > + strerror(errno)); > > + free(head); > > + exitcode = 1; > > + return 0; > > + } > > + > > + if (head->fmh_entries == 0) > > + break; > > + > > + if (vflag) > > + dump_map_verbose(&nr, head, &dumped_flags, &fsgeo); > > + else if (mflag) > > + dump_map_machine(&nr, head); > > + else > > + dump_map(&nr, head); > > + > > + p = &head->fmh_recs[head->fmh_entries - 1]; > > + if (p->fmr_flags & FMR_OF_LAST) > > + break; > > + fsmap_advance(head); > > + } while (true); > > + > > + if (dumped_flags) > > + dump_verbose_key(); > > + > > + free(head); > > + return 0; > > +} > > + > > +void > > +fsmap_init(void) > > +{ > > + fsmap_cmd.name = "fsmap"; > > + fsmap_cmd.cfunc = fsmap_f; > > + fsmap_cmd.argmin = 0; > > + fsmap_cmd.argmax = -1; > > + fsmap_cmd.flags = CMD_NOMAP_OK | CMD_FLAG_FOREIGN_OK; > > + fsmap_cmd.args = _("[-d|-l|-r] [-m|-v] [-n nx] [start] [end]"); > > + fsmap_cmd.oneline = _("print filesystem mapping for a range of blocks"); > > + fsmap_cmd.help = fsmap_help; > > + > > + add_command(&fsmap_cmd); > > +} > > diff --git a/io/init.c b/io/init.c > > index c15a1e1..20d5f80 100644 > > --- a/io/init.c > > +++ b/io/init.c > > @@ -66,6 +66,7 @@ init_commands(void) > > file_init(); > > flink_init(); > > freeze_init(); > > + fsmap_init(); > > fsync_init(); > > getrusage_init(); > > help_init(); > > @@ -139,6 +140,7 @@ init( > > char *sp; > > mode_t mode = 0600; > > xfs_fsop_geom_t geometry = { 0 }; > > + struct fs_path fsp; > > > > progname = basename(argv[0]); > > setlocale(LC_ALL, ""); > > @@ -148,6 +150,7 @@ init( > > pagesize = getpagesize(); > > gettimeofday(&stopwatch, NULL); > > > > + fs_table_initialise(0, NULL, 0, NULL); > > while ((c = getopt(argc, argv, "ac:C:dFfim:p:nrRstTVx")) != EOF) { > > switch (c) { > > case 'a': > > @@ -212,11 +215,12 @@ init( > > } > > > > while (optind < argc) { > > - if ((c = openfile(argv[optind], &geometry, flags, mode)) < 0) > > + c = openfile(argv[optind], &geometry, flags, mode, &fsp); > > + if (c < 0) > > exit(1); > > if (!platform_test_xfs_fd(c)) > > flags |= IO_FOREIGN; > > - if (addfile(argv[optind], c, &geometry, flags) < 0) > > + if (addfile(argv[optind], c, &geometry, flags, &fsp) < 0) > > exit(1); > > optind++; > > } > > diff --git a/io/io.h b/io/io.h > > index 952bdb8..6a0fe65 100644 > > --- a/io/io.h > > +++ b/io/io.h > > @@ -17,6 +17,7 @@ > > */ > > > > #include "xfs.h" > > +#include "path.h" > > > > /* > > * Read/write patterns (default is always "forward") > > @@ -47,6 +48,7 @@ typedef struct fileio { > > int flags; /* flags describing file state */ > > char *name; /* file name at time of open */ > > xfs_fsop_geom_t geom; /* XFS filesystem geometry */ > > + struct fs_path fs_path; /* XFS path information */ > > } fileio_t; > > > > extern fileio_t *filetable; /* open file table */ > > @@ -76,8 +78,10 @@ extern void *check_mapping_range(mmap_region_t *, off64_t, size_t, int); > > */ > > > > extern off64_t filesize(void); > > -extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t); > > -extern int addfile(char *, int , xfs_fsop_geom_t *, int); > > +extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t, > > + struct fs_path *); > > +extern int addfile(char *, int , xfs_fsop_geom_t *, int, > > + struct fs_path *); > > extern void printxattr(uint, int, int, const char *, int, int); > > > > extern unsigned int recurse_all; > > @@ -174,3 +178,9 @@ extern void readdir_init(void); > > extern void reflink_init(void); > > > > extern void cowextsize_init(void); > > + > > +#ifdef HAVE_GETFSMAP > > +extern void fsmap_init(void); > > +#else > > +# define fsmap_init() do { } while (0) > > +#endif > > diff --git a/io/open.c b/io/open.c > > index 2ed55cf..b50f068 100644 > > --- a/io/open.c > > +++ b/io/open.c > > @@ -52,8 +52,10 @@ openfile( > > char *path, > > xfs_fsop_geom_t *geom, > > int flags, > > - mode_t mode) > > + mode_t mode, > > + struct fs_path *fs_path) > > { > > + struct fs_path *fsp; > > int fd; > > int oflags; > > > > @@ -118,6 +120,14 @@ openfile( > > } > > } > > } > > + > > + if (fs_path) { > > + fsp = fs_table_lookup(path, FS_MOUNT_POINT); > > + if (!fsp) > > + memset(fs_path, 0, sizeof(*fs_path)); > > + else > > + *fs_path = *fsp; > > + } > > return fd; > > } > > > > @@ -126,7 +136,8 @@ addfile( > > char *name, > > int fd, > > xfs_fsop_geom_t *geometry, > > - int flags) > > + int flags, > > + struct fs_path *fs_path) > > { > > char *filename; > > > > @@ -154,6 +165,7 @@ addfile( > > file->flags = flags; > > file->name = filename; > > file->geom = *geometry; > > + file->fs_path = *fs_path; > > return 0; > > } > > > > @@ -195,6 +207,7 @@ open_f( > > char *sp; > > mode_t mode = 0600; > > xfs_fsop_geom_t geometry = { 0 }; > > + struct fs_path fsp; > > > > if (argc == 1) { > > if (file) > > @@ -257,14 +270,14 @@ open_f( > > return -1; > > } > > > > - fd = openfile(argv[optind], &geometry, flags, mode); > > + fd = openfile(argv[optind], &geometry, flags, mode, &fsp); > > if (fd < 0) > > return 0; > > > > if (!platform_test_xfs_fd(fd)) > > flags |= IO_FOREIGN; > > > > - addfile(argv[optind], fd, &geometry, flags); > > + addfile(argv[optind], fd, &geometry, flags, &fsp); > > return 0; > > } > > > > diff --git a/io/pwrite.c b/io/pwrite.c > > index 7c0bb7f..1c5dfca 100644 > > --- a/io/pwrite.c > > +++ b/io/pwrite.c > > @@ -357,7 +357,7 @@ pwrite_f( > > return 0; > > > > c = IO_READONLY | (dflag ? IO_DIRECT : 0); > > - if (infile && ((fd = openfile(infile, NULL, c, 0)) < 0)) > > + if (infile && ((fd = openfile(infile, NULL, c, 0, NULL)) < 0)) > > return 0; > > > > gettimeofday(&t1, NULL); > > diff --git a/io/reflink.c b/io/reflink.c > > index fe05d1e..f584e8f 100644 > > --- a/io/reflink.c > > +++ b/io/reflink.c > > @@ -154,7 +154,7 @@ dedupe_f( > > return 0; > > } > > > > - fd = openfile(infile, NULL, IO_READONLY, 0); > > + fd = openfile(infile, NULL, IO_READONLY, 0, NULL); > > if (fd < 0) > > return 0; > > > > @@ -278,7 +278,7 @@ reflink_f( > > } > > > > clone_all: > > - fd = openfile(infile, NULL, IO_READONLY, 0); > > + fd = openfile(infile, NULL, IO_READONLY, 0, NULL); > > if (fd < 0) > > return 0; > > > > diff --git a/io/sendfile.c b/io/sendfile.c > > index edd31c9..063fa7f 100644 > > --- a/io/sendfile.c > > +++ b/io/sendfile.c > > @@ -115,7 +115,7 @@ sendfile_f( > > > > if (!infile) > > fd = filetable[fd].fd; > > - else if ((fd = openfile(infile, NULL, IO_READONLY, 0)) < 0) > > + else if ((fd = openfile(infile, NULL, IO_READONLY, 0, NULL)) < 0) > > return 0; > > > > if (optind == argc - 2) { > > diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 > > index 29a036c..7b921e5 100644 > > --- a/man/man8/xfs_io.8 > > +++ b/man/man8/xfs_io.8 > > @@ -301,6 +301,105 @@ ioctl. Options behave as described in the > > .BR xfs_bmap (8) > > manual page. > > .TP > > +.BI "fsmap [ \-d | \-l | \-r ] [ \-m | \-v ] [ \-n " nx " ] [ " start " ] [ " end " ] > > +Prints the mapping of disk blocks used by a filesystem. > > +The map lists each extent used by files, allocation group metadata, > > +journalling logs, and static filesystem metadata, as well as any > > +regions that are unused. > > +Each line of the listings takes the following form: > > +.PP > > +.RS > > +.IR extent ": " major ":" minor " [" startblock .. endblock "]: " owner " " startoffset .. endoffset " " length > > +.PP > > +Static filesystem metadata, allocation group metadata, btrees, > > +journalling logs, and free space are marked by replacing the > > +.IR startoffset .. endoffset > > +with the appropriate marker. > > +All blocks, offsets, and lengths are specified in units of 512-byte > > +blocks, no matter what the filesystem's block size is. > > +The optional > > +.I start > > +and > > +.I end > > +arguments can be used to constrain the output to a particular range of > > +disk blocks. > > +.RE > > +.RS 1.0i > > +.PD 0 > > +.TP > > +.BI \-d > > +Display only extents from the data device. > > +This option only applies for XFS filesystems. > > +.TP > > +.BI \-l > > +Display only extents from the external log device. > > +This option only applies to XFS filesystems. > > +.TP > > +.BI \-r > > +Display only extents from the realtime device. > > +This option only applies to XFS filesystems. > > +.TP > > +.BI \-m > > +Display results in a machine readable format (CSV). > > +This option is not compatible with the > > +.B \-v > > +flag. > > +The columns of the output are: extent number, device major, device minor, > > +physical start, physical end, owner, offset start, offset end, length. > > +The start, end, and length numbers are provided in units of 512b. > > +The owner field is a special string that takes the form: > > + > > +.RS 1.0i > > +.PD 0 > > +.TP 0.4i > > +.I inode_%lld_data > > +for inode data. > > +.TP > > +.I inode_%lld_data_bmbt > > +for inode data extent maps. > > +.TP > > +.I inode_%lld_attr > > +for inode extended attribute data. > > +.TP > > +.I inode_%lld_attr_bmbt > > +for inode extended attribute extent maps. > > +.TP > > +.I special_%u:%u > > +for other filesystem metadata. > > +.PD > > +.RE > > + > > +.TP > > +.BI \-n " num_extents" > > +If this option is given, > > +.B xfs_fsmap > > +obtains the extent list of the file in groups of > > +.I num_extents > > +extents. > > +In the absence of > > +.BR \-n ", " xfs_fsmap > > +queries the system for extents in groups of 131,072 records. > > +.TP > > +.B \-v > > +Shows verbose information. > > +When this flag is specified, additional AG specific information is > > +appended to each line in the following form: > > +.IP > > +.RS 1.2i > > +.IR agno " (" startagblock .. endagblock ") " nblocks " " flags > > +.RE > > +.IP > > +A second > > +.B \-v > > +option will print out the > > +.I flags > > +legend. > > +This option is not compatible with the > > +.B \-m > > +flag. > > +.RE > > +.PD > > +.TP > > .BI "extsize [ \-R | \-D ] [ " value " ]" > > Display and/or modify the preferred extent size used when allocating > > space for the currently open file. If the > > > > -- > > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in > > the body of a message to majordomo@xxxxxxxxxxxxxxx > > More majordomo info at http://vger.kernel.org/majordomo-info.html > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html