All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 0/9] xfsprogs 4.12: GETFSMAP support
@ 2017-05-07 15:56 Darrick J. Wong
  2017-05-07 15:56 ` [PATCH 1/9] xfs_io: support the new getfsmap ioctl Darrick J. Wong
                   ` (9 more replies)
  0 siblings, 10 replies; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-07 15:56 UTC (permalink / raw)
  To: sandeen, darrick.wong; +Cc: linux-xfs

Hi all,

This patchset implements the userspace components of the new GETFSMAP
ioctl that is now in upstream for 4.12.  In order to reduce the amount
of redundant xfs/libxfs patches hitting the list, this patchset only
includes the relevant tool changes; you will need to pull the
djwong-devel tree[1] if you actually want to give the code a try.

The first patch introduce a 'fsmap' command to xfs_io so that users can
query the raw reverse mapping data that is exported by fsmap.  If the
experimental rmapbt feature is enabled, the returned results will be
straight out of the rmapbt; otherwise, the extent information is
synthesized out of the free space btres.

The second patch delegates xfs_repair's rmap comparison function to the
new libxfs version that was introduced as a part of the getfsmap kernel
patches.

The remainder of the patch set introduces xfs_spaceman, which is a new
tool to manage disk space on a mounted XFS filesystem.  The new tool can
call FITRIM, manage space reservations, and display summary information
about the free space on the filesystem.  This information is probably
most useful for developers and people surveying free space
fragmentation.

Note: The primary user of the GETFSMAP information will be the media
scan phase of the upcoming xfs_scrub tool, which will be posted later.

Questions?  Comments?

--D

[1] https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=djwong-devel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 1/9] xfs_io: support the new getfsmap ioctl
  2017-05-07 15:56 [PATCH v7 0/9] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
@ 2017-05-07 15:56 ` Darrick J. Wong
  2017-05-08 21:01   ` Eric Sandeen
  2017-05-07 15:56 ` [PATCH 2/9] xfs_repair: replace rmap_compare with libxfs version Darrick J. Wong
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-07 15:56 UTC (permalink / raw)
  To: sandeen, darrick.wong; +Cc: linux-xfs

From: Darrick J. Wong <darrick.wong@oracle.com>

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 io/Makefile          |    4 
 io/copy_file_range.c |    2 
 io/encrypt.c         |    1 
 io/fsmap.c           |  559 ++++++++++++++++++++++++++++++++++++++++++++++++++
 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    |   47 ++++
 11 files changed, 651 insertions(+), 13 deletions(-)
 create mode 100644 io/fsmap.c


diff --git a/io/Makefile b/io/Makefile
index 435ccff..8d3a30e 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -99,6 +99,10 @@ ifeq ($(HAVE_MREMAP),yes)
 LCFLAGS += -DHAVE_MREMAP
 endif
 
+ifeq ($(HAVE_GETFSMAP),yes)
+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(&copy_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..4128fae
--- /dev/null
+++ b/io/fsmap.c
@@ -0,0 +1,559 @@
+/*
+ * Copyright (C) 2017 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * 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 an XFS filesystem"
+"\n"
+" Example:\n"
+" 'fsmap -dlrv [-n nr] [startoff] [endoff]' - tabular format verbose map, including unwritten extents\n"
+"\n"
+" fsmap prints the map of disk blocks used by the whole filesystem.\n"
+" The map lists each extent used by the file, as well as regions in the\n"
+" filesystem that do not have any corresponding blocks (free space).\n"
+" By default, each line of the listing takes the following form:\n"
+"     extent: [startoffset..endoffset] owner startblock..endblock\n"
+" All the file offsets and disk blocks are in units of 512-byte blocks.\n"
+" -d -- query only the data device.\n"
+" -l -- query only the log device.\n"
+" -r -- query only the realtime device.\n"
+" -n -- query n extents.\n"
+" -v -- Verbose information, specify ag info.  Show flags legend on 2nd -v\n"
+"\n"));
+}
+
+static int
+numlen(
+	off64_t	val)
+{
+	off64_t	tmp;
+	int	len;
+
+	for (len = 0, tmp = val; tmp > 0; tmp = tmp/10)
+		len++;
+	return (len == 0 ? 1 : len);
+}
+
+#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];
+
+	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));
+		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 extent map"),
+				(long long) p->fmr_owner);
+		else
+			printf(_("inode %lld %lld..%lld"),
+				(long long)p->fmr_owner,
+				(long long)BTOBBT(p->fmr_offset),
+				(long long)BTOBBT(p->fmr_offset + p->fmr_length - 1));
+		printf(_(" %lld blocks\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_SHARED	01000000	/* shared extent */
+#define	FLG_ATTR_FORK	00100000	/* attribute fork */
+#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)));
+	}
+	agno_w = max(MINAG_WIDTH, numlen(fsgeo->agcount));
+	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 Shared extent\n"),
+		NFLG+1, NFLG+1, FLG_SHARED);
+	printf(_("    %*.*o Attribute fork\n"),
+		NFLG+1, NFLG+1, FLG_ATTR_FORK);
+	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			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, "dln:rv")) != EOF) {
+		switch (c) {
+		case 'd':	/* data device */
+			dflag = 1;
+			break;
+		case 'l':	/* log device */
+			lflag = 1;
+			break;
+		case 'n':	/* number of extents specified */
+			nflag = atoi(optarg);
+			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)
+		return command_usage(&fsmap_cmd);
+
+	if (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(&nr, head);
+		else
+			dump_map_verbose(&nr, head, &dumped_flags, &fsgeo);
+
+		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 = _("[-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..2c956b8 100644
--- a/man/man8/xfs_io.8
+++ b/man/man8/xfs_io.8
@@ -301,6 +301,53 @@ ioctl.  Options behave as described in the
 .BR xfs_bmap (8)
 manual page.
 .TP
+.BI "fsmap [ \-v ] [ \-n " nx " ] [ " start " ] [ " end " ]
+Prints the mapping of disk blocks used by an XFS 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.
+.BI "The optional " start " and " end " arguments can be used to constrain
+the output to a particular range of disk blocks.
+.RE
+.RS 1.0i
+.PD 0
+.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 the number of extents in the filesystem and uses that
+value to compute the group size.
+.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.
+.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


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 2/9] xfs_repair: replace rmap_compare with libxfs version
  2017-05-07 15:56 [PATCH v7 0/9] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
  2017-05-07 15:56 ` [PATCH 1/9] xfs_io: support the new getfsmap ioctl Darrick J. Wong
@ 2017-05-07 15:56 ` Darrick J. Wong
  2017-05-07 15:56 ` [PATCH 3/9] xfs_spaceman: space management tool Darrick J. Wong
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-07 15:56 UTC (permalink / raw)
  To: sandeen, darrick.wong; +Cc: linux-xfs

From: Darrick J. Wong <darrick.wong@oracle.com>

Now that libxfs has a function to compare rmaps, replace xfs_repair's
helper function with that.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 libxfs/libxfs_api_defs.h |    1 +
 repair/rmap.c            |   32 ++------------------------------
 2 files changed, 3 insertions(+), 30 deletions(-)


diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index 31239ca..2d8d9c8 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -144,5 +144,6 @@
 #define xfs_refcount_get_rec		libxfs_refcount_get_rec
 #define xfs_rmap_lookup_le_range	libxfs_rmap_lookup_le_range
 #define xfs_refc_block			libxfs_refc_block
+#define xfs_rmap_compare		libxfs_rmap_compare
 
 #endif /* __LIBXFS_API_DEFS_H__ */
diff --git a/repair/rmap.c b/repair/rmap.c
index 7508973..ab6e583 100644
--- a/repair/rmap.c
+++ b/repair/rmap.c
@@ -49,37 +49,9 @@ static struct xfs_ag_rmap *ag_rmaps;
 static bool rmapbt_suspect;
 static bool refcbt_suspect;
 
-/*
- * Compare rmap observations for array sorting.
- */
-static int
-rmap_compare(
-	const void		*a,
-	const void		*b)
+static inline int rmap_compare(const void *a, const void *b)
 {
-	const struct xfs_rmap_irec	*pa;
-	const struct xfs_rmap_irec	*pb;
-	__u64			oa;
-	__u64			ob;
-
-	pa = a; pb = b;
-	oa = libxfs_rmap_irec_offset_pack(pa);
-	ob = libxfs_rmap_irec_offset_pack(pb);
-
-	if (pa->rm_startblock < pb->rm_startblock)
-		return -1;
-	else if (pa->rm_startblock > pb->rm_startblock)
-		return 1;
-	else if (pa->rm_owner < pb->rm_owner)
-		return -1;
-	else if (pa->rm_owner > pb->rm_owner)
-		return 1;
-	else if (oa < ob)
-		return -1;
-	else if (oa > ob)
-		return 1;
-	else
-		return 0;
+	return libxfs_rmap_compare(a, b);
 }
 
 /*


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 3/9] xfs_spaceman: space management tool
  2017-05-07 15:56 [PATCH v7 0/9] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
  2017-05-07 15:56 ` [PATCH 1/9] xfs_io: support the new getfsmap ioctl Darrick J. Wong
  2017-05-07 15:56 ` [PATCH 2/9] xfs_repair: replace rmap_compare with libxfs version Darrick J. Wong
@ 2017-05-07 15:56 ` Darrick J. Wong
  2017-05-27  1:34   ` Eric Sandeen
  2017-05-07 15:56 ` [PATCH 4/9] xfs_spaceman: add FITRIM support Darrick J. Wong
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-07 15:56 UTC (permalink / raw)
  To: sandeen, darrick.wong; +Cc: linux-xfs, Dave Chinner

From: Dave Chinner <dchinner@redhat.com>

xfs_spaceman is intended as a diagnostic and control tool for space
management operations within XFS. Operations like examining free
space, managing allocation policies, issuing block discards on free
space, etc.

The tool is modelled on the xfs_io interface, allowing both
interactive and command line control of the tool, enabling it to be
used in scripts and automated management tools.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
[darrick: change xfsctl to ioctl]
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 Makefile          |    3 +
 spaceman/Makefile |   34 ++++++++++++
 spaceman/file.c   |  149 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 spaceman/init.c   |  117 ++++++++++++++++++++++++++++++++++++++++++
 spaceman/init.h   |   23 ++++++++
 spaceman/space.h  |   36 +++++++++++++
 6 files changed, 361 insertions(+), 1 deletion(-)
 create mode 100644 spaceman/Makefile
 create mode 100644 spaceman/file.c
 create mode 100644 spaceman/init.c
 create mode 100644 spaceman/init.h
 create mode 100644 spaceman/space.h


diff --git a/Makefile b/Makefile
index ba87327..72d0044 100644
--- a/Makefile
+++ b/Makefile
@@ -47,7 +47,7 @@ HDR_SUBDIRS = include libxfs
 DLIB_SUBDIRS = libxlog libxcmd libhandle
 LIB_SUBDIRS = libxfs $(DLIB_SUBDIRS)
 TOOL_SUBDIRS = copy db estimate fsck growfs io logprint mkfs quota \
-		mdrestore repair rtcp m4 man doc debian
+		mdrestore repair rtcp m4 man doc debian spaceman
 
 ifneq ("$(PKG_PLATFORM)","darwin")
 TOOL_SUBDIRS += fsr
@@ -88,6 +88,7 @@ quota: libxcmd
 repair: libxlog libxcmd
 copy: libxlog
 mkfs: libxcmd
+spaceman: libxcmd
 
 ifeq ($(HAVE_BUILDDEFS), yes)
 include $(BUILDRULES)
diff --git a/spaceman/Makefile b/spaceman/Makefile
new file mode 100644
index 0000000..ff8d23e
--- /dev/null
+++ b/spaceman/Makefile
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 2012 Red Hat, Inc.  All Rights Reserved.
+#
+
+TOPDIR = ..
+include $(TOPDIR)/include/builddefs
+
+LTCOMMAND = xfs_spaceman
+HFILES = init.h space.h
+CFILES = init.c \
+	file.c
+
+LLDLIBS = $(LIBXCMD)
+LTDEPENDENCIES = $(LIBXCMD)
+LLDFLAGS = -static
+
+ifeq ($(ENABLE_READLINE),yes)
+LLDLIBS += $(LIBREADLINE) $(LIBTERMCAP)
+endif
+
+ifeq ($(ENABLE_EDITLINE),yes)
+LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP)
+endif
+
+default: depend $(LTCOMMAND)
+
+include $(BUILDRULES)
+
+install: default
+	$(INSTALL) -m 755 -d $(PKG_SBIN_DIR)
+	$(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR)
+install-dev:
+
+-include .dep
diff --git a/spaceman/file.c b/spaceman/file.c
new file mode 100644
index 0000000..9356066
--- /dev/null
+++ b/spaceman/file.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2004-2005 Silicon Graphics, Inc.
+ * Copyright (c) 2012 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 "libxfs.h"
+#include <sys/mman.h>
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "space.h"
+
+static cmdinfo_t print_cmd;
+
+fileio_t	*filetable;
+int		filecount;
+fileio_t	*file;
+
+static void
+print_fileio(
+	fileio_t	*file,
+	int		index,
+	int		braces)
+{
+	printf(_("%c%03d%c %-14s (%s,%s,%s%s%s)\n"),
+		braces? '[' : ' ', index, braces? ']' : ' ', file->name,
+		file->flags & O_SYNC ? _("sync") : _("non-sync"),
+		file->flags & O_DIRECT ? _("direct") : _("non-direct"),
+		file->flags & O_RDONLY ? _("read-only") : _("read-write"),
+		file->flags & O_APPEND ? _(",append-only") : "",
+		file->flags & O_NONBLOCK ? _(",non-block") : "");
+}
+
+int
+filelist_f(void)
+{
+	int		i;
+
+	for (i = 0; i < filecount; i++)
+		print_fileio(&filetable[i], i, &filetable[i] == file);
+	return 0;
+}
+
+static int
+print_f(
+	int		argc,
+	char		**argv)
+{
+	filelist_f();
+	return 0;
+}
+
+int
+openfile(
+	char		*path,
+	xfs_fsop_geom_t	*geom,
+	int		flags,
+	mode_t		mode)
+{
+	int		fd;
+
+	fd = open(path, flags, mode);
+	if (fd < 0) {
+		if ((errno == EISDIR) && (flags & O_RDWR)) {
+			/* make it as if we asked for O_RDONLY & try again */
+			flags &= ~O_RDWR;
+			flags |= O_RDONLY;
+			fd = open(path, flags, mode);
+			if (fd < 0) {
+				perror(path);
+				return -1;
+			}
+		} else {
+			perror(path);
+			return -1;
+		}
+	}
+
+	if (ioctl(fd, XFS_IOC_FSGEOMETRY, geom) < 0) {
+		perror("XFS_IOC_FSGEOMETRY");
+		close(fd);
+		return -1;
+	}
+	return fd;
+}
+
+int
+addfile(
+	char		*name,
+	int		fd,
+	xfs_fsop_geom_t	*geometry,
+	int		flags)
+{
+	char		*filename;
+
+	filename = strdup(name);
+	if (!filename) {
+		perror("strdup");
+		close(fd);
+		return -1;
+	}
+
+	/* Extend the table of currently open files */
+	filetable = (fileio_t *)realloc(filetable,	/* growing */
+					++filecount * sizeof(fileio_t));
+	if (!filetable) {
+		perror("realloc");
+		filecount = 0;
+		free(filename);
+		close(fd);
+		return -1;
+	}
+
+	/* Finally, make this the new active open file */
+	file = &filetable[filecount - 1];
+	file->fd = fd;
+	file->flags = flags;
+	file->name = filename;
+	file->geom = *geometry;
+	return 0;
+}
+
+void
+file_init(void)
+{
+	print_cmd.name = "print";
+	print_cmd.altname = "p";
+	print_cmd.cfunc = print_f;
+	print_cmd.argmin = 0;
+	print_cmd.argmax = 0;
+	print_cmd.flags = CMD_FLAG_ONESHOT;
+	print_cmd.oneline = _("list current open files");
+
+	add_command(&print_cmd);
+}
diff --git a/spaceman/init.c b/spaceman/init.c
new file mode 100644
index 0000000..404b183
--- /dev/null
+++ b/spaceman/init.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2012 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 "libxfs.h"
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "space.h"
+
+char	*progname;
+int	exitcode;
+
+void
+usage(void)
+{
+	fprintf(stderr,
+		_("Usage: %s [-c cmd] file\n"),
+		progname);
+	exit(1);
+}
+
+static void
+init_commands(void)
+{
+	file_init();
+	help_init();
+	quit_init();
+}
+
+static int
+init_args_command(
+	int	index)
+{
+	if (index >= filecount)
+		return 0;
+	file = &filetable[index++];
+	return index;
+}
+
+static int
+init_check_command(
+	const cmdinfo_t	*ct)
+{
+	if (!(ct->flags & CMD_FLAG_ONESHOT))
+		return 0;
+	return 1;
+}
+
+void
+init(
+	int		argc,
+	char		**argv)
+{
+	int		c, flags = 0;
+	mode_t		mode = 0600;
+	xfs_fsop_geom_t	geometry = { 0 };
+
+	progname = basename(argv[0]);
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
+	while ((c = getopt(argc, argv, "c:V")) != EOF) {
+		switch (c) {
+		case 'c':
+			add_user_command(optarg);
+			break;
+		case 'V':
+			printf(_("%s version %s\n"), progname, VERSION);
+			exit(0);
+		default:
+			usage();
+		}
+	}
+
+	if (optind == argc)
+		usage();
+
+	while (optind < argc) {
+		if ((c = openfile(argv[optind], &geometry, flags, mode)) < 0)
+			exit(1);
+		if (!platform_test_xfs_fd(c))
+			printf(_("Not an XFS filesystem!\n"));
+		if (addfile(argv[optind], c, &geometry, flags) < 0)
+			exit(1);
+		optind++;
+	}
+
+	init_commands();
+	add_command_iterator(init_args_command);
+	add_check_command(init_check_command);
+}
+
+int
+main(
+	int	argc,
+	char	**argv)
+{
+	init(argc, argv);
+	command_loop();
+	return exitcode;
+}
diff --git a/spaceman/init.h b/spaceman/init.h
new file mode 100644
index 0000000..165e4f5
--- /dev/null
+++ b/spaceman/init.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2012 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
+ */
+
+extern char	*progname;
+extern int	exitcode;
+
+#define min(a,b)	(((a)<(b))?(a):(b))
+#define max(a,b)	(((a)>(b))?(a):(b))
diff --git a/spaceman/space.h b/spaceman/space.h
new file mode 100644
index 0000000..6e1bc52
--- /dev/null
+++ b/spaceman/space.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012 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
+ */
+
+typedef struct fileio {
+	int		fd;		/* open file descriptor */
+	int		flags;		/* flags describing file state */
+	char		*name;		/* file name at time of open */
+	xfs_fsop_geom_t	geom;		/* XFS filesystem geometry */
+} fileio_t;
+
+extern fileio_t		*filetable;	/* open file table */
+extern int		filecount;	/* number of open files */
+extern fileio_t		*file;		/* active file in file table */
+extern int filelist_f(void);
+
+extern int	openfile(char *, xfs_fsop_geom_t *, int, mode_t);
+extern int	addfile(char *, int , xfs_fsop_geom_t *, int);
+
+extern void	file_init(void);
+extern void	help_init(void);
+extern void	quit_init(void);


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 4/9] xfs_spaceman: add FITRIM support
  2017-05-07 15:56 [PATCH v7 0/9] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
                   ` (2 preceding siblings ...)
  2017-05-07 15:56 ` [PATCH 3/9] xfs_spaceman: space management tool Darrick J. Wong
@ 2017-05-07 15:56 ` Darrick J. Wong
  2017-05-27  0:27   ` Eric Sandeen
  2017-05-07 15:56 ` [PATCH 5/9] xfs_spaceman: add new speculative prealloc control Darrick J. Wong
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-07 15:56 UTC (permalink / raw)
  To: sandeen, darrick.wong; +Cc: linux-xfs, Dave Chinner

From: Dave Chinner <dchinner@redhat.com>

Add support for discarding free space extents via the FITRIM
command. Make it easy to discard a single range, an entire AG or all
the freespace in the filesystem.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 spaceman/Makefile |    2 -
 spaceman/init.c   |    1 
 spaceman/space.h  |    1 
 spaceman/trim.c   |  139 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 142 insertions(+), 1 deletion(-)
 create mode 100644 spaceman/trim.c


diff --git a/spaceman/Makefile b/spaceman/Makefile
index ff8d23e..9fb9142 100644
--- a/spaceman/Makefile
+++ b/spaceman/Makefile
@@ -8,7 +8,7 @@ include $(TOPDIR)/include/builddefs
 LTCOMMAND = xfs_spaceman
 HFILES = init.h space.h
 CFILES = init.c \
-	file.c
+	file.c trim.c
 
 LLDLIBS = $(LIBXCMD)
 LTDEPENDENCIES = $(LIBXCMD)
diff --git a/spaceman/init.c b/spaceman/init.c
index 404b183..ae5cfb5 100644
--- a/spaceman/init.c
+++ b/spaceman/init.c
@@ -40,6 +40,7 @@ init_commands(void)
 	file_init();
 	help_init();
 	quit_init();
+	trim_init();
 }
 
 static int
diff --git a/spaceman/space.h b/spaceman/space.h
index 6e1bc52..7b4f034 100644
--- a/spaceman/space.h
+++ b/spaceman/space.h
@@ -34,3 +34,4 @@ extern int	addfile(char *, int , xfs_fsop_geom_t *, int);
 extern void	file_init(void);
 extern void	help_init(void);
 extern void	quit_init(void);
+extern void	trim_init(void);
diff --git a/spaceman/trim.c b/spaceman/trim.c
new file mode 100644
index 0000000..9bf6565
--- /dev/null
+++ b/spaceman/trim.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2012 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 "libxfs.h"
+#include <linux/fs.h>
+#include "command.h"
+#include "init.h"
+#include "space.h"
+#include "input.h"
+
+#ifndef FITRIM
+#define FITRIM          _IOWR('X', 121, struct fstrim_range)    /* Trim */
+
+struct fstrim_range {
+	__u64 start;
+	__u64 len;
+	__u64 minlen;
+};
+#endif
+
+static cmdinfo_t trim_cmd;
+
+/*
+ * Report on trimace usage in xfs filesystem.
+ */
+static int
+trim_f(
+	int		argc,
+	char		**argv)
+{
+	struct fstrim_range trim = {0};
+	xfs_agnumber_t	agno = 0;
+	off64_t		offset = 0;
+	ssize_t		length = 0;
+	ssize_t		minlen = 0;
+	int		aflag = 0;
+	int		fflag = 0;
+	int		ret;
+	int		c;
+
+	while ((c = getopt(argc, argv, "a:fm:")) != EOF) {
+		switch (c) {
+		case 'a':
+			if (fflag)
+				return command_usage(&trim_cmd);
+			aflag = 1;
+			agno = atoi(optarg);
+			break;
+		case 'f':
+			if (aflag)
+				return command_usage(&trim_cmd);
+			fflag = 1;
+			break;
+		case 'm':
+			minlen = cvtnum(file->geom.blocksize,
+					file->geom.sectsize, argv[optind]);
+			break;
+		default:
+			return command_usage(&trim_cmd);
+		}
+	}
+
+	if (optind != argc - 2 && !(aflag || fflag))
+		return command_usage(&trim_cmd);
+	if (optind != argc) {
+		offset = cvtnum(file->geom.blocksize, file->geom.sectsize,
+				argv[optind]);
+		length = cvtnum(file->geom.blocksize, file->geom.sectsize,
+				argv[optind + 1]);
+	} else if (agno) {
+		offset = agno * file->geom.agblocks * file->geom.blocksize;
+		length = file->geom.agblocks * file->geom.blocksize;
+	} else {
+		offset = 0;
+		length = file->geom.datablocks * file->geom.blocksize;
+	}
+
+	trim.start = offset;
+	trim.len = length;
+	trim.minlen = minlen;
+
+	ret = ioctl(file->fd, FITRIM, (unsigned long)&trim);
+	if (ret < 0) {
+		fprintf(stderr, "%s: ioctl(FITRIM) [\"%s\"]: "
+			"%s\n", progname, file->name, strerror(errno));
+		exitcode = 1;
+		return 0;
+	}
+	return 0;
+}
+
+static void
+trim_help(void)
+{
+	printf(_(
+"\n"
+"Discard filesystem free space\n"
+"\n"
+"Options: [-m minlen] [-f]|[-a agno]|[offset length]\n"
+"\n"
+" -m minlen -- skip freespace extents smaller than minlen\n"
+" -f -- trim all the freespace in the entire filesystem\n"
+" -a agno -- trim all the freespace in the given AG agno\n"
+" offset length -- trim the freespace in the range {offset, length}\n"
+"\n"));
+
+}
+
+void
+trim_init(void)
+{
+	trim_cmd.name = "trim";
+	trim_cmd.altname = "tr";
+	trim_cmd.cfunc = trim_f;
+	trim_cmd.argmin = 1;
+	trim_cmd.argmax = 4;
+	trim_cmd.args = "[-m minlen] [-f]|[-a agno]|[offset length]\n";
+	trim_cmd.flags = CMD_FLAG_ONESHOT;
+	trim_cmd.oneline = _("Discard filesystem free space");
+	trim_cmd.help = trim_help;
+
+	add_command(&trim_cmd);
+}
+


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 5/9] xfs_spaceman: add new speculative prealloc control
  2017-05-07 15:56 [PATCH v7 0/9] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
                   ` (3 preceding siblings ...)
  2017-05-07 15:56 ` [PATCH 4/9] xfs_spaceman: add FITRIM support Darrick J. Wong
@ 2017-05-07 15:56 ` Darrick J. Wong
  2017-05-27  1:45   ` Eric Sandeen
  2017-05-07 15:56 ` [PATCH 6/9] xfs_spaceman: AG state control Darrick J. Wong
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-07 15:56 UTC (permalink / raw)
  To: sandeen, darrick.wong; +Cc: linux-xfs, Dave Chinner

From: Dave Chinner <dchinner@redhat.com>

Add an control interface for purging speculative
preallocation via the new ioctls.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
[darrick: change xfsctl to ioctl]
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 spaceman/Makefile   |    2 -
 spaceman/init.c     |    1 
 spaceman/prealloc.c |  135 +++++++++++++++++++++++++++++++++++++++++++++++++++
 spaceman/space.h    |    1 
 4 files changed, 138 insertions(+), 1 deletion(-)
 create mode 100644 spaceman/prealloc.c


diff --git a/spaceman/Makefile b/spaceman/Makefile
index 9fb9142..b1f1136 100644
--- a/spaceman/Makefile
+++ b/spaceman/Makefile
@@ -8,7 +8,7 @@ include $(TOPDIR)/include/builddefs
 LTCOMMAND = xfs_spaceman
 HFILES = init.h space.h
 CFILES = init.c \
-	file.c trim.c
+	file.c prealloc.c trim.c
 
 LLDLIBS = $(LIBXCMD)
 LTDEPENDENCIES = $(LIBXCMD)
diff --git a/spaceman/init.c b/spaceman/init.c
index ae5cfb5..08b5a33 100644
--- a/spaceman/init.c
+++ b/spaceman/init.c
@@ -39,6 +39,7 @@ init_commands(void)
 {
 	file_init();
 	help_init();
+	prealloc_init();
 	quit_init();
 	trim_init();
 }
diff --git a/spaceman/prealloc.c b/spaceman/prealloc.c
new file mode 100644
index 0000000..b93f909
--- /dev/null
+++ b/spaceman/prealloc.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2012 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 "libxfs.h"
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "space.h"
+
+#ifndef XFS_IOC_FREE_EOFBLOCKS
+#define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_eofblocks)
+
+#define XFS_EOFBLOCKS_VERSION           1
+struct xfs_fs_eofblocks {
+	__u32		eof_version;
+	__u32		eof_flags;
+	uid_t		eof_uid;
+	gid_t		eof_gid;
+	prid_t		eof_prid;
+	__u32		pad32;
+	__u64		eof_min_file_size;
+	__u64		pad64[12];
+};
+
+/* eof_flags values */
+#define XFS_EOF_FLAGS_SYNC		(1 << 0) /* sync/wait mode scan */
+#define XFS_EOF_FLAGS_UID		(1 << 1) /* filter by uid */
+#define XFS_EOF_FLAGS_GID		(1 << 2) /* filter by gid */
+#define XFS_EOF_FLAGS_PRID		(1 << 3) /* filter by project id */
+#define XFS_EOF_FLAGS_MINFILESIZE	(1 << 4) /* filter by min file size */
+
+#endif
+
+static cmdinfo_t prealloc_cmd;
+
+/*
+ * Control preallocation amounts.
+ */
+static int
+prealloc_f(
+	int	argc,
+	char	**argv)
+{
+	struct xfs_fs_eofblocks eofb = {0};
+	int	c;
+
+	eofb.eof_version = XFS_EOFBLOCKS_VERSION;
+
+	while ((c = getopt(argc, argv, "g:m:p:su:")) != EOF) {
+		switch (c) {
+		case 'g':
+			eofb.eof_flags |= XFS_EOF_FLAGS_GID;
+			eofb.eof_gid = atoi(optarg);
+			break;
+		case 'u':
+			eofb.eof_flags |= XFS_EOF_FLAGS_UID;
+			eofb.eof_uid = atoi(optarg);
+			break;
+		case 'p':
+			eofb.eof_flags |= XFS_EOF_FLAGS_PRID;
+			eofb.eof_prid = atoi(optarg);
+			break;
+		case 's':
+			eofb.eof_flags |= XFS_EOF_FLAGS_SYNC;
+			break;
+		case 'm':
+			eofb.eof_flags |= XFS_EOF_FLAGS_MINFILESIZE;
+			eofb.eof_min_file_size = cvtnum(file->geom.blocksize,
+							file->geom.sectsize,
+							optarg);
+			break;
+		case '?':
+		default:
+			return command_usage(&prealloc_cmd);
+		}
+	}
+	if (optind != argc)
+		return command_usage(&prealloc_cmd);
+
+	if (ioctl(file->fd, XFS_IOC_FREE_EOFBLOCKS, &eofb) < 0) {
+		fprintf(stderr, _("%s: XFS_IOC_FREE_EOFBLOCKS on %s: %s\n"),
+			progname, file->name, strerror(errno));
+	}
+	return 0;
+}
+
+static void
+prealloc_help(void)
+{
+	printf(_(
+"\n"
+"Control speculative preallocation\n"
+"\n"
+"Options: [-s] [-ugp id] [-m minlen]\n"
+"\n"
+" -s -- synchronous flush - wait for flush to complete\n"
+" -u uid -- remove prealloc on files matching user <uid>\n"
+" -g gid -- remove prealloc on files matching group <gid>\n"
+" -p prid -- remove prealloc on files matching project <prid>\n"
+" -m minlen -- only consider files larger than <minlen>\n"
+"\n"));
+
+}
+
+void
+prealloc_init(void)
+{
+	prealloc_cmd.name = "prealloc";
+	prealloc_cmd.altname = "prealloc";
+	prealloc_cmd.cfunc = prealloc_f;
+	prealloc_cmd.argmin = 1;
+	prealloc_cmd.argmax = -1;
+	prealloc_cmd.args = "[-s] [-ugp id] [-m minlen]\n";
+	prealloc_cmd.flags = CMD_FLAG_ONESHOT;
+	prealloc_cmd.oneline = _("Control speculative preallocation");
+	prealloc_cmd.help = prealloc_help;
+
+	add_command(&prealloc_cmd);
+}
+
diff --git a/spaceman/space.h b/spaceman/space.h
index 7b4f034..0ae3116 100644
--- a/spaceman/space.h
+++ b/spaceman/space.h
@@ -33,5 +33,6 @@ extern int	addfile(char *, int , xfs_fsop_geom_t *, int);
 
 extern void	file_init(void);
 extern void	help_init(void);
+extern void	prealloc_init(void);
 extern void	quit_init(void);
 extern void	trim_init(void);


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 6/9] xfs_spaceman: AG state control
  2017-05-07 15:56 [PATCH v7 0/9] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
                   ` (4 preceding siblings ...)
  2017-05-07 15:56 ` [PATCH 5/9] xfs_spaceman: add new speculative prealloc control Darrick J. Wong
@ 2017-05-07 15:56 ` Darrick J. Wong
  2017-05-26 23:06   ` Eric Sandeen
  2017-05-07 15:57 ` [PATCH 7/9] xfs_spaceman: Free space mapping command Darrick J. Wong
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-07 15:56 UTC (permalink / raw)
  To: sandeen, darrick.wong; +Cc: linux-xfs, Dave Chinner

From: Dave Chinner <dchinner@redhat.com>

Add support for a new allocation group state control ioctl. This
allows control of various AG parameters, such as whether inode
allocation is allowed in the AG, metadata preference, whether new
allocations are allowed, etc. This requires a new ioctl.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
[darrick: change xfsctl to ioctl]
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 spaceman/Makefile |    2 
 spaceman/ag.c     |  221 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 222 insertions(+), 1 deletion(-)
 create mode 100644 spaceman/ag.c


diff --git a/spaceman/Makefile b/spaceman/Makefile
index b1f1136..08709b3 100644
--- a/spaceman/Makefile
+++ b/spaceman/Makefile
@@ -8,7 +8,7 @@ include $(TOPDIR)/include/builddefs
 LTCOMMAND = xfs_spaceman
 HFILES = init.h space.h
 CFILES = init.c \
-	file.c prealloc.c trim.c
+	ag.c file.c prealloc.c trim.c
 
 LLDLIBS = $(LIBXCMD)
 LTDEPENDENCIES = $(LIBXCMD)
diff --git a/spaceman/ag.c b/spaceman/ag.c
new file mode 100644
index 0000000..1eb8aa0
--- /dev/null
+++ b/spaceman/ag.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2012 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 "libxfs.h"
+#include <linux/dqblk_xfs.h>
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "space.h"
+
+#ifndef XFS_IOC_AGCONTROL
+#define XFS_IOC_AGCONTROL _IOWR ('X', 60, struct xfs_agcontrol)
+
+#define XFS_AGCONTROL_VERSION		1
+struct xfs_agcontrol {
+	__u32		version;
+	__u32		flags;
+	__u32		agno;
+	__u32		state;
+	__u64		pad[8];
+};
+
+/* control flags */
+#define XFS_AGCONTROL_GETAGFSTATE	(1 << 0)	/* get AGF state */
+#define XFS_AGCONTROL_SETAGFSTATE	(1 << 1)	/* set AGF state */
+#define XFS_AGCONTROL_GETAGISTATE	(1 << 2)	/* get AGI state */
+#define XFS_AGCONTROL_SETAGISTATE	(1 << 3)	/* set AGI state */
+
+/* state flags */
+
+/*
+ * inode and allocation states are split. AGF and AGI online state will move in
+ * sync as it is really a whole AG state. No allocation flags imply no new
+ * allocations, but inodes and extents can be removed. Readonly means no
+ * modification (alloc or free) is allowed. This is to allow different
+ * operations to be performed. e.g. emptying an AG in preparation for a shrink
+ * require NOALLOC state, but an AG that has a corrupted freespace btree might
+ * be switched to READONLY until the freespace tree is rebuilt. An AGF/AGI in
+ * this corrupt/ro state will set the relevant corruption flag in the state
+ * field....
+ */
+#define XFS_AGFSTATE_ONLINE		(1 << 0)	/* AGF online */
+#define XFS_AGFSTATE_NOALLOC		(1 << 1)	/* No new allocation */
+#define XFS_AGFSTATE_READONLY		(1 << 2)	/* AGF is immutable */
+#define XFS_AGFSTATE_METADATA		(1 << 3)	/* metadata preferred */
+#define XFS_AGFSTATE_CORRUPT_BNO	(1 << 4)	/* bno freespace corrupt */
+#define XFS_AGFSTATE_CORRUPT_CNT	(1 << 5)	/* cnt freespace corrupt */
+#define XFS_AGFSTATE_CORRUPT_AGFL	(1 << 6)	/* AGFL freespace corrupt */
+
+#define XFS_AGISTATE_ONLINE		(1 << 0)	/* AGI online */
+#define XFS_AGISTATE_NOALLOC		(1 << 1)	/* No new allocation */
+#define XFS_AGISTATE_READONLY		(1 << 2)	/* AGI is immutable */
+#define XFS_AGISTATE_CORRUPT_TREE	(1 << 2)	/* AGI btree corrupt */
+
+#endif
+
+static cmdinfo_t agfctl_cmd;
+static cmdinfo_t agictl_cmd;
+
+static int
+agfctl_f(
+	int		argc,
+	char		**argv)
+{
+	struct xfs_agcontrol agctl = {0};
+	xfs_agnumber_t	agno;
+	int		gflag = 0;
+	int		c;
+
+	while ((c = getopt(argc, argv, "gs")) != EOF) {
+		switch (c) {
+		case 'g':
+			gflag = 1;
+			break;
+		default:
+			return command_usage(&agfctl_cmd);
+		}
+	}
+	if (optind != argc - 1)
+		return command_usage(&agfctl_cmd);
+
+	agno = atoi(argv[optind]);
+	if (agno >= file->geom.agcount) {
+		fprintf(stderr, _("%s: agno %d out of range (max %d)\n"),
+			progname, agno, file->geom.agcount);
+		exitcode = 1;
+		return 0;
+	}
+
+	agctl.version = XFS_AGCONTROL_VERSION;
+	agctl.agno = agno;
+	if (gflag)
+		agctl.flags = XFS_AGCONTROL_GETAGFSTATE;
+
+	if (ioctl(file->fd, XFS_IOC_AGCONTROL, &agctl) < 0) {
+		fprintf(stderr, _("%s: XFS_IOC_AGCONTROL on %s: %s\n"),
+			progname, file->name, strerror(errno));
+	}
+	return 0;
+}
+
+static void
+agfctl_help(void)
+{
+	printf(_(
+"\n"
+"AGF state control\n"
+"\n"
+"Options: [-g] agno\n"
+"\n"
+" -g -- get state\n"
+" agno -- AG to operate on\n"
+"\n"));
+
+}
+
+void
+agfctl_init(void)
+{
+	agfctl_cmd.name = "agfctl";
+	agfctl_cmd.altname = "agfctl";
+	agfctl_cmd.cfunc = agfctl_f;
+	agfctl_cmd.argmin = 2;
+	agfctl_cmd.argmax = -1;
+	agfctl_cmd.args = "agno\n";
+	agfctl_cmd.flags = CMD_FLAG_ONESHOT;
+	agfctl_cmd.oneline = _("AGF state control");
+	agfctl_cmd.help = agfctl_help;
+
+	add_command(&agfctl_cmd);
+}
+
+static int
+agictl_f(
+	int		argc,
+	char		**argv)
+{
+	struct xfs_agcontrol agctl = {0};
+	xfs_agnumber_t	agno;
+	int		gflag = 0;
+	int		c;
+
+	while ((c = getopt(argc, argv, "gs")) != EOF) {
+		switch (c) {
+		case 'g':
+			gflag = 1;
+			break;
+		default:
+			return command_usage(&agictl_cmd);
+		}
+	}
+	if (optind != argc - 1)
+		return command_usage(&agictl_cmd);
+
+	agno = atoi(argv[optind]);
+	if (agno >= file->geom.agcount) {
+		fprintf(stderr, _("%s: agno %d out of range (max %d)\n"),
+			progname, agno, file->geom.agcount);
+		exitcode = 1;
+		return 0;
+	}
+
+	agctl.version = XFS_AGCONTROL_VERSION;
+	agctl.agno = agno;
+	if (gflag)
+		agctl.flags = XFS_AGCONTROL_GETAGISTATE;
+
+	if (ioctl(file->fd, XFS_IOC_AGCONTROL, &agctl) < 0) {
+		fprintf(stderr, _("%s: XFS_IOC_AGCONTROL on %s: %s\n"),
+			progname, file->name, strerror(errno));
+		exitcode = 1;
+		return 0;
+	}
+	return 0;
+}
+
+static void
+agictl_help(void)
+{
+	printf(_(
+"\n"
+"AGI state control\n"
+"\n"
+"Options: [-g] agno\n"
+"\n"
+" -g -- get state\n"
+" agno -- AG to operate on\n"
+"\n"));
+
+}
+
+void
+agictl_init(void)
+{
+	agictl_cmd.name = "agictl";
+	agictl_cmd.altname = "agictl";
+	agictl_cmd.cfunc = agictl_f;
+	agictl_cmd.argmin = 2;
+	agictl_cmd.argmax = -1;
+	agictl_cmd.args = "agno\n";
+	agictl_cmd.flags = CMD_FLAG_ONESHOT;
+	agictl_cmd.oneline = _("AGI state control");
+	agictl_cmd.help = agictl_help;
+
+	add_command(&agictl_cmd);
+}


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 7/9] xfs_spaceman: Free space mapping command
  2017-05-07 15:56 [PATCH v7 0/9] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
                   ` (5 preceding siblings ...)
  2017-05-07 15:56 ` [PATCH 6/9] xfs_spaceman: AG state control Darrick J. Wong
@ 2017-05-07 15:57 ` Darrick J. Wong
  2017-05-27  1:57   ` Eric Sandeen
  2017-05-07 15:57 ` [PATCH 8/9] xfs_spaceman: add a man page Darrick J. Wong
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-07 15:57 UTC (permalink / raw)
  To: sandeen, darrick.wong; +Cc: linux-xfs, Dave Chinner

From: Dave Chinner <dchinner@redhat.com>

Add freespace mapping tool modelled on the xfs_db freesp command.
The advantage of this command over xfs_db is that it can be done
online and is coherent with concurrent modifications to the
filesystem.

This requires the kernel to support the XFS_IOC_GETFSMAP ioctl to map
free space indexes.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
[darrick: port from FIEMAPFS to GETFSMAP]
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 spaceman/Makefile   |   12 +-
 spaceman/ag.c       |    1 
 spaceman/file.c     |   18 ++-
 spaceman/freesp.c   |  367 +++++++++++++++++++++++++++++++++++++++++++++++++++
 spaceman/init.c     |    9 +
 spaceman/prealloc.c |    1 
 spaceman/space.h    |   12 +-
 spaceman/trim.c     |    1 
 8 files changed, 413 insertions(+), 8 deletions(-)
 create mode 100644 spaceman/freesp.c


diff --git a/spaceman/Makefile b/spaceman/Makefile
index 08709b3..3b059ca 100644
--- a/spaceman/Makefile
+++ b/spaceman/Makefile
@@ -7,8 +7,12 @@ include $(TOPDIR)/include/builddefs
 
 LTCOMMAND = xfs_spaceman
 HFILES = init.h space.h
-CFILES = init.c \
-	ag.c file.c prealloc.c trim.c
+CFILES = ag.c \
+	 file.c \
+	 init.c \
+	 prealloc.c \
+	 trim.c
+
 
 LLDLIBS = $(LIBXCMD)
 LTDEPENDENCIES = $(LIBXCMD)
@@ -22,6 +26,10 @@ ifeq ($(ENABLE_EDITLINE),yes)
 LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP)
 endif
 
+ifeq ($(HAVE_GETFSMAP),yes)
+CFILES += freesp.c
+endif
+
 default: depend $(LTCOMMAND)
 
 include $(BUILDRULES)
diff --git a/spaceman/ag.c b/spaceman/ag.c
index 1eb8aa0..0f1c869 100644
--- a/spaceman/ag.c
+++ b/spaceman/ag.c
@@ -21,6 +21,7 @@
 #include "command.h"
 #include "input.h"
 #include "init.h"
+#include "path.h"
 #include "space.h"
 
 #ifndef XFS_IOC_AGCONTROL
diff --git a/spaceman/file.c b/spaceman/file.c
index 9356066..7c5ea0e 100644
--- a/spaceman/file.c
+++ b/spaceman/file.c
@@ -22,6 +22,7 @@
 #include "command.h"
 #include "input.h"
 #include "init.h"
+#include "path.h"
 #include "space.h"
 
 static cmdinfo_t print_cmd;
@@ -69,8 +70,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;
 
 	fd = open(path, flags, mode);
@@ -95,6 +98,15 @@ openfile(
 		close(fd);
 		return -1;
 	}
+
+	if (fs_path) {
+		fsp = fs_table_lookup(path, FS_MOUNT_POINT);
+		if (!fsp) {
+			fprintf(stderr, _("Unable to find XFS information."));
+			return -1;
+		}
+		*fs_path = *fsp;
+	}
 	return fd;
 }
 
@@ -103,7 +115,8 @@ addfile(
 	char		*name,
 	int		fd,
 	xfs_fsop_geom_t	*geometry,
-	int		flags)
+	int		flags,
+	struct fs_path	*fs_path)
 {
 	char		*filename;
 
@@ -131,6 +144,7 @@ addfile(
 	file->flags = flags;
 	file->name = filename;
 	file->geom = *geometry;
+	file->fs_path = *fs_path;
 	return 0;
 }
 
diff --git a/spaceman/freesp.c b/spaceman/freesp.c
new file mode 100644
index 0000000..5493916
--- /dev/null
+++ b/spaceman/freesp.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
+ * Copyright (c) 2012 Red Hat, Inc.
+ * Copyright (c) 2017 Oracle.
+ * 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 "libxfs.h"
+#include <linux/fiemap.h>
+#include "command.h"
+#include "init.h"
+#include "path.h"
+#include "space.h"
+
+typedef struct histent
+{
+	int		low;
+	int		high;
+	long long	count;
+	long long	blocks;
+} histent_t;
+
+static int		agcount;
+static xfs_agnumber_t	*aglist;
+static int		dumpflag;
+static int		equalsize;
+static histent_t	*hist;
+static int		histcount;
+static int		multsize;
+static int		seen1;
+static int		summaryflag;
+static bool		rtflag;
+static long long	totblocks;
+static long long	totexts;
+
+static cmdinfo_t freesp_cmd;
+
+static void
+addhistent(
+	int	h)
+{
+	hist = realloc(hist, (histcount + 1) * sizeof(*hist));
+	if (h == 0)
+		h = 1;
+	hist[histcount].low = h;
+	hist[histcount].count = hist[histcount].blocks = 0;
+	histcount++;
+	if (h == 1)
+		seen1 = 1;
+}
+
+static void
+addtohist(
+	xfs_agnumber_t	agno,
+	xfs_agblock_t	agbno,
+	off64_t		len)
+{
+	int		i;
+
+	if (dumpflag)
+		printf("%8d %8d %8"PRId64"\n", agno, agbno, len);
+	totexts++;
+	totblocks += len;
+	for (i = 0; i < histcount; i++) {
+		if (hist[i].high >= len) {
+			hist[i].count++;
+			hist[i].blocks += len;
+			break;
+		}
+	}
+}
+
+static int
+hcmp(
+	const void	*a,
+	const void	*b)
+{
+	return ((histent_t *)a)->low - ((histent_t *)b)->low;
+}
+
+static void
+histinit(
+	int	maxlen)
+{
+	int	i;
+
+	if (equalsize) {
+		for (i = 1; i < maxlen; i += equalsize)
+			addhistent(i);
+	} else if (multsize) {
+		for (i = 1; i < maxlen; i *= multsize)
+			addhistent(i);
+	} else {
+		if (!seen1)
+			addhistent(1);
+		qsort(hist, histcount, sizeof(*hist), hcmp);
+	}
+	for (i = 0; i < histcount; i++) {
+		if (i < histcount - 1)
+			hist[i].high = hist[i + 1].low - 1;
+		else
+			hist[i].high = maxlen;
+	}
+}
+
+static void
+printhist(void)
+{
+	int	i;
+
+	printf("%7s %7s %7s %7s %6s\n",
+		_("from"), _("to"), _("extents"), _("blocks"), _("pct"));
+	for (i = 0; i < histcount; i++) {
+		if (hist[i].count)
+			printf("%7d %7d %7lld %7lld %6.2f\n", hist[i].low,
+				hist[i].high, hist[i].count, hist[i].blocks,
+				hist[i].blocks * 100.0 / totblocks);
+	}
+}
+
+static int
+inaglist(
+	xfs_agnumber_t	agno)
+{
+	int		i;
+
+	if (agcount == 0)
+		return 1;
+	for (i = 0; i < agcount; i++)
+		if (aglist[i] == agno)
+			return 1;
+	return 0;
+}
+
+#define NR_EXTENTS 128
+
+static void
+scan_ag(
+	xfs_agnumber_t		agno)
+{
+	struct fsmap_head	*fsmap;
+	struct fsmap		*extent;
+	struct fsmap		*l, *h;
+	struct fsmap		*p;
+	off64_t			blocksize = file->geom.blocksize;
+	off64_t			bperag;
+	off64_t			aglen;
+	xfs_agblock_t		agbno;
+	int			ret;
+	int			i;
+
+	bperag = (off64_t)file->geom.agblocks * blocksize;
+
+	fsmap = malloc(fsmap_sizeof(NR_EXTENTS));
+	if (!fsmap) {
+		fprintf(stderr, _("%s: fsmap malloc failed.\n"), progname);
+		exitcode = 1;
+		return;
+	}
+
+	memset(fsmap, 0, sizeof(*fsmap));
+	fsmap->fmh_count = NR_EXTENTS;
+	l = fsmap->fmh_keys;
+	h = fsmap->fmh_keys + 1;
+	if (agno != NULLAGNUMBER) {
+		l->fmr_physical = agno * bperag;
+		h->fmr_physical = ((agno + 1) * bperag) - 1;
+		l->fmr_device = h->fmr_device = file->fs_path.fs_datadev;
+	} else {
+		l->fmr_physical = 0;
+		h->fmr_physical = ULLONG_MAX;
+		l->fmr_device = h->fmr_device = file->fs_path.fs_rtdev;
+	}
+	h->fmr_owner = ULLONG_MAX;
+	h->fmr_flags = UINT_MAX;
+	h->fmr_offset = ULLONG_MAX;
+
+	while (true) {
+		ret = ioctl(file->fd, FS_IOC_GETFSMAP, fsmap);
+		if (ret < 0) {
+			fprintf(stderr,
+_("%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n"),
+				progname, file->name, strerror(errno));
+			free(fsmap);
+			exitcode = 1;
+			return;
+		}
+
+		/* No more extents to map, exit */
+		if (!fsmap->fmh_entries)
+			break;
+
+		for (i = 0, extent = fsmap->fmh_recs;
+		     i < fsmap->fmh_entries;
+		     i++, extent++) {
+			if (!(extent->fmr_flags & FMR_OF_SPECIAL_OWNER) ||
+			    extent->fmr_owner != XFS_FMR_OWN_FREE)
+				continue;
+			agbno = (extent->fmr_physical - (bperag * agno)) /
+								blocksize;
+			aglen = extent->fmr_length / blocksize;
+
+			addtohist(agno, agbno, aglen);
+		}
+
+		p = &fsmap->fmh_recs[fsmap->fmh_entries - 1];
+		if (p->fmr_flags & FMR_OF_LAST)
+			break;
+		fsmap_advance(fsmap);
+	}
+}
+static void
+aglistadd(
+	char	*a)
+{
+	aglist = realloc(aglist, (agcount + 1) * sizeof(*aglist));
+	aglist[agcount] = (xfs_agnumber_t)atoi(a);
+	agcount++;
+}
+
+static int
+init(
+	int		argc,
+	char		**argv)
+{
+	int		c;
+	int		speced = 0;
+
+	agcount = dumpflag = equalsize = multsize = optind = 0;
+	histcount = seen1 = summaryflag = 0;
+	totblocks = totexts = 0;
+	aglist = NULL;
+	hist = NULL;
+	rtflag = false;
+	while ((c = getopt(argc, argv, "a:bde:h:m:rs")) != EOF) {
+		switch (c) {
+		case 'a':
+			aglistadd(optarg);
+			break;
+		case 'b':
+			if (speced)
+				return 0;
+			multsize = 2;
+			speced = 1;
+			break;
+		case 'd':
+			dumpflag = 1;
+			break;
+		case 'e':
+			if (speced)
+				return 0;
+			equalsize = atoi(optarg);
+			speced = 1;
+			break;
+		case 'h':
+			if (speced && !histcount)
+				return 0;
+			addhistent(atoi(optarg));
+			speced = 1;
+			break;
+		case 'm':
+			if (speced)
+				return 0;
+			multsize = atoi(optarg);
+			speced = 1;
+			break;
+		case 'r':
+			rtflag = true;
+			break;
+		case 's':
+			summaryflag = 1;
+			break;
+		case '?':
+			return 0;
+		}
+	}
+	if (optind != argc)
+		return 0;
+	if (!speced)
+		multsize = 2;
+	histinit(file->geom.agblocks);
+	return 1;
+}
+
+/*
+ * Report on freespace usage in xfs filesystem.
+ */
+static int
+freesp_f(
+	int		argc,
+	char		**argv)
+{
+	xfs_agnumber_t	agno;
+
+	if (!init(argc, argv))
+		return 0;
+	if (rtflag)
+		scan_ag(NULLAGNUMBER);
+	for (agno = 0; !rtflag && agno < file->geom.agcount; agno++)  {
+		if (inaglist(agno))
+			scan_ag(agno);
+	}
+	if (histcount)
+		printhist();
+	if (summaryflag) {
+		printf(_("total free extents %lld\n"), totexts);
+		printf(_("total free blocks %lld\n"), totblocks);
+		printf(_("average free extent size %g\n"),
+			(double)totblocks / (double)totexts);
+	}
+	if (aglist)
+		free(aglist);
+	if (hist)
+		free(hist);
+	return 0;
+}
+
+static void
+freesp_help(void)
+{
+	printf(_(
+"\n"
+"Examine filesystem free space\n"
+"\n"
+"Options: [-bcds] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n"
+"\n"
+" -b -- binary histogram bin size\n"
+" -d -- debug output\n"
+" -r -- display realtime device free space information\n"
+" -s -- emit freespace summary information\n"
+" -a agno -- scan only the given AG agno\n"
+" -e bsize -- use fixed histogram bin size of bsize\n"
+" -h h1 -- use custom histogram bin size of h1. Multiple specifications allowed.\n"
+" -m bmult -- use histogram bin size multiplier of bmult\n"
+"\n"));
+
+}
+
+void
+freesp_init(void)
+{
+	freesp_cmd.name = "freesp";
+	freesp_cmd.altname = "fsp";
+	freesp_cmd.cfunc = freesp_f;
+	freesp_cmd.argmin = 0;
+	freesp_cmd.argmax = -1;
+	freesp_cmd.args = "[-bcds] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n";
+	freesp_cmd.flags = CMD_FLAG_ONESHOT | CMD_FLAG_FOREIGN_OK;
+	freesp_cmd.oneline = _("Examine filesystem free space");
+	freesp_cmd.help = freesp_help;
+
+	add_command(&freesp_cmd);
+}
+
diff --git a/spaceman/init.c b/spaceman/init.c
index 08b5a33..e6df7fe 100644
--- a/spaceman/init.c
+++ b/spaceman/init.c
@@ -20,6 +20,7 @@
 #include "command.h"
 #include "input.h"
 #include "init.h"
+#include "path.h"
 #include "space.h"
 
 char	*progname;
@@ -38,6 +39,7 @@ static void
 init_commands(void)
 {
 	file_init();
+	freesp_init();
 	help_init();
 	prealloc_init();
 	quit_init();
@@ -71,12 +73,14 @@ init(
 	int		c, flags = 0;
 	mode_t		mode = 0600;
 	xfs_fsop_geom_t	geometry = { 0 };
+	struct fs_path	fsp;
 
 	progname = basename(argv[0]);
 	setlocale(LC_ALL, "");
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
 
+	fs_table_initialise(0, NULL, 0, NULL);
 	while ((c = getopt(argc, argv, "c:V")) != EOF) {
 		switch (c) {
 		case 'c':
@@ -94,11 +98,12 @@ init(
 		usage();
 
 	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))
 			printf(_("Not an XFS filesystem!\n"));
-		if (addfile(argv[optind], c, &geometry, flags) < 0)
+		if (addfile(argv[optind], c, &geometry, flags, &fsp) < 0)
 			exit(1);
 		optind++;
 	}
diff --git a/spaceman/prealloc.c b/spaceman/prealloc.c
index b93f909..249d7a4 100644
--- a/spaceman/prealloc.c
+++ b/spaceman/prealloc.c
@@ -20,6 +20,7 @@
 #include "command.h"
 #include "input.h"
 #include "init.h"
+#include "path.h"
 #include "space.h"
 
 #ifndef XFS_IOC_FREE_EOFBLOCKS
diff --git a/spaceman/space.h b/spaceman/space.h
index 0ae3116..bf9a2df 100644
--- a/spaceman/space.h
+++ b/spaceman/space.h
@@ -21,6 +21,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 */
@@ -28,11 +29,18 @@ extern int		filecount;	/* number of open files */
 extern fileio_t		*file;		/* active file in file table */
 extern int filelist_f(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	file_init(void);
 extern void	help_init(void);
 extern void	prealloc_init(void);
 extern void	quit_init(void);
 extern void	trim_init(void);
+
+#ifdef HAVE_GETFSMAP
+extern void	freesp_init(void);
+#else
+# define freesp_init()	do { } while (0)
+#endif
diff --git a/spaceman/trim.c b/spaceman/trim.c
index 9bf6565..d1e5d82 100644
--- a/spaceman/trim.c
+++ b/spaceman/trim.c
@@ -20,6 +20,7 @@
 #include <linux/fs.h>
 #include "command.h"
 #include "init.h"
+#include "path.h"
 #include "space.h"
 #include "input.h"
 


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 8/9] xfs_spaceman: add a man page
  2017-05-07 15:56 [PATCH v7 0/9] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
                   ` (6 preceding siblings ...)
  2017-05-07 15:57 ` [PATCH 7/9] xfs_spaceman: Free space mapping command Darrick J. Wong
@ 2017-05-07 15:57 ` Darrick J. Wong
  2017-05-07 15:57 ` [PATCH 9/9] xfs_spaceman: add group summary mode Darrick J. Wong
  2017-05-08 19:47 ` [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl Darrick J. Wong
  9 siblings, 0 replies; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-07 15:57 UTC (permalink / raw)
  To: sandeen, darrick.wong; +Cc: linux-xfs

From: Darrick J. Wong <darrick.wong@oracle.com>

Add a manual page describing xfs_spaceman's behavior.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 man/man8/xfs_spaceman.8 |  102 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 102 insertions(+)
 create mode 100644 man/man8/xfs_spaceman.8


diff --git a/man/man8/xfs_spaceman.8 b/man/man8/xfs_spaceman.8
new file mode 100644
index 0000000..c1d19c0
--- /dev/null
+++ b/man/man8/xfs_spaceman.8
@@ -0,0 +1,102 @@
+.TH xfs_spaceman 8
+.SH NAME
+xfs_spaceman \- show free space information about an XFS filesystem
+.SH SYNOPSIS
+.B xfs_spaceman
+[
+.B \-c
+.I cmd
+]
+.I file
+.br
+.B xfs_spaceman \-V
+.SH DESCRIPTION
+.B xfs_spaceman
+reports and controls free space usage in an XFS filesystem.
+.SH OPTIONS
+.TP 1.0i
+.BI \-c " cmd"
+.B xfs_spaceman
+commands may be run interactively (the default) or as arguments on
+the command line. Multiple
+.B \-c
+arguments may be given. The commands are run in the sequence given,
+then the program exits.
+
+.SH COMMANDS
+.TP
+.BI "freesp [ \-sr ] [ \-b | \-e bsize | \-h h1 [ \-m bmult ]] [-a agno]"
+With no arguments,
+.B freesp
+shows a histogram of all free space extents in the filesystem.
+The
+.B -b
+argument establishes that the histogram bins are successive powers of two.
+This is the default.
+The
+.BR -h " and " -m
+options can be used to specify a custom histogram bin size as well as a
+multiplication factor for subsequent bin sizes.
+The
+.BR -e
+option fixes the histogram size to a particular value.
+The
+.BR -a " and " -r
+options constrain the free space information report to a particular AG
+or the realtime device, respectively.  The
+.B -a
+option may be specified multiple times.
+A summary of free space information will be printed if the
+.B -s
+option is given.
+.TP
+.BR "help [ " command " ]"
+Display a brief description of one or all commands.
+.TP
+.BI "prealloc [ \-ugp id ] [ \-m minlen ] [ \-s ]"
+Controls speculative preallocation.  The
+.BR -u ","
+.BR -g ","
+and
+.B -p
+options will clear all speculative preallocations for a given user,
+group, or project ID, respectively.
+The
+.B -m
+option causes the operation to ignore any file with a size smaller than
+.BR minlen "."
+The
+.B -s
+option will flush all dirty data and metadata to disk.
+.TP
+.B print
+Display a list of all open files.
+.TP
+.B quit
+Exit
+.BR xfs_spaceman .
+.TP
+.BI "trim [ \-f ] [ \-a agno ] [ \-m minlen ] [" " offset length " ]
+Instructs the underlying storage device to release all storage that may
+be backing free space in the filesystem.
+The
+.B -f
+option trims all free space in the entire filesystem.
+The
+.B -a
+option trims only the free space in a given AG.
+The
+.B -m
+option only trims free space extents that are longer than
+.IR minlen "."
+The
+.IR offset " and " length
+arguments trim all free space between
+.I offset
+and
+.IR "offset+length" "."
+The
+.BR -a " and " -f
+options are mutually exclusive with each other as well as with the
+.IR offset " and " length
+arguments.


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 9/9] xfs_spaceman: add group summary mode
  2017-05-07 15:56 [PATCH v7 0/9] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
                   ` (7 preceding siblings ...)
  2017-05-07 15:57 ` [PATCH 8/9] xfs_spaceman: add a man page Darrick J. Wong
@ 2017-05-07 15:57 ` Darrick J. Wong
  2017-05-08 19:47 ` [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl Darrick J. Wong
  9 siblings, 0 replies; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-07 15:57 UTC (permalink / raw)
  To: sandeen, darrick.wong; +Cc: linux-xfs

From: Darrick J. Wong <darrick.wong@oracle.com>

Add a -g switch to show only a per-group summary.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 man/man8/xfs_spaceman.8 |    8 +++++++-
 spaceman/freesp.c       |   27 ++++++++++++++++++++++++---
 2 files changed, 31 insertions(+), 4 deletions(-)


diff --git a/man/man8/xfs_spaceman.8 b/man/man8/xfs_spaceman.8
index c1d19c0..a57a0c3 100644
--- a/man/man8/xfs_spaceman.8
+++ b/man/man8/xfs_spaceman.8
@@ -25,7 +25,7 @@ then the program exits.
 
 .SH COMMANDS
 .TP
-.BI "freesp [ \-sr ] [ \-b | \-e bsize | \-h h1 [ \-m bmult ]] [-a agno]"
+.BI "freesp [ \-srg ] [ \-b | \-e bsize | \-h h1 [ \-m bmult ]] [-a agno]"
 With no arguments,
 .B freesp
 shows a histogram of all free space extents in the filesystem.
@@ -49,6 +49,12 @@ option may be specified multiple times.
 A summary of free space information will be printed if the
 .B -s
 option is given.
+The
+.B -g
+option prints a brief per-AG summary of the free space found in that AG.
+If
+.B -r
+is specified it will also report on free space in the realtime device.
 .TP
 .BR "help [ " command " ]"
 Display a brief description of one or all commands.
diff --git a/spaceman/freesp.c b/spaceman/freesp.c
index 5493916..da66de3 100644
--- a/spaceman/freesp.c
+++ b/spaceman/freesp.c
@@ -42,6 +42,7 @@ static int		histcount;
 static int		multsize;
 static int		seen1;
 static int		summaryflag;
+static int		gflag;
 static bool		rtflag;
 static long long	totblocks;
 static long long	totexts;
@@ -159,6 +160,8 @@ scan_ag(
 	off64_t			bperag;
 	off64_t			aglen;
 	xfs_agblock_t		agbno;
+	unsigned long long	freeblks = 0;
+	unsigned long long	freeexts = 0;
 	int			ret;
 	int			i;
 
@@ -212,6 +215,8 @@ _("%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n"),
 			agbno = (extent->fmr_physical - (bperag * agno)) /
 								blocksize;
 			aglen = extent->fmr_length / blocksize;
+			freeblks += aglen;
+			freeexts++;
 
 			addtohist(agno, agbno, aglen);
 		}
@@ -221,6 +226,15 @@ _("%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n"),
 			break;
 		fsmap_advance(fsmap);
 	}
+
+	if (gflag) {
+		if (agno == NULLAGNUMBER)
+			printf(_("     rtdev %10llu %10llu\n"), freeexts,
+					freeblks);
+		else
+			printf(_("%10u %10llu %10llu\n"), agno, freeexts,
+					freeblks);
+	}
 }
 static void
 aglistadd(
@@ -245,7 +259,7 @@ init(
 	aglist = NULL;
 	hist = NULL;
 	rtflag = false;
-	while ((c = getopt(argc, argv, "a:bde:h:m:rs")) != EOF) {
+	while ((c = getopt(argc, argv, "a:bde:gh:m:rs")) != EOF) {
 		switch (c) {
 		case 'a':
 			aglistadd(optarg);
@@ -265,6 +279,10 @@ init(
 			equalsize = atoi(optarg);
 			speced = 1;
 			break;
+		case 'g':
+			histcount = 0;
+			gflag++;
+			break;
 		case 'h':
 			if (speced && !histcount)
 				return 0;
@@ -307,13 +325,15 @@ freesp_f(
 
 	if (!init(argc, argv))
 		return 0;
+	if (gflag)
+		printf(_("        AG    extents     blocks\n"));
 	if (rtflag)
 		scan_ag(NULLAGNUMBER);
 	for (agno = 0; !rtflag && agno < file->geom.agcount; agno++)  {
 		if (inaglist(agno))
 			scan_ag(agno);
 	}
-	if (histcount)
+	if (histcount && !gflag)
 		printhist();
 	if (summaryflag) {
 		printf(_("total free extents %lld\n"), totexts);
@@ -335,10 +355,11 @@ freesp_help(void)
 "\n"
 "Examine filesystem free space\n"
 "\n"
-"Options: [-bcds] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n"
+"Options: [-bcdgs] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n"
 "\n"
 " -b -- binary histogram bin size\n"
 " -d -- debug output\n"
+" -g -- print per-AG summary\n"
 " -r -- display realtime device free space information\n"
 " -s -- emit freespace summary information\n"
 " -a agno -- scan only the given AG agno\n"


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl
  2017-05-07 15:56 [PATCH v7 0/9] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
                   ` (8 preceding siblings ...)
  2017-05-07 15:57 ` [PATCH 9/9] xfs_spaceman: add group summary mode Darrick J. Wong
@ 2017-05-08 19:47 ` Darrick J. Wong
  2017-05-10 14:46   ` Eric Sandeen
                     ` (2 more replies)
  9 siblings, 3 replies; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-08 19:47 UTC (permalink / raw)
  To: sandeen; +Cc: linux-xfs

From: Darrick J. Wong <darrick.wong@oracle.com>

Introduce a new ioctl that uses the reverse mapping btree to return
information about the physical layout of the filesystem.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 configure.ac          |    1 
 include/builddefs.in  |    7 +++
 include/linux.h       |  109 +++++++++++++++++++++++++++++++++++++++++++++++++
 libxfs/xfs_fs.h       |   13 ++++++
 libxfs/xfs_rmap.c     |   28 +++++++++++++
 libxfs/xfs_rmap.h     |    2 +
 m4/package_libcdev.m4 |   19 +++++++++
 7 files changed, 178 insertions(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index aa102e4..794a804 100644
--- a/configure.ac
+++ b/configure.ac
@@ -142,6 +142,7 @@ AC_HAVE_READDIR
 AC_HAVE_FSETXATTR
 AC_HAVE_MREMAP
 AC_NEED_INTERNAL_FSXATTR
+AC_HAVE_SYS_GETFSMAP
 
 if test "$enable_blkid" = yes; then
 AC_HAVE_BLKID_TOPO
diff --git a/include/builddefs.in b/include/builddefs.in
index 4d6bb2d..e285731 100644
--- a/include/builddefs.in
+++ b/include/builddefs.in
@@ -112,16 +112,18 @@ HAVE_FLS = @have_fls@
 HAVE_FSETXATTR = @have_fsetxattr@
 HAVE_MREMAP = @have_mremap@
 NEED_INTERNAL_FSXATTR = @need_internal_fsxattr@
+HAVE_SYS_GETFSMAP = @have_sys_getfsmap@
 
 GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
 #	   -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
 
 ifeq ($(PKG_PLATFORM),linux)
-PCFLAGS = -D_GNU_SOURCE $(GCCFLAGS)
+PCFLAGS = -D_GNU_SOURCE $(GCCFLAGS) -DHAVE_GETFSMAP
 ifeq ($(HAVE_UMODE_T),yes)
 PCFLAGS += -DHAVE_UMODE_T
 endif
 DEPENDFLAGS = -D__linux__
+HAVE_GETFSMAP = yes
 endif
 ifeq ($(PKG_PLATFORM),gnukfreebsd)
 PCFLAGS = -D_GNU_SOURCE $(GCCFLAGS)
@@ -150,6 +152,9 @@ endif
 ifeq ($(NEED_INTERNAL_FSXATTR),yes)
 PCFLAGS+= -DOVERRIDE_SYSTEM_FSXATTR
 endif
+ifeq ($(PKG_PLATFORM)_$(HAVE_SYS_GETFSMAP),linux_)
+PCFLAGS+= -DOVERRIDE_GETFSMAP
+endif
 
 
 GCFLAGS = $(DEBUG) \
diff --git a/include/linux.h b/include/linux.h
index 6a676ca..181d25c 100644
--- a/include/linux.h
+++ b/include/linux.h
@@ -35,7 +35,15 @@
 #ifdef OVERRIDE_SYSTEM_FSXATTR
 # define fsxattr sys_fsxattr
 #endif
+#ifdef OVERRIDE_GETFSMAP
+# define fsmap sys_fsmap
+# define fsmap_head sys_fsmap_head
+#endif
 #include <linux/fs.h> /* fsxattr defintion for new kernels */
+#ifdef OVERRIDE_GETFSMAP
+# undef fsmap
+# undef fsmap_head
+#endif
 #ifdef OVERRIDE_SYSTEM_FSXATTR
 # undef fsxattr
 #endif
@@ -222,4 +230,105 @@ struct fsxattr {
 #define FS_XFLAG_COWEXTSIZE	0x00010000	/* CoW extent size allocator hint */
 #endif
 
+#ifdef OVERRIDE_GETFSMAP
+/*
+ *	Structure for FS_IOC_GETFSMAP.
+ *
+ *	The memory layout for this call are the scalar values defined in
+ *	struct fsmap_head, followed by two struct fsmap that describe
+ *	the lower and upper bound of mappings to return, followed by an
+ *	array of struct fsmap mappings.
+ *
+ *	fmh_iflags control the output of the call, whereas fmh_oflags report
+ *	on the overall record output.  fmh_count should be set to the
+ *	length of the fmh_recs array, and fmh_entries will be set to the
+ *	number of entries filled out during each call.  If fmh_count is
+ *	zero, the number of reverse mappings will be returned in
+ *	fmh_entries, though no mappings will be returned.  fmh_reserved
+ *	must be set to zero.
+ *
+ *	The two elements in the fmh_keys array are used to constrain the
+ *	output.  The first element in the array should represent the
+ *	lowest disk mapping ("low key") that the user wants to learn
+ *	about.  If this value is all zeroes, the filesystem will return
+ *	the first entry it knows about.  For a subsequent call, the
+ *	contents of fsmap_head.fmh_recs[fsmap_head.fmh_count - 1] should be
+ *	copied into fmh_keys[0] to have the kernel start where it left off.
+ *
+ *	The second element in the fmh_keys array should represent the
+ *	highest disk mapping ("high key") that the user wants to learn
+ *	about.  If this value is all ones, the filesystem will not stop
+ *	until it runs out of mapping to return or runs out of space in
+ *	fmh_recs.
+ *
+ *	fmr_device can be either a 32-bit cookie representing a device, or
+ *	a 32-bit dev_t if the FMH_OF_DEV_T flag is set.  fmr_physical,
+ *	fmr_offset, and fmr_length are expressed in units of bytes.
+ *	fmr_owner is either an inode number, or a special value if
+ *	FMR_OF_SPECIAL_OWNER is set in fmr_flags.
+ */
+struct fsmap {
+	__u32		fmr_device;	/* device id */
+	__u32		fmr_flags;	/* mapping flags */
+	__u64		fmr_physical;	/* device offset of segment */
+	__u64		fmr_owner;	/* owner id */
+	__u64		fmr_offset;	/* file offset of segment */
+	__u64		fmr_length;	/* length of segment */
+	__u64		fmr_reserved[3];	/* must be zero */
+};
+
+struct fsmap_head {
+	__u32		fmh_iflags;	/* control flags */
+	__u32		fmh_oflags;	/* output flags */
+	__u32		fmh_count;	/* # of entries in array incl. input */
+	__u32		fmh_entries;	/* # of entries filled in (output). */
+	__u64		fmh_reserved[6];	/* must be zero */
+
+	struct fsmap	fmh_keys[2];	/* low and high keys for the mapping search */
+	struct fsmap	fmh_recs[];	/* returned records */
+};
+
+/* Size of an fsmap_head with room for nr records. */
+static inline size_t
+fsmap_sizeof(
+	unsigned int	nr)
+{
+	return sizeof(struct fsmap_head) + nr * sizeof(struct fsmap);
+}
+
+/* Start the next fsmap query at the end of the current query results. */
+static inline void
+fsmap_advance(
+	struct fsmap_head	*head)
+{
+	head->fmh_keys[0] = head->fmh_recs[head->fmh_entries - 1];
+}
+
+/*	fmh_iflags values - set by XFS_IOC_GETFSMAP caller in the header. */
+/* no flags defined yet */
+#define FMH_IF_VALID		0
+
+/*	fmh_oflags values - returned in the header segment only. */
+#define FMH_OF_DEV_T		0x1	/* fmr_device values will be dev_t */
+
+/*	fmr_flags values - returned for each non-header segment */
+#define FMR_OF_PREALLOC		0x1	/* segment = unwritten pre-allocation */
+#define FMR_OF_ATTR_FORK	0x2	/* segment = attribute fork */
+#define FMR_OF_EXTENT_MAP	0x4	/* segment = extent map */
+#define FMR_OF_SHARED		0x8	/* segment = shared with another file */
+#define FMR_OF_SPECIAL_OWNER	0x10	/* owner is a special value */
+#define FMR_OF_LAST		0x20	/* segment is the last in the FS */
+
+/* Each FS gets to define its own special owner codes. */
+#define FMR_OWNER(type, code)	(((__u64)type << 32) | \
+				 ((__u64)code & 0xFFFFFFFFULL))
+#define FMR_OWNER_TYPE(owner)	((__u32)((__u64)owner >> 32))
+#define FMR_OWNER_CODE(owner)	((__u32)(((__u64)owner & 0xFFFFFFFFULL)))
+#define FMR_OWN_FREE		FMR_OWNER(0, 1) /* free space */
+#define FMR_OWN_UNKNOWN		FMR_OWNER(0, 2) /* unknown owner */
+#define FMR_OWN_METADATA	FMR_OWNER(0, 3) /* metadata */
+
+#define FS_IOC_GETFSMAP		_IOWR('X', 59, struct fsmap_head)
+#endif /* OVERRIDE_GETFSMAP */
+
 #endif	/* __XFS_LINUX_H__ */
diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h
index 11fe42a..1831cff 100644
--- a/libxfs/xfs_fs.h
+++ b/libxfs/xfs_fs.h
@@ -113,6 +113,18 @@ struct getbmapx {
 #define BMV_OF_LAST		0x4	/* segment is the last in the file */
 #define BMV_OF_SHARED		0x8	/* segment shared with another file */
 
+/*	fmr_owner special values for FS_IOC_GETFSMAP */
+#define XFS_FMR_OWN_FREE	FMR_OWN_FREE      /* free space */
+#define XFS_FMR_OWN_UNKNOWN	FMR_OWN_UNKNOWN   /* unknown owner */
+#define XFS_FMR_OWN_FS		FMR_OWNER('X', 1) /* static fs metadata */
+#define XFS_FMR_OWN_LOG		FMR_OWNER('X', 2) /* journalling log */
+#define XFS_FMR_OWN_AG		FMR_OWNER('X', 3) /* per-AG metadata */
+#define XFS_FMR_OWN_INOBT	FMR_OWNER('X', 4) /* inode btree blocks */
+#define XFS_FMR_OWN_INODES	FMR_OWNER('X', 5) /* inodes */
+#define XFS_FMR_OWN_REFC	FMR_OWNER('X', 6) /* refcount tree */
+#define XFS_FMR_OWN_COW		FMR_OWNER('X', 7) /* cow staging */
+#define XFS_FMR_OWN_DEFECTIVE	FMR_OWNER('X', 8) /* bad blocks */
+
 /*
  * Structure for XFS_IOC_FSSETDM.
  * For use by backup and restore programs to set the XFS on-disk inode
@@ -522,6 +534,7 @@ typedef struct xfs_swapext
 #define XFS_IOC_GETBMAPX	_IOWR('X', 56, struct getbmap)
 #define XFS_IOC_ZERO_RANGE	_IOW ('X', 57, struct xfs_flock64)
 #define XFS_IOC_FREE_EOFBLOCKS	_IOR ('X', 58, struct xfs_fs_eofblocks)
+/*	XFS_IOC_GETFSMAP ------ hoisted 59         */
 
 /*
  * ioctl commands that replace IRIX syssgi()'s
diff --git a/libxfs/xfs_rmap.c b/libxfs/xfs_rmap.c
index 7738f50..f78771d 100644
--- a/libxfs/xfs_rmap.c
+++ b/libxfs/xfs_rmap.c
@@ -2303,3 +2303,31 @@ xfs_rmap_free_extent(
 	return __xfs_rmap_add(mp, dfops, XFS_RMAP_FREE, owner,
 			XFS_DATA_FORK, &bmap);
 }
+
+/* Compare rmap records.  Returns -1 if a < b, 1 if a > b, and 0 if equal. */
+int
+xfs_rmap_compare(
+	const struct xfs_rmap_irec	*a,
+	const struct xfs_rmap_irec	*b)
+{
+	__u64				oa;
+	__u64				ob;
+
+	oa = xfs_rmap_irec_offset_pack(a);
+	ob = xfs_rmap_irec_offset_pack(b);
+
+	if (a->rm_startblock < b->rm_startblock)
+		return -1;
+	else if (a->rm_startblock > b->rm_startblock)
+		return 1;
+	else if (a->rm_owner < b->rm_owner)
+		return -1;
+	else if (a->rm_owner > b->rm_owner)
+		return 1;
+	else if (oa < ob)
+		return -1;
+	else if (oa > ob)
+		return 1;
+	else
+		return 0;
+}
diff --git a/libxfs/xfs_rmap.h b/libxfs/xfs_rmap.h
index faf2c1a..98f908f 100644
--- a/libxfs/xfs_rmap.h
+++ b/libxfs/xfs_rmap.h
@@ -214,5 +214,7 @@ int xfs_rmap_find_left_neighbor(struct xfs_btree_cur *cur, xfs_agblock_t bno,
 int xfs_rmap_lookup_le_range(struct xfs_btree_cur *cur, xfs_agblock_t bno,
 		uint64_t owner, uint64_t offset, unsigned int flags,
 		struct xfs_rmap_irec *irec, int	*stat);
+int xfs_rmap_compare(const struct xfs_rmap_irec *a,
+		const struct xfs_rmap_irec *b);
 
 #endif	/* __XFS_RMAP_H__ */
diff --git a/m4/package_libcdev.m4 b/m4/package_libcdev.m4
index bc3b4ce..f9b0945 100644
--- a/m4/package_libcdev.m4
+++ b/m4/package_libcdev.m4
@@ -277,3 +277,22 @@ AC_DEFUN([AC_NEED_INTERNAL_FSXATTR],
     )
     AC_SUBST(need_internal_fsxattr)
   ])
+
+#
+# Check if we have a FS_IOC_GETFSMAP ioctl (Linux)
+#
+AC_DEFUN([AC_HAVE_SYS_GETFSMAP],
+  [ AC_MSG_CHECKING([for GETFSMAP])
+    AC_TRY_LINK([
+#define _GNU_SOURCE
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <linux/fsmap.h>
+    ], [
+         unsigned long x = FS_IOC_GETFSMAP;
+         struct fsmap_head fh;
+    ], have_sys_getfsmap=yes
+       AC_MSG_RESULT(yes),
+       AC_MSG_RESULT(no))
+    AC_SUBST(have_sys_getfsmap)
+  ])

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/9] xfs_io: support the new getfsmap ioctl
  2017-05-07 15:56 ` [PATCH 1/9] xfs_io: support the new getfsmap ioctl Darrick J. Wong
@ 2017-05-08 21:01   ` Eric Sandeen
  2017-05-15 19:18     ` Darrick J. Wong
  0 siblings, 1 reply; 40+ messages in thread
From: Eric Sandeen @ 2017-05-08 21:01 UTC (permalink / raw)
  To: Darrick J. Wong, sandeen; +Cc: linux-xfs

On 5/7/17 10:56 AM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  io/Makefile          |    4 
>  io/copy_file_range.c |    2 
>  io/encrypt.c         |    1 
>  io/fsmap.c           |  559 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  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    |   47 ++++
>  11 files changed, 651 insertions(+), 13 deletions(-)
>  create mode 100644 io/fsmap.c
> 
> 
> diff --git a/io/Makefile b/io/Makefile
> index 435ccff..8d3a30e 100644
> --- a/io/Makefile
> +++ b/io/Makefile
> @@ -99,6 +99,10 @@ ifeq ($(HAVE_MREMAP),yes)
>  LCFLAGS += -DHAVE_MREMAP
>  endif
>  
> +ifeq ($(HAVE_GETFSMAP),yes)
> +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(&copy_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..4128fae
> --- /dev/null
> +++ b/io/fsmap.c
> @@ -0,0 +1,559 @@
> +/*
> + * Copyright (C) 2017 Oracle.  All Rights Reserved.
> + *
> + * Author: Darrick J. Wong <darrick.wong@oracle.com>
> + *
> + * 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 an XFS filesystem"

Did you want an \n" on the above line too?  Seems a bit odd to have it only on the next line.
(one \n is fine too, but not like this) :)

> +"\n"
> +" Example:\n"
> +" 'fsmap -dlrv [-n nr] [startoff] [endoff]' - tabular format verbose map, including unwritten extents\n"

This doesn't match the short help:

+	fsmap_cmd.args = _("[-v] [-n nx] [start] [end]");

or the manpage:

+.BI "fsmap [ \-v ] [ \-n " nx " ] [ " start " ] [ " end " ]

but getopt sez:

> +	while ((c = getopt(argc, argv, "dln:rv")) != EOF) {

so I guess the short help & manpage need updates.

Also, I don't think the "Example:" above is valid:

        if (dflag + lflag + rflag > 1)
                return command_usage(&fsmap_cmd);

so the help needs to indicate that exactly 1 of -d, -l, or -r is required.

> +"\n"
> +" fsmap prints the map of disk blocks used by the whole filesystem.\n"
> +" The map lists each extent used by the file

<newbie>

"the file?"  what file?

                                               , as well as regions in the\n"
> +" filesystem that do not have any corresponding blocks (free space).\n"
> +" By default, each line of the listing takes the following form:\n"
> +"     extent: [startoffset..endoffset] owner startblock..endblock\n"

say what "owner" means in this case?  </newbie>

> +" All the file offsets and disk blocks are in units of 512-byte blocks.\n"
> +" -d -- query only the data device.\n"
> +" -l -- query only the log device.\n"
> +" -r -- query only the realtime device.\n"
> +" -n -- query n extents.\n"
> +" -v -- Verbose information, specify ag info.  Show flags legend on 2nd -v\n"
> +"\n"));
> +}
> +
> +static int
> +numlen(
> +	off64_t	val)
> +{
> +	off64_t	tmp;
> +	int	len;
> +
> +	for (len = 0, tmp = val; tmp > 0; tmp = tmp/10)
> +		len++;
> +	return (len == 0 ? 1 : len);
> +}

Hm, copy #3, do we still not have anywhere to put common stuff like this?

> +
> +#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];
> +
> +	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));
> +		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 extent map"),
> +				(long long) p->fmr_owner);
> +		else
> +			printf(_("inode %lld %lld..%lld"),
> +				(long long)p->fmr_owner,
> +				(long long)BTOBBT(p->fmr_offset),
> +				(long long)BTOBBT(p->fmr_offset + p->fmr_length - 1));
> +		printf(_(" %lld blocks\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_SHARED	01000000	/* shared extent */
> +#define	FLG_ATTR_FORK	00100000	/* attribute fork */
> +#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 */

These really couldn't share w/ io/bmap.c?  :(
(could FLG_ATTR_FORK go to the end so that it matches bmap until then?)

speakinawhich, I wonder how much of this is copied from bmap, and what could
be shared?

I'm going to go off & look at that a bit, may have further comments.  :)


> diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
> index 29a036c..2c956b8 100644
> --- a/man/man8/xfs_io.8
> +++ b/man/man8/xfs_io.8
> @@ -301,6 +301,53 @@ ioctl.  Options behave as described in the
>  .BR xfs_bmap (8)
>  manual page.
>  .TP
> +.BI "fsmap [ \-v ] [ \-n " nx " ] [ " start " ] [ " end " ]
> +Prints the mapping of disk blocks used by an XFS filesystem.

FOREIGN_OK too right?

-Eric

>  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.
> +.BI "The optional " start " and " end " arguments can be used to constrain
> +the output to a particular range of disk blocks.
> +.RE
> +.RS 1.0i
> +.PD 0
> +.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 the number of extents in the filesystem and uses that
> +value to compute the group size.
> +.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.
> +.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@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl
  2017-05-08 19:47 ` [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl Darrick J. Wong
@ 2017-05-10 14:46   ` Eric Sandeen
  2017-05-10 17:03     ` Darrick J. Wong
  2017-05-12 22:29   ` Eric Sandeen
  2017-05-26 21:20   ` Eric Sandeen
  2 siblings, 1 reply; 40+ messages in thread
From: Eric Sandeen @ 2017-05-10 14:46 UTC (permalink / raw)
  To: Darrick J. Wong, sandeen; +Cc: linux-xfs

On 5/8/17 2:47 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Introduce a new ioctl that uses the reverse mapping btree to return
> information about the physical layout of the filesystem.

Thanks, I think it makes sense to pull in most of this via the normal
libxfs-sync method, then fix up the build infra for userspace
separately.  Sound ok?

-Eric
 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  configure.ac          |    1 
>  include/builddefs.in  |    7 +++
>  include/linux.h       |  109 +++++++++++++++++++++++++++++++++++++++++++++++++
>  libxfs/xfs_fs.h       |   13 ++++++
>  libxfs/xfs_rmap.c     |   28 +++++++++++++
>  libxfs/xfs_rmap.h     |    2 +
>  m4/package_libcdev.m4 |   19 +++++++++
>  7 files changed, 178 insertions(+), 1 deletion(-)
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl
  2017-05-10 14:46   ` Eric Sandeen
@ 2017-05-10 17:03     ` Darrick J. Wong
  0 siblings, 0 replies; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-10 17:03 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: sandeen, linux-xfs

On Wed, May 10, 2017 at 09:46:01AM -0500, Eric Sandeen wrote:
> On 5/8/17 2:47 PM, Darrick J. Wong wrote:
> > From: Darrick J. Wong <darrick.wong@oracle.com>
> > 
> > Introduce a new ioctl that uses the reverse mapping btree to return
> > information about the physical layout of the filesystem.
> 
> Thanks, I think it makes sense to pull in most of this via the normal
> libxfs-sync method, then fix up the build infra for userspace
> separately.  Sound ok?

Sure.  If you post a libxfs-sync-4.12 later I'll rebase on that and
send you the remaining pieces + review fixes.

--D

> 
> -Eric
>  
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> >  configure.ac          |    1 
> >  include/builddefs.in  |    7 +++
> >  include/linux.h       |  109 +++++++++++++++++++++++++++++++++++++++++++++++++
> >  libxfs/xfs_fs.h       |   13 ++++++
> >  libxfs/xfs_rmap.c     |   28 +++++++++++++
> >  libxfs/xfs_rmap.h     |    2 +
> >  m4/package_libcdev.m4 |   19 +++++++++
> >  7 files changed, 178 insertions(+), 1 deletion(-)
> > 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl
  2017-05-08 19:47 ` [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl Darrick J. Wong
  2017-05-10 14:46   ` Eric Sandeen
@ 2017-05-12 22:29   ` Eric Sandeen
  2017-05-12 23:05     ` Darrick J. Wong
  2017-05-26 21:20   ` Eric Sandeen
  2 siblings, 1 reply; 40+ messages in thread
From: Eric Sandeen @ 2017-05-12 22:29 UTC (permalink / raw)
  To: Darrick J. Wong, sandeen; +Cc: linux-xfs

On 5/8/17 2:47 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Introduce a new ioctl that uses the reverse mapping btree to return
> information about the physical layout of the filesystem.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  configure.ac          |    1 
>  include/builddefs.in  |    7 +++
>  include/linux.h       |  109 +++++++++++++++++++++++++++++++++++++++++++++++++

So, I'm torn about whether we should be adding all the fsmap definitions
into xfsprogs.  (I know... I did it for statx; I'm wondering if that was a
bad precedent, and/or if it being a syscall makes it a different situation...).

I don't know when we ever deprecate or remove this stuff.

If you use packaged kernels, you'll get updated headers pretty quickly, right,
or on a devel box you might install your own?

Not trying to be difficult, just trying to make sure we have a consistent
plan for new interfaces like this...

Thanks,
-Eric

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl
  2017-05-12 22:29   ` Eric Sandeen
@ 2017-05-12 23:05     ` Darrick J. Wong
  2017-05-12 23:11       ` Eric Sandeen
  0 siblings, 1 reply; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-12 23:05 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: sandeen, linux-xfs

On Fri, May 12, 2017 at 05:29:32PM -0500, Eric Sandeen wrote:
> On 5/8/17 2:47 PM, Darrick J. Wong wrote:
> > From: Darrick J. Wong <darrick.wong@oracle.com>
> > 
> > Introduce a new ioctl that uses the reverse mapping btree to return
> > information about the physical layout of the filesystem.
> > 
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> >  configure.ac          |    1 
> >  include/builddefs.in  |    7 +++
> >  include/linux.h       |  109 +++++++++++++++++++++++++++++++++++++++++++++++++
> 
> So, I'm torn about whether we should be adding all the fsmap definitions
> into xfsprogs.  (I know... I did it for statx; I'm wondering if that was a
> bad precedent, and/or if it being a syscall makes it a different situation...).
> 
> I don't know when we ever deprecate or remove this stuff.
> 
> If you use packaged kernels, you'll get updated headers pretty quickly, right,
> or on a devel box you might install your own?
> 
> Not trying to be difficult, just trying to make sure we have a consistent
> plan for new interfaces like this...

I was under the impression that we employ this evil hackery so that
developers (at least) can build binaries for testing until the kernel
headers in their build environments catch up.

...unfortunately, that sort of implies that the sunset horizon is
quite a ways out since I've never seen this stuff get removed.

--D

> 
> Thanks,
> -Eric
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl
  2017-05-12 23:05     ` Darrick J. Wong
@ 2017-05-12 23:11       ` Eric Sandeen
  0 siblings, 0 replies; 40+ messages in thread
From: Eric Sandeen @ 2017-05-12 23:11 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: sandeen, linux-xfs

On 5/12/17 6:05 PM, Darrick J. Wong wrote:
> On Fri, May 12, 2017 at 05:29:32PM -0500, Eric Sandeen wrote:
>> On 5/8/17 2:47 PM, Darrick J. Wong wrote:
>>> From: Darrick J. Wong <darrick.wong@oracle.com>
>>>
>>> Introduce a new ioctl that uses the reverse mapping btree to return
>>> information about the physical layout of the filesystem.
>>>
>>> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
>>> ---
>>>  configure.ac          |    1 
>>>  include/builddefs.in  |    7 +++
>>>  include/linux.h       |  109 +++++++++++++++++++++++++++++++++++++++++++++++++
>>
>> So, I'm torn about whether we should be adding all the fsmap definitions
>> into xfsprogs.  (I know... I did it for statx; I'm wondering if that was a
>> bad precedent, and/or if it being a syscall makes it a different situation...).
>>
>> I don't know when we ever deprecate or remove this stuff.
>>
>> If you use packaged kernels, you'll get updated headers pretty quickly, right,
>> or on a devel box you might install your own?
>>
>> Not trying to be difficult, just trying to make sure we have a consistent
>> plan for new interfaces like this...
> 
> I was under the impression that we employ this evil hackery so that
> developers (at least) can build binaries for testing until the kernel
> headers in their build environments catch up.

Well, like I said, yeah I did it for statx.  So, that's probably enough
for you to say "stop whining and merge it!"

But do we have it for anything else?

Ok, we do override fsxattr - that was also your doing.  ;)

I guess we did the same for the FS_IOC_SET_ENCRYPTION_POLICY stuff,
though /that/ is all self-contained in io/encrypt.c.

hohum.

Ok, let's merge it, but maybe we need a policy of "nuke it after a year"

-eric

> ...unfortunately, that sort of implies that the sunset horizon is
> quite a ways out since I've never seen this stuff get removed.
> 
> --D
> 
>>
>> Thanks,
>> -Eric
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/9] xfs_io: support the new getfsmap ioctl
  2017-05-08 21:01   ` Eric Sandeen
@ 2017-05-15 19:18     ` Darrick J. Wong
  2017-05-15 19:30       ` Eric Sandeen
  0 siblings, 1 reply; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-15 19:18 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: sandeen, linux-xfs

On Mon, May 08, 2017 at 04:01:11PM -0500, Eric Sandeen wrote:
> On 5/7/17 10:56 AM, Darrick J. Wong wrote:
> > From: Darrick J. Wong <darrick.wong@oracle.com>
> > 
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> >  io/Makefile          |    4 
> >  io/copy_file_range.c |    2 
> >  io/encrypt.c         |    1 
> >  io/fsmap.c           |  559 ++++++++++++++++++++++++++++++++++++++++++++++++++
> >  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    |   47 ++++
> >  11 files changed, 651 insertions(+), 13 deletions(-)
> >  create mode 100644 io/fsmap.c
> > 
> > 
> > diff --git a/io/Makefile b/io/Makefile
> > index 435ccff..8d3a30e 100644
> > --- a/io/Makefile
> > +++ b/io/Makefile
> > @@ -99,6 +99,10 @@ ifeq ($(HAVE_MREMAP),yes)
> >  LCFLAGS += -DHAVE_MREMAP
> >  endif
> >  
> > +ifeq ($(HAVE_GETFSMAP),yes)
> > +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(&copy_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..4128fae
> > --- /dev/null
> > +++ b/io/fsmap.c
> > @@ -0,0 +1,559 @@
> > +/*
> > + * Copyright (C) 2017 Oracle.  All Rights Reserved.
> > + *
> > + * Author: Darrick J. Wong <darrick.wong@oracle.com>
> > + *
> > + * 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 an XFS filesystem"
> 
> Did you want an \n" on the above line too?  Seems a bit odd to have it only on the next line.
> (one \n is fine too, but not like this) :)
> 
> > +"\n"
> > +" Example:\n"
> > +" 'fsmap -dlrv [-n nr] [startoff] [endoff]' - tabular format verbose map, including unwritten extents\n"
> 
> This doesn't match the short help:
> 
> +	fsmap_cmd.args = _("[-v] [-n nx] [start] [end]");
> 
> or the manpage:
> 
> +.BI "fsmap [ \-v ] [ \-n " nx " ] [ " start " ] [ " end " ]
> 
> but getopt sez:
> 
> > +	while ((c = getopt(argc, argv, "dln:rv")) != EOF) {
> 
> so I guess the short help & manpage need updates.
> 
> Also, I don't think the "Example:" above is valid:
> 
>         if (dflag + lflag + rflag > 1)
>                 return command_usage(&fsmap_cmd);
> 
> so the help needs to indicate that exactly 1 of -d, -l, or -r is required.
> 
> > +"\n"
> > +" fsmap prints the map of disk blocks used by the whole filesystem.\n"
> > +" The map lists each extent used by the file
> 
> <newbie>
> 
> "the file?"  what file?
> 
>                                                , as well as regions in the\n"
> > +" filesystem that do not have any corresponding blocks (free space).\n"
> > +" By default, each line of the listing takes the following form:\n"
> > +"     extent: [startoffset..endoffset] owner startblock..endblock\n"
> 
> say what "owner" means in this case?  </newbie>
> 
> > +" All the file offsets and disk blocks are in units of 512-byte blocks.\n"
> > +" -d -- query only the data device.\n"
> > +" -l -- query only the log device.\n"
> > +" -r -- query only the realtime device.\n"
> > +" -n -- query n extents.\n"
> > +" -v -- Verbose information, specify ag info.  Show flags legend on 2nd -v\n"
> > +"\n"));
> > +}
> > +
> > +static int
> > +numlen(
> > +	off64_t	val)
> > +{
> > +	off64_t	tmp;
> > +	int	len;
> > +
> > +	for (len = 0, tmp = val; tmp > 0; tmp = tmp/10)
> > +		len++;
> > +	return (len == 0 ? 1 : len);
> > +}
> 
> Hm, copy #3, do we still not have anywhere to put common stuff like this?
> 
> > +
> > +#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];
> > +
> > +	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));
> > +		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 extent map"),
> > +				(long long) p->fmr_owner);
> > +		else
> > +			printf(_("inode %lld %lld..%lld"),
> > +				(long long)p->fmr_owner,
> > +				(long long)BTOBBT(p->fmr_offset),
> > +				(long long)BTOBBT(p->fmr_offset + p->fmr_length - 1));
> > +		printf(_(" %lld blocks\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_SHARED	01000000	/* shared extent */
> > +#define	FLG_ATTR_FORK	00100000	/* attribute fork */
> > +#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 */
> 
> These really couldn't share w/ io/bmap.c?  :(
> (could FLG_ATTR_FORK go to the end so that it matches bmap until then?)

Well yes, we could flip them (I already did); afaict the only change
that needs to happen is an update to xfs/274.

> speakinawhich, I wonder how much of this is copied from bmap, and what could
> be shared?
> 
> I'm going to go off & look at that a bit, may have further comments.  :)

Do you have further comments?

--D

> 
> 
> > diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
> > index 29a036c..2c956b8 100644
> > --- a/man/man8/xfs_io.8
> > +++ b/man/man8/xfs_io.8
> > @@ -301,6 +301,53 @@ ioctl.  Options behave as described in the
> >  .BR xfs_bmap (8)
> >  manual page.
> >  .TP
> > +.BI "fsmap [ \-v ] [ \-n " nx " ] [ " start " ] [ " end " ]
> > +Prints the mapping of disk blocks used by an XFS filesystem.
> 
> FOREIGN_OK too right?
> 
> -Eric
> 
> >  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.
> > +.BI "The optional " start " and " end " arguments can be used to constrain
> > +the output to a particular range of disk blocks.
> > +.RE
> > +.RS 1.0i
> > +.PD 0
> > +.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 the number of extents in the filesystem and uses that
> > +value to compute the group size.
> > +.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.
> > +.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@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/9] xfs_io: support the new getfsmap ioctl
  2017-05-15 19:18     ` Darrick J. Wong
@ 2017-05-15 19:30       ` Eric Sandeen
  0 siblings, 0 replies; 40+ messages in thread
From: Eric Sandeen @ 2017-05-15 19:30 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: sandeen, linux-xfs



On 5/15/17 2:18 PM, Darrick J. Wong wrote:
>> speakinawhich, I wonder how much of this is copied from bmap, and what could
>> be shared?
>>
>> I'm going to go off & look at that a bit, may have further comments.  :)
> Do you have further comments?

Not on this patch, I guess - I had thought that there was an inordinate amount
of cut & paste from bmap but at least a quick look didn't bear that out.

TBH haven't looked at the rest of the series yet, I keep getting sucked
into other things, sorry.

-Eric

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl
  2017-05-08 19:47 ` [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl Darrick J. Wong
  2017-05-10 14:46   ` Eric Sandeen
  2017-05-12 22:29   ` Eric Sandeen
@ 2017-05-26 21:20   ` Eric Sandeen
  2017-05-26 21:41     ` Darrick J. Wong
  2 siblings, 1 reply; 40+ messages in thread
From: Eric Sandeen @ 2017-05-26 21:20 UTC (permalink / raw)
  To: Darrick J. Wong, sandeen; +Cc: linux-xfs



On 5/8/17 2:47 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Introduce a new ioctl that uses the reverse mapping btree to return
> information about the physical layout of the filesystem.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>

Ok, howzabout this:

Changes from your version:

- remove libxfs stuff, I synced that separately already
- rename sys_fsmap just fsmap (it's not a syscall)
- change meaning of "have_fsmap" - it now means we have it on the
  system, not that this platform (linux) might support it.*
- remove OVERRIDE_GETFSMAP - we aren't overriding anything now,
  we are using our own definition only if the system doesn't have it
- #include <linux/fs.h> before fsmap.h in autoconf or it'll /never/
  build and be detected

* we didn't bother with this for i.e. fiemap or anything else,
  afaict, and I'd like to just kill off the other platforms anyway.
  (I guess they didn't carry along their own copy, though, but meh,
  I have no idea if they even build at this point)

See what you think?


diff --git a/configure.ac b/configure.ac
index aa102e4..9534986 100644
--- a/configure.ac
+++ b/configure.ac
@@ -142,6 +142,7 @@ AC_HAVE_READDIR
 AC_HAVE_FSETXATTR
 AC_HAVE_MREMAP
 AC_NEED_INTERNAL_FSXATTR
+AC_HAVE_GETFSMAP
 
 if test "$enable_blkid" = yes; then
 AC_HAVE_BLKID_TOPO
diff --git a/include/builddefs.in b/include/builddefs.in
index 4d6bb2d..675bedf 100644
--- a/include/builddefs.in
+++ b/include/builddefs.in
@@ -112,6 +112,7 @@ HAVE_FLS = @have_fls@
 HAVE_FSETXATTR = @have_fsetxattr@
 HAVE_MREMAP = @have_mremap@
 NEED_INTERNAL_FSXATTR = @need_internal_fsxattr@
+HAVE_GETFSMAP = @have_getfsmap@
 
 GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
 #	   -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
@@ -150,6 +151,9 @@ endif
 ifeq ($(NEED_INTERNAL_FSXATTR),yes)
 PCFLAGS+= -DOVERRIDE_SYSTEM_FSXATTR
 endif
+ifeq ($(HAVE_FSMAP),yes)
+PCFLAGS+= -DHAVE_FSMAP
+endif
 
 
 GCFLAGS = $(DEBUG) \
diff --git a/include/linux.h b/include/linux.h
index 6a676ca..38969d1 100644
--- a/include/linux.h
+++ b/include/linux.h
@@ -222,4 +222,107 @@ struct fsxattr {
 #define FS_XFLAG_COWEXTSIZE	0x00010000	/* CoW extent size allocator hint */
 #endif
 
+#ifndef HAVE_GETFSMAP
+/*
+ *	Structure for FS_IOC_GETFSMAP.
+ *
+ *	The memory layout for this call are the scalar values defined in
+ *	struct fsmap_head, followed by two struct fsmap that describe
+ *	the lower and upper bound of mappings to return, followed by an
+ *	array of struct fsmap mappings.
+ *
+ *	fmh_iflags control the output of the call, whereas fmh_oflags report
+ *	on the overall record output.  fmh_count should be set to the
+ *	length of the fmh_recs array, and fmh_entries will be set to the
+ *	number of entries filled out during each call.  If fmh_count is
+ *	zero, the number of reverse mappings will be returned in
+ *	fmh_entries, though no mappings will be returned.  fmh_reserved
+ *	must be set to zero.
+ *
+ *	The two elements in the fmh_keys array are used to constrain the
+ *	output.  The first element in the array should represent the
+ *	lowest disk mapping ("low key") that the user wants to learn
+ *	about.  If this value is all zeroes, the filesystem will return
+ *	the first entry it knows about.  For a subsequent call, the
+ *	contents of fsmap_head.fmh_recs[fsmap_head.fmh_count - 1] should be
+ *	copied into fmh_keys[0] to have the kernel start where it left off.
+ *
+ *	The second element in the fmh_keys array should represent the
+ *	highest disk mapping ("high key") that the user wants to learn
+ *	about.  If this value is all ones, the filesystem will not stop
+ *	until it runs out of mapping to return or runs out of space in
+ *	fmh_recs.
+ *
+ *	fmr_device can be either a 32-bit cookie representing a device, or
+ *	a 32-bit dev_t if the FMH_OF_DEV_T flag is set.  fmr_physical,
+ *	fmr_offset, and fmr_length are expressed in units of bytes.
+ *	fmr_owner is either an inode number, or a special value if
+ *	FMR_OF_SPECIAL_OWNER is set in fmr_flags.
+ */
+struct fsmap {
+	__u32		fmr_device;	/* device id */
+	__u32		fmr_flags;	/* mapping flags */
+	__u64		fmr_physical;	/* device offset of segment */
+	__u64		fmr_owner;	/* owner id */
+	__u64		fmr_offset;	/* file offset of segment */
+	__u64		fmr_length;	/* length of segment */
+	__u64		fmr_reserved[3];	/* must be zero */
+};
+
+struct fsmap_head {
+	__u32		fmh_iflags;	/* control flags */
+	__u32		fmh_oflags;	/* output flags */
+	__u32		fmh_count;	/* # of entries in array incl. input */
+	__u32		fmh_entries;	/* # of entries filled in (output). */
+	__u64		fmh_reserved[6];	/* must be zero */
+
+	struct fsmap	fmh_keys[2];	/* low and high keys for the mapping search */
+	struct fsmap	fmh_recs[];	/* returned records */
+};
+
+/* Size of an fsmap_head with room for nr records. */
+static inline size_t
+fsmap_sizeof(
+	unsigned int	nr)
+{
+	return sizeof(struct fsmap_head) + nr * sizeof(struct fsmap);
+}
+
+/* Start the next fsmap query at the end of the current query results. */
+static inline void
+fsmap_advance(
+	struct fsmap_head	*head)
+{
+	head->fmh_keys[0] = head->fmh_recs[head->fmh_entries - 1];
+}
+
+/*	fmh_iflags values - set by XFS_IOC_GETFSMAP caller in the header. */
+/* no flags defined yet */
+#define FMH_IF_VALID		0
+
+/*	fmh_oflags values - returned in the header segment only. */
+#define FMH_OF_DEV_T		0x1	/* fmr_device values will be dev_t */
+
+/*	fmr_flags values - returned for each non-header segment */
+#define FMR_OF_PREALLOC		0x1	/* segment = unwritten pre-allocation */
+#define FMR_OF_ATTR_FORK	0x2	/* segment = attribute fork */
+#define FMR_OF_EXTENT_MAP	0x4	/* segment = extent map */
+#define FMR_OF_SHARED		0x8	/* segment = shared with another file */
+#define FMR_OF_SPECIAL_OWNER	0x10	/* owner is a special value */
+#define FMR_OF_LAST		0x20	/* segment is the last in the FS */
+
+/* Each FS gets to define its own special owner codes. */
+#define FMR_OWNER(type, code)	(((__u64)type << 32) | \
+				 ((__u64)code & 0xFFFFFFFFULL))
+#define FMR_OWNER_TYPE(owner)	((__u32)((__u64)owner >> 32))
+#define FMR_OWNER_CODE(owner)	((__u32)(((__u64)owner & 0xFFFFFFFFULL)))
+#define FMR_OWN_FREE		FMR_OWNER(0, 1) /* free space */
+#define FMR_OWN_UNKNOWN		FMR_OWNER(0, 2) /* unknown owner */
+#define FMR_OWN_METADATA	FMR_OWNER(0, 3) /* metadata */
+
+#define FS_IOC_GETFSMAP		_IOWR('X', 59, struct fsmap_head)
+
+#define HAVE_GETFSMAP
+#endif /* HAVE_GETFSMAP */
+
 #endif	/* __XFS_LINUX_H__ */
diff --git a/m4/package_libcdev.m4 b/m4/package_libcdev.m4
index bc3b4ce..fa5b639 100644
--- a/m4/package_libcdev.m4
+++ b/m4/package_libcdev.m4
@@ -277,3 +277,23 @@ AC_DEFUN([AC_NEED_INTERNAL_FSXATTR],
     )
     AC_SUBST(need_internal_fsxattr)
   ])
+
+#
+# Check if we have a FS_IOC_GETFSMAP ioctl (Linux)
+#
+AC_DEFUN([AC_HAVE_GETFSMAP],
+  [ AC_MSG_CHECKING([for GETFSMAP])
+    AC_TRY_LINK([
+#define _GNU_SOURCE
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <linux/fs.h>
+#include <linux/fsmap.h>
+    ], [
+         unsigned long x = FS_IOC_GETFSMAP;
+         struct fsmap_head fh;
+    ], have_getfsmap=yes
+       AC_MSG_RESULT(yes),
+       AC_MSG_RESULT(no))
+    AC_SUBST(have_getfsmap)
+  ])


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl
  2017-05-26 21:20   ` Eric Sandeen
@ 2017-05-26 21:41     ` Darrick J. Wong
  2017-05-26 22:12       ` Eric Sandeen
  0 siblings, 1 reply; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-26 21:41 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: sandeen, linux-xfs

On Fri, May 26, 2017 at 04:20:49PM -0500, Eric Sandeen wrote:
> 
> 
> On 5/8/17 2:47 PM, Darrick J. Wong wrote:
> > From: Darrick J. Wong <darrick.wong@oracle.com>
> > 
> > Introduce a new ioctl that uses the reverse mapping btree to return
> > information about the physical layout of the filesystem.
> > 
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Ok, howzabout this:
> 
> Changes from your version:
> 
> - remove libxfs stuff, I synced that separately already
> - rename sys_fsmap just fsmap (it's not a syscall)
> - change meaning of "have_fsmap" - it now means we have it on the
>   system, not that this platform (linux) might support it.*

I'll have a look... though afaict this removes anything that would
prevent us from building the fsmap stuff on a non-linux platform.
Seeing as fsmap is linux-only, we might as well restrict it on the
platforms we still support.

Darwin?  (I think Jan Tulak added this, though OSX doen't do XFS...)
BSD?  (Wasn't XFS removed from their kernel a few years ago?)

> - remove OVERRIDE_GETFSMAP - we aren't overriding anything now,
>   we are using our own definition only if the system doesn't have it

Ok.

> - #include <linux/fs.h> before fsmap.h in autoconf or it'll /never/
>   build and be detected

Ok.

> * we didn't bother with this for i.e. fiemap or anything else,
>   afaict, and I'd like to just kill off the other platforms anyway.
>   (I guess they didn't carry along their own copy, though, but meh,
>   I have no idea if they even build at this point)
> 
> See what you think?
> 
> 
> diff --git a/configure.ac b/configure.ac
> index aa102e4..9534986 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -142,6 +142,7 @@ AC_HAVE_READDIR
>  AC_HAVE_FSETXATTR
>  AC_HAVE_MREMAP
>  AC_NEED_INTERNAL_FSXATTR
> +AC_HAVE_GETFSMAP
>  
>  if test "$enable_blkid" = yes; then
>  AC_HAVE_BLKID_TOPO
> diff --git a/include/builddefs.in b/include/builddefs.in
> index 4d6bb2d..675bedf 100644
> --- a/include/builddefs.in
> +++ b/include/builddefs.in
> @@ -112,6 +112,7 @@ HAVE_FLS = @have_fls@
>  HAVE_FSETXATTR = @have_fsetxattr@
>  HAVE_MREMAP = @have_mremap@
>  NEED_INTERNAL_FSXATTR = @need_internal_fsxattr@
> +HAVE_GETFSMAP = @have_getfsmap@
>  
>  GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
>  #	   -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
> @@ -150,6 +151,9 @@ endif
>  ifeq ($(NEED_INTERNAL_FSXATTR),yes)
>  PCFLAGS+= -DOVERRIDE_SYSTEM_FSXATTR
>  endif
> +ifeq ($(HAVE_FSMAP),yes)
> +PCFLAGS+= -DHAVE_FSMAP
> +endif
>  
>  
>  GCFLAGS = $(DEBUG) \
> diff --git a/include/linux.h b/include/linux.h
> index 6a676ca..38969d1 100644
> --- a/include/linux.h
> +++ b/include/linux.h
> @@ -222,4 +222,107 @@ struct fsxattr {
>  #define FS_XFLAG_COWEXTSIZE	0x00010000	/* CoW extent size allocator hint */
>  #endif
>  
> +#ifndef HAVE_GETFSMAP
> +/*
> + *	Structure for FS_IOC_GETFSMAP.
> + *
> + *	The memory layout for this call are the scalar values defined in
> + *	struct fsmap_head, followed by two struct fsmap that describe
> + *	the lower and upper bound of mappings to return, followed by an
> + *	array of struct fsmap mappings.
> + *
> + *	fmh_iflags control the output of the call, whereas fmh_oflags report
> + *	on the overall record output.  fmh_count should be set to the
> + *	length of the fmh_recs array, and fmh_entries will be set to the
> + *	number of entries filled out during each call.  If fmh_count is
> + *	zero, the number of reverse mappings will be returned in
> + *	fmh_entries, though no mappings will be returned.  fmh_reserved
> + *	must be set to zero.
> + *
> + *	The two elements in the fmh_keys array are used to constrain the
> + *	output.  The first element in the array should represent the
> + *	lowest disk mapping ("low key") that the user wants to learn
> + *	about.  If this value is all zeroes, the filesystem will return
> + *	the first entry it knows about.  For a subsequent call, the
> + *	contents of fsmap_head.fmh_recs[fsmap_head.fmh_count - 1] should be
> + *	copied into fmh_keys[0] to have the kernel start where it left off.
> + *
> + *	The second element in the fmh_keys array should represent the
> + *	highest disk mapping ("high key") that the user wants to learn
> + *	about.  If this value is all ones, the filesystem will not stop
> + *	until it runs out of mapping to return or runs out of space in
> + *	fmh_recs.
> + *
> + *	fmr_device can be either a 32-bit cookie representing a device, or
> + *	a 32-bit dev_t if the FMH_OF_DEV_T flag is set.  fmr_physical,
> + *	fmr_offset, and fmr_length are expressed in units of bytes.
> + *	fmr_owner is either an inode number, or a special value if
> + *	FMR_OF_SPECIAL_OWNER is set in fmr_flags.
> + */
> +struct fsmap {
> +	__u32		fmr_device;	/* device id */
> +	__u32		fmr_flags;	/* mapping flags */
> +	__u64		fmr_physical;	/* device offset of segment */
> +	__u64		fmr_owner;	/* owner id */
> +	__u64		fmr_offset;	/* file offset of segment */
> +	__u64		fmr_length;	/* length of segment */
> +	__u64		fmr_reserved[3];	/* must be zero */
> +};
> +
> +struct fsmap_head {
> +	__u32		fmh_iflags;	/* control flags */
> +	__u32		fmh_oflags;	/* output flags */
> +	__u32		fmh_count;	/* # of entries in array incl. input */
> +	__u32		fmh_entries;	/* # of entries filled in (output). */
> +	__u64		fmh_reserved[6];	/* must be zero */
> +
> +	struct fsmap	fmh_keys[2];	/* low and high keys for the mapping search */
> +	struct fsmap	fmh_recs[];	/* returned records */
> +};
> +
> +/* Size of an fsmap_head with room for nr records. */
> +static inline size_t
> +fsmap_sizeof(
> +	unsigned int	nr)
> +{
> +	return sizeof(struct fsmap_head) + nr * sizeof(struct fsmap);
> +}
> +
> +/* Start the next fsmap query at the end of the current query results. */
> +static inline void
> +fsmap_advance(
> +	struct fsmap_head	*head)
> +{
> +	head->fmh_keys[0] = head->fmh_recs[head->fmh_entries - 1];
> +}
> +
> +/*	fmh_iflags values - set by XFS_IOC_GETFSMAP caller in the header. */
> +/* no flags defined yet */
> +#define FMH_IF_VALID		0
> +
> +/*	fmh_oflags values - returned in the header segment only. */
> +#define FMH_OF_DEV_T		0x1	/* fmr_device values will be dev_t */
> +
> +/*	fmr_flags values - returned for each non-header segment */
> +#define FMR_OF_PREALLOC		0x1	/* segment = unwritten pre-allocation */
> +#define FMR_OF_ATTR_FORK	0x2	/* segment = attribute fork */
> +#define FMR_OF_EXTENT_MAP	0x4	/* segment = extent map */
> +#define FMR_OF_SHARED		0x8	/* segment = shared with another file */
> +#define FMR_OF_SPECIAL_OWNER	0x10	/* owner is a special value */
> +#define FMR_OF_LAST		0x20	/* segment is the last in the FS */
> +
> +/* Each FS gets to define its own special owner codes. */
> +#define FMR_OWNER(type, code)	(((__u64)type << 32) | \
> +				 ((__u64)code & 0xFFFFFFFFULL))
> +#define FMR_OWNER_TYPE(owner)	((__u32)((__u64)owner >> 32))
> +#define FMR_OWNER_CODE(owner)	((__u32)(((__u64)owner & 0xFFFFFFFFULL)))
> +#define FMR_OWN_FREE		FMR_OWNER(0, 1) /* free space */
> +#define FMR_OWN_UNKNOWN		FMR_OWNER(0, 2) /* unknown owner */
> +#define FMR_OWN_METADATA	FMR_OWNER(0, 3) /* metadata */
> +
> +#define FS_IOC_GETFSMAP		_IOWR('X', 59, struct fsmap_head)
> +
> +#define HAVE_GETFSMAP
> +#endif /* HAVE_GETFSMAP */
> +
>  #endif	/* __XFS_LINUX_H__ */
> diff --git a/m4/package_libcdev.m4 b/m4/package_libcdev.m4
> index bc3b4ce..fa5b639 100644
> --- a/m4/package_libcdev.m4
> +++ b/m4/package_libcdev.m4
> @@ -277,3 +277,23 @@ AC_DEFUN([AC_NEED_INTERNAL_FSXATTR],
>      )
>      AC_SUBST(need_internal_fsxattr)
>    ])
> +
> +#
> +# Check if we have a FS_IOC_GETFSMAP ioctl (Linux)
> +#
> +AC_DEFUN([AC_HAVE_GETFSMAP],
> +  [ AC_MSG_CHECKING([for GETFSMAP])
> +    AC_TRY_LINK([
> +#define _GNU_SOURCE
> +#include <sys/syscall.h>
> +#include <unistd.h>
> +#include <linux/fs.h>
> +#include <linux/fsmap.h>
> +    ], [
> +         unsigned long x = FS_IOC_GETFSMAP;
> +         struct fsmap_head fh;
> +    ], have_getfsmap=yes
> +       AC_MSG_RESULT(yes),
> +       AC_MSG_RESULT(no))
> +    AC_SUBST(have_getfsmap)
> +  ])
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl
  2017-05-26 21:41     ` Darrick J. Wong
@ 2017-05-26 22:12       ` Eric Sandeen
  2017-05-30 18:44         ` Darrick J. Wong
  0 siblings, 1 reply; 40+ messages in thread
From: Eric Sandeen @ 2017-05-26 22:12 UTC (permalink / raw)
  To: Darrick J. Wong, Eric Sandeen; +Cc: linux-xfs

On 5/26/17 4:41 PM, Darrick J. Wong wrote:
> On Fri, May 26, 2017 at 04:20:49PM -0500, Eric Sandeen wrote:
>>
>>
>> On 5/8/17 2:47 PM, Darrick J. Wong wrote:
>>> From: Darrick J. Wong <darrick.wong@oracle.com>
>>>
>>> Introduce a new ioctl that uses the reverse mapping btree to return
>>> information about the physical layout of the filesystem.
>>>
>>> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
>>
>> Ok, howzabout this:
>>
>> Changes from your version:
>>
>> - remove libxfs stuff, I synced that separately already
>> - rename sys_fsmap just fsmap (it's not a syscall)
>> - change meaning of "have_fsmap" - it now means we have it on the
>>   system, not that this platform (linux) might support it.*
> 
> I'll have a look... though afaict this removes anything that would
> prevent us from building the fsmap stuff on a non-linux platform.
> Seeing as fsmap is linux-only, we might as well restrict it on the
> platforms we still support.

Right, so in this patch, either we define HAVE_GETFSMAP if we find
it on the system, or we implement it in include/linux.h and define
it then.  So HAVE_GETFSMAP won't get set on non-linux.

But in the next patch that actually makes use of the fsmap ioctl,
we'll need to conditionally include fsmap.c, and then all should
be good, I think, right?  Something like:

+# 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

> Darwin?  (I think Jan Tulak added this, though OSX doen't do XFS...)
> BSD?  (Wasn't XFS removed from their kernel a few years ago?)

Jan, do you still use it? 

-Eric

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/9] xfs_spaceman: AG state control
  2017-05-07 15:56 ` [PATCH 6/9] xfs_spaceman: AG state control Darrick J. Wong
@ 2017-05-26 23:06   ` Eric Sandeen
  2017-05-30 18:30     ` Darrick J. Wong
  0 siblings, 1 reply; 40+ messages in thread
From: Eric Sandeen @ 2017-05-26 23:06 UTC (permalink / raw)
  To: Darrick J. Wong, sandeen; +Cc: linux-xfs, Dave Chinner

On 5/7/17 10:56 AM, Darrick J. Wong wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Add support for a new allocation group state control ioctl. This
> allows control of various AG parameters, such as whether inode
> allocation is allowed in the AG, metadata preference, whether new
> allocations are allowed, etc. This requires a new ioctl.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> [darrick: change xfsctl to ioctl]
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>

Sounds like a great patch to send if this ever gets implemented in
the kernel; for now, I think, I'll not merge it.  :)

-Eric



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 4/9] xfs_spaceman: add FITRIM support
  2017-05-07 15:56 ` [PATCH 4/9] xfs_spaceman: add FITRIM support Darrick J. Wong
@ 2017-05-27  0:27   ` Eric Sandeen
  2017-05-30 18:24     ` Darrick J. Wong
  0 siblings, 1 reply; 40+ messages in thread
From: Eric Sandeen @ 2017-05-27  0:27 UTC (permalink / raw)
  To: Darrick J. Wong, sandeen; +Cc: linux-xfs, Dave Chinner

On 5/7/17 10:56 AM, Darrick J. Wong wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Add support for discarding free space extents via the FITRIM
> command. Make it easy to discard a single range, an entire AG or all
> the freespace in the filesystem.

So we re-implemented fstrim?  Do we need that?
Ok I guess it knows per-AG, so... that's a thing.

> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  spaceman/Makefile |    2 -
>  spaceman/init.c   |    1 
>  spaceman/space.h  |    1 
>  spaceman/trim.c   |  139 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 142 insertions(+), 1 deletion(-)
>  create mode 100644 spaceman/trim.c
> 
> 
> diff --git a/spaceman/Makefile b/spaceman/Makefile
> index ff8d23e..9fb9142 100644
> --- a/spaceman/Makefile
> +++ b/spaceman/Makefile
> @@ -8,7 +8,7 @@ include $(TOPDIR)/include/builddefs
>  LTCOMMAND = xfs_spaceman
>  HFILES = init.h space.h
>  CFILES = init.c \
> -	file.c
> +	file.c trim.c
>  
>  LLDLIBS = $(LIBXCMD)
>  LTDEPENDENCIES = $(LIBXCMD)
> diff --git a/spaceman/init.c b/spaceman/init.c
> index 404b183..ae5cfb5 100644
> --- a/spaceman/init.c
> +++ b/spaceman/init.c
> @@ -40,6 +40,7 @@ init_commands(void)
>  	file_init();
>  	help_init();
>  	quit_init();
> +	trim_init();
>  }
>  
>  static int
> diff --git a/spaceman/space.h b/spaceman/space.h
> index 6e1bc52..7b4f034 100644
> --- a/spaceman/space.h
> +++ b/spaceman/space.h
> @@ -34,3 +34,4 @@ extern int	addfile(char *, int , xfs_fsop_geom_t *, int);
>  extern void	file_init(void);
>  extern void	help_init(void);
>  extern void	quit_init(void);
> +extern void	trim_init(void);
> diff --git a/spaceman/trim.c b/spaceman/trim.c
> new file mode 100644
> index 0000000..9bf6565
> --- /dev/null
> +++ b/spaceman/trim.c
> @@ -0,0 +1,139 @@
> +/*
> + * Copyright (c) 2012 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 "libxfs.h"
> +#include <linux/fs.h>
> +#include "command.h"
> +#include "init.h"
> +#include "space.h"
> +#include "input.h"
> +
> +#ifndef FITRIM

I wonder if we really still need this compat #ifndef...

> +#define FITRIM          _IOWR('X', 121, struct fstrim_range)    /* Trim */
> +
> +struct fstrim_range {
> +	__u64 start;
> +	__u64 len;
> +	__u64 minlen;
> +};
> +#endif
> +
> +static cmdinfo_t trim_cmd;
> +
> +/*
> + * Report on trimace usage in xfs filesystem.

"Report on trimace?"  (Is that like a grimace?)

> + */
> +static int
> +trim_f(
> +	int		argc,
> +	char		**argv)
> +{
> +	struct fstrim_range trim = {0};
> +	xfs_agnumber_t	agno = 0;
> +	off64_t		offset = 0;
> +	ssize_t		length = 0;
> +	ssize_t		minlen = 0;

len & minlen in the trim command are 64-bit, is ssize_t
sufficient?

> +	int		aflag = 0;
> +	int		fflag = 0;
> +	int		ret;
> +	int		c;
> +
> +	while ((c = getopt(argc, argv, "a:fm:")) != EOF) {
> +		switch (c) {
> +		case 'a':
> +			if (fflag)
> +				return command_usage(&trim_cmd);
> +			aflag = 1;
> +			agno = atoi(optarg);
> +			break;
> +		case 'f':
> +			if (aflag)
> +				return command_usage(&trim_cmd);
> +			fflag = 1;
> +			break;
> +		case 'm':
> +			minlen = cvtnum(file->geom.blocksize,
> +					file->geom.sectsize, argv[optind]);
> +			break;
> +		default:
> +			return command_usage(&trim_cmd);
> +		}
> +	}

Not a huge deal, but maybe move the above command_usage stuff down here:

+	if (aflag && fflag)
+		return command_usage(&trim_cmd);

so all the checking is in one spot.  Save Future-jtulak some grief ;)

> +
> +	if (optind != argc - 2 && !(aflag || fflag))
> +		return command_usage(&trim_cmd);
> +	if (optind != argc) {
> +		offset = cvtnum(file->geom.blocksize, file->geom.sectsize,
> +				argv[optind]);
> +		length = cvtnum(file->geom.blocksize, file->geom.sectsize,
> +				argv[optind + 1]);
> +	} else if (agno) {
> +		offset = agno * file->geom.agblocks * file->geom.blocksize;
> +		length = file->geom.agblocks * file->geom.blocksize;
> +	} else {
> +		offset = 0;
> +		length = file->geom.datablocks * file->geom.blocksize;
> +	}
> +
> +	trim.start = offset;
> +	trim.len = length;
> +	trim.minlen = minlen;
> +
> +	ret = ioctl(file->fd, FITRIM, (unsigned long)&trim);
> +	if (ret < 0) {
> +		fprintf(stderr, "%s: ioctl(FITRIM) [\"%s\"]: "
> +			"%s\n", progname, file->name, strerror(errno));

+	if (ret < 0) {
+		fprintf(stderr, "%s: ioctl(FITRIM) [\"%s\"]: %s\n",
+			progname, file->name, strerror(errno));

> +		exitcode = 1;
> +		return 0;

maybe don't need that return here (but don't really care)

> +	}
> +	return 0;
> +}
> +
> +static void
> +trim_help(void)
> +{
> +	printf(_(
> +"\n"
> +"Discard filesystem free space\n"
> +"\n"
> +"Options: [-m minlen] [-f]|[-a agno]|[offset length]\n"
> +"\n"
> +" -m minlen -- skip freespace extents smaller than minlen\n"
> +" -f -- trim all the freespace in the entire filesystem\n"
> +" -a agno -- trim all the freespace in the given AG agno\n"
> +" offset length -- trim the freespace in the range {offset, length}\n"

xfs_io lines these things up (brute force whitespace) and looks nicer:

 -S   -- use an alternate seed number for filling the write buffer
 -i   -- input file, source of data to write (used when writing forward)
 -d   -- open the input file for direct IO
 -s   -- skip a number of bytes at the start of the input file
 -w   -- call fdatasync(2) at the end (included in timing results)

so:

+" -m minle      -- skip freespace extents smaller than minlen\n"
+" -f            -- trim all the freespace in the entire filesystem\n"
+" -a agno       -- trim all the freespace in the given AG agno\n"
+" offset length -- trim the freespace in the range {offset, length}\n"

> +"\n"));
> +
> +}
> +
> +void
> +trim_init(void)
> +{
> +	trim_cmd.name = "trim";
> +	trim_cmd.altname = "tr";
> +	trim_cmd.cfunc = trim_f;
> +	trim_cmd.argmin = 1;
> +	trim_cmd.argmax = 4;
> +	trim_cmd.args = "[-m minlen] [-f]|[-a agno]|[offset length]\n";

Not sure we want \n at the end:

xfs_spaceman> help trim
trim [-m minlen] [-f]|[-a agno]|[offset length]
 -- Discard filesystem free space

xfs_io tends to put that all on one line - or are we worried about 80cols?

> +	trim_cmd.flags = CMD_FLAG_ONESHOT;
> +	trim_cmd.oneline = _("Discard filesystem free space");
> +	trim_cmd.help = trim_help;
> +
> +	add_command(&trim_cmd);
> +}
> +
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 3/9] xfs_spaceman: space management tool
  2017-05-07 15:56 ` [PATCH 3/9] xfs_spaceman: space management tool Darrick J. Wong
@ 2017-05-27  1:34   ` Eric Sandeen
  2017-05-30 17:37     ` Darrick J. Wong
  0 siblings, 1 reply; 40+ messages in thread
From: Eric Sandeen @ 2017-05-27  1:34 UTC (permalink / raw)
  To: Darrick J. Wong, sandeen; +Cc: linux-xfs, Dave Chinner

On 5/7/17 10:56 AM, Darrick J. Wong wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> xfs_spaceman is intended as a diagnostic and control tool for space
> management operations within XFS. Operations like examining free
> space, managing allocation policies, issuing block discards on free
> space, etc.
> 
> The tool is modelled on the xfs_io interface, allowing both
> interactive and command line control of the tool, enabling it to be
> used in scripts and automated management tools.

This may be a result of the xfs_io ancestry, but:

# xfs_spaceman /mnt/test2 /mnt/test

Cool, we can open 2 files(ystems)

xfs_spaceman> print
 000  /mnt/test2     (non-sync,non-direct,read-write)
[001] /mnt/test      (non-sync,non-direct,read-write)

(what does non-direct mean for a mountpoint?)
(actually where do these flags come from ... hm.)

Yep there we are!  Now how do we switch to the other?

xfs_spaceman> help
help [command] -- help for one or all commands
print -- list current open files
quit -- exit the program

Use 'help commandname' for extended help.

hmmm... I guess we can't switch.  Should we be able to?

Is the intent to open files or filesystems...  both?  Is there ever
a reason to be opening a file not a filesystem?

> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> [darrick: change xfsctl to ioctl]
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  Makefile          |    3 +
>  spaceman/Makefile |   34 ++++++++++++
>  spaceman/file.c   |  149 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  spaceman/init.c   |  117 ++++++++++++++++++++++++++++++++++++++++++
>  spaceman/init.h   |   23 ++++++++
>  spaceman/space.h  |   36 +++++++++++++
>  6 files changed, 361 insertions(+), 1 deletion(-)
>  create mode 100644 spaceman/Makefile
>  create mode 100644 spaceman/file.c
>  create mode 100644 spaceman/init.c
>  create mode 100644 spaceman/init.h
>  create mode 100644 spaceman/space.h
> 
> 
> diff --git a/Makefile b/Makefile
> index ba87327..72d0044 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -47,7 +47,7 @@ HDR_SUBDIRS = include libxfs
>  DLIB_SUBDIRS = libxlog libxcmd libhandle
>  LIB_SUBDIRS = libxfs $(DLIB_SUBDIRS)
>  TOOL_SUBDIRS = copy db estimate fsck growfs io logprint mkfs quota \
> -		mdrestore repair rtcp m4 man doc debian
> +		mdrestore repair rtcp m4 man doc debian spaceman
>  
>  ifneq ("$(PKG_PLATFORM)","darwin")
>  TOOL_SUBDIRS += fsr
> @@ -88,6 +88,7 @@ quota: libxcmd
>  repair: libxlog libxcmd
>  copy: libxlog
>  mkfs: libxcmd
> +spaceman: libxcmd
>  
>  ifeq ($(HAVE_BUILDDEFS), yes)
>  include $(BUILDRULES)
> diff --git a/spaceman/Makefile b/spaceman/Makefile
> new file mode 100644
> index 0000000..ff8d23e
> --- /dev/null
> +++ b/spaceman/Makefile
> @@ -0,0 +1,34 @@
> +#
> +# Copyright (c) 2012 Red Hat, Inc.  All Rights Reserved.
> +#
> +
> +TOPDIR = ..
> +include $(TOPDIR)/include/builddefs
> +
> +LTCOMMAND = xfs_spaceman
> +HFILES = init.h space.h
> +CFILES = init.c \
> +	file.c
> +
> +LLDLIBS = $(LIBXCMD)
> +LTDEPENDENCIES = $(LIBXCMD)
> +LLDFLAGS = -static
> +
> +ifeq ($(ENABLE_READLINE),yes)
> +LLDLIBS += $(LIBREADLINE) $(LIBTERMCAP)
> +endif
> +
> +ifeq ($(ENABLE_EDITLINE),yes)
> +LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP)
> +endif
> +
> +default: depend $(LTCOMMAND)
> +
> +include $(BUILDRULES)
> +
> +install: default
> +	$(INSTALL) -m 755 -d $(PKG_SBIN_DIR)
> +	$(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR)
> +install-dev:
> +
> +-include .dep
> diff --git a/spaceman/file.c b/spaceman/file.c
> new file mode 100644
> index 0000000..9356066
> --- /dev/null
> +++ b/spaceman/file.c
> @@ -0,0 +1,149 @@
> +/*
> + * Copyright (c) 2004-2005 Silicon Graphics, Inc.
> + * Copyright (c) 2012 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 "libxfs.h"
> +#include <sys/mman.h>
> +#include "command.h"
> +#include "input.h"
> +#include "init.h"
> +#include "space.h"
> +
> +static cmdinfo_t print_cmd;
> +
> +fileio_t	*filetable;
> +int		filecount;
> +fileio_t	*file;
> +
> +static void
> +print_fileio(
> +	fileio_t	*file,
> +	int		index,
> +	int		braces)
> +{
> +	printf(_("%c%03d%c %-14s (%s,%s,%s%s%s)\n"),
> +		braces? '[' : ' ', index, braces? ']' : ' ', file->name,
> +		file->flags & O_SYNC ? _("sync") : _("non-sync"),
> +		file->flags & O_DIRECT ? _("direct") : _("non-direct"),
> +		file->flags & O_RDONLY ? _("read-only") : _("read-write"),
> +		file->flags & O_APPEND ? _(",append-only") : "",
> +		file->flags & O_NONBLOCK ? _(",non-block") : "");

I don't think this is working:

# chattr +aS appendonly_sync 

# xfs_spaceman -c print appendonly_sync 
[000] appendonly_sync (non-sync,non-direct,read-write)

I don't see that file->flags ever gets set.

> +}
> +
> +int
> +filelist_f(void)
> +{
> +	int		i;
> +
> +	for (i = 0; i < filecount; i++)
> +		print_fileio(&filetable[i], i, &filetable[i] == file);
> +	return 0;
> +}
> +
> +static int
> +print_f(
> +	int		argc,
> +	char		**argv)
> +{
> +	filelist_f();
> +	return 0;
> +}
> +
> +int
> +openfile(
> +	char		*path,
> +	xfs_fsop_geom_t	*geom,
> +	int		flags,
> +	mode_t		mode)
> +{
> +	int		fd;
> +
> +	fd = open(path, flags, mode);
> +	if (fd < 0) {
> +		if ((errno == EISDIR) && (flags & O_RDWR)) {

can we even get here w/ flags != 0?

(but anyway, we can open a dir just fine ...)

> +			/* make it as if we asked for O_RDONLY & try again */
> +			flags &= ~O_RDWR;
> +			flags |= O_RDONLY;
> +			fd = open(path, flags, mode);
> +			if (fd < 0) {
> +				perror(path);
> +				return -1;
> +			}
> +		} else {
> +			perror(path);
> +			return -1;
> +		}
> +	}
> +
> +	if (ioctl(fd, XFS_IOC_FSGEOMETRY, geom) < 0) {
> +		perror("XFS_IOC_FSGEOMETRY");
> +		close(fd);
> +		return -1;
> +	}
> +	return fd;
> +}
> +
> +int
> +addfile(
> +	char		*name,
> +	int		fd,
> +	xfs_fsop_geom_t	*geometry,
> +	int		flags)
> +{
> +	char		*filename;
> +
> +	filename = strdup(name);
> +	if (!filename) {
> +		perror("strdup");
> +		close(fd);
> +		return -1;
> +	}
> +
> +	/* Extend the table of currently open files */
> +	filetable = (fileio_t *)realloc(filetable,	/* growing */
> +					++filecount * sizeof(fileio_t));
> +	if (!filetable) {
> +		perror("realloc");
> +		filecount = 0;
> +		free(filename);
> +		close(fd);
> +		return -1;
> +	}
> +
> +	/* Finally, make this the new active open file */
> +	file = &filetable[filecount - 1];
> +	file->fd = fd;
> +	file->flags = flags;
> +	file->name = filename;
> +	file->geom = *geometry;
> +	return 0;
> +}
> +
> +void
> +file_init(void)
> +{
> +	print_cmd.name = "print";
> +	print_cmd.altname = "p";
> +	print_cmd.cfunc = print_f;
> +	print_cmd.argmin = 0;
> +	print_cmd.argmax = 0;
> +	print_cmd.flags = CMD_FLAG_ONESHOT;
> +	print_cmd.oneline = _("list current open files");
> +
> +	add_command(&print_cmd);
> +}
> diff --git a/spaceman/init.c b/spaceman/init.c
> new file mode 100644
> index 0000000..404b183
> --- /dev/null
> +++ b/spaceman/init.c
> @@ -0,0 +1,117 @@
> +/*
> + * Copyright (c) 2012 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 "libxfs.h"
> +#include "command.h"
> +#include "input.h"
> +#include "init.h"
> +#include "space.h"
> +
> +char	*progname;
> +int	exitcode;
> +
> +void
> +usage(void)
> +{
> +	fprintf(stderr,
> +		_("Usage: %s [-c cmd] file\n"),
> +		progname);
> +	exit(1);
> +}
> +
> +static void
> +init_commands(void)
> +{
> +	file_init();
> +	help_init();
> +	quit_init();
> +}
> +
> +static int
> +init_args_command(
> +	int	index)
> +{
> +	if (index >= filecount)
> +		return 0;
> +	file = &filetable[index++];
> +	return index;
> +}
> +
> +static int
> +init_check_command(
> +	const cmdinfo_t	*ct)
> +{
> +	if (!(ct->flags & CMD_FLAG_ONESHOT))
> +		return 0;
> +	return 1;
> +}
> +
> +void
> +init(
> +	int		argc,
> +	char		**argv)
> +{
> +	int		c, flags = 0;

flags is 0 ...

> +	mode_t		mode = 0600;
> +	xfs_fsop_geom_t	geometry = { 0 };
> +
> +	progname = basename(argv[0]);
> +	setlocale(LC_ALL, "");
> +	bindtextdomain(PACKAGE, LOCALEDIR);
> +	textdomain(PACKAGE);
> +
> +	while ((c = getopt(argc, argv, "c:V")) != EOF) {
> +		switch (c) {
> +		case 'c':
> +			add_user_command(optarg);
> +			break;
> +		case 'V':
> +			printf(_("%s version %s\n"), progname, VERSION);
> +			exit(0);
> +		default:
> +			usage();
> +		}
> +	}
> +
> +	if (optind == argc)
> +		usage();
> +
> +	while (optind < argc) {
> +		if ((c = openfile(argv[optind], &geometry, flags, mode)) < 0)

openfile with flags ...

> +			exit(1);
> +		if (!platform_test_xfs_fd(c))
> +			printf(_("Not an XFS filesystem!\n"));

file? filesystem?

> +		if (addfile(argv[optind], c, &geometry, flags) < 0)

addfile with flags ... what's flags for?  it's always 0.

> +			exit(1);
> +		optind++;
> +	}
> +
> +	init_commands();
> +	add_command_iterator(init_args_command);
> +	add_check_command(init_check_command);
> +}
> +
> +int
> +main(
> +	int	argc,
> +	char	**argv)
> +{
> +	init(argc, argv);
> +	command_loop();
> +	return exitcode;
> +}
> diff --git a/spaceman/init.h b/spaceman/init.h
> new file mode 100644
> index 0000000..165e4f5
> --- /dev/null
> +++ b/spaceman/init.h
> @@ -0,0 +1,23 @@
> +/*
> + * Copyright (c) 2012 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
> + */
> +
> +extern char	*progname;
> +extern int	exitcode;
> +
> +#define min(a,b)	(((a)<(b))?(a):(b))
> +#define max(a,b)	(((a)>(b))?(a):(b))
> diff --git a/spaceman/space.h b/spaceman/space.h
> new file mode 100644
> index 0000000..6e1bc52
> --- /dev/null
> +++ b/spaceman/space.h
> @@ -0,0 +1,36 @@
> +/*
> + * Copyright (c) 2012 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
> + */
> +
> +typedef struct fileio {
> +	int		fd;		/* open file descriptor */
> +	int		flags;		/* flags describing file state */
> +	char		*name;		/* file name at time of open */
> +	xfs_fsop_geom_t	geom;		/* XFS filesystem geometry */
> +} fileio_t;
> +
> +extern fileio_t		*filetable;	/* open file table */
> +extern int		filecount;	/* number of open files */
> +extern fileio_t		*file;		/* active file in file table */
> +extern int filelist_f(void);
> +
> +extern int	openfile(char *, xfs_fsop_geom_t *, int, mode_t);
> +extern int	addfile(char *, int , xfs_fsop_geom_t *, int);
> +
> +extern void	file_init(void);
> +extern void	help_init(void);
> +extern void	quit_init(void);
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 5/9] xfs_spaceman: add new speculative prealloc control
  2017-05-07 15:56 ` [PATCH 5/9] xfs_spaceman: add new speculative prealloc control Darrick J. Wong
@ 2017-05-27  1:45   ` Eric Sandeen
  2017-05-30 18:34     ` Darrick J. Wong
  0 siblings, 1 reply; 40+ messages in thread
From: Eric Sandeen @ 2017-05-27  1:45 UTC (permalink / raw)
  To: Darrick J. Wong, sandeen; +Cc: linux-xfs, Dave Chinner



On 5/7/17 10:56 AM, Darrick J. Wong wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Add an control interface for purging speculative
> preallocation via the new ioctls.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> [darrick: change xfsctl to ioctl]
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  spaceman/Makefile   |    2 -
>  spaceman/init.c     |    1 
>  spaceman/prealloc.c |  135 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  spaceman/space.h    |    1 
>  4 files changed, 138 insertions(+), 1 deletion(-)
>  create mode 100644 spaceman/prealloc.c
> 
> 
> diff --git a/spaceman/Makefile b/spaceman/Makefile
> index 9fb9142..b1f1136 100644
> --- a/spaceman/Makefile
> +++ b/spaceman/Makefile
> @@ -8,7 +8,7 @@ include $(TOPDIR)/include/builddefs
>  LTCOMMAND = xfs_spaceman
>  HFILES = init.h space.h
>  CFILES = init.c \
> -	file.c trim.c
> +	file.c prealloc.c trim.c
>  
>  LLDLIBS = $(LIBXCMD)
>  LTDEPENDENCIES = $(LIBXCMD)
> diff --git a/spaceman/init.c b/spaceman/init.c
> index ae5cfb5..08b5a33 100644
> --- a/spaceman/init.c
> +++ b/spaceman/init.c
> @@ -39,6 +39,7 @@ init_commands(void)
>  {
>  	file_init();
>  	help_init();
> +	prealloc_init();
>  	quit_init();
>  	trim_init();
>  }
> diff --git a/spaceman/prealloc.c b/spaceman/prealloc.c
> new file mode 100644
> index 0000000..b93f909
> --- /dev/null
> +++ b/spaceman/prealloc.c
> @@ -0,0 +1,135 @@
> +/*
> + * Copyright (c) 2012 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 "libxfs.h"
> +#include "command.h"
> +#include "input.h"
> +#include "init.h"
> +#include "space.h"
> +
> +#ifndef XFS_IOC_FREE_EOFBLOCKS
> +#define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_eofblocks)
> +
> +#define XFS_EOFBLOCKS_VERSION           1
> +struct xfs_fs_eofblocks {
> +	__u32		eof_version;
> +	__u32		eof_flags;
> +	uid_t		eof_uid;
> +	gid_t		eof_gid;
> +	prid_t		eof_prid;
> +	__u32		pad32;
> +	__u64		eof_min_file_size;
> +	__u64		pad64[12];
> +};
> +
> +/* eof_flags values */
> +#define XFS_EOF_FLAGS_SYNC		(1 << 0) /* sync/wait mode scan */
> +#define XFS_EOF_FLAGS_UID		(1 << 1) /* filter by uid */
> +#define XFS_EOF_FLAGS_GID		(1 << 2) /* filter by gid */
> +#define XFS_EOF_FLAGS_PRID		(1 << 3) /* filter by project id */
> +#define XFS_EOF_FLAGS_MINFILESIZE	(1 << 4) /* filter by min file size */
> +
> +#endif

I think including libxfs defines XFS_IOC_FREE_EOFBLOCKS, via xfs_fs.h
and that whole hunk can go, no?

> +
> +static cmdinfo_t prealloc_cmd;
> +
> +/*
> + * Control preallocation amounts.
> + */
> +static int
> +prealloc_f(
> +	int	argc,
> +	char	**argv)
> +{
> +	struct xfs_fs_eofblocks eofb = {0};
> +	int	c;
> +
> +	eofb.eof_version = XFS_EOFBLOCKS_VERSION;
> +
> +	while ((c = getopt(argc, argv, "g:m:p:su:")) != EOF) {
> +		switch (c) {
> +		case 'g':
> +			eofb.eof_flags |= XFS_EOF_FLAGS_GID;
> +			eofb.eof_gid = atoi(optarg);
> +			break;
> +		case 'u':
> +			eofb.eof_flags |= XFS_EOF_FLAGS_UID;
> +			eofb.eof_uid = atoi(optarg);
> +			break;
> +		case 'p':
> +			eofb.eof_flags |= XFS_EOF_FLAGS_PRID;
> +			eofb.eof_prid = atoi(optarg);
> +			break;
> +		case 's':
> +			eofb.eof_flags |= XFS_EOF_FLAGS_SYNC;
> +			break;
> +		case 'm':
> +			eofb.eof_flags |= XFS_EOF_FLAGS_MINFILESIZE;
> +			eofb.eof_min_file_size = cvtnum(file->geom.blocksize,
> +							file->geom.sectsize,
> +							optarg);
> +			break;
> +		case '?':
> +		default:
> +			return command_usage(&prealloc_cmd);
> +		}
> +	}
> +	if (optind != argc)
> +		return command_usage(&prealloc_cmd);
> +
> +	if (ioctl(file->fd, XFS_IOC_FREE_EOFBLOCKS, &eofb) < 0) {
> +		fprintf(stderr, _("%s: XFS_IOC_FREE_EOFBLOCKS on %s: %s\n"),
> +			progname, file->name, strerror(errno));
> +	}
> +	return 0;
> +}
> +
> +static void
> +prealloc_help(void)
> +{
> +	printf(_(
> +"\n"
> +"Control speculative preallocation\n"
> +"\n"
> +"Options: [-s] [-ugp id] [-m minlen]\n"
> +"\n"
> +" -s -- synchronous flush - wait for flush to complete\n"

really flush?  (maybe removal? scan?)

> +" -u uid -- remove prealloc on files matching user <uid>\n"
> +" -g gid -- remove prealloc on files matching group <gid>\n"
> +" -p prid -- remove prealloc on files matching project <prid>\n"
> +" -m minlen -- only consider files larger than <minlen>\n"
> +"\n"));

+" -s        -- synchronous flush - wait for flush to complete\n"
+" -u uid    -- remove prealloc on files matching user <uid>\n"
+" -g gid    -- remove prealloc on files matching group <gid>\n"
+" -p prid   -- remove prealloc on files matching project <prid>\n"
+" -m minlen -- only consider files larger than <minlen>\n"


> +
> +}
> +
> +void
> +prealloc_init(void)
> +{
> +	prealloc_cmd.name = "prealloc";
> +	prealloc_cmd.altname = "prealloc";
> +	prealloc_cmd.cfunc = prealloc_f;
> +	prealloc_cmd.argmin = 1;
> +	prealloc_cmd.argmax = -1;
> +	prealloc_cmd.args = "[-s] [-ugp id] [-m minlen]\n";

no \n please:

xfs_spaceman> help
...

prealloc [-s] [-ugp id] [-m minlen]
 -- Control speculative preallocation

should be on same line ala xfs_io IMHO

> +	prealloc_cmd.flags = CMD_FLAG_ONESHOT;
> +	prealloc_cmd.oneline = _("Control speculative preallocation");
> +	prealloc_cmd.help = prealloc_help;
> +
> +	add_command(&prealloc_cmd);
> +}
> +
> diff --git a/spaceman/space.h b/spaceman/space.h
> index 7b4f034..0ae3116 100644
> --- a/spaceman/space.h
> +++ b/spaceman/space.h
> @@ -33,5 +33,6 @@ extern int	addfile(char *, int , xfs_fsop_geom_t *, int);
>  
>  extern void	file_init(void);
>  extern void	help_init(void);
> +extern void	prealloc_init(void);
>  extern void	quit_init(void);
>  extern void	trim_init(void);
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 7/9] xfs_spaceman: Free space mapping command
  2017-05-07 15:57 ` [PATCH 7/9] xfs_spaceman: Free space mapping command Darrick J. Wong
@ 2017-05-27  1:57   ` Eric Sandeen
  2017-05-30 18:40     ` Darrick J. Wong
  0 siblings, 1 reply; 40+ messages in thread
From: Eric Sandeen @ 2017-05-27  1:57 UTC (permalink / raw)
  To: Darrick J. Wong, sandeen; +Cc: linux-xfs, Dave Chinner



On 5/7/17 10:57 AM, Darrick J. Wong wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Add freespace mapping tool modelled on the xfs_db freesp command.
> The advantage of this command over xfs_db is that it can be done
> online and is coherent with concurrent modifications to the
> filesystem.
> 
> This requires the kernel to support the XFS_IOC_GETFSMAP ioctl to map
> free space indexes.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> [darrick: port from FIEMAPFS to GETFSMAP]
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  spaceman/Makefile   |   12 +-
>  spaceman/ag.c       |    1 
>  spaceman/file.c     |   18 ++-
>  spaceman/freesp.c   |  367 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  spaceman/init.c     |    9 +
>  spaceman/prealloc.c |    1 
>  spaceman/space.h    |   12 +-
>  spaceman/trim.c     |    1 
>  8 files changed, 413 insertions(+), 8 deletions(-)
>  create mode 100644 spaceman/freesp.c
> 
> 
> diff --git a/spaceman/Makefile b/spaceman/Makefile
> index 08709b3..3b059ca 100644
> --- a/spaceman/Makefile
> +++ b/spaceman/Makefile
> @@ -7,8 +7,12 @@ include $(TOPDIR)/include/builddefs
>  
>  LTCOMMAND = xfs_spaceman
>  HFILES = init.h space.h
> -CFILES = init.c \
> -	ag.c file.c prealloc.c trim.c
> +CFILES = ag.c \
> +	 file.c \
> +	 init.c \
> +	 prealloc.c \
> +	 trim.c
> +
>  
>  LLDLIBS = $(LIBXCMD)
>  LTDEPENDENCIES = $(LIBXCMD)
> @@ -22,6 +26,10 @@ ifeq ($(ENABLE_EDITLINE),yes)
>  LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP)
>  endif
>  
> +ifeq ($(HAVE_GETFSMAP),yes)
> +CFILES += freesp.c
> +endif
> +
>  default: depend $(LTCOMMAND)
>  
>  include $(BUILDRULES)
> diff --git a/spaceman/ag.c b/spaceman/ag.c
> index 1eb8aa0..0f1c869 100644
> --- a/spaceman/ag.c
> +++ b/spaceman/ag.c
> @@ -21,6 +21,7 @@
>  #include "command.h"
>  #include "input.h"
>  #include "init.h"
> +#include "path.h"
>  #include "space.h"
>  
>  #ifndef XFS_IOC_AGCONTROL
> diff --git a/spaceman/file.c b/spaceman/file.c
> index 9356066..7c5ea0e 100644
> --- a/spaceman/file.c
> +++ b/spaceman/file.c
> @@ -22,6 +22,7 @@
>  #include "command.h"
>  #include "input.h"
>  #include "init.h"
> +#include "path.h"
>  #include "space.h"
>  
>  static cmdinfo_t print_cmd;
> @@ -69,8 +70,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;
>  
>  	fd = open(path, flags, mode);
> @@ -95,6 +98,15 @@ openfile(
>  		close(fd);
>  		return -1;
>  	}
> +
> +	if (fs_path) {
> +		fsp = fs_table_lookup(path, FS_MOUNT_POINT);
> +		if (!fsp) {
> +			fprintf(stderr, _("Unable to find XFS information."));

If I got that error I wouldn't know what it meant...

> +			return -1;
> +		}
> +		*fs_path = *fsp;
> +	}
>  	return fd;
>  }
>  
> @@ -103,7 +115,8 @@ addfile(
>  	char		*name,
>  	int		fd,
>  	xfs_fsop_geom_t	*geometry,
> -	int		flags)
> +	int		flags,
> +	struct fs_path	*fs_path)
>  {
>  	char		*filename;
>  
> @@ -131,6 +144,7 @@ addfile(
>  	file->flags = flags;
>  	file->name = filename;
>  	file->geom = *geometry;
> +	file->fs_path = *fs_path;
>  	return 0;
>  }
>  
> diff --git a/spaceman/freesp.c b/spaceman/freesp.c
> new file mode 100644
> index 0000000..5493916
> --- /dev/null
> +++ b/spaceman/freesp.c
> @@ -0,0 +1,367 @@
> +/*
> + * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
> + * Copyright (c) 2012 Red Hat, Inc.
> + * Copyright (c) 2017 Oracle.
> + * 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 "libxfs.h"
> +#include <linux/fiemap.h>
> +#include "command.h"
> +#include "init.h"
> +#include "path.h"
> +#include "space.h"
> +
> +typedef struct histent
> +{
> +	int		low;
> +	int		high;
> +	long long	count;
> +	long long	blocks;
> +} histent_t;
> +
> +static int		agcount;
> +static xfs_agnumber_t	*aglist;
> +static int		dumpflag;
> +static int		equalsize;
> +static histent_t	*hist;
> +static int		histcount;
> +static int		multsize;
> +static int		seen1;
> +static int		summaryflag;
> +static bool		rtflag;
> +static long long	totblocks;
> +static long long	totexts;
> +
> +static cmdinfo_t freesp_cmd;
> +
> +static void
> +addhistent(
> +	int	h)
> +{
> +	hist = realloc(hist, (histcount + 1) * sizeof(*hist));
> +	if (h == 0)
> +		h = 1;
> +	hist[histcount].low = h;
> +	hist[histcount].count = hist[histcount].blocks = 0;
> +	histcount++;
> +	if (h == 1)
> +		seen1 = 1;
> +}
> +
> +static void
> +addtohist(
> +	xfs_agnumber_t	agno,
> +	xfs_agblock_t	agbno,
> +	off64_t		len)
> +{
> +	int		i;
> +
> +	if (dumpflag)
> +		printf("%8d %8d %8"PRId64"\n", agno, agbno, len);
> +	totexts++;
> +	totblocks += len;
> +	for (i = 0; i < histcount; i++) {
> +		if (hist[i].high >= len) {
> +			hist[i].count++;
> +			hist[i].blocks += len;
> +			break;
> +		}
> +	}
> +}
> +
> +static int
> +hcmp(
> +	const void	*a,
> +	const void	*b)
> +{
> +	return ((histent_t *)a)->low - ((histent_t *)b)->low;
> +}
> +
> +static void
> +histinit(
> +	int	maxlen)
> +{
> +	int	i;
> +
> +	if (equalsize) {
> +		for (i = 1; i < maxlen; i += equalsize)
> +			addhistent(i);
> +	} else if (multsize) {
> +		for (i = 1; i < maxlen; i *= multsize)
> +			addhistent(i);
> +	} else {
> +		if (!seen1)
> +			addhistent(1);
> +		qsort(hist, histcount, sizeof(*hist), hcmp);
> +	}
> +	for (i = 0; i < histcount; i++) {
> +		if (i < histcount - 1)
> +			hist[i].high = hist[i + 1].low - 1;
> +		else
> +			hist[i].high = maxlen;
> +	}
> +}
> +
> +static void
> +printhist(void)
> +{
> +	int	i;
> +
> +	printf("%7s %7s %7s %7s %6s\n",
> +		_("from"), _("to"), _("extents"), _("blocks"), _("pct"));
> +	for (i = 0; i < histcount; i++) {
> +		if (hist[i].count)
> +			printf("%7d %7d %7lld %7lld %6.2f\n", hist[i].low,
> +				hist[i].high, hist[i].count, hist[i].blocks,
> +				hist[i].blocks * 100.0 / totblocks);
> +	}
> +}
> +
> +static int
> +inaglist(
> +	xfs_agnumber_t	agno)
> +{
> +	int		i;
> +
> +	if (agcount == 0)
> +		return 1;
> +	for (i = 0; i < agcount; i++)
> +		if (aglist[i] == agno)
> +			return 1;
> +	return 0;
> +}
> +
> +#define NR_EXTENTS 128
> +
> +static void
> +scan_ag(
> +	xfs_agnumber_t		agno)
> +{
> +	struct fsmap_head	*fsmap;
> +	struct fsmap		*extent;
> +	struct fsmap		*l, *h;
> +	struct fsmap		*p;
> +	off64_t			blocksize = file->geom.blocksize;
> +	off64_t			bperag;
> +	off64_t			aglen;
> +	xfs_agblock_t		agbno;
> +	int			ret;
> +	int			i;
> +
> +	bperag = (off64_t)file->geom.agblocks * blocksize;
> +
> +	fsmap = malloc(fsmap_sizeof(NR_EXTENTS));
> +	if (!fsmap) {
> +		fprintf(stderr, _("%s: fsmap malloc failed.\n"), progname);
> +		exitcode = 1;
> +		return;
> +	}
> +
> +	memset(fsmap, 0, sizeof(*fsmap));
> +	fsmap->fmh_count = NR_EXTENTS;
> +	l = fsmap->fmh_keys;
> +	h = fsmap->fmh_keys + 1;
> +	if (agno != NULLAGNUMBER) {
> +		l->fmr_physical = agno * bperag;
> +		h->fmr_physical = ((agno + 1) * bperag) - 1;
> +		l->fmr_device = h->fmr_device = file->fs_path.fs_datadev;
> +	} else {
> +		l->fmr_physical = 0;
> +		h->fmr_physical = ULLONG_MAX;
> +		l->fmr_device = h->fmr_device = file->fs_path.fs_rtdev;
> +	}
> +	h->fmr_owner = ULLONG_MAX;
> +	h->fmr_flags = UINT_MAX;
> +	h->fmr_offset = ULLONG_MAX;
> +
> +	while (true) {
> +		ret = ioctl(file->fd, FS_IOC_GETFSMAP, fsmap);
> +		if (ret < 0) {
> +			fprintf(stderr,
> +_("%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n"),

huh, is this an email artifact that wrapped the line?

> +				progname, file->name, strerror(errno));
> +			free(fsmap);
> +			exitcode = 1;
> +			return;
> +		}
> +
> +		/* No more extents to map, exit */
> +		if (!fsmap->fmh_entries)
> +			break;
> +
> +		for (i = 0, extent = fsmap->fmh_recs;
> +		     i < fsmap->fmh_entries;
> +		     i++, extent++) {
> +			if (!(extent->fmr_flags & FMR_OF_SPECIAL_OWNER) ||
> +			    extent->fmr_owner != XFS_FMR_OWN_FREE)
> +				continue;
> +			agbno = (extent->fmr_physical - (bperag * agno)) /
> +								blocksize;
> +			aglen = extent->fmr_length / blocksize;
> +
> +			addtohist(agno, agbno, aglen);
> +		}
> +
> +		p = &fsmap->fmh_recs[fsmap->fmh_entries - 1];
> +		if (p->fmr_flags & FMR_OF_LAST)
> +			break;
> +		fsmap_advance(fsmap);
> +	}
> +}
> +static void
> +aglistadd(
> +	char	*a)
> +{
> +	aglist = realloc(aglist, (agcount + 1) * sizeof(*aglist));
> +	aglist[agcount] = (xfs_agnumber_t)atoi(a);
> +	agcount++;
> +}
> +
> +static int
> +init(
> +	int		argc,
> +	char		**argv)
> +{
> +	int		c;
> +	int		speced = 0;
> +
> +	agcount = dumpflag = equalsize = multsize = optind = 0;
> +	histcount = seen1 = summaryflag = 0;
> +	totblocks = totexts = 0;
> +	aglist = NULL;
> +	hist = NULL;
> +	rtflag = false;
> +	while ((c = getopt(argc, argv, "a:bde:h:m:rs")) != EOF) {
> +		switch (c) {
> +		case 'a':
> +			aglistadd(optarg);
> +			break;
> +		case 'b':
> +			if (speced)
> +				return 0;
> +			multsize = 2;
> +			speced = 1;
> +			break;
> +		case 'd':
> +			dumpflag = 1;
> +			break;
> +		case 'e':
> +			if (speced)
> +				return 0;
> +			equalsize = atoi(optarg);
> +			speced = 1;
> +			break;
> +		case 'h':
> +			if (speced && !histcount)
> +				return 0;
> +			addhistent(atoi(optarg));
> +			speced = 1;
> +			break;
> +		case 'm':
> +			if (speced)
> +				return 0;
> +			multsize = atoi(optarg);
> +			speced = 1;
> +			break;
> +		case 'r':
> +			rtflag = true;
> +			break;
> +		case 's':
> +			summaryflag = 1;
> +			break;
> +		case '?':
> +			return 0;
> +		}
> +	}
> +	if (optind != argc)
> +		return 0;
> +	if (!speced)
> +		multsize = 2;
> +	histinit(file->geom.agblocks);
> +	return 1;
> +}
> +
> +/*
> + * Report on freespace usage in xfs filesystem.
> + */
> +static int
> +freesp_f(
> +	int		argc,
> +	char		**argv)
> +{
> +	xfs_agnumber_t	agno;
> +
> +	if (!init(argc, argv))
> +		return 0;
> +	if (rtflag)
> +		scan_ag(NULLAGNUMBER);
> +	for (agno = 0; !rtflag && agno < file->geom.agcount; agno++)  {
> +		if (inaglist(agno))
> +			scan_ag(agno);
> +	}
> +	if (histcount)
> +		printhist();
> +	if (summaryflag) {
> +		printf(_("total free extents %lld\n"), totexts);
> +		printf(_("total free blocks %lld\n"), totblocks);
> +		printf(_("average free extent size %g\n"),
> +			(double)totblocks / (double)totexts);
> +	}
> +	if (aglist)
> +		free(aglist);
> +	if (hist)
> +		free(hist);
> +	return 0;
> +}
> +
> +static void
> +freesp_help(void)
> +{
> +	printf(_(
> +"\n"
> +"Examine filesystem free space\n"
> +"\n"
> +"Options: [-bcds] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n"

no "c" ... missing "r"

"a:bde:h:m:rs"

> +"\n"
> +" -b -- binary histogram bin size\n"
> +" -d -- debug output\n"
> +" -r -- display realtime device free space information\n"
> +" -s -- emit freespace summary information\n"
> +" -a agno -- scan only the given AG agno\n"
> +" -e bsize -- use fixed histogram bin size of bsize\n"
> +" -h h1 -- use custom histogram bin size of h1. Multiple specifications allowed.\n"
> +" -m bmult -- use histogram bin size multiplier of bmult\n"


+" -b       -- binary histogram bin size\n"
+" -d       -- debug output\n"
+" -r       -- display realtime device free space information\n"
+" -s       -- emit freespace summary information\n"
+" -a agno  -- scan only the given AG agno\n"
+" -e bsize -- use fixed histogram bin size of bsize\n"
+" -h h1    -- use custom histogram bin size of h1. Multiple specifications allowed.\n"
+" -m bmult -- use histogram bin size multiplier of bmult\n"

also, "h1?" - I guess that's modeled on xfs_db ... long as the manpage
explains it, I guess...

> +"\n"));
> +
> +}
> +
> +void
> +freesp_init(void)
> +{
> +	freesp_cmd.name = "freesp";
> +	freesp_cmd.altname = "fsp";
> +	freesp_cmd.cfunc = freesp_f;
> +	freesp_cmd.argmin = 0;
> +	freesp_cmd.argmax = -1;
> +	freesp_cmd.args = "[-bcds] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n";

no \n again here, I think

> +	freesp_cmd.flags = CMD_FLAG_ONESHOT | CMD_FLAG_FOREIGN_OK;
> +	freesp_cmd.oneline = _("Examine filesystem free space");
> +	freesp_cmd.help = freesp_help;
> +
> +	add_command(&freesp_cmd);
> +}
> +
> diff --git a/spaceman/init.c b/spaceman/init.c
> index 08b5a33..e6df7fe 100644
> --- a/spaceman/init.c
> +++ b/spaceman/init.c
> @@ -20,6 +20,7 @@
>  #include "command.h"
>  #include "input.h"
>  #include "init.h"
> +#include "path.h"
>  #include "space.h"
>  
>  char	*progname;
> @@ -38,6 +39,7 @@ static void
>  init_commands(void)
>  {
>  	file_init();
> +	freesp_init();
>  	help_init();
>  	prealloc_init();
>  	quit_init();
> @@ -71,12 +73,14 @@ init(
>  	int		c, flags = 0;
>  	mode_t		mode = 0600;
>  	xfs_fsop_geom_t	geometry = { 0 };
> +	struct fs_path	fsp;
>  
>  	progname = basename(argv[0]);
>  	setlocale(LC_ALL, "");
>  	bindtextdomain(PACKAGE, LOCALEDIR);
>  	textdomain(PACKAGE);
>  
> +	fs_table_initialise(0, NULL, 0, NULL);
>  	while ((c = getopt(argc, argv, "c:V")) != EOF) {
>  		switch (c) {
>  		case 'c':
> @@ -94,11 +98,12 @@ init(
>  		usage();
>  
>  	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))
>  			printf(_("Not an XFS filesystem!\n"));
> -		if (addfile(argv[optind], c, &geometry, flags) < 0)
> +		if (addfile(argv[optind], c, &geometry, flags, &fsp) < 0)
>  			exit(1);
>  		optind++;
>  	}
> diff --git a/spaceman/prealloc.c b/spaceman/prealloc.c
> index b93f909..249d7a4 100644
> --- a/spaceman/prealloc.c
> +++ b/spaceman/prealloc.c
> @@ -20,6 +20,7 @@
>  #include "command.h"
>  #include "input.h"
>  #include "init.h"
> +#include "path.h"
>  #include "space.h"
>  
>  #ifndef XFS_IOC_FREE_EOFBLOCKS
> diff --git a/spaceman/space.h b/spaceman/space.h
> index 0ae3116..bf9a2df 100644
> --- a/spaceman/space.h
> +++ b/spaceman/space.h
> @@ -21,6 +21,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 */
> @@ -28,11 +29,18 @@ extern int		filecount;	/* number of open files */
>  extern fileio_t		*file;		/* active file in file table */
>  extern int filelist_f(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	file_init(void);
>  extern void	help_init(void);
>  extern void	prealloc_init(void);
>  extern void	quit_init(void);
>  extern void	trim_init(void);
> +
> +#ifdef HAVE_GETFSMAP
> +extern void	freesp_init(void);
> +#else
> +# define freesp_init()	do { } while (0)
> +#endif
> diff --git a/spaceman/trim.c b/spaceman/trim.c
> index 9bf6565..d1e5d82 100644
> --- a/spaceman/trim.c
> +++ b/spaceman/trim.c
> @@ -20,6 +20,7 @@
>  #include <linux/fs.h>
>  #include "command.h"
>  #include "init.h"
> +#include "path.h"
>  #include "space.h"
>  #include "input.h"
>  
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 3/9] xfs_spaceman: space management tool
  2017-05-27  1:34   ` Eric Sandeen
@ 2017-05-30 17:37     ` Darrick J. Wong
  2017-05-30 18:17       ` Eric Sandeen
  0 siblings, 1 reply; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-30 17:37 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: sandeen, linux-xfs, Dave Chinner

On Fri, May 26, 2017 at 08:34:18PM -0500, Eric Sandeen wrote:
> On 5/7/17 10:56 AM, Darrick J. Wong wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > xfs_spaceman is intended as a diagnostic and control tool for space
> > management operations within XFS. Operations like examining free
> > space, managing allocation policies, issuing block discards on free
> > space, etc.
> > 
> > The tool is modelled on the xfs_io interface, allowing both
> > interactive and command line control of the tool, enabling it to be
> > used in scripts and automated management tools.
> 
> This may be a result of the xfs_io ancestry, but:
> 
> # xfs_spaceman /mnt/test2 /mnt/test
> 
> Cool, we can open 2 files(ystems)
> 
> xfs_spaceman> print
>  000  /mnt/test2     (non-sync,non-direct,read-write)
> [001] /mnt/test      (non-sync,non-direct,read-write)
> 
> (what does non-direct mean for a mountpoint?)
> (actually where do these flags come from ... hm.)
> 
> Yep there we are!  Now how do we switch to the other?
> 
> xfs_spaceman> help
> help [command] -- help for one or all commands
> print -- list current open files
> quit -- exit the program
> 
> Use 'help commandname' for extended help.
> 
> hmmm... I guess we can't switch.  Should we be able to?
> 
> Is the intent to open files or filesystems...  both?  Is there ever
> a reason to be opening a file not a filesystem?

<shrug> I mostly just passed on Dave's original patches from whenever
ago, but TBH I'm not 100% sure about the usecases for multiple
arguments.  The commands that spaceman has now are all fs-oriented, not
file-oriented... but maybe people want to be able to issue one command
against multiple fses?  OTOH all the commands provided so far are
oneshot, so they only act upon one open file.

So, I'm inclined to ditch the 'list' command and disallow multiple open
files, like Eric suggests, unless anyone really wants it?

--D

> 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > [darrick: change xfsctl to ioctl]
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> >  Makefile          |    3 +
> >  spaceman/Makefile |   34 ++++++++++++
> >  spaceman/file.c   |  149 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  spaceman/init.c   |  117 ++++++++++++++++++++++++++++++++++++++++++
> >  spaceman/init.h   |   23 ++++++++
> >  spaceman/space.h  |   36 +++++++++++++
> >  6 files changed, 361 insertions(+), 1 deletion(-)
> >  create mode 100644 spaceman/Makefile
> >  create mode 100644 spaceman/file.c
> >  create mode 100644 spaceman/init.c
> >  create mode 100644 spaceman/init.h
> >  create mode 100644 spaceman/space.h
> > 
> > 
> > diff --git a/Makefile b/Makefile
> > index ba87327..72d0044 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -47,7 +47,7 @@ HDR_SUBDIRS = include libxfs
> >  DLIB_SUBDIRS = libxlog libxcmd libhandle
> >  LIB_SUBDIRS = libxfs $(DLIB_SUBDIRS)
> >  TOOL_SUBDIRS = copy db estimate fsck growfs io logprint mkfs quota \
> > -		mdrestore repair rtcp m4 man doc debian
> > +		mdrestore repair rtcp m4 man doc debian spaceman
> >  
> >  ifneq ("$(PKG_PLATFORM)","darwin")
> >  TOOL_SUBDIRS += fsr
> > @@ -88,6 +88,7 @@ quota: libxcmd
> >  repair: libxlog libxcmd
> >  copy: libxlog
> >  mkfs: libxcmd
> > +spaceman: libxcmd
> >  
> >  ifeq ($(HAVE_BUILDDEFS), yes)
> >  include $(BUILDRULES)
> > diff --git a/spaceman/Makefile b/spaceman/Makefile
> > new file mode 100644
> > index 0000000..ff8d23e
> > --- /dev/null
> > +++ b/spaceman/Makefile
> > @@ -0,0 +1,34 @@
> > +#
> > +# Copyright (c) 2012 Red Hat, Inc.  All Rights Reserved.
> > +#
> > +
> > +TOPDIR = ..
> > +include $(TOPDIR)/include/builddefs
> > +
> > +LTCOMMAND = xfs_spaceman
> > +HFILES = init.h space.h
> > +CFILES = init.c \
> > +	file.c
> > +
> > +LLDLIBS = $(LIBXCMD)
> > +LTDEPENDENCIES = $(LIBXCMD)
> > +LLDFLAGS = -static
> > +
> > +ifeq ($(ENABLE_READLINE),yes)
> > +LLDLIBS += $(LIBREADLINE) $(LIBTERMCAP)
> > +endif
> > +
> > +ifeq ($(ENABLE_EDITLINE),yes)
> > +LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP)
> > +endif
> > +
> > +default: depend $(LTCOMMAND)
> > +
> > +include $(BUILDRULES)
> > +
> > +install: default
> > +	$(INSTALL) -m 755 -d $(PKG_SBIN_DIR)
> > +	$(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR)
> > +install-dev:
> > +
> > +-include .dep
> > diff --git a/spaceman/file.c b/spaceman/file.c
> > new file mode 100644
> > index 0000000..9356066
> > --- /dev/null
> > +++ b/spaceman/file.c
> > @@ -0,0 +1,149 @@
> > +/*
> > + * Copyright (c) 2004-2005 Silicon Graphics, Inc.
> > + * Copyright (c) 2012 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 "libxfs.h"
> > +#include <sys/mman.h>
> > +#include "command.h"
> > +#include "input.h"
> > +#include "init.h"
> > +#include "space.h"
> > +
> > +static cmdinfo_t print_cmd;
> > +
> > +fileio_t	*filetable;
> > +int		filecount;
> > +fileio_t	*file;
> > +
> > +static void
> > +print_fileio(
> > +	fileio_t	*file,
> > +	int		index,
> > +	int		braces)
> > +{
> > +	printf(_("%c%03d%c %-14s (%s,%s,%s%s%s)\n"),
> > +		braces? '[' : ' ', index, braces? ']' : ' ', file->name,
> > +		file->flags & O_SYNC ? _("sync") : _("non-sync"),
> > +		file->flags & O_DIRECT ? _("direct") : _("non-direct"),
> > +		file->flags & O_RDONLY ? _("read-only") : _("read-write"),
> > +		file->flags & O_APPEND ? _(",append-only") : "",
> > +		file->flags & O_NONBLOCK ? _(",non-block") : "");
> 
> I don't think this is working:
> 
> # chattr +aS appendonly_sync 
> 
> # xfs_spaceman -c print appendonly_sync 
> [000] appendonly_sync (non-sync,non-direct,read-write)
> 
> I don't see that file->flags ever gets set.
> 
> > +}
> > +
> > +int
> > +filelist_f(void)
> > +{
> > +	int		i;
> > +
> > +	for (i = 0; i < filecount; i++)
> > +		print_fileio(&filetable[i], i, &filetable[i] == file);
> > +	return 0;
> > +}
> > +
> > +static int
> > +print_f(
> > +	int		argc,
> > +	char		**argv)
> > +{
> > +	filelist_f();
> > +	return 0;
> > +}
> > +
> > +int
> > +openfile(
> > +	char		*path,
> > +	xfs_fsop_geom_t	*geom,
> > +	int		flags,
> > +	mode_t		mode)
> > +{
> > +	int		fd;
> > +
> > +	fd = open(path, flags, mode);
> > +	if (fd < 0) {
> > +		if ((errno == EISDIR) && (flags & O_RDWR)) {
> 
> can we even get here w/ flags != 0?
> 
> (but anyway, we can open a dir just fine ...)
> 
> > +			/* make it as if we asked for O_RDONLY & try again */
> > +			flags &= ~O_RDWR;
> > +			flags |= O_RDONLY;
> > +			fd = open(path, flags, mode);
> > +			if (fd < 0) {
> > +				perror(path);
> > +				return -1;
> > +			}
> > +		} else {
> > +			perror(path);
> > +			return -1;
> > +		}
> > +	}
> > +
> > +	if (ioctl(fd, XFS_IOC_FSGEOMETRY, geom) < 0) {
> > +		perror("XFS_IOC_FSGEOMETRY");
> > +		close(fd);
> > +		return -1;
> > +	}
> > +	return fd;
> > +}
> > +
> > +int
> > +addfile(
> > +	char		*name,
> > +	int		fd,
> > +	xfs_fsop_geom_t	*geometry,
> > +	int		flags)
> > +{
> > +	char		*filename;
> > +
> > +	filename = strdup(name);
> > +	if (!filename) {
> > +		perror("strdup");
> > +		close(fd);
> > +		return -1;
> > +	}
> > +
> > +	/* Extend the table of currently open files */
> > +	filetable = (fileio_t *)realloc(filetable,	/* growing */
> > +					++filecount * sizeof(fileio_t));
> > +	if (!filetable) {
> > +		perror("realloc");
> > +		filecount = 0;
> > +		free(filename);
> > +		close(fd);
> > +		return -1;
> > +	}
> > +
> > +	/* Finally, make this the new active open file */
> > +	file = &filetable[filecount - 1];
> > +	file->fd = fd;
> > +	file->flags = flags;
> > +	file->name = filename;
> > +	file->geom = *geometry;
> > +	return 0;
> > +}
> > +
> > +void
> > +file_init(void)
> > +{
> > +	print_cmd.name = "print";
> > +	print_cmd.altname = "p";
> > +	print_cmd.cfunc = print_f;
> > +	print_cmd.argmin = 0;
> > +	print_cmd.argmax = 0;
> > +	print_cmd.flags = CMD_FLAG_ONESHOT;
> > +	print_cmd.oneline = _("list current open files");
> > +
> > +	add_command(&print_cmd);
> > +}
> > diff --git a/spaceman/init.c b/spaceman/init.c
> > new file mode 100644
> > index 0000000..404b183
> > --- /dev/null
> > +++ b/spaceman/init.c
> > @@ -0,0 +1,117 @@
> > +/*
> > + * Copyright (c) 2012 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 "libxfs.h"
> > +#include "command.h"
> > +#include "input.h"
> > +#include "init.h"
> > +#include "space.h"
> > +
> > +char	*progname;
> > +int	exitcode;
> > +
> > +void
> > +usage(void)
> > +{
> > +	fprintf(stderr,
> > +		_("Usage: %s [-c cmd] file\n"),
> > +		progname);
> > +	exit(1);
> > +}
> > +
> > +static void
> > +init_commands(void)
> > +{
> > +	file_init();
> > +	help_init();
> > +	quit_init();
> > +}
> > +
> > +static int
> > +init_args_command(
> > +	int	index)
> > +{
> > +	if (index >= filecount)
> > +		return 0;
> > +	file = &filetable[index++];
> > +	return index;
> > +}
> > +
> > +static int
> > +init_check_command(
> > +	const cmdinfo_t	*ct)
> > +{
> > +	if (!(ct->flags & CMD_FLAG_ONESHOT))
> > +		return 0;
> > +	return 1;
> > +}
> > +
> > +void
> > +init(
> > +	int		argc,
> > +	char		**argv)
> > +{
> > +	int		c, flags = 0;
> 
> flags is 0 ...
> 
> > +	mode_t		mode = 0600;
> > +	xfs_fsop_geom_t	geometry = { 0 };
> > +
> > +	progname = basename(argv[0]);
> > +	setlocale(LC_ALL, "");
> > +	bindtextdomain(PACKAGE, LOCALEDIR);
> > +	textdomain(PACKAGE);
> > +
> > +	while ((c = getopt(argc, argv, "c:V")) != EOF) {
> > +		switch (c) {
> > +		case 'c':
> > +			add_user_command(optarg);
> > +			break;
> > +		case 'V':
> > +			printf(_("%s version %s\n"), progname, VERSION);
> > +			exit(0);
> > +		default:
> > +			usage();
> > +		}
> > +	}
> > +
> > +	if (optind == argc)
> > +		usage();
> > +
> > +	while (optind < argc) {
> > +		if ((c = openfile(argv[optind], &geometry, flags, mode)) < 0)
> 
> openfile with flags ...
> 
> > +			exit(1);
> > +		if (!platform_test_xfs_fd(c))
> > +			printf(_("Not an XFS filesystem!\n"));
> 
> file? filesystem?
> 
> > +		if (addfile(argv[optind], c, &geometry, flags) < 0)
> 
> addfile with flags ... what's flags for?  it's always 0.
> 
> > +			exit(1);
> > +		optind++;
> > +	}
> > +
> > +	init_commands();
> > +	add_command_iterator(init_args_command);
> > +	add_check_command(init_check_command);
> > +}
> > +
> > +int
> > +main(
> > +	int	argc,
> > +	char	**argv)
> > +{
> > +	init(argc, argv);
> > +	command_loop();
> > +	return exitcode;
> > +}
> > diff --git a/spaceman/init.h b/spaceman/init.h
> > new file mode 100644
> > index 0000000..165e4f5
> > --- /dev/null
> > +++ b/spaceman/init.h
> > @@ -0,0 +1,23 @@
> > +/*
> > + * Copyright (c) 2012 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
> > + */
> > +
> > +extern char	*progname;
> > +extern int	exitcode;
> > +
> > +#define min(a,b)	(((a)<(b))?(a):(b))
> > +#define max(a,b)	(((a)>(b))?(a):(b))
> > diff --git a/spaceman/space.h b/spaceman/space.h
> > new file mode 100644
> > index 0000000..6e1bc52
> > --- /dev/null
> > +++ b/spaceman/space.h
> > @@ -0,0 +1,36 @@
> > +/*
> > + * Copyright (c) 2012 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
> > + */
> > +
> > +typedef struct fileio {
> > +	int		fd;		/* open file descriptor */
> > +	int		flags;		/* flags describing file state */
> > +	char		*name;		/* file name at time of open */
> > +	xfs_fsop_geom_t	geom;		/* XFS filesystem geometry */
> > +} fileio_t;
> > +
> > +extern fileio_t		*filetable;	/* open file table */
> > +extern int		filecount;	/* number of open files */
> > +extern fileio_t		*file;		/* active file in file table */
> > +extern int filelist_f(void);
> > +
> > +extern int	openfile(char *, xfs_fsop_geom_t *, int, mode_t);
> > +extern int	addfile(char *, int , xfs_fsop_geom_t *, int);
> > +
> > +extern void	file_init(void);
> > +extern void	help_init(void);
> > +extern void	quit_init(void);
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > the body of a message to majordomo@vger.kernel.org
> > 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@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 3/9] xfs_spaceman: space management tool
  2017-05-30 17:37     ` Darrick J. Wong
@ 2017-05-30 18:17       ` Eric Sandeen
  2017-05-30 18:47         ` Darrick J. Wong
  0 siblings, 1 reply; 40+ messages in thread
From: Eric Sandeen @ 2017-05-30 18:17 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: sandeen, linux-xfs, Dave Chinner

On 5/30/17 12:37 PM, Darrick J. Wong wrote:
> On Fri, May 26, 2017 at 08:34:18PM -0500, Eric Sandeen wrote:
>> On 5/7/17 10:56 AM, Darrick J. Wong wrote:
>>> From: Dave Chinner <dchinner@redhat.com>
>>>
>>> xfs_spaceman is intended as a diagnostic and control tool for space
>>> management operations within XFS. Operations like examining free
>>> space, managing allocation policies, issuing block discards on free
>>> space, etc.
>>>
>>> The tool is modelled on the xfs_io interface, allowing both
>>> interactive and command line control of the tool, enabling it to be
>>> used in scripts and automated management tools.
>> This may be a result of the xfs_io ancestry, but:
>>
>> # xfs_spaceman /mnt/test2 /mnt/test
>>
>> Cool, we can open 2 files(ystems)
>>
>> xfs_spaceman> print
>>  000  /mnt/test2     (non-sync,non-direct,read-write)
>> [001] /mnt/test      (non-sync,non-direct,read-write)
>>
>> (what does non-direct mean for a mountpoint?)
>> (actually where do these flags come from ... hm.)
>>
>> Yep there we are!  Now how do we switch to the other?
>>
>> xfs_spaceman> help
>> help [command] -- help for one or all commands
>> print -- list current open files
>> quit -- exit the program
>>
>> Use 'help commandname' for extended help.
>>
>> hmmm... I guess we can't switch.  Should we be able to?
>>
>> Is the intent to open files or filesystems...  both?  Is there ever
>> a reason to be opening a file not a filesystem?
> <shrug> I mostly just passed on Dave's original patches from whenever
> ago, but TBH I'm not 100% sure about the usecases for multiple
> arguments.  The commands that spaceman has now are all fs-oriented, not
> file-oriented... but maybe people want to be able to issue one command
> against multiple fses?  OTOH all the commands provided so far are
> oneshot, so they only act upon one open file.
> 
> So, I'm inclined to ditch the 'list' command and disallow multiple open
> files, like Eric suggests, unless anyone really wants it?

Either way is fine: multiple (fs) targets with the ability to switch,
or restrict to just one, but allowing one to open multiple and only
use one makes little sense.

-Eric

> --D
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 4/9] xfs_spaceman: add FITRIM support
  2017-05-27  0:27   ` Eric Sandeen
@ 2017-05-30 18:24     ` Darrick J. Wong
  0 siblings, 0 replies; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-30 18:24 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: sandeen, linux-xfs, Dave Chinner

On Fri, May 26, 2017 at 07:27:40PM -0500, Eric Sandeen wrote:
> On 5/7/17 10:56 AM, Darrick J. Wong wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > Add support for discarding free space extents via the FITRIM
> > command. Make it easy to discard a single range, an entire AG or all
> > the freespace in the filesystem.
> 
> So we re-implemented fstrim?  Do we need that?
> Ok I guess it knows per-AG, so... that's a thing.
> 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> >  spaceman/Makefile |    2 -
> >  spaceman/init.c   |    1 
> >  spaceman/space.h  |    1 
> >  spaceman/trim.c   |  139 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 142 insertions(+), 1 deletion(-)
> >  create mode 100644 spaceman/trim.c
> > 
> > 
> > diff --git a/spaceman/Makefile b/spaceman/Makefile
> > index ff8d23e..9fb9142 100644
> > --- a/spaceman/Makefile
> > +++ b/spaceman/Makefile
> > @@ -8,7 +8,7 @@ include $(TOPDIR)/include/builddefs
> >  LTCOMMAND = xfs_spaceman
> >  HFILES = init.h space.h
> >  CFILES = init.c \
> > -	file.c
> > +	file.c trim.c
> >  
> >  LLDLIBS = $(LIBXCMD)
> >  LTDEPENDENCIES = $(LIBXCMD)
> > diff --git a/spaceman/init.c b/spaceman/init.c
> > index 404b183..ae5cfb5 100644
> > --- a/spaceman/init.c
> > +++ b/spaceman/init.c
> > @@ -40,6 +40,7 @@ init_commands(void)
> >  	file_init();
> >  	help_init();
> >  	quit_init();
> > +	trim_init();
> >  }
> >  
> >  static int
> > diff --git a/spaceman/space.h b/spaceman/space.h
> > index 6e1bc52..7b4f034 100644
> > --- a/spaceman/space.h
> > +++ b/spaceman/space.h
> > @@ -34,3 +34,4 @@ extern int	addfile(char *, int , xfs_fsop_geom_t *, int);
> >  extern void	file_init(void);
> >  extern void	help_init(void);
> >  extern void	quit_init(void);
> > +extern void	trim_init(void);
> > diff --git a/spaceman/trim.c b/spaceman/trim.c
> > new file mode 100644
> > index 0000000..9bf6565
> > --- /dev/null
> > +++ b/spaceman/trim.c
> > @@ -0,0 +1,139 @@
> > +/*
> > + * Copyright (c) 2012 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 "libxfs.h"
> > +#include <linux/fs.h>
> > +#include "command.h"
> > +#include "init.h"
> > +#include "space.h"
> > +#include "input.h"
> > +
> > +#ifndef FITRIM
> 
> I wonder if we really still need this compat #ifndef...

Well, it's been in the kernel since 2.6.37 (2010) and XFS since 2.6.38
(2011).  Seven years seems long enough; even the RHEL6 kernel seems to
have FITRIM defined in it. (I think?)

> > +#define FITRIM          _IOWR('X', 121, struct fstrim_range)    /* Trim */
> > +
> > +struct fstrim_range {
> > +	__u64 start;
> > +	__u64 len;
> > +	__u64 minlen;
> > +};
> > +#endif
> > +
> > +static cmdinfo_t trim_cmd;
> > +
> > +/*
> > + * Report on trimace usage in xfs filesystem.
> 
> "Report on trimace?"  (Is that like a grimace?)

"Trim unused space"....

> > + */
> > +static int
> > +trim_f(
> > +	int		argc,
> > +	char		**argv)
> > +{
> > +	struct fstrim_range trim = {0};
> > +	xfs_agnumber_t	agno = 0;
> > +	off64_t		offset = 0;
> > +	ssize_t		length = 0;
> > +	ssize_t		minlen = 0;
> 
> len & minlen in the trim command are 64-bit, is ssize_t
> sufficient?

Probably, since cvtnum returns (signed long long) and file offsets in
Linux can't be larger than 2^63 anyway.

> > +	int		aflag = 0;
> > +	int		fflag = 0;
> > +	int		ret;
> > +	int		c;
> > +
> > +	while ((c = getopt(argc, argv, "a:fm:")) != EOF) {
> > +		switch (c) {
> > +		case 'a':
> > +			if (fflag)
> > +				return command_usage(&trim_cmd);
> > +			aflag = 1;
> > +			agno = atoi(optarg);
> > +			break;
> > +		case 'f':
> > +			if (aflag)
> > +				return command_usage(&trim_cmd);
> > +			fflag = 1;
> > +			break;
> > +		case 'm':
> > +			minlen = cvtnum(file->geom.blocksize,
> > +					file->geom.sectsize, argv[optind]);
> > +			break;
> > +		default:
> > +			return command_usage(&trim_cmd);
> > +		}
> > +	}
> 
> Not a huge deal, but maybe move the above command_usage stuff down here:
> 
> +	if (aflag && fflag)
> +		return command_usage(&trim_cmd);
> 
> so all the checking is in one spot.  Save Future-jtulak some grief ;)

Ok.

> > +
> > +	if (optind != argc - 2 && !(aflag || fflag))
> > +		return command_usage(&trim_cmd);
> > +	if (optind != argc) {
> > +		offset = cvtnum(file->geom.blocksize, file->geom.sectsize,
> > +				argv[optind]);
> > +		length = cvtnum(file->geom.blocksize, file->geom.sectsize,
> > +				argv[optind + 1]);
> > +	} else if (agno) {
> > +		offset = agno * file->geom.agblocks * file->geom.blocksize;
> > +		length = file->geom.agblocks * file->geom.blocksize;
> > +	} else {
> > +		offset = 0;
> > +		length = file->geom.datablocks * file->geom.blocksize;
> > +	}
> > +
> > +	trim.start = offset;
> > +	trim.len = length;
> > +	trim.minlen = minlen;
> > +
> > +	ret = ioctl(file->fd, FITRIM, (unsigned long)&trim);
> > +	if (ret < 0) {
> > +		fprintf(stderr, "%s: ioctl(FITRIM) [\"%s\"]: "
> > +			"%s\n", progname, file->name, strerror(errno));
> 
> +	if (ret < 0) {
> +		fprintf(stderr, "%s: ioctl(FITRIM) [\"%s\"]: %s\n",
> +			progname, file->name, strerror(errno));
> 
> > +		exitcode = 1;
> > +		return 0;
> 
> maybe don't need that return here (but don't really care)

Fixed.

> > +	}
> > +	return 0;
> > +}
> > +
> > +static void
> > +trim_help(void)
> > +{
> > +	printf(_(
> > +"\n"
> > +"Discard filesystem free space\n"
> > +"\n"
> > +"Options: [-m minlen] [-f]|[-a agno]|[offset length]\n"
> > +"\n"
> > +" -m minlen -- skip freespace extents smaller than minlen\n"
> > +" -f -- trim all the freespace in the entire filesystem\n"
> > +" -a agno -- trim all the freespace in the given AG agno\n"
> > +" offset length -- trim the freespace in the range {offset, length}\n"
> 
> xfs_io lines these things up (brute force whitespace) and looks nicer:
> 
>  -S   -- use an alternate seed number for filling the write buffer
>  -i   -- input file, source of data to write (used when writing forward)
>  -d   -- open the input file for direct IO
>  -s   -- skip a number of bytes at the start of the input file
>  -w   -- call fdatasync(2) at the end (included in timing results)
> 
> so:
> 
> +" -m minle      -- skip freespace extents smaller than minlen\n"
> +" -f            -- trim all the freespace in the entire filesystem\n"
> +" -a agno       -- trim all the freespace in the given AG agno\n"
> +" offset length -- trim the freespace in the range {offset, length}\n"

Ok.

> > +"\n"));
> > +
> > +}
> > +
> > +void
> > +trim_init(void)
> > +{
> > +	trim_cmd.name = "trim";
> > +	trim_cmd.altname = "tr";
> > +	trim_cmd.cfunc = trim_f;
> > +	trim_cmd.argmin = 1;
> > +	trim_cmd.argmax = 4;
> > +	trim_cmd.args = "[-m minlen] [-f]|[-a agno]|[offset length]\n";
> 
> Not sure we want \n at the end:
> 
> xfs_spaceman> help trim
> trim [-m minlen] [-f]|[-a agno]|[offset length]
>  -- Discard filesystem free space
> 
> xfs_io tends to put that all on one line - or are we worried about 80cols?

We aren't, since various xfs_io commands spill the first line over
80col.  Will fix.

--D

> > +	trim_cmd.flags = CMD_FLAG_ONESHOT;
> > +	trim_cmd.oneline = _("Discard filesystem free space");
> > +	trim_cmd.help = trim_help;
> > +
> > +	add_command(&trim_cmd);
> > +}
> > +
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > the body of a message to majordomo@vger.kernel.org
> > 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@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/9] xfs_spaceman: AG state control
  2017-05-26 23:06   ` Eric Sandeen
@ 2017-05-30 18:30     ` Darrick J. Wong
  0 siblings, 0 replies; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-30 18:30 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: sandeen, linux-xfs, Dave Chinner

On Fri, May 26, 2017 at 06:06:46PM -0500, Eric Sandeen wrote:
> On 5/7/17 10:56 AM, Darrick J. Wong wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > Add support for a new allocation group state control ioctl. This
> > allows control of various AG parameters, such as whether inode
> > allocation is allowed in the AG, metadata preference, whether new
> > allocations are allowed, etc. This requires a new ioctl.
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > [darrick: change xfsctl to ioctl]
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Sounds like a great patch to send if this ever gets implemented in
> the kernel; for now, I think, I'll not merge it.  :)

Oops, this one got sucked into the patch series despite not having
a corresponding kernel ioctl, so I will drop this.

--D

> 
> -Eric
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 5/9] xfs_spaceman: add new speculative prealloc control
  2017-05-27  1:45   ` Eric Sandeen
@ 2017-05-30 18:34     ` Darrick J. Wong
  0 siblings, 0 replies; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-30 18:34 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: sandeen, linux-xfs, Dave Chinner

On Fri, May 26, 2017 at 08:45:58PM -0500, Eric Sandeen wrote:
> 
> 
> On 5/7/17 10:56 AM, Darrick J. Wong wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > Add an control interface for purging speculative
> > preallocation via the new ioctls.
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > [darrick: change xfsctl to ioctl]
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> >  spaceman/Makefile   |    2 -
> >  spaceman/init.c     |    1 
> >  spaceman/prealloc.c |  135 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  spaceman/space.h    |    1 
> >  4 files changed, 138 insertions(+), 1 deletion(-)
> >  create mode 100644 spaceman/prealloc.c
> > 
> > 
> > diff --git a/spaceman/Makefile b/spaceman/Makefile
> > index 9fb9142..b1f1136 100644
> > --- a/spaceman/Makefile
> > +++ b/spaceman/Makefile
> > @@ -8,7 +8,7 @@ include $(TOPDIR)/include/builddefs
> >  LTCOMMAND = xfs_spaceman
> >  HFILES = init.h space.h
> >  CFILES = init.c \
> > -	file.c trim.c
> > +	file.c prealloc.c trim.c
> >  
> >  LLDLIBS = $(LIBXCMD)
> >  LTDEPENDENCIES = $(LIBXCMD)
> > diff --git a/spaceman/init.c b/spaceman/init.c
> > index ae5cfb5..08b5a33 100644
> > --- a/spaceman/init.c
> > +++ b/spaceman/init.c
> > @@ -39,6 +39,7 @@ init_commands(void)
> >  {
> >  	file_init();
> >  	help_init();
> > +	prealloc_init();
> >  	quit_init();
> >  	trim_init();
> >  }
> > diff --git a/spaceman/prealloc.c b/spaceman/prealloc.c
> > new file mode 100644
> > index 0000000..b93f909
> > --- /dev/null
> > +++ b/spaceman/prealloc.c
> > @@ -0,0 +1,135 @@
> > +/*
> > + * Copyright (c) 2012 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 "libxfs.h"
> > +#include "command.h"
> > +#include "input.h"
> > +#include "init.h"
> > +#include "space.h"
> > +
> > +#ifndef XFS_IOC_FREE_EOFBLOCKS
> > +#define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_eofblocks)
> > +
> > +#define XFS_EOFBLOCKS_VERSION           1
> > +struct xfs_fs_eofblocks {
> > +	__u32		eof_version;
> > +	__u32		eof_flags;
> > +	uid_t		eof_uid;
> > +	gid_t		eof_gid;
> > +	prid_t		eof_prid;
> > +	__u32		pad32;
> > +	__u64		eof_min_file_size;
> > +	__u64		pad64[12];
> > +};
> > +
> > +/* eof_flags values */
> > +#define XFS_EOF_FLAGS_SYNC		(1 << 0) /* sync/wait mode scan */
> > +#define XFS_EOF_FLAGS_UID		(1 << 1) /* filter by uid */
> > +#define XFS_EOF_FLAGS_GID		(1 << 2) /* filter by gid */
> > +#define XFS_EOF_FLAGS_PRID		(1 << 3) /* filter by project id */
> > +#define XFS_EOF_FLAGS_MINFILESIZE	(1 << 4) /* filter by min file size */
> > +
> > +#endif
> 
> I think including libxfs defines XFS_IOC_FREE_EOFBLOCKS, via xfs_fs.h
> and that whole hunk can go, no?

Yeah.

> > +
> > +static cmdinfo_t prealloc_cmd;
> > +
> > +/*
> > + * Control preallocation amounts.
> > + */
> > +static int
> > +prealloc_f(
> > +	int	argc,
> > +	char	**argv)
> > +{
> > +	struct xfs_fs_eofblocks eofb = {0};
> > +	int	c;
> > +
> > +	eofb.eof_version = XFS_EOFBLOCKS_VERSION;
> > +
> > +	while ((c = getopt(argc, argv, "g:m:p:su:")) != EOF) {
> > +		switch (c) {
> > +		case 'g':
> > +			eofb.eof_flags |= XFS_EOF_FLAGS_GID;
> > +			eofb.eof_gid = atoi(optarg);
> > +			break;
> > +		case 'u':
> > +			eofb.eof_flags |= XFS_EOF_FLAGS_UID;
> > +			eofb.eof_uid = atoi(optarg);
> > +			break;
> > +		case 'p':
> > +			eofb.eof_flags |= XFS_EOF_FLAGS_PRID;
> > +			eofb.eof_prid = atoi(optarg);
> > +			break;
> > +		case 's':
> > +			eofb.eof_flags |= XFS_EOF_FLAGS_SYNC;
> > +			break;
> > +		case 'm':
> > +			eofb.eof_flags |= XFS_EOF_FLAGS_MINFILESIZE;
> > +			eofb.eof_min_file_size = cvtnum(file->geom.blocksize,
> > +							file->geom.sectsize,
> > +							optarg);
> > +			break;
> > +		case '?':
> > +		default:
> > +			return command_usage(&prealloc_cmd);
> > +		}
> > +	}
> > +	if (optind != argc)
> > +		return command_usage(&prealloc_cmd);
> > +
> > +	if (ioctl(file->fd, XFS_IOC_FREE_EOFBLOCKS, &eofb) < 0) {
> > +		fprintf(stderr, _("%s: XFS_IOC_FREE_EOFBLOCKS on %s: %s\n"),
> > +			progname, file->name, strerror(errno));
> > +	}
> > +	return 0;
> > +}
> > +
> > +static void
> > +prealloc_help(void)
> > +{
> > +	printf(_(
> > +"\n"
> > +"Control speculative preallocation\n"
> > +"\n"
> > +"Options: [-s] [-ugp id] [-m minlen]\n"
> > +"\n"
> > +" -s -- synchronous flush - wait for flush to complete\n"
> 
> really flush?  (maybe removal? scan?)

"-s        -- wait for removal to complete\n"

> 
> > +" -u uid -- remove prealloc on files matching user <uid>\n"
> > +" -g gid -- remove prealloc on files matching group <gid>\n"
> > +" -p prid -- remove prealloc on files matching project <prid>\n"
> > +" -m minlen -- only consider files larger than <minlen>\n"
> > +"\n"));
> 
> +" -s        -- synchronous flush - wait for flush to complete\n"
> +" -u uid    -- remove prealloc on files matching user <uid>\n"
> +" -g gid    -- remove prealloc on files matching group <gid>\n"
> +" -p prid   -- remove prealloc on files matching project <prid>\n"
> +" -m minlen -- only consider files larger than <minlen>\n"
> 
> 
> > +
> > +}
> > +
> > +void
> > +prealloc_init(void)
> > +{
> > +	prealloc_cmd.name = "prealloc";
> > +	prealloc_cmd.altname = "prealloc";
> > +	prealloc_cmd.cfunc = prealloc_f;
> > +	prealloc_cmd.argmin = 1;
> > +	prealloc_cmd.argmax = -1;
> > +	prealloc_cmd.args = "[-s] [-ugp id] [-m minlen]\n";
> 
> no \n please:
> 
> xfs_spaceman> help
> ...
> 
> prealloc [-s] [-ugp id] [-m minlen]
>  -- Control speculative preallocation
> 
> should be on same line ala xfs_io IMHO

Ok.

--D

> 
> > +	prealloc_cmd.flags = CMD_FLAG_ONESHOT;
> > +	prealloc_cmd.oneline = _("Control speculative preallocation");
> > +	prealloc_cmd.help = prealloc_help;
> > +
> > +	add_command(&prealloc_cmd);
> > +}
> > +
> > diff --git a/spaceman/space.h b/spaceman/space.h
> > index 7b4f034..0ae3116 100644
> > --- a/spaceman/space.h
> > +++ b/spaceman/space.h
> > @@ -33,5 +33,6 @@ extern int	addfile(char *, int , xfs_fsop_geom_t *, int);
> >  
> >  extern void	file_init(void);
> >  extern void	help_init(void);
> > +extern void	prealloc_init(void);
> >  extern void	quit_init(void);
> >  extern void	trim_init(void);
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > the body of a message to majordomo@vger.kernel.org
> > 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@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 7/9] xfs_spaceman: Free space mapping command
  2017-05-27  1:57   ` Eric Sandeen
@ 2017-05-30 18:40     ` Darrick J. Wong
  2017-05-30 18:56       ` Eric Sandeen
  0 siblings, 1 reply; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-30 18:40 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: sandeen, linux-xfs, Dave Chinner

On Fri, May 26, 2017 at 08:57:14PM -0500, Eric Sandeen wrote:
> 
> 
> On 5/7/17 10:57 AM, Darrick J. Wong wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > Add freespace mapping tool modelled on the xfs_db freesp command.
> > The advantage of this command over xfs_db is that it can be done
> > online and is coherent with concurrent modifications to the
> > filesystem.
> > 
> > This requires the kernel to support the XFS_IOC_GETFSMAP ioctl to map
> > free space indexes.
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > [darrick: port from FIEMAPFS to GETFSMAP]
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> >  spaceman/Makefile   |   12 +-
> >  spaceman/ag.c       |    1 
> >  spaceman/file.c     |   18 ++-
> >  spaceman/freesp.c   |  367 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  spaceman/init.c     |    9 +
> >  spaceman/prealloc.c |    1 
> >  spaceman/space.h    |   12 +-
> >  spaceman/trim.c     |    1 
> >  8 files changed, 413 insertions(+), 8 deletions(-)
> >  create mode 100644 spaceman/freesp.c
> > 
> > 
> > diff --git a/spaceman/Makefile b/spaceman/Makefile
> > index 08709b3..3b059ca 100644
> > --- a/spaceman/Makefile
> > +++ b/spaceman/Makefile
> > @@ -7,8 +7,12 @@ include $(TOPDIR)/include/builddefs
> >  
> >  LTCOMMAND = xfs_spaceman
> >  HFILES = init.h space.h
> > -CFILES = init.c \
> > -	ag.c file.c prealloc.c trim.c
> > +CFILES = ag.c \
> > +	 file.c \
> > +	 init.c \
> > +	 prealloc.c \
> > +	 trim.c
> > +
> >  
> >  LLDLIBS = $(LIBXCMD)
> >  LTDEPENDENCIES = $(LIBXCMD)
> > @@ -22,6 +26,10 @@ ifeq ($(ENABLE_EDITLINE),yes)
> >  LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP)
> >  endif
> >  
> > +ifeq ($(HAVE_GETFSMAP),yes)
> > +CFILES += freesp.c
> > +endif
> > +
> >  default: depend $(LTCOMMAND)
> >  
> >  include $(BUILDRULES)
> > diff --git a/spaceman/ag.c b/spaceman/ag.c
> > index 1eb8aa0..0f1c869 100644
> > --- a/spaceman/ag.c
> > +++ b/spaceman/ag.c
> > @@ -21,6 +21,7 @@
> >  #include "command.h"
> >  #include "input.h"
> >  #include "init.h"
> > +#include "path.h"
> >  #include "space.h"
> >  
> >  #ifndef XFS_IOC_AGCONTROL
> > diff --git a/spaceman/file.c b/spaceman/file.c
> > index 9356066..7c5ea0e 100644
> > --- a/spaceman/file.c
> > +++ b/spaceman/file.c
> > @@ -22,6 +22,7 @@
> >  #include "command.h"
> >  #include "input.h"
> >  #include "init.h"
> > +#include "path.h"
> >  #include "space.h"
> >  
> >  static cmdinfo_t print_cmd;
> > @@ -69,8 +70,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;
> >  
> >  	fd = open(path, flags, mode);
> > @@ -95,6 +98,15 @@ openfile(
> >  		close(fd);
> >  		return -1;
> >  	}
> > +
> > +	if (fs_path) {
> > +		fsp = fs_table_lookup(path, FS_MOUNT_POINT);
> > +		if (!fsp) {
> > +			fprintf(stderr, _("Unable to find XFS information."));
> 
> If I got that error I wouldn't know what it meant...

"Unable to find mount information." ?

> 
> > +			return -1;
> > +		}
> > +		*fs_path = *fsp;
> > +	}
> >  	return fd;
> >  }
> >  
> > @@ -103,7 +115,8 @@ addfile(
> >  	char		*name,
> >  	int		fd,
> >  	xfs_fsop_geom_t	*geometry,
> > -	int		flags)
> > +	int		flags,
> > +	struct fs_path	*fs_path)
> >  {
> >  	char		*filename;
> >  
> > @@ -131,6 +144,7 @@ addfile(
> >  	file->flags = flags;
> >  	file->name = filename;
> >  	file->geom = *geometry;
> > +	file->fs_path = *fs_path;
> >  	return 0;
> >  }
> >  
> > diff --git a/spaceman/freesp.c b/spaceman/freesp.c
> > new file mode 100644
> > index 0000000..5493916
> > --- /dev/null
> > +++ b/spaceman/freesp.c
> > @@ -0,0 +1,367 @@
> > +/*
> > + * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
> > + * Copyright (c) 2012 Red Hat, Inc.
> > + * Copyright (c) 2017 Oracle.
> > + * 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 "libxfs.h"
> > +#include <linux/fiemap.h>
> > +#include "command.h"
> > +#include "init.h"
> > +#include "path.h"
> > +#include "space.h"
> > +
> > +typedef struct histent
> > +{
> > +	int		low;
> > +	int		high;
> > +	long long	count;
> > +	long long	blocks;
> > +} histent_t;
> > +
> > +static int		agcount;
> > +static xfs_agnumber_t	*aglist;
> > +static int		dumpflag;
> > +static int		equalsize;
> > +static histent_t	*hist;
> > +static int		histcount;
> > +static int		multsize;
> > +static int		seen1;
> > +static int		summaryflag;
> > +static bool		rtflag;
> > +static long long	totblocks;
> > +static long long	totexts;
> > +
> > +static cmdinfo_t freesp_cmd;
> > +
> > +static void
> > +addhistent(
> > +	int	h)
> > +{
> > +	hist = realloc(hist, (histcount + 1) * sizeof(*hist));
> > +	if (h == 0)
> > +		h = 1;
> > +	hist[histcount].low = h;
> > +	hist[histcount].count = hist[histcount].blocks = 0;
> > +	histcount++;
> > +	if (h == 1)
> > +		seen1 = 1;
> > +}
> > +
> > +static void
> > +addtohist(
> > +	xfs_agnumber_t	agno,
> > +	xfs_agblock_t	agbno,
> > +	off64_t		len)
> > +{
> > +	int		i;
> > +
> > +	if (dumpflag)
> > +		printf("%8d %8d %8"PRId64"\n", agno, agbno, len);
> > +	totexts++;
> > +	totblocks += len;
> > +	for (i = 0; i < histcount; i++) {
> > +		if (hist[i].high >= len) {
> > +			hist[i].count++;
> > +			hist[i].blocks += len;
> > +			break;
> > +		}
> > +	}
> > +}
> > +
> > +static int
> > +hcmp(
> > +	const void	*a,
> > +	const void	*b)
> > +{
> > +	return ((histent_t *)a)->low - ((histent_t *)b)->low;
> > +}
> > +
> > +static void
> > +histinit(
> > +	int	maxlen)
> > +{
> > +	int	i;
> > +
> > +	if (equalsize) {
> > +		for (i = 1; i < maxlen; i += equalsize)
> > +			addhistent(i);
> > +	} else if (multsize) {
> > +		for (i = 1; i < maxlen; i *= multsize)
> > +			addhistent(i);
> > +	} else {
> > +		if (!seen1)
> > +			addhistent(1);
> > +		qsort(hist, histcount, sizeof(*hist), hcmp);
> > +	}
> > +	for (i = 0; i < histcount; i++) {
> > +		if (i < histcount - 1)
> > +			hist[i].high = hist[i + 1].low - 1;
> > +		else
> > +			hist[i].high = maxlen;
> > +	}
> > +}
> > +
> > +static void
> > +printhist(void)
> > +{
> > +	int	i;
> > +
> > +	printf("%7s %7s %7s %7s %6s\n",
> > +		_("from"), _("to"), _("extents"), _("blocks"), _("pct"));
> > +	for (i = 0; i < histcount; i++) {
> > +		if (hist[i].count)
> > +			printf("%7d %7d %7lld %7lld %6.2f\n", hist[i].low,
> > +				hist[i].high, hist[i].count, hist[i].blocks,
> > +				hist[i].blocks * 100.0 / totblocks);
> > +	}
> > +}
> > +
> > +static int
> > +inaglist(
> > +	xfs_agnumber_t	agno)
> > +{
> > +	int		i;
> > +
> > +	if (agcount == 0)
> > +		return 1;
> > +	for (i = 0; i < agcount; i++)
> > +		if (aglist[i] == agno)
> > +			return 1;
> > +	return 0;
> > +}
> > +
> > +#define NR_EXTENTS 128
> > +
> > +static void
> > +scan_ag(
> > +	xfs_agnumber_t		agno)
> > +{
> > +	struct fsmap_head	*fsmap;
> > +	struct fsmap		*extent;
> > +	struct fsmap		*l, *h;
> > +	struct fsmap		*p;
> > +	off64_t			blocksize = file->geom.blocksize;
> > +	off64_t			bperag;
> > +	off64_t			aglen;
> > +	xfs_agblock_t		agbno;
> > +	int			ret;
> > +	int			i;
> > +
> > +	bperag = (off64_t)file->geom.agblocks * blocksize;
> > +
> > +	fsmap = malloc(fsmap_sizeof(NR_EXTENTS));
> > +	if (!fsmap) {
> > +		fprintf(stderr, _("%s: fsmap malloc failed.\n"), progname);
> > +		exitcode = 1;
> > +		return;
> > +	}
> > +
> > +	memset(fsmap, 0, sizeof(*fsmap));
> > +	fsmap->fmh_count = NR_EXTENTS;
> > +	l = fsmap->fmh_keys;
> > +	h = fsmap->fmh_keys + 1;
> > +	if (agno != NULLAGNUMBER) {
> > +		l->fmr_physical = agno * bperag;
> > +		h->fmr_physical = ((agno + 1) * bperag) - 1;
> > +		l->fmr_device = h->fmr_device = file->fs_path.fs_datadev;
> > +	} else {
> > +		l->fmr_physical = 0;
> > +		h->fmr_physical = ULLONG_MAX;
> > +		l->fmr_device = h->fmr_device = file->fs_path.fs_rtdev;
> > +	}
> > +	h->fmr_owner = ULLONG_MAX;
> > +	h->fmr_flags = UINT_MAX;
> > +	h->fmr_offset = ULLONG_MAX;
> > +
> > +	while (true) {
> > +		ret = ioctl(file->fd, FS_IOC_GETFSMAP, fsmap);
> > +		if (ret < 0) {
> > +			fprintf(stderr,
> > +_("%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n"),
> 
> huh, is this an email artifact that wrapped the line?

Probably a leftover from when I removed the 'X' from FS_IOC_GETFSMAP which
means it no longer hangs over 80col.  Fixed.

> > +				progname, file->name, strerror(errno));
> > +			free(fsmap);
> > +			exitcode = 1;
> > +			return;
> > +		}
> > +
> > +		/* No more extents to map, exit */
> > +		if (!fsmap->fmh_entries)
> > +			break;
> > +
> > +		for (i = 0, extent = fsmap->fmh_recs;
> > +		     i < fsmap->fmh_entries;
> > +		     i++, extent++) {
> > +			if (!(extent->fmr_flags & FMR_OF_SPECIAL_OWNER) ||
> > +			    extent->fmr_owner != XFS_FMR_OWN_FREE)
> > +				continue;
> > +			agbno = (extent->fmr_physical - (bperag * agno)) /
> > +								blocksize;
> > +			aglen = extent->fmr_length / blocksize;
> > +
> > +			addtohist(agno, agbno, aglen);
> > +		}
> > +
> > +		p = &fsmap->fmh_recs[fsmap->fmh_entries - 1];
> > +		if (p->fmr_flags & FMR_OF_LAST)
> > +			break;
> > +		fsmap_advance(fsmap);
> > +	}
> > +}
> > +static void
> > +aglistadd(
> > +	char	*a)
> > +{
> > +	aglist = realloc(aglist, (agcount + 1) * sizeof(*aglist));
> > +	aglist[agcount] = (xfs_agnumber_t)atoi(a);
> > +	agcount++;
> > +}
> > +
> > +static int
> > +init(
> > +	int		argc,
> > +	char		**argv)
> > +{
> > +	int		c;
> > +	int		speced = 0;
> > +
> > +	agcount = dumpflag = equalsize = multsize = optind = 0;
> > +	histcount = seen1 = summaryflag = 0;
> > +	totblocks = totexts = 0;
> > +	aglist = NULL;
> > +	hist = NULL;
> > +	rtflag = false;
> > +	while ((c = getopt(argc, argv, "a:bde:h:m:rs")) != EOF) {
> > +		switch (c) {
> > +		case 'a':
> > +			aglistadd(optarg);
> > +			break;
> > +		case 'b':
> > +			if (speced)
> > +				return 0;
> > +			multsize = 2;
> > +			speced = 1;
> > +			break;
> > +		case 'd':
> > +			dumpflag = 1;
> > +			break;
> > +		case 'e':
> > +			if (speced)
> > +				return 0;
> > +			equalsize = atoi(optarg);
> > +			speced = 1;
> > +			break;
> > +		case 'h':
> > +			if (speced && !histcount)
> > +				return 0;
> > +			addhistent(atoi(optarg));
> > +			speced = 1;
> > +			break;
> > +		case 'm':
> > +			if (speced)
> > +				return 0;
> > +			multsize = atoi(optarg);
> > +			speced = 1;
> > +			break;
> > +		case 'r':
> > +			rtflag = true;
> > +			break;
> > +		case 's':
> > +			summaryflag = 1;
> > +			break;
> > +		case '?':
> > +			return 0;
> > +		}
> > +	}
> > +	if (optind != argc)
> > +		return 0;
> > +	if (!speced)
> > +		multsize = 2;
> > +	histinit(file->geom.agblocks);
> > +	return 1;
> > +}
> > +
> > +/*
> > + * Report on freespace usage in xfs filesystem.
> > + */
> > +static int
> > +freesp_f(
> > +	int		argc,
> > +	char		**argv)
> > +{
> > +	xfs_agnumber_t	agno;
> > +
> > +	if (!init(argc, argv))
> > +		return 0;
> > +	if (rtflag)
> > +		scan_ag(NULLAGNUMBER);
> > +	for (agno = 0; !rtflag && agno < file->geom.agcount; agno++)  {
> > +		if (inaglist(agno))
> > +			scan_ag(agno);
> > +	}
> > +	if (histcount)
> > +		printhist();
> > +	if (summaryflag) {
> > +		printf(_("total free extents %lld\n"), totexts);
> > +		printf(_("total free blocks %lld\n"), totblocks);
> > +		printf(_("average free extent size %g\n"),
> > +			(double)totblocks / (double)totexts);
> > +	}
> > +	if (aglist)
> > +		free(aglist);
> > +	if (hist)
> > +		free(hist);
> > +	return 0;
> > +}
> > +
> > +static void
> > +freesp_help(void)
> > +{
> > +	printf(_(
> > +"\n"
> > +"Examine filesystem free space\n"
> > +"\n"
> > +"Options: [-bcds] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n"
> 
> no "c" ... missing "r"
> 
> "a:bde:h:m:rs"
> 
> > +"\n"
> > +" -b -- binary histogram bin size\n"
> > +" -d -- debug output\n"
> > +" -r -- display realtime device free space information\n"
> > +" -s -- emit freespace summary information\n"
> > +" -a agno -- scan only the given AG agno\n"
> > +" -e bsize -- use fixed histogram bin size of bsize\n"
> > +" -h h1 -- use custom histogram bin size of h1. Multiple specifications allowed.\n"
> > +" -m bmult -- use histogram bin size multiplier of bmult\n"
> 
> 
> +" -b       -- binary histogram bin size\n"
> +" -d       -- debug output\n"
> +" -r       -- display realtime device free space information\n"
> +" -s       -- emit freespace summary information\n"
> +" -a agno  -- scan only the given AG agno\n"
> +" -e bsize -- use fixed histogram bin size of bsize\n"
> +" -h h1    -- use custom histogram bin size of h1. Multiple specifications allowed.\n"
> +" -m bmult -- use histogram bin size multiplier of bmult\n"
> 
> also, "h1?" - I guess that's modeled on xfs_db ... long as the manpage
> explains it, I guess...

hbsz...

> 
> > +"\n"));
> > +
> > +}
> > +
> > +void
> > +freesp_init(void)
> > +{
> > +	freesp_cmd.name = "freesp";
> > +	freesp_cmd.altname = "fsp";
> > +	freesp_cmd.cfunc = freesp_f;
> > +	freesp_cmd.argmin = 0;
> > +	freesp_cmd.argmax = -1;
> > +	freesp_cmd.args = "[-bcds] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n";
> 
> no \n again here, I think

Yes.

--D

> > +	freesp_cmd.flags = CMD_FLAG_ONESHOT | CMD_FLAG_FOREIGN_OK;
> > +	freesp_cmd.oneline = _("Examine filesystem free space");
> > +	freesp_cmd.help = freesp_help;
> > +
> > +	add_command(&freesp_cmd);
> > +}
> > +
> > diff --git a/spaceman/init.c b/spaceman/init.c
> > index 08b5a33..e6df7fe 100644
> > --- a/spaceman/init.c
> > +++ b/spaceman/init.c
> > @@ -20,6 +20,7 @@
> >  #include "command.h"
> >  #include "input.h"
> >  #include "init.h"
> > +#include "path.h"
> >  #include "space.h"
> >  
> >  char	*progname;
> > @@ -38,6 +39,7 @@ static void
> >  init_commands(void)
> >  {
> >  	file_init();
> > +	freesp_init();
> >  	help_init();
> >  	prealloc_init();
> >  	quit_init();
> > @@ -71,12 +73,14 @@ init(
> >  	int		c, flags = 0;
> >  	mode_t		mode = 0600;
> >  	xfs_fsop_geom_t	geometry = { 0 };
> > +	struct fs_path	fsp;
> >  
> >  	progname = basename(argv[0]);
> >  	setlocale(LC_ALL, "");
> >  	bindtextdomain(PACKAGE, LOCALEDIR);
> >  	textdomain(PACKAGE);
> >  
> > +	fs_table_initialise(0, NULL, 0, NULL);
> >  	while ((c = getopt(argc, argv, "c:V")) != EOF) {
> >  		switch (c) {
> >  		case 'c':
> > @@ -94,11 +98,12 @@ init(
> >  		usage();
> >  
> >  	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))
> >  			printf(_("Not an XFS filesystem!\n"));
> > -		if (addfile(argv[optind], c, &geometry, flags) < 0)
> > +		if (addfile(argv[optind], c, &geometry, flags, &fsp) < 0)
> >  			exit(1);
> >  		optind++;
> >  	}
> > diff --git a/spaceman/prealloc.c b/spaceman/prealloc.c
> > index b93f909..249d7a4 100644
> > --- a/spaceman/prealloc.c
> > +++ b/spaceman/prealloc.c
> > @@ -20,6 +20,7 @@
> >  #include "command.h"
> >  #include "input.h"
> >  #include "init.h"
> > +#include "path.h"
> >  #include "space.h"
> >  
> >  #ifndef XFS_IOC_FREE_EOFBLOCKS
> > diff --git a/spaceman/space.h b/spaceman/space.h
> > index 0ae3116..bf9a2df 100644
> > --- a/spaceman/space.h
> > +++ b/spaceman/space.h
> > @@ -21,6 +21,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 */
> > @@ -28,11 +29,18 @@ extern int		filecount;	/* number of open files */
> >  extern fileio_t		*file;		/* active file in file table */
> >  extern int filelist_f(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	file_init(void);
> >  extern void	help_init(void);
> >  extern void	prealloc_init(void);
> >  extern void	quit_init(void);
> >  extern void	trim_init(void);
> > +
> > +#ifdef HAVE_GETFSMAP
> > +extern void	freesp_init(void);
> > +#else
> > +# define freesp_init()	do { } while (0)
> > +#endif
> > diff --git a/spaceman/trim.c b/spaceman/trim.c
> > index 9bf6565..d1e5d82 100644
> > --- a/spaceman/trim.c
> > +++ b/spaceman/trim.c
> > @@ -20,6 +20,7 @@
> >  #include <linux/fs.h>
> >  #include "command.h"
> >  #include "init.h"
> > +#include "path.h"
> >  #include "space.h"
> >  #include "input.h"
> >  
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > the body of a message to majordomo@vger.kernel.org
> > 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@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl
  2017-05-26 22:12       ` Eric Sandeen
@ 2017-05-30 18:44         ` Darrick J. Wong
  2017-05-30 18:47           ` Eric Sandeen
  0 siblings, 1 reply; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-30 18:44 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: Eric Sandeen, linux-xfs

On Fri, May 26, 2017 at 05:12:25PM -0500, Eric Sandeen wrote:
> On 5/26/17 4:41 PM, Darrick J. Wong wrote:
> > On Fri, May 26, 2017 at 04:20:49PM -0500, Eric Sandeen wrote:
> >>
> >>
> >> On 5/8/17 2:47 PM, Darrick J. Wong wrote:
> >>> From: Darrick J. Wong <darrick.wong@oracle.com>
> >>>
> >>> Introduce a new ioctl that uses the reverse mapping btree to return
> >>> information about the physical layout of the filesystem.
> >>>
> >>> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> >>
> >> Ok, howzabout this:
> >>
> >> Changes from your version:
> >>
> >> - remove libxfs stuff, I synced that separately already
> >> - rename sys_fsmap just fsmap (it's not a syscall)
> >> - change meaning of "have_fsmap" - it now means we have it on the
> >>   system, not that this platform (linux) might support it.*
> > 
> > I'll have a look... though afaict this removes anything that would
> > prevent us from building the fsmap stuff on a non-linux platform.
> > Seeing as fsmap is linux-only, we might as well restrict it on the
> > platforms we still support.
> 
> Right, so in this patch, either we define HAVE_GETFSMAP if we find
> it on the system, or we implement it in include/linux.h and define
> it then.  So HAVE_GETFSMAP won't get set on non-linux.
> 
> But in the next patch that actually makes use of the fsmap ioctl,
> we'll need to conditionally include fsmap.c, and then all should
> be good, I think, right?  Something like:
> 
> +# 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

Yes, I think that will be fine.  Do you want me to respin the patches
as they are now (having been fixed), or should I wait for a for-next
rebase with whatever's in your tree?

--D

> 
> > Darwin?  (I think Jan Tulak added this, though OSX doen't do XFS...)
> > BSD?  (Wasn't XFS removed from their kernel a few years ago?)
> 
> Jan, do you still use it? 
> 
> -Eric
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl
  2017-05-30 18:44         ` Darrick J. Wong
@ 2017-05-30 18:47           ` Eric Sandeen
  2017-05-30 18:59             ` Eric Sandeen
  0 siblings, 1 reply; 40+ messages in thread
From: Eric Sandeen @ 2017-05-30 18:47 UTC (permalink / raw)
  To: Darrick J. Wong, Eric Sandeen; +Cc: linux-xfs

On 5/30/17 1:44 PM, Darrick J. Wong wrote:
> On Fri, May 26, 2017 at 05:12:25PM -0500, Eric Sandeen wrote:
>> On 5/26/17 4:41 PM, Darrick J. Wong wrote:
>>> On Fri, May 26, 2017 at 04:20:49PM -0500, Eric Sandeen wrote:
>>>>
>>>>
>>>> On 5/8/17 2:47 PM, Darrick J. Wong wrote:
>>>>> From: Darrick J. Wong <darrick.wong@oracle.com>
>>>>>
>>>>> Introduce a new ioctl that uses the reverse mapping btree to return
>>>>> information about the physical layout of the filesystem.
>>>>>
>>>>> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
>>>>
>>>> Ok, howzabout this:
>>>>
>>>> Changes from your version:
>>>>
>>>> - remove libxfs stuff, I synced that separately already
>>>> - rename sys_fsmap just fsmap (it's not a syscall)
>>>> - change meaning of "have_fsmap" - it now means we have it on the
>>>>   system, not that this platform (linux) might support it.*
>>>
>>> I'll have a look... though afaict this removes anything that would
>>> prevent us from building the fsmap stuff on a non-linux platform.
>>> Seeing as fsmap is linux-only, we might as well restrict it on the
>>> platforms we still support.
>>
>> Right, so in this patch, either we define HAVE_GETFSMAP if we find
>> it on the system, or we implement it in include/linux.h and define
>> it then.  So HAVE_GETFSMAP won't get set on non-linux.
>>
>> But in the next patch that actually makes use of the fsmap ioctl,
>> we'll need to conditionally include fsmap.c, and then all should
>> be good, I think, right?  Something like:
>>
>> +# 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
> 
> Yes, I think that will be fine.  Do you want me to respin the patches
> as they are now (having been fixed), or should I wait for a for-next
> rebase with whatever's in your tree?

A respin is fine, I hacked at this patch but I don't exactly have it
staged & ready.

-Eric

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 3/9] xfs_spaceman: space management tool
  2017-05-30 18:17       ` Eric Sandeen
@ 2017-05-30 18:47         ` Darrick J. Wong
  2017-06-02 19:44           ` Darrick J. Wong
  0 siblings, 1 reply; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-30 18:47 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: sandeen, linux-xfs, Dave Chinner

On Tue, May 30, 2017 at 01:17:56PM -0500, Eric Sandeen wrote:
> On 5/30/17 12:37 PM, Darrick J. Wong wrote:
> > On Fri, May 26, 2017 at 08:34:18PM -0500, Eric Sandeen wrote:
> >> On 5/7/17 10:56 AM, Darrick J. Wong wrote:
> >>> From: Dave Chinner <dchinner@redhat.com>
> >>>
> >>> xfs_spaceman is intended as a diagnostic and control tool for space
> >>> management operations within XFS. Operations like examining free
> >>> space, managing allocation policies, issuing block discards on free
> >>> space, etc.
> >>>
> >>> The tool is modelled on the xfs_io interface, allowing both
> >>> interactive and command line control of the tool, enabling it to be
> >>> used in scripts and automated management tools.
> >> This may be a result of the xfs_io ancestry, but:
> >>
> >> # xfs_spaceman /mnt/test2 /mnt/test
> >>
> >> Cool, we can open 2 files(ystems)
> >>
> >> xfs_spaceman> print
> >>  000  /mnt/test2     (non-sync,non-direct,read-write)
> >> [001] /mnt/test      (non-sync,non-direct,read-write)
> >>
> >> (what does non-direct mean for a mountpoint?)
> >> (actually where do these flags come from ... hm.)
> >>
> >> Yep there we are!  Now how do we switch to the other?
> >>
> >> xfs_spaceman> help
> >> help [command] -- help for one or all commands
> >> print -- list current open files
> >> quit -- exit the program
> >>
> >> Use 'help commandname' for extended help.
> >>
> >> hmmm... I guess we can't switch.  Should we be able to?
> >>
> >> Is the intent to open files or filesystems...  both?  Is there ever
> >> a reason to be opening a file not a filesystem?
> > <shrug> I mostly just passed on Dave's original patches from whenever
> > ago, but TBH I'm not 100% sure about the usecases for multiple
> > arguments.  The commands that spaceman has now are all fs-oriented, not
> > file-oriented... but maybe people want to be able to issue one command
> > against multiple fses?  OTOH all the commands provided so far are
> > oneshot, so they only act upon one open file.
> > 
> > So, I'm inclined to ditch the 'list' command and disallow multiple open
> > files, like Eric suggests, unless anyone really wants it?
> 
> Either way is fine: multiple (fs) targets with the ability to switch,
> or restrict to just one, but allowing one to open multiple and only
> use one makes little sense.

I think of all the commands we have, only trim and prealloc seem geared
towards being callable against all the paths specified in the command
line.  OTOH I don't see a lot of harm in letting people run reports
against multiple filesystems, though the output will be sort of messy.

I'll play around with removing the ONESHOT designation and see if that
doesn't turn into a horrible mess.

--D

> 
> -Eric
> 
> > --D
> > 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 7/9] xfs_spaceman: Free space mapping command
  2017-05-30 18:40     ` Darrick J. Wong
@ 2017-05-30 18:56       ` Eric Sandeen
  2017-05-30 19:19         ` Darrick J. Wong
  0 siblings, 1 reply; 40+ messages in thread
From: Eric Sandeen @ 2017-05-30 18:56 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: sandeen, linux-xfs, Dave Chinner

On 5/30/17 1:40 PM, Darrick J. Wong wrote:
> On Fri, May 26, 2017 at 08:57:14PM -0500, Eric Sandeen wrote:
>>
>>
>> On 5/7/17 10:57 AM, Darrick J. Wong wrote:
>>> From: Dave Chinner <dchinner@redhat.com>
>>>
>>> Add freespace mapping tool modelled on the xfs_db freesp command.
>>> The advantage of this command over xfs_db is that it can be done
>>> online and is coherent with concurrent modifications to the
>>> filesystem.
>>>
>>> This requires the kernel to support the XFS_IOC_GETFSMAP ioctl to map
>>> free space indexes.
>>>
>>> Signed-off-by: Dave Chinner <dchinner@redhat.com>
>>> [darrick: port from FIEMAPFS to GETFSMAP]
>>> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
>>> ---
>>>  spaceman/Makefile   |   12 +-
>>>  spaceman/ag.c       |    1 
>>>  spaceman/file.c     |   18 ++-
>>>  spaceman/freesp.c   |  367 +++++++++++++++++++++++++++++++++++++++++++++++++++
>>>  spaceman/init.c     |    9 +
>>>  spaceman/prealloc.c |    1 
>>>  spaceman/space.h    |   12 +-
>>>  spaceman/trim.c     |    1 
>>>  8 files changed, 413 insertions(+), 8 deletions(-)
>>>  create mode 100644 spaceman/freesp.c
>>>
>>>
>>> diff --git a/spaceman/Makefile b/spaceman/Makefile
>>> index 08709b3..3b059ca 100644
>>> --- a/spaceman/Makefile
>>> +++ b/spaceman/Makefile
>>> @@ -7,8 +7,12 @@ include $(TOPDIR)/include/builddefs
>>>  
>>>  LTCOMMAND = xfs_spaceman
>>>  HFILES = init.h space.h
>>> -CFILES = init.c \
>>> -	ag.c file.c prealloc.c trim.c
>>> +CFILES = ag.c \
>>> +	 file.c \
>>> +	 init.c \
>>> +	 prealloc.c \
>>> +	 trim.c
>>> +
>>>  
>>>  LLDLIBS = $(LIBXCMD)
>>>  LTDEPENDENCIES = $(LIBXCMD)
>>> @@ -22,6 +26,10 @@ ifeq ($(ENABLE_EDITLINE),yes)
>>>  LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP)
>>>  endif
>>>  
>>> +ifeq ($(HAVE_GETFSMAP),yes)
>>> +CFILES += freesp.c
>>> +endif
>>> +
>>>  default: depend $(LTCOMMAND)
>>>  
>>>  include $(BUILDRULES)
>>> diff --git a/spaceman/ag.c b/spaceman/ag.c
>>> index 1eb8aa0..0f1c869 100644
>>> --- a/spaceman/ag.c
>>> +++ b/spaceman/ag.c
>>> @@ -21,6 +21,7 @@
>>>  #include "command.h"
>>>  #include "input.h"
>>>  #include "init.h"
>>> +#include "path.h"
>>>  #include "space.h"
>>>  
>>>  #ifndef XFS_IOC_AGCONTROL
>>> diff --git a/spaceman/file.c b/spaceman/file.c
>>> index 9356066..7c5ea0e 100644
>>> --- a/spaceman/file.c
>>> +++ b/spaceman/file.c
>>> @@ -22,6 +22,7 @@
>>>  #include "command.h"
>>>  #include "input.h"
>>>  #include "init.h"
>>> +#include "path.h"
>>>  #include "space.h"
>>>  
>>>  static cmdinfo_t print_cmd;
>>> @@ -69,8 +70,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;
>>>  
>>>  	fd = open(path, flags, mode);
>>> @@ -95,6 +98,15 @@ openfile(
>>>  		close(fd);
>>>  		return -1;
>>>  	}
>>> +
>>> +	if (fs_path) {
>>> +		fsp = fs_table_lookup(path, FS_MOUNT_POINT);
>>> +		if (!fsp) {
>>> +			fprintf(stderr, _("Unable to find XFS information."));
>>
>> If I got that error I wouldn't know what it meant...
> 
> "Unable to find mount information." ?

I think that if the path isn't found in the table, that means it wasn't
populated on startup, which means it's not [on] an XFS filesystem:

        fs = fs_table_lookup(argv[optind], FS_MOUNT_POINT);
        if (!fs) {
                fprintf(stderr, _("%s: %s is not a mounted XFS filesystem\n"),
                        progname, argv[optind]);
                return 1;
        }

or

                fprintf(stderr, _("file argument, \"%s\", is not in a mounted XFS filesystem\n"),
                        file->name);

is what other tools do (although quota does:

                fprintf(stderr, "%s: unknown mount point %s\n", progname, dir);
or
                fprintf(stderr, "%s: cannot find mount point %s\n",)


Anyway: I think the failure means that the path is not [on] an xfs filesystem,
so that's probably the best information to convey.

-Eric

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl
  2017-05-30 18:47           ` Eric Sandeen
@ 2017-05-30 18:59             ` Eric Sandeen
  0 siblings, 0 replies; 40+ messages in thread
From: Eric Sandeen @ 2017-05-30 18:59 UTC (permalink / raw)
  To: Eric Sandeen, Darrick J. Wong; +Cc: linux-xfs

Here's what I landed at, but giant grains of salt may apply.

In particular this doesn't have the:


+# 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

in the Makefile, which I tried in a throwaway vm I think.  Sorry
for the disarray.

diff --git a/configure.ac b/configure.ac
index aa102e4..9534986 100644
--- a/configure.ac
+++ b/configure.ac
@@ -142,6 +142,7 @@ AC_HAVE_READDIR
 AC_HAVE_FSETXATTR
 AC_HAVE_MREMAP
 AC_NEED_INTERNAL_FSXATTR
+AC_HAVE_GETFSMAP
 
 if test "$enable_blkid" = yes; then
 AC_HAVE_BLKID_TOPO
diff --git a/include/builddefs.in b/include/builddefs.in
index 4d6bb2d..ec630bd 100644
--- a/include/builddefs.in
+++ b/include/builddefs.in
@@ -112,6 +112,7 @@ HAVE_FLS = @have_fls@
 HAVE_FSETXATTR = @have_fsetxattr@
 HAVE_MREMAP = @have_mremap@
 NEED_INTERNAL_FSXATTR = @need_internal_fsxattr@
+HAVE_GETFSMAP = @have_getfsmap@
 
 GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
 #	   -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
@@ -150,6 +151,9 @@ endif
 ifeq ($(NEED_INTERNAL_FSXATTR),yes)
 PCFLAGS+= -DOVERRIDE_SYSTEM_FSXATTR
 endif
+ifeq ($(HAVE_GETFSMAP),yes)
+PCFLAGS+= -DHAVE_GETFSMAP
+endif
 
 
 GCFLAGS = $(DEBUG) \
diff --git a/include/linux.h b/include/linux.h
index 6a676ca..38969d1 100644
--- a/include/linux.h
+++ b/include/linux.h
@@ -222,4 +222,107 @@ struct fsxattr {
 #define FS_XFLAG_COWEXTSIZE	0x00010000	/* CoW extent size allocator hint */
 #endif
 
+#ifndef HAVE_GETFSMAP
+/*
+ *	Structure for FS_IOC_GETFSMAP.
+ *
+ *	The memory layout for this call are the scalar values defined in
+ *	struct fsmap_head, followed by two struct fsmap that describe
+ *	the lower and upper bound of mappings to return, followed by an
+ *	array of struct fsmap mappings.
+ *
+ *	fmh_iflags control the output of the call, whereas fmh_oflags report
+ *	on the overall record output.  fmh_count should be set to the
+ *	length of the fmh_recs array, and fmh_entries will be set to the
+ *	number of entries filled out during each call.  If fmh_count is
+ *	zero, the number of reverse mappings will be returned in
+ *	fmh_entries, though no mappings will be returned.  fmh_reserved
+ *	must be set to zero.
+ *
+ *	The two elements in the fmh_keys array are used to constrain the
+ *	output.  The first element in the array should represent the
+ *	lowest disk mapping ("low key") that the user wants to learn
+ *	about.  If this value is all zeroes, the filesystem will return
+ *	the first entry it knows about.  For a subsequent call, the
+ *	contents of fsmap_head.fmh_recs[fsmap_head.fmh_count - 1] should be
+ *	copied into fmh_keys[0] to have the kernel start where it left off.
+ *
+ *	The second element in the fmh_keys array should represent the
+ *	highest disk mapping ("high key") that the user wants to learn
+ *	about.  If this value is all ones, the filesystem will not stop
+ *	until it runs out of mapping to return or runs out of space in
+ *	fmh_recs.
+ *
+ *	fmr_device can be either a 32-bit cookie representing a device, or
+ *	a 32-bit dev_t if the FMH_OF_DEV_T flag is set.  fmr_physical,
+ *	fmr_offset, and fmr_length are expressed in units of bytes.
+ *	fmr_owner is either an inode number, or a special value if
+ *	FMR_OF_SPECIAL_OWNER is set in fmr_flags.
+ */
+struct fsmap {
+	__u32		fmr_device;	/* device id */
+	__u32		fmr_flags;	/* mapping flags */
+	__u64		fmr_physical;	/* device offset of segment */
+	__u64		fmr_owner;	/* owner id */
+	__u64		fmr_offset;	/* file offset of segment */
+	__u64		fmr_length;	/* length of segment */
+	__u64		fmr_reserved[3];	/* must be zero */
+};
+
+struct fsmap_head {
+	__u32		fmh_iflags;	/* control flags */
+	__u32		fmh_oflags;	/* output flags */
+	__u32		fmh_count;	/* # of entries in array incl. input */
+	__u32		fmh_entries;	/* # of entries filled in (output). */
+	__u64		fmh_reserved[6];	/* must be zero */
+
+	struct fsmap	fmh_keys[2];	/* low and high keys for the mapping search */
+	struct fsmap	fmh_recs[];	/* returned records */
+};
+
+/* Size of an fsmap_head with room for nr records. */
+static inline size_t
+fsmap_sizeof(
+	unsigned int	nr)
+{
+	return sizeof(struct fsmap_head) + nr * sizeof(struct fsmap);
+}
+
+/* Start the next fsmap query at the end of the current query results. */
+static inline void
+fsmap_advance(
+	struct fsmap_head	*head)
+{
+	head->fmh_keys[0] = head->fmh_recs[head->fmh_entries - 1];
+}
+
+/*	fmh_iflags values - set by XFS_IOC_GETFSMAP caller in the header. */
+/* no flags defined yet */
+#define FMH_IF_VALID		0
+
+/*	fmh_oflags values - returned in the header segment only. */
+#define FMH_OF_DEV_T		0x1	/* fmr_device values will be dev_t */
+
+/*	fmr_flags values - returned for each non-header segment */
+#define FMR_OF_PREALLOC		0x1	/* segment = unwritten pre-allocation */
+#define FMR_OF_ATTR_FORK	0x2	/* segment = attribute fork */
+#define FMR_OF_EXTENT_MAP	0x4	/* segment = extent map */
+#define FMR_OF_SHARED		0x8	/* segment = shared with another file */
+#define FMR_OF_SPECIAL_OWNER	0x10	/* owner is a special value */
+#define FMR_OF_LAST		0x20	/* segment is the last in the FS */
+
+/* Each FS gets to define its own special owner codes. */
+#define FMR_OWNER(type, code)	(((__u64)type << 32) | \
+				 ((__u64)code & 0xFFFFFFFFULL))
+#define FMR_OWNER_TYPE(owner)	((__u32)((__u64)owner >> 32))
+#define FMR_OWNER_CODE(owner)	((__u32)(((__u64)owner & 0xFFFFFFFFULL)))
+#define FMR_OWN_FREE		FMR_OWNER(0, 1) /* free space */
+#define FMR_OWN_UNKNOWN		FMR_OWNER(0, 2) /* unknown owner */
+#define FMR_OWN_METADATA	FMR_OWNER(0, 3) /* metadata */
+
+#define FS_IOC_GETFSMAP		_IOWR('X', 59, struct fsmap_head)
+
+#define HAVE_GETFSMAP
+#endif /* HAVE_GETFSMAP */
+
 #endif	/* __XFS_LINUX_H__ */
diff --git a/m4/package_libcdev.m4 b/m4/package_libcdev.m4
index bc3b4ce..fa5b639 100644
--- a/m4/package_libcdev.m4
+++ b/m4/package_libcdev.m4
@@ -277,3 +277,23 @@ AC_DEFUN([AC_NEED_INTERNAL_FSXATTR],
     )
     AC_SUBST(need_internal_fsxattr)
   ])
+
+#
+# Check if we have a FS_IOC_GETFSMAP ioctl (Linux)
+#
+AC_DEFUN([AC_HAVE_GETFSMAP],
+  [ AC_MSG_CHECKING([for GETFSMAP])
+    AC_TRY_LINK([
+#define _GNU_SOURCE
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <linux/fs.h>
+#include <linux/fsmap.h>
+    ], [
+         unsigned long x = FS_IOC_GETFSMAP;
+         struct fsmap_head fh;
+    ], have_getfsmap=yes
+       AC_MSG_RESULT(yes),
+       AC_MSG_RESULT(no))
+    AC_SUBST(have_getfsmap)
+  ])


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH 7/9] xfs_spaceman: Free space mapping command
  2017-05-30 18:56       ` Eric Sandeen
@ 2017-05-30 19:19         ` Darrick J. Wong
  0 siblings, 0 replies; 40+ messages in thread
From: Darrick J. Wong @ 2017-05-30 19:19 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: sandeen, linux-xfs, Dave Chinner

On Tue, May 30, 2017 at 01:56:39PM -0500, Eric Sandeen wrote:
> On 5/30/17 1:40 PM, Darrick J. Wong wrote:
> > On Fri, May 26, 2017 at 08:57:14PM -0500, Eric Sandeen wrote:
> >>
> >>
> >> On 5/7/17 10:57 AM, Darrick J. Wong wrote:
> >>> From: Dave Chinner <dchinner@redhat.com>
> >>>
> >>> Add freespace mapping tool modelled on the xfs_db freesp command.
> >>> The advantage of this command over xfs_db is that it can be done
> >>> online and is coherent with concurrent modifications to the
> >>> filesystem.
> >>>
> >>> This requires the kernel to support the XFS_IOC_GETFSMAP ioctl to map
> >>> free space indexes.
> >>>
> >>> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> >>> [darrick: port from FIEMAPFS to GETFSMAP]
> >>> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> >>> ---
> >>>  spaceman/Makefile   |   12 +-
> >>>  spaceman/ag.c       |    1 
> >>>  spaceman/file.c     |   18 ++-
> >>>  spaceman/freesp.c   |  367 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >>>  spaceman/init.c     |    9 +
> >>>  spaceman/prealloc.c |    1 
> >>>  spaceman/space.h    |   12 +-
> >>>  spaceman/trim.c     |    1 
> >>>  8 files changed, 413 insertions(+), 8 deletions(-)
> >>>  create mode 100644 spaceman/freesp.c
> >>>
> >>>
> >>> diff --git a/spaceman/Makefile b/spaceman/Makefile
> >>> index 08709b3..3b059ca 100644
> >>> --- a/spaceman/Makefile
> >>> +++ b/spaceman/Makefile
> >>> @@ -7,8 +7,12 @@ include $(TOPDIR)/include/builddefs
> >>>  
> >>>  LTCOMMAND = xfs_spaceman
> >>>  HFILES = init.h space.h
> >>> -CFILES = init.c \
> >>> -	ag.c file.c prealloc.c trim.c
> >>> +CFILES = ag.c \
> >>> +	 file.c \
> >>> +	 init.c \
> >>> +	 prealloc.c \
> >>> +	 trim.c
> >>> +
> >>>  
> >>>  LLDLIBS = $(LIBXCMD)
> >>>  LTDEPENDENCIES = $(LIBXCMD)
> >>> @@ -22,6 +26,10 @@ ifeq ($(ENABLE_EDITLINE),yes)
> >>>  LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP)
> >>>  endif
> >>>  
> >>> +ifeq ($(HAVE_GETFSMAP),yes)
> >>> +CFILES += freesp.c
> >>> +endif
> >>> +
> >>>  default: depend $(LTCOMMAND)
> >>>  
> >>>  include $(BUILDRULES)
> >>> diff --git a/spaceman/ag.c b/spaceman/ag.c
> >>> index 1eb8aa0..0f1c869 100644
> >>> --- a/spaceman/ag.c
> >>> +++ b/spaceman/ag.c
> >>> @@ -21,6 +21,7 @@
> >>>  #include "command.h"
> >>>  #include "input.h"
> >>>  #include "init.h"
> >>> +#include "path.h"
> >>>  #include "space.h"
> >>>  
> >>>  #ifndef XFS_IOC_AGCONTROL
> >>> diff --git a/spaceman/file.c b/spaceman/file.c
> >>> index 9356066..7c5ea0e 100644
> >>> --- a/spaceman/file.c
> >>> +++ b/spaceman/file.c
> >>> @@ -22,6 +22,7 @@
> >>>  #include "command.h"
> >>>  #include "input.h"
> >>>  #include "init.h"
> >>> +#include "path.h"
> >>>  #include "space.h"
> >>>  
> >>>  static cmdinfo_t print_cmd;
> >>> @@ -69,8 +70,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;
> >>>  
> >>>  	fd = open(path, flags, mode);
> >>> @@ -95,6 +98,15 @@ openfile(
> >>>  		close(fd);
> >>>  		return -1;
> >>>  	}
> >>> +
> >>> +	if (fs_path) {
> >>> +		fsp = fs_table_lookup(path, FS_MOUNT_POINT);
> >>> +		if (!fsp) {
> >>> +			fprintf(stderr, _("Unable to find XFS information."));
> >>
> >> If I got that error I wouldn't know what it meant...
> > 
> > "Unable to find mount information." ?
> 
> I think that if the path isn't found in the table, that means it wasn't
> populated on startup, which means it's not [on] an XFS filesystem:
> 
>         fs = fs_table_lookup(argv[optind], FS_MOUNT_POINT);
>         if (!fs) {
>                 fprintf(stderr, _("%s: %s is not a mounted XFS filesystem\n"),
>                         progname, argv[optind]);
>                 return 1;
>         }
> 
> or
> 
>                 fprintf(stderr, _("file argument, \"%s\", is not in a mounted XFS filesystem\n"),
>                         file->name);
> 
> is what other tools do (although quota does:
> 
>                 fprintf(stderr, "%s: unknown mount point %s\n", progname, dir);
> or
>                 fprintf(stderr, "%s: cannot find mount point %s\n",)
> 
> 
> Anyway: I think the failure means that the path is not [on] an xfs filesystem,
> so that's probably the best information to convey.

I like the second option better, so I'll change it to that.

--D

> 
> -Eric
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 3/9] xfs_spaceman: space management tool
  2017-05-30 18:47         ` Darrick J. Wong
@ 2017-06-02 19:44           ` Darrick J. Wong
  0 siblings, 0 replies; 40+ messages in thread
From: Darrick J. Wong @ 2017-06-02 19:44 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: sandeen, linux-xfs, Dave Chinner

On Tue, May 30, 2017 at 11:47:39AM -0700, Darrick J. Wong wrote:
> On Tue, May 30, 2017 at 01:17:56PM -0500, Eric Sandeen wrote:
> > On 5/30/17 12:37 PM, Darrick J. Wong wrote:
> > > On Fri, May 26, 2017 at 08:34:18PM -0500, Eric Sandeen wrote:
> > >> On 5/7/17 10:56 AM, Darrick J. Wong wrote:
> > >>> From: Dave Chinner <dchinner@redhat.com>
> > >>>
> > >>> xfs_spaceman is intended as a diagnostic and control tool for space
> > >>> management operations within XFS. Operations like examining free
> > >>> space, managing allocation policies, issuing block discards on free
> > >>> space, etc.
> > >>>
> > >>> The tool is modelled on the xfs_io interface, allowing both
> > >>> interactive and command line control of the tool, enabling it to be
> > >>> used in scripts and automated management tools.
> > >> This may be a result of the xfs_io ancestry, but:
> > >>
> > >> # xfs_spaceman /mnt/test2 /mnt/test
> > >>
> > >> Cool, we can open 2 files(ystems)
> > >>
> > >> xfs_spaceman> print
> > >>  000  /mnt/test2     (non-sync,non-direct,read-write)
> > >> [001] /mnt/test      (non-sync,non-direct,read-write)
> > >>
> > >> (what does non-direct mean for a mountpoint?)
> > >> (actually where do these flags come from ... hm.)
> > >>
> > >> Yep there we are!  Now how do we switch to the other?
> > >>
> > >> xfs_spaceman> help
> > >> help [command] -- help for one or all commands
> > >> print -- list current open files
> > >> quit -- exit the program
> > >>
> > >> Use 'help commandname' for extended help.
> > >>
> > >> hmmm... I guess we can't switch.  Should we be able to?
> > >>
> > >> Is the intent to open files or filesystems...  both?  Is there ever
> > >> a reason to be opening a file not a filesystem?
> > > <shrug> I mostly just passed on Dave's original patches from whenever
> > > ago, but TBH I'm not 100% sure about the usecases for multiple
> > > arguments.  The commands that spaceman has now are all fs-oriented, not
> > > file-oriented... but maybe people want to be able to issue one command
> > > against multiple fses?  OTOH all the commands provided so far are
> > > oneshot, so they only act upon one open file.
> > > 
> > > So, I'm inclined to ditch the 'list' command and disallow multiple open
> > > files, like Eric suggests, unless anyone really wants it?
> > 
> > Either way is fine: multiple (fs) targets with the ability to switch,
> > or restrict to just one, but allowing one to open multiple and only
> > use one makes little sense.
> 
> I think of all the commands we have, only trim and prealloc seem geared
> towards being callable against all the paths specified in the command
> line.  OTOH I don't see a lot of harm in letting people run reports
> against multiple filesystems, though the output will be sort of messy.
> 
> I'll play around with removing the ONESHOT designation and see if that
> doesn't turn into a horrible mess.

FWIW it worked, but ... watching report for multiple filesystems scroll
seemed messy and so it was easier to restrict spaceman to take only one
file argument.  I'm going to resend this series atop for-next, and we
can move the discussion there.

--D

> 
> --D
> 
> > 
> > -Eric
> > 
> > > --D
> > > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > the body of a message to majordomo@vger.kernel.org
> > 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@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2017-06-02 19:45 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-07 15:56 [PATCH v7 0/9] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
2017-05-07 15:56 ` [PATCH 1/9] xfs_io: support the new getfsmap ioctl Darrick J. Wong
2017-05-08 21:01   ` Eric Sandeen
2017-05-15 19:18     ` Darrick J. Wong
2017-05-15 19:30       ` Eric Sandeen
2017-05-07 15:56 ` [PATCH 2/9] xfs_repair: replace rmap_compare with libxfs version Darrick J. Wong
2017-05-07 15:56 ` [PATCH 3/9] xfs_spaceman: space management tool Darrick J. Wong
2017-05-27  1:34   ` Eric Sandeen
2017-05-30 17:37     ` Darrick J. Wong
2017-05-30 18:17       ` Eric Sandeen
2017-05-30 18:47         ` Darrick J. Wong
2017-06-02 19:44           ` Darrick J. Wong
2017-05-07 15:56 ` [PATCH 4/9] xfs_spaceman: add FITRIM support Darrick J. Wong
2017-05-27  0:27   ` Eric Sandeen
2017-05-30 18:24     ` Darrick J. Wong
2017-05-07 15:56 ` [PATCH 5/9] xfs_spaceman: add new speculative prealloc control Darrick J. Wong
2017-05-27  1:45   ` Eric Sandeen
2017-05-30 18:34     ` Darrick J. Wong
2017-05-07 15:56 ` [PATCH 6/9] xfs_spaceman: AG state control Darrick J. Wong
2017-05-26 23:06   ` Eric Sandeen
2017-05-30 18:30     ` Darrick J. Wong
2017-05-07 15:57 ` [PATCH 7/9] xfs_spaceman: Free space mapping command Darrick J. Wong
2017-05-27  1:57   ` Eric Sandeen
2017-05-30 18:40     ` Darrick J. Wong
2017-05-30 18:56       ` Eric Sandeen
2017-05-30 19:19         ` Darrick J. Wong
2017-05-07 15:57 ` [PATCH 8/9] xfs_spaceman: add a man page Darrick J. Wong
2017-05-07 15:57 ` [PATCH 9/9] xfs_spaceman: add group summary mode Darrick J. Wong
2017-05-08 19:47 ` [PATCH 0.9/9] xfs: introduce the XFS_IOC_GETFSMAP ioctl Darrick J. Wong
2017-05-10 14:46   ` Eric Sandeen
2017-05-10 17:03     ` Darrick J. Wong
2017-05-12 22:29   ` Eric Sandeen
2017-05-12 23:05     ` Darrick J. Wong
2017-05-12 23:11       ` Eric Sandeen
2017-05-26 21:20   ` Eric Sandeen
2017-05-26 21:41     ` Darrick J. Wong
2017-05-26 22:12       ` Eric Sandeen
2017-05-30 18:44         ` Darrick J. Wong
2017-05-30 18:47           ` Eric Sandeen
2017-05-30 18:59             ` Eric Sandeen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.