All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] e2fsprogs: new tools e2info/e2spacey
@ 2017-03-02  4:52 Darrick J. Wong
  2017-03-02  4:52 ` [PATCH 1/3] misc: fix all the compiler warnings Darrick J. Wong
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Darrick J. Wong @ 2017-03-02  4:52 UTC (permalink / raw)
  To: tytso, darrick.wong; +Cc: linux-ext4

Hi all,

Here are some minor fixes and two new e2fsprogs tools!  The first patch
fixes a bunch of compiler warnings.

The first tool, e2info, uses the proposed ext4 geometry ioctl to query a
mounted ext4 filesystem for geometry information and prints it.

The second tool, e2spacey, uses the proposed GETFSMAP and ext4 ioctls to
find all the free space on a mounted filesystem to display a histogram
of extent sizes, or optionally how much free space can be found in each
flexbg.  (Note: the xfs_io tool can be used for general getfsmap queries
on ext4 filesystems.)

If you want to go play with these tools, you can grab the source from my
git repo[1].  You'll need the patches on mailing list, or my
djwong-devel kernel tree[2].

This is a tremendous way to eat your data!

--D

[1] https://git.kernel.org/cgit/linux/kernel/git/djwong/e2fsprogs.git/log/?h=djwong-devel
[2] https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-linux.git/log/?h=djwong-devel

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

* [PATCH 1/3] misc: fix all the compiler warnings
  2017-03-02  4:52 [PATCH 0/3] e2fsprogs: new tools e2info/e2spacey Darrick J. Wong
@ 2017-03-02  4:52 ` Darrick J. Wong
  2017-03-03 15:04   ` Theodore Ts'o
  2017-03-02  4:52 ` [PATCH 2/3] e2info: create a tool to display ext4 fs geometry online Darrick J. Wong
  2017-03-02  4:52 ` [PATCH 3/3] e2spacey: create a program to use getfsmap to profile free space Darrick J. Wong
  2 siblings, 1 reply; 11+ messages in thread
From: Darrick J. Wong @ 2017-03-02  4:52 UTC (permalink / raw)
  To: tytso, darrick.wong; +Cc: linux-ext4

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

Fix the various compiler warnings that have crept in, and only define
__bitwise if the system headers haven't already done so.  Linux 4.10
changes the __bitwise definition so that our redefinition here is
just different enough that gcc complains.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 debugfs/debugfs.c          |    2 --
 debugfs/xattrs.c           |    5 ++---
 e2fsck/pass2.c             |    2 +-
 lib/ext2fs/ext2_types.h.in |    8 ++++++--
 lib/ext2fs/ext_attr.c      |    2 --
 lib/support/cstring.c      |    6 +++---
 misc/dumpe2fs.c            |   15 ---------------
 7 files changed, 12 insertions(+), 28 deletions(-)


diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index 165f924..366ae5f 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -1588,9 +1588,7 @@ void do_unlink(int argc, char *argv[])
 void do_copy_inode(int argc, char *argv[])
 {
 	ext2_ino_t	src_ino, dest_ino;
-	struct ext2_inode inode;
 	unsigned char	buf[4096];
-	int		retval;
 
 	if (common_args_process(argc, argv, 3, 3, "copy_inode",
 				"<source file> <dest_name>", CHECK_FS_RW))
diff --git a/debugfs/xattrs.c b/debugfs/xattrs.c
index 2443518..9b87d14 100644
--- a/debugfs/xattrs.c
+++ b/debugfs/xattrs.c
@@ -146,7 +146,7 @@ void do_get_xattr(int argc, char **argv)
 	size_t buflen;
 	int i;
 	int print_flags = 0;
-	int handle_flags = 0;
+	unsigned int handle_flags = 0;
 	errcode_t err;
 
 	reset_getopt();
@@ -241,8 +241,7 @@ void do_set_xattr(int argc, char **argv)
 	FILE *fp = NULL;
 	char *buf = NULL;
 	size_t buflen;
-	int print_flags = 0;
-	int handle_flags = 0;
+	unsigned int handle_flags = 0;
 	int i;
 	errcode_t err;
 
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 11c19e8..170878c 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -90,7 +90,7 @@ void e2fsck_pass2(e2fsck_t ctx)
 	struct ext2_super_block *sb = ctx->fs->super;
 	struct problem_context	pctx;
 	ext2_filsys 		fs = ctx->fs;
-	char			*buf;
+	char			*buf = NULL;
 #ifdef RESOURCE_TRACK
 	struct resource_track	rtrack;
 #endif
diff --git a/lib/ext2fs/ext2_types.h.in b/lib/ext2fs/ext2_types.h.in
index 07adc64..fb36a5d 100644
--- a/lib/ext2fs/ext2_types.h.in
+++ b/lib/ext2fs/ext2_types.h.in
@@ -173,10 +173,14 @@ typedef long		__s64;
 #define EXT2_ENDIAN_H_
 
 #ifdef __CHECKER__
-#define __bitwise		__attribute__((bitwise))
+# ifndef __bitwise
+#  define __bitwise		__attribute__((bitwise))
+# endif
 #define __force			__attribute__((force))
 #else
-#define __bitwise
+# ifndef __bitwise
+#  define __bitwise
+# endif
 #define __force
 #endif
 
diff --git a/lib/ext2fs/ext_attr.c b/lib/ext2fs/ext_attr.c
index ce2f48f..7a9a2d5 100644
--- a/lib/ext2fs/ext_attr.c
+++ b/lib/ext2fs/ext_attr.c
@@ -478,7 +478,6 @@ static errcode_t convert_posix_acl_to_disk_buffer(const void *value, size_t size
 	ext4_acl_header *ext_acl;
 	size_t s;
 	void *e;
-	int err;
 
 	int count;
 
@@ -532,7 +531,6 @@ static errcode_t convert_disk_buffer_to_posix_acl(const void *value, size_t size
 	errcode_t err;
 	const char *cp;
 	char *out;
-	int count;
 
 	if ((!value) ||
 	    (size < sizeof(ext4_acl_header)) ||
diff --git a/lib/support/cstring.c b/lib/support/cstring.c
index 7965e95..57f4522 100644
--- a/lib/support/cstring.c
+++ b/lib/support/cstring.c
@@ -15,12 +15,12 @@
 
 int parse_c_string(char *str)
 {
-	unsigned char *to, *from, ch;
+	char *to, *from, ch;
 	int v;
 
 	to = from = str;
 
-	for (to = from = (unsigned char *) str;
+	for (to = from = (char *) str;
 	     *from && *from != '"'; to++, from++) {
 		if (*from == '\\') {
 			ch = *(++from);
@@ -93,7 +93,7 @@ int parse_c_string(char *str)
 		*to = *from;
 	}
 	*to = '\0';
-	return to - (unsigned char *) str;
+	return to - (char *) str;
 }
 
 void print_c_string(FILE *f, const char *cp, int len)
diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c
index 621840a..395ea9e 100644
--- a/misc/dumpe2fs.c
+++ b/misc/dumpe2fs.c
@@ -356,16 +356,6 @@ static void list_bad_blocks(ext2_filsys fs, int dump)
 	ext2fs_badblocks_list_free(bb_list);
 }
 
-static const char *journal_checksum_type_str(__u8 type)
-{
-	switch (type) {
-	case JBD2_CRC32C_CHKSUM:
-		return "crc32c";
-	default:
-		return "unknown";
-	}
-}

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

* [PATCH 2/3] e2info: create a tool to display ext4 fs geometry online
  2017-03-02  4:52 [PATCH 0/3] e2fsprogs: new tools e2info/e2spacey Darrick J. Wong
  2017-03-02  4:52 ` [PATCH 1/3] misc: fix all the compiler warnings Darrick J. Wong
@ 2017-03-02  4:52 ` Darrick J. Wong
  2017-03-02 19:49   ` Andreas Dilger
  2017-03-02  4:52 ` [PATCH 3/3] e2spacey: create a program to use getfsmap to profile free space Darrick J. Wong
  2 siblings, 1 reply; 11+ messages in thread
From: Darrick J. Wong @ 2017-03-02  4:52 UTC (permalink / raw)
  To: tytso, darrick.wong; +Cc: linux-ext4

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

Create e2info, which reports the fs geometry of an online ext4 filesystem.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 configure            |    4 +
 configure.ac         |    3 +
 lib/ext2fs/ext2_fs.h |   34 ++++++++
 misc/Makefile.in     |   30 ++++++-
 misc/e2info.8.in     |   64 ++++++++++++++++
 misc/e2info.c        |  205 ++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 336 insertions(+), 4 deletions(-)
 create mode 100644 misc/e2info.8.in
 create mode 100644 misc/e2info.c


diff --git a/configure b/configure
index 5f7b429..b553da1 100755
--- a/configure
+++ b/configure
@@ -642,6 +642,7 @@ root_prefix
 UNIX_CMT
 CYGWIN_CMT
 LINUX_CMT
+E2INFO_CMT
 UNI_DIFF_OPTS
 SEM_INIT_LIB
 FUSE_CMT
@@ -13663,13 +13664,16 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UNI_DIFF_OPTS" >&5
 $as_echo "$UNI_DIFF_OPTS" >&6; }
 
+E2INFO_CMT="#"
 case "$host_os" in
 linux*)
 
 $as_echo "#define HAVE_EXT2_IOCTLS 1" >>confdefs.h
 
+	E2INFO_CMT=
 	;;
 esac
+
 LINUX_CMT="#"
 CYGWIN_CMT="#"
 UNIX_CMT=
diff --git a/configure.ac b/configure.ac
index 9da7b86..bf613fd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1260,11 +1260,14 @@ AC_SUBST(UNI_DIFF_OPTS)
 dnl
 dnl We use the EXT2 ioctls only under Linux
 dnl
+E2INFO_CMT="#"
 case "$host_os" in
 linux*)
 	AC_DEFINE(HAVE_EXT2_IOCTLS, 1, [Define to 1 if Ext2 ioctls present])
+	E2INFO_CMT=
 	;;
 esac
+AC_SUBST(E2INFO_CMT)
 dnl
 dnl OS-specific uncomment control
 dnl
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 27a7d3a..bad7648 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -372,6 +372,40 @@ struct ext4_new_group_input {
 #define EXT4_IOC_GROUP_ADD		_IOW('f', 8,struct ext4_new_group_input)
 #define EXT4_IOC_RESIZE_FS		_IOW('f', 16, __u64)
 
+/* ext4 fs geometry. */
+struct ext4_fsop_geom {
+	__u32		efg_blocksize;	/* filesystem (data) block size */
+	__u32		efg_bgblocks;	/* fsblocks in an AG		*/
+	__u32		efg_bgcount;	/* number of allocation groups	*/
+	__u32		efg_logblocks;	/* fsblocks in the log		*/
+	__u32		efg_resvblocks;	/* number of reserved blocks	*/
+	__u32		efg_inodesize;	/* inode size in bytes		*/
+	__u32		efg_bg_iblocks;	/* inode blocks per AG		*/
+	__u32		efg_flags;	/* superblock version flags	*/
+	__u64		efg_inodecount;	/* inode count			*/
+	__u64		efg_blockcount;	/* fsblocks in filesystem	*/
+	unsigned char	efg_uuid[16];	/* unique id of the filesystem	*/
+	__u32		efg_sunit;	/* stripe unit, fsblocks	*/
+	__u32		efg_swidth;	/* stripe width, fsblocks	*/
+	__u32		efg_clustersize;/* fs cluster size		*/
+	__u32		efg_flexbgsize;	/* number of bg's in a flexbg	*/
+	__u64		efg_resv[6];
+};
+
+#define EXT4_FSOP_GEOM_FLAGS_ATTR	0x00001	/* extended attr in use	 */
+#define EXT4_FSOP_GEOM_FLAGS_NLINK	0x00002	/* 32-bit nlink values	 */
+#define EXT4_FSOP_GEOM_FLAGS_QUOTA	0x00004	/* quotas enabled	 */
+#define EXT4_FSOP_GEOM_FLAGS_PROJQ	0x00008	/* project quotas	 */
+#define EXT4_FSOP_GEOM_FLAGS_META_CSUM	0x00010	/* metadata checksums	 */
+#define EXT4_FSOP_GEOM_FLAGS_FTYPE	0x00020	/* inode directory types */
+#define EXT4_FSOP_GEOM_FLAGS_64BIT	0x00040	/* 64-bit support	 */
+#define EXT4_FSOP_GEOM_FLAGS_INLINEDATA	0x00080	/* inline data		 */
+#define EXT4_FSOP_GEOM_FLAGS_ENCRYPT	0x00100	/* encrypted files	 */
+#define EXT4_FSOP_GEOM_FLAGS_LARGEDIR	0x00200	/* large directories	 */
+#define EXT4_FSOP_GEOM_FLAGS_EXTENTS	0x00400	/* extents		 */
+
+#define EXT4_IOC_FSGEOMETRY		_IOR ('f', 19, struct ext4_fsop_geom)
+
 /*
  * Structure of an inode on the disk
  */
diff --git a/misc/Makefile.in b/misc/Makefile.in
index 467c15d..311aa57 100644
--- a/misc/Makefile.in
+++ b/misc/Makefile.in
@@ -32,14 +32,19 @@ INSTALL = @INSTALL@
 
 @FUSE_CMT@FUSE_PROG= fuse2fs
 
+@E2INFO_CMT@E2INFO_PROG= e2info
+@E2INFO_CMT@E2INFO_MAN= e2info.8
+
 SPROGS=		mke2fs badblocks tune2fs dumpe2fs $(BLKID_PROG) logsave \
 			$(E2IMAGE_PROG) @FSCK_PROG@ e2undo
 USPROGS=	mklost+found filefrag e2freefrag $(UUIDD_PROG) \
-			$(E4DEFRAG_PROG) $(E4CRYPT_PROG) $(FUSE_PROG)
+			$(E4DEFRAG_PROG) $(E4CRYPT_PROG) $(FUSE_PROG) \
+			$(E2INFO_PROG)
 SMANPAGES=	tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \
 			e2label.8 $(FINDFS_MAN) $(BLKID_MAN) $(E2IMAGE_MAN) \
 			logsave.8 filefrag.8 e2freefrag.8 e2undo.8 \
-			$(UUIDD_MAN) $(E4DEFRAG_MAN) $(E4CRYPT_MAN) @FSCK_MAN@
+			$(UUIDD_MAN) $(E4DEFRAG_MAN) $(E4CRYPT_MAN) @FSCK_MAN@ \
+			$(E2INFO_MAN)
 FMANPAGES=	mke2fs.conf.5 ext4.5
 
 UPROGS=		chattr lsattr @UUID_CMT@ uuidgen
@@ -68,6 +73,7 @@ E4CRYPT_OBJS=   e4crypt.o
 E2FREEFRAG_OBJS= e2freefrag.o
 E2FUZZ_OBJS=	e2fuzz.o
 FUSE2FS_OBJS=	fuse2fs.o journal.o recovery.o revoke.o
+E2INFO_OBJS=	e2info.o
 
 PROFILED_TUNE2FS_OBJS=	profiled/tune2fs.o profiled/util.o
 PROFILED_MKLPF_OBJS=	profiled/mklost+found.o
@@ -90,8 +96,9 @@ PROFILED_E2FREEFRAG_OBJS= profiled/e2freefrag.o
 PROFILED_E2UNDO_OBJS=	profiled/e2undo.o
 PROFILED_E4DEFRAG_OBJS=	profiled/e4defrag.o
 PROFILED_E4CRYPT_OBJS=	profiled/e4crypt.o
-PROFILED_FUSE2FS_OJBS=	profiled/fuse2fs.o profiled/journal.o \
+PROFILED_FUSE2FS_OBJS=	profiled/fuse2fs.o profiled/journal.o \
 			profiled/recovery.o profiled/revoke.o
+PROFILED_E2INFO_OBJS=	profiled/e2info.o
 
 SRCS=	$(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c $(srcdir)/mk_hugefiles.c \
 		$(srcdir)/chattr.c $(srcdir)/lsattr.c $(srcdir)/dumpe2fs.c \
@@ -102,7 +109,7 @@ SRCS=	$(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c $(srcdir)/
 		$(srcdir)/e2freefrag.c $(srcdir)/create_inode.c \
 		$(srcdir)/fuse2fs.c \
 		$(srcdir)/../debugfs/journal.c $(srcdir)/../e2fsck/revoke.c \
-		$(srcdir)/../e2fsck/recovery.c
+		$(srcdir)/../e2fsck/recovery.c $(srcdir)/e2info.c
 
 LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBSUPPORT)
 DEPLIBS= $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBSUPPORT)
@@ -391,6 +398,11 @@ fuse2fs: $(FUSE2FS_OBJS) $(DEPLIBS) $(DEPLIBBLKID) $(DEPLIBUUID) \
 		$(LIBFUSE) $(LIBBLKID) $(LIBUUID) $(LIBEXT2FS) $(LIBINTL) \
 		$(CLOCK_GETTIME_LIB) $(SYSLIBS)
 
+e2info: $(E2INFO_OBJS) $(DEPLIBS)
+	$(E) "	LD $@"
+	$(Q) $(CC) $(ALL_LDFLAGS) -o e2info $(E2INFO_OBJS) $(LIBINTL) \
+		$(SYSLIBS)
+
 journal.o: $(srcdir)/../debugfs/journal.c
 	$(E) "	CC $@"
 	$(Q) $(CC) -c $(JOURNAL_CFLAGS) -I$(srcdir) \
@@ -411,6 +423,10 @@ tst_ismounted: $(srcdir)/ismounted.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
 	$(CC) -o tst_ismounted $(srcdir)/ismounted.c -DDEBUG $(ALL_CFLAGS) \
 		$(LIBCOM_ERR) $(SYSLIBS)
 
+e2info.8: $(DEP_SUBSTITUTE) $(srcdir)/e2info.8.in
+	$(E) "	SUBST $@"
+	$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2info.8.in e2info.8
+
 tune2fs.8: $(DEP_SUBSTITUTE) $(srcdir)/tune2fs.8.in
 	$(E) "	SUBST $@"
 	$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/tune2fs.8.in tune2fs.8
@@ -844,3 +860,9 @@ recovery.o: $(srcdir)/../e2fsck/recovery.c $(srcdir)/../e2fsck/jfs_user.h \
  $(top_srcdir)/lib/support/quotaio_tree.h \
  $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \
  $(top_srcdir)/lib/ext2fs/kernel-list.h
+e2info.o: $(srcdir)/e2info.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h
diff --git a/misc/e2info.8.in b/misc/e2info.8.in
new file mode 100644
index 0000000..c7f580f
--- /dev/null
+++ b/misc/e2info.8.in
@@ -0,0 +1,64 @@
+.\" -*- nroff -*-
+.\" Copyright 2017 Oracle Inc.  All Rights Reserved.
+.\" This file may be copied under the terms of the GNU Public License.
+.\" 
+.\" Verbatim blocks taken from openssl req manpage content
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+
+.TH E2INFO 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+e2info \- Display information about a mounted ext4 filesystem
+.SH SYNOPSIS
+.B e2info
+.I mount-point
+.br
+.B e2info \-V
+.SH DESCRIPTION
+Prints the filesystem geometry of an ext4 filesystem.  If the mounted
+filesystem is an ext2 or ext3 filesystem mounted with the ext4 driver,
+the geometry will be displayed.
+.SH "EXAMPLES"
+
+Understanding e2info output.
+.PP
+Suppose one has the following "e2info /dev/sda" output:
+.PP
+.RS 2
+.Vb
+\&meta-data=/dev/loop0             isize=256    bgcount=14808 bgsize=32768 blks
+\&         =                       attr=1       quota=0 pquota=0
+\&         =                       crc=0        64bit=0 inlinedata=0 extents=1
+\&         =                       flexbg=16
+\&data     =                       bsize=4096   blocks=485198848 bg_iblocks=512
+\&         =                       sunit=32     swidth=128 blks clustersize=0
+\&         =                       encrypt=0
+\&naming   =                       bsize=4096   largedir=0 ftype=1 nlink=1
+\&log      =                       bsize=4096   blocks=32768
+.Ve
+.RE
+.PP
+
+Here, the data section of the output indicates "bsize=4096",
+meaning the data block size for this filesystem is 4096 bytes.
+This section also shows "sunit=32 swidth=128 blks", which means
+the stripe unit is 32*4096 bytes = 128 kibibytes and the stripe
+width is 128*4096 bytes = 512 kibibytes.
+A single stripe of this filesystem therefore consists
+of four stripe units (128 blocks / 32 blocks per unit).
+Note also that "flexbg=16", which means that this filesystem has
+512MB flex block groups.
+That is the upper limit of how much physical disk space can be mapped
+into a file.
+.SH SEE ALSO
+.BR mkfs.ext4 (8),
+.BR md (4),
+.BR lvm (8),
+.BR mount (8).
diff --git a/misc/e2info.c b/misc/e2info.c
new file mode 100644
index 0000000..675f005
--- /dev/null
+++ b/misc/e2info.c
@@ -0,0 +1,205 @@
+/*
+ * 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 "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <mntent.h>
+#include <limits.h>
+
+#include "ext2fs/ext2_fs.h"
+
+#include "../version.h"
+#include "support/nls-enable.h"
+
+static const char *progname = "e2info";
+
+static void
+usage(void)
+{
+	fprintf(stderr, _(
+"Usage: %s [options] mountpoint\n\n\
+	-V          print version information\n"),
+		progname);
+	exit(2);
+}
+
+#define PROC_MOUNTS	"/proc/mounts"
+int
+find_datadev(
+	const char	*arg,
+	char		*datadev,
+	char		*mntpoint)
+{
+	struct mntent	*mnt;
+	FILE		*mtp;
+	char		*mtab_file;
+	char		rmnt_fsname[PATH_MAX], rmnt_dir[PATH_MAX];
+	struct stat	sbuf;
+	dev_t		fd_dev;
+
+	if (stat(arg, &sbuf) < 0)
+		return errno;
+	/*
+	 * We want to match st_rdev if the path provided is a device
+	 * special file.  Otherwise we are looking for the the
+	 * device id for the containing filesystem, in st_dev.
+	 */
+	if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode))
+		fd_dev = sbuf.st_rdev;
+	else
+		fd_dev = sbuf.st_dev;
+
+	mtab_file = PROC_MOUNTS;
+	if (access(mtab_file, R_OK) != 0)
+		mtab_file = MOUNTED;
+
+	if ((mtp = setmntent(mtab_file, "r")) == NULL)
+		return ENOENT;
+
+	while ((mnt = getmntent(mtp)) != NULL) {
+		if (!realpath(mnt->mnt_dir, rmnt_dir))
+			continue;
+		if (!realpath(mnt->mnt_fsname, rmnt_fsname))
+			continue;
+
+		if (stat(rmnt_fsname, &sbuf) < 0)
+			continue;
+		if (sbuf.st_rdev == fd_dev) {
+			strncpy(datadev, rmnt_fsname, PATH_MAX);
+			strncpy(mntpoint, rmnt_dir, PATH_MAX);
+			break;
+		}
+	}
+	endmntent(mtp);
+	return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct ext4_fsop_geom	geo;
+	char			*progname;
+	int			fd;
+	int			c;
+	int			attr_enabled;
+	int			nlink_enabled;
+	int			quota_enabled;
+	int			projquota_enabled;
+	int			metacrc_enabled;
+	int			ftype_enabled;
+	int			is_64bit;
+	int			inlinedata_enabled;
+	int			encrypt_enabled;
+	int			largedir_enabled;
+	int			extents_enabled;
+	char			datadev[PATH_MAX];
+	char			mntpoint[PATH_MAX];
+
+	progname = basename(argv[0]);
+#ifdef ENABLE_NLS
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+#endif
+
+	while ((c = getopt(argc, argv, "V")) != EOF) {
+		switch (c) {
+		case 'V':
+			printf(_("%s version %s\n"), progname, VERSION);
+			exit(0);
+		case '?':
+		default:
+			usage();
+		}
+	}
+	if (argc - optind != 1)
+		usage();
+
+	fd = open(argv[optind], O_RDONLY);
+	if (fd < 0) {
+		perror(argv[optind]);
+		return 1;
+	}
+
+	if (find_datadev(argv[optind], datadev, mntpoint)) {
+		perror("find_datadev");
+		strncpy(datadev, argv[optind], PATH_MAX);
+		strncpy(mntpoint, argv[optind], PATH_MAX);
+	}
+
+	close(fd);
+	fd = open(mntpoint, O_RDONLY);
+	if (fd < 0) {
+		perror(mntpoint);
+		return 1;
+	}
+
+	/* get the current filesystem size & geometry */
+	if (ioctl(fd, EXT4_IOC_FSGEOMETRY, &geo) < 0) {
+		fprintf(stderr, _(
+			"%s: cannot determine geometry of filesystem"
+			" mounted at %s: %s\n"),
+			progname, argv[optind], strerror(errno));
+		exit(1);
+	}
+
+	attr_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_ATTR ? 1 : 0;
+	nlink_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_NLINK ? 1 : 0;
+	quota_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_QUOTA ? 1 : 0;
+	projquota_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_PROJQ ? 1 : 0;
+	metacrc_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_META_CSUM ? 1 : 0;
+	ftype_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_FTYPE ? 1 : 0;
+	is_64bit = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_64BIT ? 1 : 0;
+	inlinedata_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_INLINEDATA ? 1 : 0;
+	encrypt_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_ENCRYPT ? 1 : 0;
+	largedir_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_LARGEDIR ? 1 : 0;
+	extents_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_EXTENTS ? 1 : 0;
+
+	printf(_(
+	    "meta-data=%-22s isize=%-6u bgcount=%u bgsize=%u blks\n"
+	    "         =%-22s attr=%-7u quota=%u pquota=%u\n"
+	    "         =%-22s crc=%-8u 64bit=%u inlinedata=%u extents=%u\n"
+	    "         =%-22s flexbg=%u\n"
+	    "data     =%-22s bsize=%-6u blocks=%llu bg_iblocks=%u\n"
+	    "         =%-22s sunit=%-6u swidth=%u blks clustersize=%u\n"
+	    "         =%-22s encrypt=%u\n"
+	    "naming   =%-22s bsize=%-6u largedir=%d ftype=%d nlink=%u\n"
+	    "log      =%-22s bsize=%-6u blocks=%u\n"),
+		datadev, geo.efg_inodesize, geo.efg_bgcount, geo.efg_bgblocks,
+		"", attr_enabled, quota_enabled, projquota_enabled,
+		"", metacrc_enabled, is_64bit, inlinedata_enabled,
+			extents_enabled,
+		"", geo.efg_flexbgsize,
+		"", geo.efg_blocksize, (unsigned long long)geo.efg_blockcount,
+			geo.efg_bg_iblocks,
+		"", geo.efg_sunit, geo.efg_swidth, geo.efg_clustersize,
+		"", encrypt_enabled,
+		"", geo.efg_blocksize, largedir_enabled, ftype_enabled,
+			nlink_enabled,
+		"", geo.efg_blocksize, geo.efg_logblocks);
+
+	exit(0);
+}

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

* [PATCH 3/3] e2spacey: create a program to use getfsmap to profile free space
  2017-03-02  4:52 [PATCH 0/3] e2fsprogs: new tools e2info/e2spacey Darrick J. Wong
  2017-03-02  4:52 ` [PATCH 1/3] misc: fix all the compiler warnings Darrick J. Wong
  2017-03-02  4:52 ` [PATCH 2/3] e2info: create a tool to display ext4 fs geometry online Darrick J. Wong
@ 2017-03-02  4:52 ` Darrick J. Wong
  2017-03-02 19:45   ` Andreas Dilger
  2 siblings, 1 reply; 11+ messages in thread
From: Darrick J. Wong @ 2017-03-02  4:52 UTC (permalink / raw)
  To: tytso, darrick.wong; +Cc: linux-ext4

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

e2spacey is a new tool that uses the GETFSMAP ioctl and the FSGEOMETRY
ioctl to find all the free extents in a mounted filesystem and display
either per-flexbg free block counts or a histogram of free extents.
At this point it's mostly useful as a debugging tool.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 Makefile.in          |    3 
 configure            |    6 +
 configure.ac         |    5 -
 lib/ext2fs/ext2_fs.h |    8 +
 spacey/Makefile.in   |  152 +++++++++++++++++
 spacey/e2spacey.8.in |   65 +++++++
 spacey/fsmap.h       |   89 ++++++++++
 spacey/main.c        |  456 ++++++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 781 insertions(+), 3 deletions(-)
 create mode 100644 spacey/Makefile.in
 create mode 100644 spacey/e2spacey.8.in
 create mode 100644 spacey/fsmap.h
 create mode 100644 spacey/main.c


diff --git a/Makefile.in b/Makefile.in
index 7da9ad7..b48d0f9 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -13,10 +13,11 @@ INSTALL = @INSTALL@
 @DEBUGFS_CMT@DEBUGFS_DIR= debugfs
 @UUID_CMT@UUID_LIB_SUBDIR= lib/uuid
 @BLKID_CMT@BLKID_LIB_SUBDIR= lib/blkid
+@SPACEY_CMT@SPACEY_DIR= spacey
 SUPPORT_LIB_SUBDIR= lib/support
 
 LIB_SUBDIRS=lib/et lib/ss lib/e2p $(UUID_LIB_SUBDIR) $(BLKID_LIB_SUBDIR) $(SUPPORT_LIB_SUBDIR) lib/ext2fs intl
-PROG_SUBDIRS=e2fsck $(DEBUGFS_DIR) misc $(RESIZE_DIR) tests/progs po
+PROG_SUBDIRS=e2fsck $(DEBUGFS_DIR) misc $(RESIZE_DIR) tests/progs po $(SPACEY_DIR)
 SUBDIRS=util $(LIB_SUBDIRS) $(PROG_SUBDIRS) tests
 
 SUBS= util/subst.conf lib/config.h $(top_builddir)/lib/dirpaths.h \
diff --git a/configure b/configure
index b553da1..940b11c 100755
--- a/configure
+++ b/configure
@@ -642,6 +642,7 @@ root_prefix
 UNIX_CMT
 CYGWIN_CMT
 LINUX_CMT
+SPACEY_CMT
 E2INFO_CMT
 UNI_DIFF_OPTS
 SEM_INIT_LIB
@@ -13665,15 +13666,18 @@ fi
 $as_echo "$UNI_DIFF_OPTS" >&6; }
 
 E2INFO_CMT="#"
+SPACEY_CMT="#"
 case "$host_os" in
 linux*)
 
 $as_echo "#define HAVE_EXT2_IOCTLS 1" >>confdefs.h
 
 	E2INFO_CMT=
+	SPACEY_CMT=
 	;;
 esac
 
+
 LINUX_CMT="#"
 CYGWIN_CMT="#"
 UNIX_CMT=
@@ -13875,7 +13879,7 @@ for i in MCONFIG Makefile e2fsprogs.spec \
 	misc/Makefile ext2ed/Makefile e2fsck/Makefile \
 	debugfs/Makefile tests/Makefile tests/progs/Makefile \
 	resize/Makefile doc/Makefile intl/Makefile \
-	intl/libgnuintl.h po/Makefile.in ; do
+	intl/libgnuintl.h po/Makefile.in spacey/Makefile ; do
 	if test -d `dirname ${srcdir}/$i` ; then
 		outlist="$outlist $i"
 	fi
diff --git a/configure.ac b/configure.ac
index bf613fd..5b95f6b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1261,13 +1261,16 @@ dnl
 dnl We use the EXT2 ioctls only under Linux
 dnl
 E2INFO_CMT="#"
+SPACEY_CMT="#"
 case "$host_os" in
 linux*)
 	AC_DEFINE(HAVE_EXT2_IOCTLS, 1, [Define to 1 if Ext2 ioctls present])
 	E2INFO_CMT=
+	SPACEY_CMT=
 	;;
 esac
 AC_SUBST(E2INFO_CMT)
+AC_SUBST(SPACEY_CMT)
 dnl
 dnl OS-specific uncomment control
 dnl
@@ -1469,7 +1472,7 @@ for i in MCONFIG Makefile e2fsprogs.spec \
 	misc/Makefile ext2ed/Makefile e2fsck/Makefile \
 	debugfs/Makefile tests/Makefile tests/progs/Makefile \
 	resize/Makefile doc/Makefile intl/Makefile \
-	intl/libgnuintl.h po/Makefile.in ; do
+	intl/libgnuintl.h po/Makefile.in spacey/Makefile ; do
 	if test -d `dirname ${srcdir}/$i` ; then
 		outlist="$outlist $i"
 	fi
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index bad7648..4beebb6 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -406,6 +406,14 @@ struct ext4_fsop_geom {
 
 #define EXT4_IOC_FSGEOMETRY		_IOR ('f', 19, struct ext4_fsop_geom)
 
+/* Custom FS_IOC_GETFSMAP owner codes */
+#define EXT4_FMR_OWN_FREE	FMR_OWN_FREE      /* free space */
+#define EXT4_FMR_OWN_UNKNOWN	FMR_OWN_UNKNOWN   /* unknown owner */
+#define EXT4_FMR_OWN_GDT	FMR_OWNER('f', 1) /* group descriptors */
+#define EXT4_FMR_OWN_RESV_GDT	FMR_OWNER('f', 2) /* reserved gdt blocks */
+#define EXT4_FMR_OWN_BLKBM	FMR_OWNER('f', 3) /* inode bitmap */
+#define EXT4_FMR_OWN_INOBM	FMR_OWNER('f', 4) /* block bitmap */
+
 /*
  * Structure of an inode on the disk
  */
diff --git a/spacey/Makefile.in b/spacey/Makefile.in
new file mode 100644
index 0000000..3c842f3
--- /dev/null
+++ b/spacey/Makefile.in
@@ -0,0 +1,152 @@
+#
+# Makefile for e2spacey
+#
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+top_builddir = ..
+my_dir = scrub
+INSTALL = @INSTALL@
+
+@MCONFIG@
+
+PROGS=		e2spacey
+MANPAGES=	e2spacey.8
+
+LIBS= $(LIBSUPPORT) $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBBLKID) $(LIBUUID) \
+	$(LIBINTL) $(LIBE2P) $(LIBMAGIC) $(SYSLIBS)
+DEPLIBS= $(DEPLIBSUPPORT) $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBBLKID) \
+	 $(DEPLIBUUID) $(DEPLIBE2P)
+
+STATIC_LIBS= $(STATIC_LIBSUPPORT) $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) \
+	     $(STATIC_LIBBLKID) $(STATIC_LIBUUID) $(LIBINTL) $(STATIC_LIBE2P) \
+	     $(LIBMAGIC) $(SYSLIBS)
+STATIC_DEPLIBS= $(DEPSTATIC_LIBSUPPORT) $(STATIC_LIBEXT2FS) \
+		$(DEPSTATIC_LIBCOM_ERR) $(DEPSTATIC_LIBBLKID) \
+		$(DEPSTATIC_LIBUUID) $(DEPSTATIC_LIBE2P)
+
+PROFILED_LIBS= $(PROFILED_LIBSUPPORT) $(PROFILED_LIBEXT2FS) \
+	       $(PROFILED_LIBCOM_ERR) $(PROFILED_LIBBLKID) $(PROFILED_LIBUUID) \
+	       $(PROFILED_LIBE2P) $(LIBINTL) $(LIBMAGIC) $(SYSLIBS)
+PROFILED_DEPLIBS= $(DEPPROFILED_LIBSUPPORT) $(PROFILED_LIBEXT2FS) \
+		  $(DEPPROFILED_LIBCOM_ERR) $(DEPPROFILED_LIBBLKID) \
+		  $(DEPPROFILED_LIBUUID) $(DEPPROFILED_LIBE2P)
+
+COMPILE_ET=	_ET_DIR_OVERRIDE=$(srcdir)/../lib/et/et ../lib/et/compile_et
+
+.c.o:
+	$(E) "	CC $<"
+	$(Q) $(CC) -c $(ALL_CFLAGS) $< -o $@
+	$(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+	$(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
+@PROFILE_CMT@	$(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/$*.o -c $<
+
+#
+# Flags for doing mtrace --- uncomment to produce mtracing e2spacey
+# 	Note:  The optimization flags must include -g
+#
+#MTRACE=	-DMTRACE
+#MTRACE_OBJ= mtrace.o
+#MTRACE_SRC= $(srcdir)/mtrace.c
+#OPT= -g
+
+#
+# Flags for doing mcheck --- uncomment to produce mchecking e2spacey
+# 	Note:  The optimization flags must include -g
+#
+#MCHECK= -DMCHECK
+
+OBJS= main.o
+
+PROFILED_OBJS= profiled/main.o
+
+SRCS= $(srcdir)/main.o
+
+all:: profiled $(PROGS) $(MANPAGES)
+
+@PROFILE_CMT@all:: e2spacey.profiled
+
+e2spacey: $(OBJS)  $(DEPLIBS)
+	$(E) "	LD $@"
+	$(Q) $(LD) $(ALL_LDFLAGS) $(RDYNAMIC) -o e2spacey $(OBJS) $(LIBS)
+
+e2spacey.static: $(OBJS) $(STATIC_DEPLIBS)
+	$(E) "	LD $@"
+	$(Q) $(LD) $(LDFLAGS_STATIC) -o e2spacey.static $(OBJS) $(STATIC_LIBS) -lpthread
+
+e2spacey.profiled: $(OBJS)  $(PROFILED_DEPLIBS)
+	$(E) "	LD $@"
+	$(Q) $(LD) $(ALL_LDFLAGS) -g -pg -o e2spacey.profiled $(PROFILED_OBJS) \
+		$(PROFILED_LIBS) -lpthread
+
+test_profile: $(srcdir)/profile.c profile_helpers.o argv_parse.o \
+		prof_err.o profile.h $(DEPSTATIC_LIBCOM_ERR)
+	$(E) "	LD $@"
+	$(Q) $(CC) -o test_profile -DDEBUG_PROGRAM $(srcdir)/profile.c prof_err.o \
+		profile_helpers.o argv_parse.o $(STATIC_LIBCOM_ERR) \
+		$(ALL_CFLAGS)
+
+profiled:
+@PROFILE_CMT@	$(E) "	MKDIR $@"
+@PROFILE_CMT@	$(Q) mkdir profiled
+
+e2spacey.8: $(DEP_SUBSTITUTE) $(srcdir)/e2spacey.8.in
+	$(E) "	SUBST $@"
+	$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2spacey.8.in e2spacey.8
+
+installdirs:
+	$(E) "	MKINSTALLDIRS $(root_sbindir) $(man8dir)"
+	$(Q) $(MKINSTALLDIRS) $(DESTDIR)$(root_sbindir) \
+		$(DESTDIR)$(man8dir) $(DESTDIR)$(man5dir)
+
+install: $(PROGS) $(MANPAGES) $(FMANPAGES) installdirs
+	$(Q) for i in $(PROGS); do \
+		$(ES) "	INSTALL $(root_sbindir)/$$i"; \
+		$(INSTALL_PROGRAM) $$i $(DESTDIR)$(root_sbindir)/$$i; \
+	done
+	$(Q) for i in $(MANPAGES); do \
+		for j in $(COMPRESS_EXT); do \
+			$(RM) -f $(DESTDIR)$(man8dir)/$$i.$$j; \
+		done; \
+		$(ES) "	INSTALL_DATA $(man8dir)/$$i"; \
+		$(INSTALL_DATA) $$i $(DESTDIR)$(man8dir)/$$i; \
+	done
+
+install-strip: install
+	$(Q) for i in $(PROGS); do \
+		$(ES) "	STRIP $(root_sbindir)/$$i"; \
+		$(STRIP) $(DESTDIR)$(root_sbindir)/$$i; \
+	done
+
+uninstall:
+	for i in $(PROGS); do \
+		$(RM) -f $(DESTDIR)$(root_sbindir)/$$i; \
+	done
+	for i in $(MANPAGES); do \
+		$(RM) -f $(DESTDIR)$(man8dir)/$$i; \
+	done
+
+clean::
+	$(RM) -f $(PROGS)
+	$(RM) -rf profiled
+
+mostlyclean: clean
+distclean: clean
+	$(RM) -f .depend Makefile $(srcdir)/TAGS $(srcdir)/Makefile.in.old
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+main.o: $(srcdir)/main.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/fsmap.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \
+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \
+ $(top_srcdir)/lib/support/quotaio_tree.h
diff --git a/spacey/e2spacey.8.in b/spacey/e2spacey.8.in
new file mode 100644
index 0000000..f4956fc
--- /dev/null
+++ b/spacey/e2spacey.8.in
@@ -0,0 +1,65 @@
+.TH E2SPACEY 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+e2spacey \- show free space information about an ext4 filesystem
+.SH SYNOPSIS
+.B e2spacey
+[
+.B \-srg
+]
+[
+.B \-b
+|
+.B \-e
+.I bsize
+|
+.B \-h
+.I h1
+[
+.B \-m
+.I bmult
+]
+]
+[
+.B \-a
+.I group
+]
+.I mountpoint
+.br
+.B e2spacey \-V
+.SH DESCRIPTION
+.B e2spacey
+reports and controls free space usage in an ext4 filesystem.
+When the
+.B flex_bg
+feature is enabled, the free space information is grouped by flex block groups
+instead of regular block groups.
+This enables reporting of free space extents that span multiple block groups.
+
+.SH OPTIONS
+.TP 1.0i
+.BI \-a " group"
+Only query the specified block group's free space information.
+Multiple options may be provided.
+.TP
+.B \-b
+Establish histogram bins sized in successive powers of two.
+.TP
+.B \-e
+Fix the histogram bin size to a specific value.
+.TP
+.B \-g
+Instead of printing a histogram, simply report the number of free extents
+and number of free blocks per block group.
+.TP
+.BI \-h " hist"
+Fix the histogram bin size to a specific initial value.
+Use this in comination with the
+.B \-m
+option to specify a custom histgram bin size growth function.
+.TP
+.BI \-m " mult"
+The size of each histogram bin should be computed by multiplying the
+previous bin's size by this quantity.
+.TP
+.B \-s
+Print a summary of the free space before exiting.
diff --git a/spacey/fsmap.h b/spacey/fsmap.h
new file mode 100644
index 0000000..3c5084c
--- /dev/null
+++ b/spacey/fsmap.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ *
+ * 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
+ */
+#ifndef FSMAP_H_
+#define FSMAP_H_
+
+/* FS_IOC_GETFSMAP ioctl definitions */
+#ifndef FS_IOC_GETFSMAP
+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 FS_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 /* FS_IOC_GETFSMAP */ 
+
+#endif
diff --git a/spacey/main.c b/spacey/main.c
new file mode 100644
index 0000000..009a965
--- /dev/null
+++ b/spacey/main.c
@@ -0,0 +1,456 @@
+/*
+ * 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.
+ *
+ * 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 "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <mntent.h>
+#include <limits.h>
+#include "ext2fs/ext2_types.h"
+#include "ext2fs/ext2fs.h"
+#include "fsmap.h"
+#include "ext2fs/ext2_fs.h"
+
+#include "../version.h"
+#include "support/nls-enable.h"
+
+static const char *progname = "e2spaceman";
+
+struct histent
+{
+	blk64_t		low;
+	blk64_t		high;
+	size_t		count;
+	blk64_t		blocks;
+};
+
+static struct ext4_fsop_geom fsgeo;
+static struct ext4_fsop_geom flexgeo;
+
+static struct histent *hist;
+static size_t histcount;
+
+static dgrp_t *bglist;
+static size_t bgcount;
+
+static blk64_t totblocks;
+static long long totexts;
+
+static int equalsize;
+static int multsize;
+
+static int seen1;
+static int dumpflag;
+static int gflag;
+static const char *filename;
+static dev_t datadev;
+
+static inline dgrp_t f2b(dgrp_t fgroup)
+{
+	return fsgeo.efg_flexbgsize ? fgroup * fsgeo.efg_flexbgsize : fgroup;
+}
+
+static inline dgrp_t b2f(dgrp_t group)
+{
+	return fsgeo.efg_flexbgsize ? group / fsgeo.efg_flexbgsize : group;
+}
+
+static void usage(void)
+{
+	fprintf(stderr, _(
+"Usage: %s [options] mountpoint\n\n\
+	-V          print version information\n"),
+		progname);
+	exit(2);
+}
+
+#define PROC_MOUNTS	"/proc/mounts"
+int find_datadev(const char *arg, dev_t *datadev, char *mntpoint)
+{
+	struct mntent *mnt;
+	FILE *mtp;
+	char *mtab_file;
+	char rmnt_fsname[PATH_MAX], rmnt_dir[PATH_MAX];
+	struct stat sbuf;
+	dev_t fd_dev;
+
+	if (stat(arg, &sbuf) < 0)
+		return errno;
+	/*
+	 * We want to match st_rdev if the path provided is a device
+	 * special file.  Otherwise we are looking for the the
+	 * device id for the containing filesystem, in st_dev.
+	 */
+	if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode))
+		fd_dev = sbuf.st_rdev;
+	else
+		fd_dev = sbuf.st_dev;
+
+	mtab_file = PROC_MOUNTS;
+	if (access(mtab_file, R_OK) != 0)
+		mtab_file = MOUNTED;
+
+	if ((mtp = setmntent(mtab_file, "r")) == NULL)
+		return ENOENT;
+
+	while ((mnt = getmntent(mtp)) != NULL) {
+		if (!realpath(mnt->mnt_dir, rmnt_dir))
+			continue;
+		if (!realpath(mnt->mnt_fsname, rmnt_fsname))
+			continue;
+
+		if (stat(rmnt_fsname, &sbuf) < 0)
+			continue;
+		if (sbuf.st_rdev == fd_dev) {
+			*datadev = fd_dev;
+			strncpy(mntpoint, rmnt_dir, PATH_MAX);
+			break;
+		}
+	}
+	endmntent(mtp);
+	return 0;
+}
+
+static void addhistent(blk64_t h)
+{
+	hist = realloc(hist, (histcount + 1) * sizeof(*hist));
+	if (!hist) {
+		perror("addhistent");
+		exit(2);
+	}
+	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(dgrp_t group, blk64_t fsb, blk64_t len)
+{
+	size_t i;
+
+	if (dumpflag)
+		printf("%8u %8llu %8llu\n", group, fsb, 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 ((struct histent *)a)->low - ((struct histent *)b)->low;
+}
+
+static void histinit(blk64_t maxlen)
+{
+	blk64_t 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)
+{
+	size_t i;
+
+	printf("%7s %7s %7s %7s %6s\n",
+		_("from"), _("to"), _("extents"), _("blocks"), _("pct"));
+	for (i = 0; i < histcount; i++) {
+		if (hist[i].count)
+			printf("%7llu %7llu %7Zu %7llu %6.2f\n", hist[i].low,
+				hist[i].high, hist[i].count, hist[i].blocks,
+				hist[i].blocks * 100.0 / totblocks);
+	}
+}
+
+static int inbglist(dgrp_t fgroup)
+{
+	size_t i;
+
+	if (bgcount == 0)
+		return 1;
+	for (i = 0; i < bgcount; i++)
+		if (b2f(bglist[i]) == fgroup)
+			return 1;
+	return 0;
+}
+
+#define NR_EXTENTS 1024
+
+static void scan_bg(int fd, dgrp_t fgroup)
+{
+	struct fsmap_head *fsmap;
+	struct fsmap *extent;
+	struct fsmap *l, *h;
+	struct fsmap *p;
+	off64_t blocksize = flexgeo.efg_blocksize;
+	off64_t bytes_per_bg;
+	off64_t len;
+	blk64_t fsb;
+	blk64_t freeblks = 0;
+	blk64_t freeexts = 0;
+	int ret;
+	int i;
+
+	bytes_per_bg = (off64_t)flexgeo.efg_bgblocks * blocksize;
+
+	fsmap = malloc(fsmap_sizeof(NR_EXTENTS));
+	if (!fsmap) {
+		fprintf(stderr, _("%s: fsmap malloc failed.\n"), progname);
+		exit(1);
+	}
+
+	memset(fsmap, 0, sizeof(*fsmap));
+	fsmap->fmh_count = NR_EXTENTS;
+	l = fsmap->fmh_keys;
+	h = fsmap->fmh_keys + 1;
+	l->fmr_physical = fgroup * bytes_per_bg;
+	h->fmr_physical = ((fgroup + 1) * bytes_per_bg) - 1;
+	l->fmr_device = h->fmr_device = datadev;
+	h->fmr_owner = ULLONG_MAX;
+	h->fmr_flags = UINT_MAX;
+	h->fmr_offset = ULLONG_MAX;
+
+	while (1) {
+		ret = ioctl(fd, FS_IOC_GETFSMAP, fsmap);
+		if (ret < 0) {
+			fprintf(stderr,
+_("%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n"),
+				progname, filename, strerror(errno));
+			free(fsmap);
+			exit(1);
+		}
+
+		/* 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 != FMR_OWN_FREE)
+				continue;
+
+			fsb = extent->fmr_physical / blocksize;
+			len = extent->fmr_length / blocksize;
+			freeblks += len;
+			freeexts++;
+
+			addtohist(f2b(fgroup), fsb, len);
+		}
+
+		p = &fsmap->fmh_recs[fsmap->fmh_entries - 1];
+		if (p->fmr_flags & FMR_OF_LAST)
+			break;
+		fsmap_advance(fsmap);
+	}
+
+	if (gflag)
+		printf(_("%10u %10llu %10llu\n"), f2b(fgroup), freeexts,
+		       freeblks);
+}
+
+static void bglistadd(char *a)
+{
+	bglist = realloc(bglist, (bgcount + 1) * sizeof(*bglist));
+	bglist[bgcount] = (dgrp_t)atoi(a);
+	bgcount++;
+}
+
+
+static void setup_fsgeo(int fd)
+{
+	/* Get the current filesystem size & geometry */
+	if (ioctl(fd, EXT4_IOC_FSGEOMETRY, &fsgeo) < 0) {
+		fprintf(stderr, _(
+			"%s: cannot determine geometry of ext4 filesystem"
+			" mounted at %s.\n"),
+			progname, filename);
+		exit(1);
+	}
+
+	/*
+	 * Refactor the geometry so that a "group" is the size of the smallest
+	 * number of BGs required to contain the longest free extent possible.
+	 *
+	 * (IOWs, we handle everything in terms of flexbgs.)
+	 */
+	flexgeo = fsgeo;
+	if (fsgeo.efg_flexbgsize) {
+		flexgeo.efg_bgblocks *= fsgeo.efg_flexbgsize;
+		flexgeo.efg_bgcount = (fsgeo.efg_bgcount +
+				       fsgeo.efg_flexbgsize - 1) /
+				      fsgeo.efg_flexbgsize;
+		flexgeo.efg_bg_iblocks *= fsgeo.efg_flexbgsize;
+		flexgeo.efg_flexbgsize = 0;
+	}
+}
+
+int main(int argc, char **argv)
+{
+	char *progname;
+	int fd;
+	int c;
+	char mntpoint[PATH_MAX];
+	blk64_t max_extent;
+	int speced, summaryflag;
+	dgrp_t fgroup;
+
+	speced = dumpflag = summaryflag = gflag = 0;
+
+	progname = basename(argv[0]);
+#ifdef ENABLE_NLS
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+#endif
+
+	while ((c = getopt(argc, argv, "a:bde:gh:m:sV")) != EOF) {
+		switch (c) {
+		case 'a':
+			bglistadd(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 'g':
+			histcount = 0;
+			gflag++;
+			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 's':
+			summaryflag = 1;
+			break;
+		case 'V':
+			printf(_("%s version %s\n"), progname, VERSION);
+			exit(0);
+		case '?':
+		default:
+			usage();
+		}
+	}
+	if (argc - optind != 1)
+		usage();
+
+	filename = argv[optind];
+	fd = open(argv[optind], O_RDONLY);
+	if (fd < 0) {
+		perror(argv[optind]);
+		return 1;
+	}
+
+	if (find_datadev(argv[optind], &datadev, mntpoint)) {
+		perror("find_datadev");
+		exit(1);
+	}
+
+	close(fd);
+	fd = open(mntpoint, O_RDONLY);
+	if (fd < 0) {
+		perror(mntpoint);
+		return 1;
+	}
+
+	setup_fsgeo(fd);
+
+	/* Set up histogram */
+	max_extent = flexgeo.efg_bgblocks;
+
+	if (!speced)
+		multsize = 2;
+	histinit(max_extent);
+
+	/* Collect data and print */
+	if (gflag)
+		printf(_("        AG    extents     blocks\n"));
+	for (fgroup = 0; fgroup < flexgeo.efg_bgcount; fgroup++)  {
+		if (inbglist(fgroup))
+			scan_bg(fd, fgroup);
+	}
+	if (histcount && !gflag)
+		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 (bglist)
+		free(bglist);
+	if (hist)
+		free(hist);
+	close(fd);
+
+	return 0;
+}

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

* Re: [PATCH 3/3] e2spacey: create a program to use getfsmap to profile free space
  2017-03-02  4:52 ` [PATCH 3/3] e2spacey: create a program to use getfsmap to profile free space Darrick J. Wong
@ 2017-03-02 19:45   ` Andreas Dilger
  2017-03-02 21:27     ` Darrick J. Wong
  0 siblings, 1 reply; 11+ messages in thread
From: Andreas Dilger @ 2017-03-02 19:45 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: Theodore Ts'o, linux-ext4

[-- Attachment #1: Type: text/plain, Size: 27527 bytes --]

On Mar 1, 2017, at 9:52 PM, Darrick J. Wong <darrick.wong@oracle.com> wrote:
> 
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> e2spacey is a new tool that uses the GETFSMAP ioctl and the FSGEOMETRY
> ioctl to find all the free extents in a mounted filesystem and display
> either per-flexbg free block counts or a histogram of free extents.
> At this point it's mostly useful as a debugging tool.

It would be better to wire the GETFSMAP ioctl into e2freefrag.c to use
on mounted filesystems, rather than introducing a new-but-almost-identical
tool.  e2freefrag has existed for a long time already and is doing this
same thing (reporting a histogram of free extents).  If there is some new
functionality that GETFSMAP allows, it could be added as a new option to
e2freefrag as well.

Otherwise, we have two tools to maintain, and we couldn't even deprecate
e2freefrag (assuming we wanted to) since e2spacey only works on mounted
filesystems.

Cheers, Andreas

> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
> Makefile.in          |    3
> configure            |    6 +
> configure.ac         |    5 -
> lib/ext2fs/ext2_fs.h |    8 +
> spacey/Makefile.in   |  152 +++++++++++++++++
> spacey/e2spacey.8.in |   65 +++++++
> spacey/fsmap.h       |   89 ++++++++++
> spacey/main.c        |  456 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 8 files changed, 781 insertions(+), 3 deletions(-)
> create mode 100644 spacey/Makefile.in
> create mode 100644 spacey/e2spacey.8.in
> create mode 100644 spacey/fsmap.h
> create mode 100644 spacey/main.c
> 
> 
> diff --git a/Makefile.in b/Makefile.in
> index 7da9ad7..b48d0f9 100644
> --- a/Makefile.in
> +++ b/Makefile.in
> @@ -13,10 +13,11 @@ INSTALL = @INSTALL@
> @DEBUGFS_CMT@DEBUGFS_DIR= debugfs
> @UUID_CMT@UUID_LIB_SUBDIR= lib/uuid
> @BLKID_CMT@BLKID_LIB_SUBDIR= lib/blkid
> +@SPACEY_CMT@SPACEY_DIR= spacey
> SUPPORT_LIB_SUBDIR= lib/support
> 
> LIB_SUBDIRS=lib/et lib/ss lib/e2p $(UUID_LIB_SUBDIR) $(BLKID_LIB_SUBDIR) $(SUPPORT_LIB_SUBDIR) lib/ext2fs intl
> -PROG_SUBDIRS=e2fsck $(DEBUGFS_DIR) misc $(RESIZE_DIR) tests/progs po
> +PROG_SUBDIRS=e2fsck $(DEBUGFS_DIR) misc $(RESIZE_DIR) tests/progs po $(SPACEY_DIR)
> SUBDIRS=util $(LIB_SUBDIRS) $(PROG_SUBDIRS) tests
> 
> SUBS= util/subst.conf lib/config.h $(top_builddir)/lib/dirpaths.h \
> diff --git a/configure b/configure
> index b553da1..940b11c 100755
> --- a/configure
> +++ b/configure
> @@ -642,6 +642,7 @@ root_prefix
> UNIX_CMT
> CYGWIN_CMT
> LINUX_CMT
> +SPACEY_CMT
> E2INFO_CMT
> UNI_DIFF_OPTS
> SEM_INIT_LIB
> @@ -13665,15 +13666,18 @@ fi
> $as_echo "$UNI_DIFF_OPTS" >&6; }
> 
> E2INFO_CMT="#"
> +SPACEY_CMT="#"
> case "$host_os" in
> linux*)
> 
> $as_echo "#define HAVE_EXT2_IOCTLS 1" >>confdefs.h
> 
> 	E2INFO_CMT=
> +	SPACEY_CMT=
> 	;;
> esac
> 
> +
> LINUX_CMT="#"
> CYGWIN_CMT="#"
> UNIX_CMT=
> @@ -13875,7 +13879,7 @@ for i in MCONFIG Makefile e2fsprogs.spec \
> 	misc/Makefile ext2ed/Makefile e2fsck/Makefile \
> 	debugfs/Makefile tests/Makefile tests/progs/Makefile \
> 	resize/Makefile doc/Makefile intl/Makefile \
> -	intl/libgnuintl.h po/Makefile.in ; do
> +	intl/libgnuintl.h po/Makefile.in spacey/Makefile ; do
> 	if test -d `dirname ${srcdir}/$i` ; then
> 		outlist="$outlist $i"
> 	fi
> diff --git a/configure.ac b/configure.ac
> index bf613fd..5b95f6b 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -1261,13 +1261,16 @@ dnl
> dnl We use the EXT2 ioctls only under Linux
> dnl
> E2INFO_CMT="#"
> +SPACEY_CMT="#"
> case "$host_os" in
> linux*)
> 	AC_DEFINE(HAVE_EXT2_IOCTLS, 1, [Define to 1 if Ext2 ioctls present])
> 	E2INFO_CMT=
> +	SPACEY_CMT=
> 	;;
> esac
> AC_SUBST(E2INFO_CMT)
> +AC_SUBST(SPACEY_CMT)
> dnl
> dnl OS-specific uncomment control
> dnl
> @@ -1469,7 +1472,7 @@ for i in MCONFIG Makefile e2fsprogs.spec \
> 	misc/Makefile ext2ed/Makefile e2fsck/Makefile \
> 	debugfs/Makefile tests/Makefile tests/progs/Makefile \
> 	resize/Makefile doc/Makefile intl/Makefile \
> -	intl/libgnuintl.h po/Makefile.in ; do
> +	intl/libgnuintl.h po/Makefile.in spacey/Makefile ; do
> 	if test -d `dirname ${srcdir}/$i` ; then
> 		outlist="$outlist $i"
> 	fi
> diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> index bad7648..4beebb6 100644
> --- a/lib/ext2fs/ext2_fs.h
> +++ b/lib/ext2fs/ext2_fs.h
> @@ -406,6 +406,14 @@ struct ext4_fsop_geom {
> 
> #define EXT4_IOC_FSGEOMETRY		_IOR ('f', 19, struct ext4_fsop_geom)
> 
> +/* Custom FS_IOC_GETFSMAP owner codes */
> +#define EXT4_FMR_OWN_FREE	FMR_OWN_FREE      /* free space */
> +#define EXT4_FMR_OWN_UNKNOWN	FMR_OWN_UNKNOWN   /* unknown owner */
> +#define EXT4_FMR_OWN_GDT	FMR_OWNER('f', 1) /* group descriptors */
> +#define EXT4_FMR_OWN_RESV_GDT	FMR_OWNER('f', 2) /* reserved gdt blocks */
> +#define EXT4_FMR_OWN_BLKBM	FMR_OWNER('f', 3) /* inode bitmap */
> +#define EXT4_FMR_OWN_INOBM	FMR_OWNER('f', 4) /* block bitmap */
> +
> /*
>  * Structure of an inode on the disk
>  */
> diff --git a/spacey/Makefile.in b/spacey/Makefile.in
> new file mode 100644
> index 0000000..3c842f3
> --- /dev/null
> +++ b/spacey/Makefile.in
> @@ -0,0 +1,152 @@
> +#
> +# Makefile for e2spacey
> +#
> +
> +srcdir = @srcdir@
> +top_srcdir = @top_srcdir@
> +VPATH = @srcdir@
> +top_builddir = ..
> +my_dir = scrub
> +INSTALL = @INSTALL@
> +
> +@MCONFIG@
> +
> +PROGS=		e2spacey
> +MANPAGES=	e2spacey.8
> +
> +LIBS= $(LIBSUPPORT) $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBBLKID) $(LIBUUID) \
> +	$(LIBINTL) $(LIBE2P) $(LIBMAGIC) $(SYSLIBS)
> +DEPLIBS= $(DEPLIBSUPPORT) $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBBLKID) \
> +	 $(DEPLIBUUID) $(DEPLIBE2P)
> +
> +STATIC_LIBS= $(STATIC_LIBSUPPORT) $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) \
> +	     $(STATIC_LIBBLKID) $(STATIC_LIBUUID) $(LIBINTL) $(STATIC_LIBE2P) \
> +	     $(LIBMAGIC) $(SYSLIBS)
> +STATIC_DEPLIBS= $(DEPSTATIC_LIBSUPPORT) $(STATIC_LIBEXT2FS) \
> +		$(DEPSTATIC_LIBCOM_ERR) $(DEPSTATIC_LIBBLKID) \
> +		$(DEPSTATIC_LIBUUID) $(DEPSTATIC_LIBE2P)
> +
> +PROFILED_LIBS= $(PROFILED_LIBSUPPORT) $(PROFILED_LIBEXT2FS) \
> +	       $(PROFILED_LIBCOM_ERR) $(PROFILED_LIBBLKID) $(PROFILED_LIBUUID) \
> +	       $(PROFILED_LIBE2P) $(LIBINTL) $(LIBMAGIC) $(SYSLIBS)
> +PROFILED_DEPLIBS= $(DEPPROFILED_LIBSUPPORT) $(PROFILED_LIBEXT2FS) \
> +		  $(DEPPROFILED_LIBCOM_ERR) $(DEPPROFILED_LIBBLKID) \
> +		  $(DEPPROFILED_LIBUUID) $(DEPPROFILED_LIBE2P)
> +
> +COMPILE_ET=	_ET_DIR_OVERRIDE=$(srcdir)/../lib/et/et ../lib/et/compile_et
> +
> +.c.o:
> +	$(E) "	CC $<"
> +	$(Q) $(CC) -c $(ALL_CFLAGS) $< -o $@
> +	$(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
> +	$(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
> +@PROFILE_CMT@	$(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/$*.o -c $<
> +
> +#
> +# Flags for doing mtrace --- uncomment to produce mtracing e2spacey
> +# 	Note:  The optimization flags must include -g
> +#
> +#MTRACE=	-DMTRACE
> +#MTRACE_OBJ= mtrace.o
> +#MTRACE_SRC= $(srcdir)/mtrace.c
> +#OPT= -g
> +
> +#
> +# Flags for doing mcheck --- uncomment to produce mchecking e2spacey
> +# 	Note:  The optimization flags must include -g
> +#
> +#MCHECK= -DMCHECK
> +
> +OBJS= main.o
> +
> +PROFILED_OBJS= profiled/main.o
> +
> +SRCS= $(srcdir)/main.o
> +
> +all:: profiled $(PROGS) $(MANPAGES)
> +
> +@PROFILE_CMT@all:: e2spacey.profiled
> +
> +e2spacey: $(OBJS)  $(DEPLIBS)
> +	$(E) "	LD $@"
> +	$(Q) $(LD) $(ALL_LDFLAGS) $(RDYNAMIC) -o e2spacey $(OBJS) $(LIBS)
> +
> +e2spacey.static: $(OBJS) $(STATIC_DEPLIBS)
> +	$(E) "	LD $@"
> +	$(Q) $(LD) $(LDFLAGS_STATIC) -o e2spacey.static $(OBJS) $(STATIC_LIBS) -lpthread
> +
> +e2spacey.profiled: $(OBJS)  $(PROFILED_DEPLIBS)
> +	$(E) "	LD $@"
> +	$(Q) $(LD) $(ALL_LDFLAGS) -g -pg -o e2spacey.profiled $(PROFILED_OBJS) \
> +		$(PROFILED_LIBS) -lpthread
> +
> +test_profile: $(srcdir)/profile.c profile_helpers.o argv_parse.o \
> +		prof_err.o profile.h $(DEPSTATIC_LIBCOM_ERR)
> +	$(E) "	LD $@"
> +	$(Q) $(CC) -o test_profile -DDEBUG_PROGRAM $(srcdir)/profile.c prof_err.o \
> +		profile_helpers.o argv_parse.o $(STATIC_LIBCOM_ERR) \
> +		$(ALL_CFLAGS)
> +
> +profiled:
> +@PROFILE_CMT@	$(E) "	MKDIR $@"
> +@PROFILE_CMT@	$(Q) mkdir profiled
> +
> +e2spacey.8: $(DEP_SUBSTITUTE) $(srcdir)/e2spacey.8.in
> +	$(E) "	SUBST $@"
> +	$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2spacey.8.in e2spacey.8
> +
> +installdirs:
> +	$(E) "	MKINSTALLDIRS $(root_sbindir) $(man8dir)"
> +	$(Q) $(MKINSTALLDIRS) $(DESTDIR)$(root_sbindir) \
> +		$(DESTDIR)$(man8dir) $(DESTDIR)$(man5dir)
> +
> +install: $(PROGS) $(MANPAGES) $(FMANPAGES) installdirs
> +	$(Q) for i in $(PROGS); do \
> +		$(ES) "	INSTALL $(root_sbindir)/$$i"; \
> +		$(INSTALL_PROGRAM) $$i $(DESTDIR)$(root_sbindir)/$$i; \
> +	done
> +	$(Q) for i in $(MANPAGES); do \
> +		for j in $(COMPRESS_EXT); do \
> +			$(RM) -f $(DESTDIR)$(man8dir)/$$i.$$j; \
> +		done; \
> +		$(ES) "	INSTALL_DATA $(man8dir)/$$i"; \
> +		$(INSTALL_DATA) $$i $(DESTDIR)$(man8dir)/$$i; \
> +	done
> +
> +install-strip: install
> +	$(Q) for i in $(PROGS); do \
> +		$(ES) "	STRIP $(root_sbindir)/$$i"; \
> +		$(STRIP) $(DESTDIR)$(root_sbindir)/$$i; \
> +	done
> +
> +uninstall:
> +	for i in $(PROGS); do \
> +		$(RM) -f $(DESTDIR)$(root_sbindir)/$$i; \
> +	done
> +	for i in $(MANPAGES); do \
> +		$(RM) -f $(DESTDIR)$(man8dir)/$$i; \
> +	done
> +
> +clean::
> +	$(RM) -f $(PROGS)
> +	$(RM) -rf profiled
> +
> +mostlyclean: clean
> +distclean: clean
> +	$(RM) -f .depend Makefile $(srcdir)/TAGS $(srcdir)/Makefile.in.old
> +
> +# +++ Dependency line eater +++
> +#
> +# Makefile dependencies follow.  This must be the last section in
> +# the Makefile.in file
> +#
> +main.o: $(srcdir)/main.c $(top_builddir)/lib/config.h \
> + $(top_builddir)/lib/dirpaths.h $(srcdir)/fsmap.h \
> + $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
> + $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
> + $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
> + $(top_builddir)/lib/ext2fs/ext2_err.h \
> + $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
> + $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \
> + $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \
> + $(top_srcdir)/lib/support/quotaio_tree.h
> diff --git a/spacey/e2spacey.8.in b/spacey/e2spacey.8.in
> new file mode 100644
> index 0000000..f4956fc
> --- /dev/null
> +++ b/spacey/e2spacey.8.in
> @@ -0,0 +1,65 @@
> +.TH E2SPACEY 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
> +.SH NAME
> +e2spacey \- show free space information about an ext4 filesystem
> +.SH SYNOPSIS
> +.B e2spacey
> +[
> +.B \-srg
> +]
> +[
> +.B \-b
> +|
> +.B \-e
> +.I bsize
> +|
> +.B \-h
> +.I h1
> +[
> +.B \-m
> +.I bmult
> +]
> +]
> +[
> +.B \-a
> +.I group
> +]
> +.I mountpoint
> +.br
> +.B e2spacey \-V
> +.SH DESCRIPTION
> +.B e2spacey
> +reports and controls free space usage in an ext4 filesystem.
> +When the
> +.B flex_bg
> +feature is enabled, the free space information is grouped by flex block groups
> +instead of regular block groups.
> +This enables reporting of free space extents that span multiple block groups.
> +
> +.SH OPTIONS
> +.TP 1.0i
> +.BI \-a " group"
> +Only query the specified block group's free space information.
> +Multiple options may be provided.
> +.TP
> +.B \-b
> +Establish histogram bins sized in successive powers of two.
> +.TP
> +.B \-e
> +Fix the histogram bin size to a specific value.
> +.TP
> +.B \-g
> +Instead of printing a histogram, simply report the number of free extents
> +and number of free blocks per block group.
> +.TP
> +.BI \-h " hist"
> +Fix the histogram bin size to a specific initial value.
> +Use this in comination with the
> +.B \-m
> +option to specify a custom histgram bin size growth function.
> +.TP
> +.BI \-m " mult"
> +The size of each histogram bin should be computed by multiplying the
> +previous bin's size by this quantity.
> +.TP
> +.B \-s
> +Print a summary of the free space before exiting.
> diff --git a/spacey/fsmap.h b/spacey/fsmap.h
> new file mode 100644
> index 0000000..3c5084c
> --- /dev/null
> +++ b/spacey/fsmap.h
> @@ -0,0 +1,89 @@
> +/*
> + * 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.
> + *
> + * 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
> + */
> +#ifndef FSMAP_H_
> +#define FSMAP_H_
> +
> +/* FS_IOC_GETFSMAP ioctl definitions */
> +#ifndef FS_IOC_GETFSMAP
> +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 FS_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 /* FS_IOC_GETFSMAP */
> +
> +#endif
> diff --git a/spacey/main.c b/spacey/main.c
> new file mode 100644
> index 0000000..009a965
> --- /dev/null
> +++ b/spacey/main.c
> @@ -0,0 +1,456 @@
> +/*
> + * 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.
> + *
> + * 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 "config.h"
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <libgen.h>
> +#include <unistd.h>
> +#include <sys/ioctl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <mntent.h>
> +#include <limits.h>
> +#include "ext2fs/ext2_types.h"
> +#include "ext2fs/ext2fs.h"
> +#include "fsmap.h"
> +#include "ext2fs/ext2_fs.h"
> +
> +#include "../version.h"
> +#include "support/nls-enable.h"
> +
> +static const char *progname = "e2spaceman";
> +
> +struct histent
> +{
> +	blk64_t		low;
> +	blk64_t		high;
> +	size_t		count;
> +	blk64_t		blocks;
> +};
> +
> +static struct ext4_fsop_geom fsgeo;
> +static struct ext4_fsop_geom flexgeo;
> +
> +static struct histent *hist;
> +static size_t histcount;
> +
> +static dgrp_t *bglist;
> +static size_t bgcount;
> +
> +static blk64_t totblocks;
> +static long long totexts;
> +
> +static int equalsize;
> +static int multsize;
> +
> +static int seen1;
> +static int dumpflag;
> +static int gflag;
> +static const char *filename;
> +static dev_t datadev;
> +
> +static inline dgrp_t f2b(dgrp_t fgroup)
> +{
> +	return fsgeo.efg_flexbgsize ? fgroup * fsgeo.efg_flexbgsize : fgroup;
> +}
> +
> +static inline dgrp_t b2f(dgrp_t group)
> +{
> +	return fsgeo.efg_flexbgsize ? group / fsgeo.efg_flexbgsize : group;
> +}
> +
> +static void usage(void)
> +{
> +	fprintf(stderr, _(
> +"Usage: %s [options] mountpoint\n\n\
> +	-V          print version information\n"),
> +		progname);
> +	exit(2);
> +}
> +
> +#define PROC_MOUNTS	"/proc/mounts"
> +int find_datadev(const char *arg, dev_t *datadev, char *mntpoint)
> +{
> +	struct mntent *mnt;
> +	FILE *mtp;
> +	char *mtab_file;
> +	char rmnt_fsname[PATH_MAX], rmnt_dir[PATH_MAX];
> +	struct stat sbuf;
> +	dev_t fd_dev;
> +
> +	if (stat(arg, &sbuf) < 0)
> +		return errno;
> +	/*
> +	 * We want to match st_rdev if the path provided is a device
> +	 * special file.  Otherwise we are looking for the the
> +	 * device id for the containing filesystem, in st_dev.
> +	 */
> +	if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode))
> +		fd_dev = sbuf.st_rdev;
> +	else
> +		fd_dev = sbuf.st_dev;
> +
> +	mtab_file = PROC_MOUNTS;
> +	if (access(mtab_file, R_OK) != 0)
> +		mtab_file = MOUNTED;
> +
> +	if ((mtp = setmntent(mtab_file, "r")) == NULL)
> +		return ENOENT;
> +
> +	while ((mnt = getmntent(mtp)) != NULL) {
> +		if (!realpath(mnt->mnt_dir, rmnt_dir))
> +			continue;
> +		if (!realpath(mnt->mnt_fsname, rmnt_fsname))
> +			continue;
> +
> +		if (stat(rmnt_fsname, &sbuf) < 0)
> +			continue;
> +		if (sbuf.st_rdev == fd_dev) {
> +			*datadev = fd_dev;
> +			strncpy(mntpoint, rmnt_dir, PATH_MAX);
> +			break;
> +		}
> +	}
> +	endmntent(mtp);
> +	return 0;
> +}
> +
> +static void addhistent(blk64_t h)
> +{
> +	hist = realloc(hist, (histcount + 1) * sizeof(*hist));
> +	if (!hist) {
> +		perror("addhistent");
> +		exit(2);
> +	}
> +	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(dgrp_t group, blk64_t fsb, blk64_t len)
> +{
> +	size_t i;
> +
> +	if (dumpflag)
> +		printf("%8u %8llu %8llu\n", group, fsb, 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 ((struct histent *)a)->low - ((struct histent *)b)->low;
> +}
> +
> +static void histinit(blk64_t maxlen)
> +{
> +	blk64_t 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)
> +{
> +	size_t i;
> +
> +	printf("%7s %7s %7s %7s %6s\n",
> +		_("from"), _("to"), _("extents"), _("blocks"), _("pct"));
> +	for (i = 0; i < histcount; i++) {
> +		if (hist[i].count)
> +			printf("%7llu %7llu %7Zu %7llu %6.2f\n", hist[i].low,
> +				hist[i].high, hist[i].count, hist[i].blocks,
> +				hist[i].blocks * 100.0 / totblocks);
> +	}
> +}
> +
> +static int inbglist(dgrp_t fgroup)
> +{
> +	size_t i;
> +
> +	if (bgcount == 0)
> +		return 1;
> +	for (i = 0; i < bgcount; i++)
> +		if (b2f(bglist[i]) == fgroup)
> +			return 1;
> +	return 0;
> +}
> +
> +#define NR_EXTENTS 1024
> +
> +static void scan_bg(int fd, dgrp_t fgroup)
> +{
> +	struct fsmap_head *fsmap;
> +	struct fsmap *extent;
> +	struct fsmap *l, *h;
> +	struct fsmap *p;
> +	off64_t blocksize = flexgeo.efg_blocksize;
> +	off64_t bytes_per_bg;
> +	off64_t len;
> +	blk64_t fsb;
> +	blk64_t freeblks = 0;
> +	blk64_t freeexts = 0;
> +	int ret;
> +	int i;
> +
> +	bytes_per_bg = (off64_t)flexgeo.efg_bgblocks * blocksize;
> +
> +	fsmap = malloc(fsmap_sizeof(NR_EXTENTS));
> +	if (!fsmap) {
> +		fprintf(stderr, _("%s: fsmap malloc failed.\n"), progname);
> +		exit(1);
> +	}
> +
> +	memset(fsmap, 0, sizeof(*fsmap));
> +	fsmap->fmh_count = NR_EXTENTS;
> +	l = fsmap->fmh_keys;
> +	h = fsmap->fmh_keys + 1;
> +	l->fmr_physical = fgroup * bytes_per_bg;
> +	h->fmr_physical = ((fgroup + 1) * bytes_per_bg) - 1;
> +	l->fmr_device = h->fmr_device = datadev;
> +	h->fmr_owner = ULLONG_MAX;
> +	h->fmr_flags = UINT_MAX;
> +	h->fmr_offset = ULLONG_MAX;
> +
> +	while (1) {
> +		ret = ioctl(fd, FS_IOC_GETFSMAP, fsmap);
> +		if (ret < 0) {
> +			fprintf(stderr,
> +_("%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n"),
> +				progname, filename, strerror(errno));
> +			free(fsmap);
> +			exit(1);
> +		}
> +
> +		/* 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 != FMR_OWN_FREE)
> +				continue;
> +
> +			fsb = extent->fmr_physical / blocksize;
> +			len = extent->fmr_length / blocksize;
> +			freeblks += len;
> +			freeexts++;
> +
> +			addtohist(f2b(fgroup), fsb, len);
> +		}
> +
> +		p = &fsmap->fmh_recs[fsmap->fmh_entries - 1];
> +		if (p->fmr_flags & FMR_OF_LAST)
> +			break;
> +		fsmap_advance(fsmap);
> +	}
> +
> +	if (gflag)
> +		printf(_("%10u %10llu %10llu\n"), f2b(fgroup), freeexts,
> +		       freeblks);
> +}
> +
> +static void bglistadd(char *a)
> +{
> +	bglist = realloc(bglist, (bgcount + 1) * sizeof(*bglist));
> +	bglist[bgcount] = (dgrp_t)atoi(a);
> +	bgcount++;
> +}
> +
> +
> +static void setup_fsgeo(int fd)
> +{
> +	/* Get the current filesystem size & geometry */
> +	if (ioctl(fd, EXT4_IOC_FSGEOMETRY, &fsgeo) < 0) {
> +		fprintf(stderr, _(
> +			"%s: cannot determine geometry of ext4 filesystem"
> +			" mounted at %s.\n"),
> +			progname, filename);
> +		exit(1);
> +	}
> +
> +	/*
> +	 * Refactor the geometry so that a "group" is the size of the smallest
> +	 * number of BGs required to contain the longest free extent possible.
> +	 *
> +	 * (IOWs, we handle everything in terms of flexbgs.)
> +	 */
> +	flexgeo = fsgeo;
> +	if (fsgeo.efg_flexbgsize) {
> +		flexgeo.efg_bgblocks *= fsgeo.efg_flexbgsize;
> +		flexgeo.efg_bgcount = (fsgeo.efg_bgcount +
> +				       fsgeo.efg_flexbgsize - 1) /
> +				      fsgeo.efg_flexbgsize;
> +		flexgeo.efg_bg_iblocks *= fsgeo.efg_flexbgsize;
> +		flexgeo.efg_flexbgsize = 0;
> +	}
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	char *progname;
> +	int fd;
> +	int c;
> +	char mntpoint[PATH_MAX];
> +	blk64_t max_extent;
> +	int speced, summaryflag;
> +	dgrp_t fgroup;
> +
> +	speced = dumpflag = summaryflag = gflag = 0;
> +
> +	progname = basename(argv[0]);
> +#ifdef ENABLE_NLS
> +	setlocale(LC_ALL, "");
> +	bindtextdomain(PACKAGE, LOCALEDIR);
> +	textdomain(PACKAGE);
> +#endif
> +
> +	while ((c = getopt(argc, argv, "a:bde:gh:m:sV")) != EOF) {
> +		switch (c) {
> +		case 'a':
> +			bglistadd(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 'g':
> +			histcount = 0;
> +			gflag++;
> +			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 's':
> +			summaryflag = 1;
> +			break;
> +		case 'V':
> +			printf(_("%s version %s\n"), progname, VERSION);
> +			exit(0);
> +		case '?':
> +		default:
> +			usage();
> +		}
> +	}
> +	if (argc - optind != 1)
> +		usage();
> +
> +	filename = argv[optind];
> +	fd = open(argv[optind], O_RDONLY);
> +	if (fd < 0) {
> +		perror(argv[optind]);
> +		return 1;
> +	}
> +
> +	if (find_datadev(argv[optind], &datadev, mntpoint)) {
> +		perror("find_datadev");
> +		exit(1);
> +	}
> +
> +	close(fd);
> +	fd = open(mntpoint, O_RDONLY);
> +	if (fd < 0) {
> +		perror(mntpoint);
> +		return 1;
> +	}
> +
> +	setup_fsgeo(fd);
> +
> +	/* Set up histogram */
> +	max_extent = flexgeo.efg_bgblocks;
> +
> +	if (!speced)
> +		multsize = 2;
> +	histinit(max_extent);
> +
> +	/* Collect data and print */
> +	if (gflag)
> +		printf(_("        AG    extents     blocks\n"));
> +	for (fgroup = 0; fgroup < flexgeo.efg_bgcount; fgroup++)  {
> +		if (inbglist(fgroup))
> +			scan_bg(fd, fgroup);
> +	}
> +	if (histcount && !gflag)
> +		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 (bglist)
> +		free(bglist);
> +	if (hist)
> +		free(hist);
> +	close(fd);
> +
> +	return 0;
> +}
> 


Cheers, Andreas






[-- Attachment #2: Message signed with OpenPGP --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

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

* Re: [PATCH 2/3] e2info: create a tool to display ext4 fs geometry online
  2017-03-02  4:52 ` [PATCH 2/3] e2info: create a tool to display ext4 fs geometry online Darrick J. Wong
@ 2017-03-02 19:49   ` Andreas Dilger
  2017-03-02 21:50     ` Darrick J. Wong
  0 siblings, 1 reply; 11+ messages in thread
From: Andreas Dilger @ 2017-03-02 19:49 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: tytso, linux-ext4

[-- Attachment #1: Type: text/plain, Size: 17214 bytes --]

On Mar 1, 2017, at 9:52 PM, Darrick J. Wong <darrick.wong@oracle.com> wrote:
> 
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Create e2info, which reports the fs geometry of an online ext4 filesystem.

Besides providing a place to call the new EXT4_IOC_FSGEOMETRY ioctl, I
don't see how this is much different from "dumpe2fs -h"?

Cheers, Andreas

> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
> configure            |    4 +
> configure.ac         |    3 +
> lib/ext2fs/ext2_fs.h |   34 ++++++++
> misc/Makefile.in     |   30 ++++++-
> misc/e2info.8.in     |   64 ++++++++++++++++
> misc/e2info.c        |  205 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 6 files changed, 336 insertions(+), 4 deletions(-)
> create mode 100644 misc/e2info.8.in
> create mode 100644 misc/e2info.c
> 
> 
> diff --git a/configure b/configure
> index 5f7b429..b553da1 100755
> --- a/configure
> +++ b/configure
> @@ -642,6 +642,7 @@ root_prefix
> UNIX_CMT
> CYGWIN_CMT
> LINUX_CMT
> +E2INFO_CMT
> UNI_DIFF_OPTS
> SEM_INIT_LIB
> FUSE_CMT
> @@ -13663,13 +13664,16 @@ fi
> { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UNI_DIFF_OPTS" >&5
> $as_echo "$UNI_DIFF_OPTS" >&6; }
> 
> +E2INFO_CMT="#"
> case "$host_os" in
> linux*)
> 
> $as_echo "#define HAVE_EXT2_IOCTLS 1" >>confdefs.h
> 
> +	E2INFO_CMT=
> 	;;
> esac
> +
> LINUX_CMT="#"
> CYGWIN_CMT="#"
> UNIX_CMT=
> diff --git a/configure.ac b/configure.ac
> index 9da7b86..bf613fd 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -1260,11 +1260,14 @@ AC_SUBST(UNI_DIFF_OPTS)
> dnl
> dnl We use the EXT2 ioctls only under Linux
> dnl
> +E2INFO_CMT="#"
> case "$host_os" in
> linux*)
> 	AC_DEFINE(HAVE_EXT2_IOCTLS, 1, [Define to 1 if Ext2 ioctls present])
> +	E2INFO_CMT=
> 	;;
> esac
> +AC_SUBST(E2INFO_CMT)
> dnl
> dnl OS-specific uncomment control
> dnl
> diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> index 27a7d3a..bad7648 100644
> --- a/lib/ext2fs/ext2_fs.h
> +++ b/lib/ext2fs/ext2_fs.h
> @@ -372,6 +372,40 @@ struct ext4_new_group_input {
> #define EXT4_IOC_GROUP_ADD		_IOW('f', 8,struct ext4_new_group_input)
> #define EXT4_IOC_RESIZE_FS		_IOW('f', 16, __u64)
> 
> +/* ext4 fs geometry. */
> +struct ext4_fsop_geom {
> +	__u32		efg_blocksize;	/* filesystem (data) block size */
> +	__u32		efg_bgblocks;	/* fsblocks in an AG		*/
> +	__u32		efg_bgcount;	/* number of allocation groups	*/
> +	__u32		efg_logblocks;	/* fsblocks in the log		*/
> +	__u32		efg_resvblocks;	/* number of reserved blocks	*/
> +	__u32		efg_inodesize;	/* inode size in bytes		*/
> +	__u32		efg_bg_iblocks;	/* inode blocks per AG		*/
> +	__u32		efg_flags;	/* superblock version flags	*/
> +	__u64		efg_inodecount;	/* inode count			*/
> +	__u64		efg_blockcount;	/* fsblocks in filesystem	*/
> +	unsigned char	efg_uuid[16];	/* unique id of the filesystem	*/
> +	__u32		efg_sunit;	/* stripe unit, fsblocks	*/
> +	__u32		efg_swidth;	/* stripe width, fsblocks	*/
> +	__u32		efg_clustersize;/* fs cluster size		*/
> +	__u32		efg_flexbgsize;	/* number of bg's in a flexbg	*/
> +	__u64		efg_resv[6];
> +};
> +
> +#define EXT4_FSOP_GEOM_FLAGS_ATTR	0x00001	/* extended attr in use	 */
> +#define EXT4_FSOP_GEOM_FLAGS_NLINK	0x00002	/* 32-bit nlink values	 */
> +#define EXT4_FSOP_GEOM_FLAGS_QUOTA	0x00004	/* quotas enabled	 */
> +#define EXT4_FSOP_GEOM_FLAGS_PROJQ	0x00008	/* project quotas	 */
> +#define EXT4_FSOP_GEOM_FLAGS_META_CSUM	0x00010	/* metadata checksums	 */
> +#define EXT4_FSOP_GEOM_FLAGS_FTYPE	0x00020	/* inode directory types */
> +#define EXT4_FSOP_GEOM_FLAGS_64BIT	0x00040	/* 64-bit support	 */
> +#define EXT4_FSOP_GEOM_FLAGS_INLINEDATA	0x00080	/* inline data		 */
> +#define EXT4_FSOP_GEOM_FLAGS_ENCRYPT	0x00100	/* encrypted files	 */
> +#define EXT4_FSOP_GEOM_FLAGS_LARGEDIR	0x00200	/* large directories	 */
> +#define EXT4_FSOP_GEOM_FLAGS_EXTENTS	0x00400	/* extents		 */
> +
> +#define EXT4_IOC_FSGEOMETRY		_IOR ('f', 19, struct ext4_fsop_geom)
> +
> /*
>  * Structure of an inode on the disk
>  */
> diff --git a/misc/Makefile.in b/misc/Makefile.in
> index 467c15d..311aa57 100644
> --- a/misc/Makefile.in
> +++ b/misc/Makefile.in
> @@ -32,14 +32,19 @@ INSTALL = @INSTALL@
> 
> @FUSE_CMT@FUSE_PROG= fuse2fs
> 
> +@E2INFO_CMT@E2INFO_PROG= e2info
> +@E2INFO_CMT@E2INFO_MAN= e2info.8
> +
> SPROGS=		mke2fs badblocks tune2fs dumpe2fs $(BLKID_PROG) logsave \
> 			$(E2IMAGE_PROG) @FSCK_PROG@ e2undo
> USPROGS=	mklost+found filefrag e2freefrag $(UUIDD_PROG) \
> -			$(E4DEFRAG_PROG) $(E4CRYPT_PROG) $(FUSE_PROG)
> +			$(E4DEFRAG_PROG) $(E4CRYPT_PROG) $(FUSE_PROG) \
> +			$(E2INFO_PROG)
> SMANPAGES=	tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \
> 			e2label.8 $(FINDFS_MAN) $(BLKID_MAN) $(E2IMAGE_MAN) \
> 			logsave.8 filefrag.8 e2freefrag.8 e2undo.8 \
> -			$(UUIDD_MAN) $(E4DEFRAG_MAN) $(E4CRYPT_MAN) @FSCK_MAN@
> +			$(UUIDD_MAN) $(E4DEFRAG_MAN) $(E4CRYPT_MAN) @FSCK_MAN@ \
> +			$(E2INFO_MAN)
> FMANPAGES=	mke2fs.conf.5 ext4.5
> 
> UPROGS=		chattr lsattr @UUID_CMT@ uuidgen
> @@ -68,6 +73,7 @@ E4CRYPT_OBJS=   e4crypt.o
> E2FREEFRAG_OBJS= e2freefrag.o
> E2FUZZ_OBJS=	e2fuzz.o
> FUSE2FS_OBJS=	fuse2fs.o journal.o recovery.o revoke.o
> +E2INFO_OBJS=	e2info.o
> 
> PROFILED_TUNE2FS_OBJS=	profiled/tune2fs.o profiled/util.o
> PROFILED_MKLPF_OBJS=	profiled/mklost+found.o
> @@ -90,8 +96,9 @@ PROFILED_E2FREEFRAG_OBJS= profiled/e2freefrag.o
> PROFILED_E2UNDO_OBJS=	profiled/e2undo.o
> PROFILED_E4DEFRAG_OBJS=	profiled/e4defrag.o
> PROFILED_E4CRYPT_OBJS=	profiled/e4crypt.o
> -PROFILED_FUSE2FS_OJBS=	profiled/fuse2fs.o profiled/journal.o \
> +PROFILED_FUSE2FS_OBJS=	profiled/fuse2fs.o profiled/journal.o \
> 			profiled/recovery.o profiled/revoke.o
> +PROFILED_E2INFO_OBJS=	profiled/e2info.o
> 
> SRCS=	$(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c $(srcdir)/mk_hugefiles.c \
> 		$(srcdir)/chattr.c $(srcdir)/lsattr.c $(srcdir)/dumpe2fs.c \
> @@ -102,7 +109,7 @@ SRCS=	$(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c $(srcdir)/
> 		$(srcdir)/e2freefrag.c $(srcdir)/create_inode.c \
> 		$(srcdir)/fuse2fs.c \
> 		$(srcdir)/../debugfs/journal.c $(srcdir)/../e2fsck/revoke.c \
> -		$(srcdir)/../e2fsck/recovery.c
> +		$(srcdir)/../e2fsck/recovery.c $(srcdir)/e2info.c
> 
> LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBSUPPORT)
> DEPLIBS= $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBSUPPORT)
> @@ -391,6 +398,11 @@ fuse2fs: $(FUSE2FS_OBJS) $(DEPLIBS) $(DEPLIBBLKID) $(DEPLIBUUID) \
> 		$(LIBFUSE) $(LIBBLKID) $(LIBUUID) $(LIBEXT2FS) $(LIBINTL) \
> 		$(CLOCK_GETTIME_LIB) $(SYSLIBS)
> 
> +e2info: $(E2INFO_OBJS) $(DEPLIBS)
> +	$(E) "	LD $@"
> +	$(Q) $(CC) $(ALL_LDFLAGS) -o e2info $(E2INFO_OBJS) $(LIBINTL) \
> +		$(SYSLIBS)
> +
> journal.o: $(srcdir)/../debugfs/journal.c
> 	$(E) "	CC $@"
> 	$(Q) $(CC) -c $(JOURNAL_CFLAGS) -I$(srcdir) \
> @@ -411,6 +423,10 @@ tst_ismounted: $(srcdir)/ismounted.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
> 	$(CC) -o tst_ismounted $(srcdir)/ismounted.c -DDEBUG $(ALL_CFLAGS) \
> 		$(LIBCOM_ERR) $(SYSLIBS)
> 
> +e2info.8: $(DEP_SUBSTITUTE) $(srcdir)/e2info.8.in
> +	$(E) "	SUBST $@"
> +	$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2info.8.in e2info.8
> +
> tune2fs.8: $(DEP_SUBSTITUTE) $(srcdir)/tune2fs.8.in
> 	$(E) "	SUBST $@"
> 	$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/tune2fs.8.in tune2fs.8
> @@ -844,3 +860,9 @@ recovery.o: $(srcdir)/../e2fsck/recovery.c $(srcdir)/../e2fsck/jfs_user.h \
>  $(top_srcdir)/lib/support/quotaio_tree.h \
>  $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \
>  $(top_srcdir)/lib/ext2fs/kernel-list.h
> +e2info.o: $(srcdir)/e2info.c $(top_builddir)/lib/config.h \
> + $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
> + $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
> + $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
> + $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
> + $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h
> diff --git a/misc/e2info.8.in b/misc/e2info.8.in
> new file mode 100644
> index 0000000..c7f580f
> --- /dev/null
> +++ b/misc/e2info.8.in
> @@ -0,0 +1,64 @@
> +.\" -*- nroff -*-
> +.\" Copyright 2017 Oracle Inc.  All Rights Reserved.
> +.\" This file may be copied under the terms of the GNU Public License.
> +.\"
> +.\" Verbatim blocks taken from openssl req manpage content
> +.de Vb \" Begin verbatim text
> +.ft CW
> +.nf
> +.ne \\$1
> +..
> +.de Ve \" End verbatim text
> +.ft R
> +.fi
> +..
> +
> +.TH E2INFO 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
> +.SH NAME
> +e2info \- Display information about a mounted ext4 filesystem
> +.SH SYNOPSIS
> +.B e2info
> +.I mount-point
> +.br
> +.B e2info \-V
> +.SH DESCRIPTION
> +Prints the filesystem geometry of an ext4 filesystem.  If the mounted
> +filesystem is an ext2 or ext3 filesystem mounted with the ext4 driver,
> +the geometry will be displayed.
> +.SH "EXAMPLES"
> +
> +Understanding e2info output.
> +.PP
> +Suppose one has the following "e2info /dev/sda" output:
> +.PP
> +.RS 2
> +.Vb
> +\&meta-data=/dev/loop0             isize=256    bgcount=14808 bgsize=32768 blks
> +\&         =                       attr=1       quota=0 pquota=0
> +\&         =                       crc=0        64bit=0 inlinedata=0 extents=1
> +\&         =                       flexbg=16
> +\&data     =                       bsize=4096   blocks=485198848 bg_iblocks=512
> +\&         =                       sunit=32     swidth=128 blks clustersize=0
> +\&         =                       encrypt=0
> +\&naming   =                       bsize=4096   largedir=0 ftype=1 nlink=1
> +\&log      =                       bsize=4096   blocks=32768
> +.Ve
> +.RE
> +.PP
> +
> +Here, the data section of the output indicates "bsize=4096",
> +meaning the data block size for this filesystem is 4096 bytes.
> +This section also shows "sunit=32 swidth=128 blks", which means
> +the stripe unit is 32*4096 bytes = 128 kibibytes and the stripe
> +width is 128*4096 bytes = 512 kibibytes.
> +A single stripe of this filesystem therefore consists
> +of four stripe units (128 blocks / 32 blocks per unit).
> +Note also that "flexbg=16", which means that this filesystem has
> +512MB flex block groups.
> +That is the upper limit of how much physical disk space can be mapped
> +into a file.
> +.SH SEE ALSO
> +.BR mkfs.ext4 (8),
> +.BR md (4),
> +.BR lvm (8),
> +.BR mount (8).
> diff --git a/misc/e2info.c b/misc/e2info.c
> new file mode 100644
> index 0000000..675f005
> --- /dev/null
> +++ b/misc/e2info.c
> @@ -0,0 +1,205 @@
> +/*
> + * 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 "config.h"
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <libgen.h>
> +#include <unistd.h>
> +#include <sys/ioctl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <mntent.h>
> +#include <limits.h>
> +
> +#include "ext2fs/ext2_fs.h"
> +
> +#include "../version.h"
> +#include "support/nls-enable.h"
> +
> +static const char *progname = "e2info";
> +
> +static void
> +usage(void)
> +{
> +	fprintf(stderr, _(
> +"Usage: %s [options] mountpoint\n\n\
> +	-V          print version information\n"),
> +		progname);
> +	exit(2);
> +}
> +
> +#define PROC_MOUNTS	"/proc/mounts"
> +int
> +find_datadev(
> +	const char	*arg,
> +	char		*datadev,
> +	char		*mntpoint)
> +{
> +	struct mntent	*mnt;
> +	FILE		*mtp;
> +	char		*mtab_file;
> +	char		rmnt_fsname[PATH_MAX], rmnt_dir[PATH_MAX];
> +	struct stat	sbuf;
> +	dev_t		fd_dev;
> +
> +	if (stat(arg, &sbuf) < 0)
> +		return errno;
> +	/*
> +	 * We want to match st_rdev if the path provided is a device
> +	 * special file.  Otherwise we are looking for the the
> +	 * device id for the containing filesystem, in st_dev.
> +	 */
> +	if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode))
> +		fd_dev = sbuf.st_rdev;
> +	else
> +		fd_dev = sbuf.st_dev;
> +
> +	mtab_file = PROC_MOUNTS;
> +	if (access(mtab_file, R_OK) != 0)
> +		mtab_file = MOUNTED;
> +
> +	if ((mtp = setmntent(mtab_file, "r")) == NULL)
> +		return ENOENT;
> +
> +	while ((mnt = getmntent(mtp)) != NULL) {
> +		if (!realpath(mnt->mnt_dir, rmnt_dir))
> +			continue;
> +		if (!realpath(mnt->mnt_fsname, rmnt_fsname))
> +			continue;
> +
> +		if (stat(rmnt_fsname, &sbuf) < 0)
> +			continue;
> +		if (sbuf.st_rdev == fd_dev) {
> +			strncpy(datadev, rmnt_fsname, PATH_MAX);
> +			strncpy(mntpoint, rmnt_dir, PATH_MAX);
> +			break;
> +		}
> +	}
> +	endmntent(mtp);
> +	return 0;
> +}
> +
> +int
> +main(int argc, char **argv)
> +{
> +	struct ext4_fsop_geom	geo;
> +	char			*progname;
> +	int			fd;
> +	int			c;
> +	int			attr_enabled;
> +	int			nlink_enabled;
> +	int			quota_enabled;
> +	int			projquota_enabled;
> +	int			metacrc_enabled;
> +	int			ftype_enabled;
> +	int			is_64bit;
> +	int			inlinedata_enabled;
> +	int			encrypt_enabled;
> +	int			largedir_enabled;
> +	int			extents_enabled;
> +	char			datadev[PATH_MAX];
> +	char			mntpoint[PATH_MAX];
> +
> +	progname = basename(argv[0]);
> +#ifdef ENABLE_NLS
> +	setlocale(LC_ALL, "");
> +	bindtextdomain(PACKAGE, LOCALEDIR);
> +	textdomain(PACKAGE);
> +#endif
> +
> +	while ((c = getopt(argc, argv, "V")) != EOF) {
> +		switch (c) {
> +		case 'V':
> +			printf(_("%s version %s\n"), progname, VERSION);
> +			exit(0);
> +		case '?':
> +		default:
> +			usage();
> +		}
> +	}
> +	if (argc - optind != 1)
> +		usage();
> +
> +	fd = open(argv[optind], O_RDONLY);
> +	if (fd < 0) {
> +		perror(argv[optind]);
> +		return 1;
> +	}
> +
> +	if (find_datadev(argv[optind], datadev, mntpoint)) {
> +		perror("find_datadev");
> +		strncpy(datadev, argv[optind], PATH_MAX);
> +		strncpy(mntpoint, argv[optind], PATH_MAX);
> +	}
> +
> +	close(fd);
> +	fd = open(mntpoint, O_RDONLY);
> +	if (fd < 0) {
> +		perror(mntpoint);
> +		return 1;
> +	}
> +
> +	/* get the current filesystem size & geometry */
> +	if (ioctl(fd, EXT4_IOC_FSGEOMETRY, &geo) < 0) {
> +		fprintf(stderr, _(
> +			"%s: cannot determine geometry of filesystem"
> +			" mounted at %s: %s\n"),
> +			progname, argv[optind], strerror(errno));
> +		exit(1);
> +	}
> +
> +	attr_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_ATTR ? 1 : 0;
> +	nlink_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_NLINK ? 1 : 0;
> +	quota_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_QUOTA ? 1 : 0;
> +	projquota_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_PROJQ ? 1 : 0;
> +	metacrc_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_META_CSUM ? 1 : 0;
> +	ftype_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_FTYPE ? 1 : 0;
> +	is_64bit = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_64BIT ? 1 : 0;
> +	inlinedata_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_INLINEDATA ? 1 : 0;
> +	encrypt_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_ENCRYPT ? 1 : 0;
> +	largedir_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_LARGEDIR ? 1 : 0;
> +	extents_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_EXTENTS ? 1 : 0;
> +
> +	printf(_(
> +	    "meta-data=%-22s isize=%-6u bgcount=%u bgsize=%u blks\n"
> +	    "         =%-22s attr=%-7u quota=%u pquota=%u\n"
> +	    "         =%-22s crc=%-8u 64bit=%u inlinedata=%u extents=%u\n"
> +	    "         =%-22s flexbg=%u\n"
> +	    "data     =%-22s bsize=%-6u blocks=%llu bg_iblocks=%u\n"
> +	    "         =%-22s sunit=%-6u swidth=%u blks clustersize=%u\n"
> +	    "         =%-22s encrypt=%u\n"
> +	    "naming   =%-22s bsize=%-6u largedir=%d ftype=%d nlink=%u\n"
> +	    "log      =%-22s bsize=%-6u blocks=%u\n"),
> +		datadev, geo.efg_inodesize, geo.efg_bgcount, geo.efg_bgblocks,
> +		"", attr_enabled, quota_enabled, projquota_enabled,
> +		"", metacrc_enabled, is_64bit, inlinedata_enabled,
> +			extents_enabled,
> +		"", geo.efg_flexbgsize,
> +		"", geo.efg_blocksize, (unsigned long long)geo.efg_blockcount,
> +			geo.efg_bg_iblocks,
> +		"", geo.efg_sunit, geo.efg_swidth, geo.efg_clustersize,
> +		"", encrypt_enabled,
> +		"", geo.efg_blocksize, largedir_enabled, ftype_enabled,
> +			nlink_enabled,
> +		"", geo.efg_blocksize, geo.efg_logblocks);
> +
> +	exit(0);
> +}
> 


Cheers, Andreas






[-- Attachment #2: Message signed with OpenPGP --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

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

* Re: [PATCH 3/3] e2spacey: create a program to use getfsmap to profile free space
  2017-03-02 19:45   ` Andreas Dilger
@ 2017-03-02 21:27     ` Darrick J. Wong
  0 siblings, 0 replies; 11+ messages in thread
From: Darrick J. Wong @ 2017-03-02 21:27 UTC (permalink / raw)
  To: Andreas Dilger; +Cc: Theodore Ts'o, linux-ext4

On Thu, Mar 02, 2017 at 12:45:24PM -0700, Andreas Dilger wrote:
> On Mar 1, 2017, at 9:52 PM, Darrick J. Wong <darrick.wong@oracle.com> wrote:
> > 
> > From: Darrick J. Wong <darrick.wong@oracle.com>
> > 
> > e2spacey is a new tool that uses the GETFSMAP ioctl and the FSGEOMETRY
> > ioctl to find all the free extents in a mounted filesystem and display
> > either per-flexbg free block counts or a histogram of free extents.
> > At this point it's mostly useful as a debugging tool.
> 
> It would be better to wire the GETFSMAP ioctl into e2freefrag.c to use
> on mounted filesystems, rather than introducing a new-but-almost-identical
> tool.  e2freefrag has existed for a long time already and is doing this
> same thing (reporting a histogram of free extents).  If there is some new
> functionality that GETFSMAP allows, it could be added as a new option to
> e2freefrag as well.
> 
> Otherwise, we have two tools to maintain, and we couldn't even deprecate
> e2freefrag (assuming we wanted to) since e2spacey only works on mounted
> filesystems.

Good point.  e2spacey had the interesting feature that it could return
per-flexbg information, but I'm not sure that has much use outside of
developer debugging.

It wasn't that hard to enhance e2freefrag to figure out that the
filesystem is mounted and use the getfsmap information to get live free
space information from the fs, so I'll post that patch later.

--D

> 
> Cheers, Andreas
> 
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> > Makefile.in          |    3
> > configure            |    6 +
> > configure.ac         |    5 -
> > lib/ext2fs/ext2_fs.h |    8 +
> > spacey/Makefile.in   |  152 +++++++++++++++++
> > spacey/e2spacey.8.in |   65 +++++++
> > spacey/fsmap.h       |   89 ++++++++++
> > spacey/main.c        |  456 ++++++++++++++++++++++++++++++++++++++++++++++++++
> > 8 files changed, 781 insertions(+), 3 deletions(-)
> > create mode 100644 spacey/Makefile.in
> > create mode 100644 spacey/e2spacey.8.in
> > create mode 100644 spacey/fsmap.h
> > create mode 100644 spacey/main.c
> > 
> > 
> > diff --git a/Makefile.in b/Makefile.in
> > index 7da9ad7..b48d0f9 100644
> > --- a/Makefile.in
> > +++ b/Makefile.in
> > @@ -13,10 +13,11 @@ INSTALL = @INSTALL@
> > @DEBUGFS_CMT@DEBUGFS_DIR= debugfs
> > @UUID_CMT@UUID_LIB_SUBDIR= lib/uuid
> > @BLKID_CMT@BLKID_LIB_SUBDIR= lib/blkid
> > +@SPACEY_CMT@SPACEY_DIR= spacey
> > SUPPORT_LIB_SUBDIR= lib/support
> > 
> > LIB_SUBDIRS=lib/et lib/ss lib/e2p $(UUID_LIB_SUBDIR) $(BLKID_LIB_SUBDIR) $(SUPPORT_LIB_SUBDIR) lib/ext2fs intl
> > -PROG_SUBDIRS=e2fsck $(DEBUGFS_DIR) misc $(RESIZE_DIR) tests/progs po
> > +PROG_SUBDIRS=e2fsck $(DEBUGFS_DIR) misc $(RESIZE_DIR) tests/progs po $(SPACEY_DIR)
> > SUBDIRS=util $(LIB_SUBDIRS) $(PROG_SUBDIRS) tests
> > 
> > SUBS= util/subst.conf lib/config.h $(top_builddir)/lib/dirpaths.h \
> > diff --git a/configure b/configure
> > index b553da1..940b11c 100755
> > --- a/configure
> > +++ b/configure
> > @@ -642,6 +642,7 @@ root_prefix
> > UNIX_CMT
> > CYGWIN_CMT
> > LINUX_CMT
> > +SPACEY_CMT
> > E2INFO_CMT
> > UNI_DIFF_OPTS
> > SEM_INIT_LIB
> > @@ -13665,15 +13666,18 @@ fi
> > $as_echo "$UNI_DIFF_OPTS" >&6; }
> > 
> > E2INFO_CMT="#"
> > +SPACEY_CMT="#"
> > case "$host_os" in
> > linux*)
> > 
> > $as_echo "#define HAVE_EXT2_IOCTLS 1" >>confdefs.h
> > 
> > 	E2INFO_CMT=
> > +	SPACEY_CMT=
> > 	;;
> > esac
> > 
> > +
> > LINUX_CMT="#"
> > CYGWIN_CMT="#"
> > UNIX_CMT=
> > @@ -13875,7 +13879,7 @@ for i in MCONFIG Makefile e2fsprogs.spec \
> > 	misc/Makefile ext2ed/Makefile e2fsck/Makefile \
> > 	debugfs/Makefile tests/Makefile tests/progs/Makefile \
> > 	resize/Makefile doc/Makefile intl/Makefile \
> > -	intl/libgnuintl.h po/Makefile.in ; do
> > +	intl/libgnuintl.h po/Makefile.in spacey/Makefile ; do
> > 	if test -d `dirname ${srcdir}/$i` ; then
> > 		outlist="$outlist $i"
> > 	fi
> > diff --git a/configure.ac b/configure.ac
> > index bf613fd..5b95f6b 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -1261,13 +1261,16 @@ dnl
> > dnl We use the EXT2 ioctls only under Linux
> > dnl
> > E2INFO_CMT="#"
> > +SPACEY_CMT="#"
> > case "$host_os" in
> > linux*)
> > 	AC_DEFINE(HAVE_EXT2_IOCTLS, 1, [Define to 1 if Ext2 ioctls present])
> > 	E2INFO_CMT=
> > +	SPACEY_CMT=
> > 	;;
> > esac
> > AC_SUBST(E2INFO_CMT)
> > +AC_SUBST(SPACEY_CMT)
> > dnl
> > dnl OS-specific uncomment control
> > dnl
> > @@ -1469,7 +1472,7 @@ for i in MCONFIG Makefile e2fsprogs.spec \
> > 	misc/Makefile ext2ed/Makefile e2fsck/Makefile \
> > 	debugfs/Makefile tests/Makefile tests/progs/Makefile \
> > 	resize/Makefile doc/Makefile intl/Makefile \
> > -	intl/libgnuintl.h po/Makefile.in ; do
> > +	intl/libgnuintl.h po/Makefile.in spacey/Makefile ; do
> > 	if test -d `dirname ${srcdir}/$i` ; then
> > 		outlist="$outlist $i"
> > 	fi
> > diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> > index bad7648..4beebb6 100644
> > --- a/lib/ext2fs/ext2_fs.h
> > +++ b/lib/ext2fs/ext2_fs.h
> > @@ -406,6 +406,14 @@ struct ext4_fsop_geom {
> > 
> > #define EXT4_IOC_FSGEOMETRY		_IOR ('f', 19, struct ext4_fsop_geom)
> > 
> > +/* Custom FS_IOC_GETFSMAP owner codes */
> > +#define EXT4_FMR_OWN_FREE	FMR_OWN_FREE      /* free space */
> > +#define EXT4_FMR_OWN_UNKNOWN	FMR_OWN_UNKNOWN   /* unknown owner */
> > +#define EXT4_FMR_OWN_GDT	FMR_OWNER('f', 1) /* group descriptors */
> > +#define EXT4_FMR_OWN_RESV_GDT	FMR_OWNER('f', 2) /* reserved gdt blocks */
> > +#define EXT4_FMR_OWN_BLKBM	FMR_OWNER('f', 3) /* inode bitmap */
> > +#define EXT4_FMR_OWN_INOBM	FMR_OWNER('f', 4) /* block bitmap */
> > +
> > /*
> >  * Structure of an inode on the disk
> >  */
> > diff --git a/spacey/Makefile.in b/spacey/Makefile.in
> > new file mode 100644
> > index 0000000..3c842f3
> > --- /dev/null
> > +++ b/spacey/Makefile.in
> > @@ -0,0 +1,152 @@
> > +#
> > +# Makefile for e2spacey
> > +#
> > +
> > +srcdir = @srcdir@
> > +top_srcdir = @top_srcdir@
> > +VPATH = @srcdir@
> > +top_builddir = ..
> > +my_dir = scrub
> > +INSTALL = @INSTALL@
> > +
> > +@MCONFIG@
> > +
> > +PROGS=		e2spacey
> > +MANPAGES=	e2spacey.8
> > +
> > +LIBS= $(LIBSUPPORT) $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBBLKID) $(LIBUUID) \
> > +	$(LIBINTL) $(LIBE2P) $(LIBMAGIC) $(SYSLIBS)
> > +DEPLIBS= $(DEPLIBSUPPORT) $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBBLKID) \
> > +	 $(DEPLIBUUID) $(DEPLIBE2P)
> > +
> > +STATIC_LIBS= $(STATIC_LIBSUPPORT) $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) \
> > +	     $(STATIC_LIBBLKID) $(STATIC_LIBUUID) $(LIBINTL) $(STATIC_LIBE2P) \
> > +	     $(LIBMAGIC) $(SYSLIBS)
> > +STATIC_DEPLIBS= $(DEPSTATIC_LIBSUPPORT) $(STATIC_LIBEXT2FS) \
> > +		$(DEPSTATIC_LIBCOM_ERR) $(DEPSTATIC_LIBBLKID) \
> > +		$(DEPSTATIC_LIBUUID) $(DEPSTATIC_LIBE2P)
> > +
> > +PROFILED_LIBS= $(PROFILED_LIBSUPPORT) $(PROFILED_LIBEXT2FS) \
> > +	       $(PROFILED_LIBCOM_ERR) $(PROFILED_LIBBLKID) $(PROFILED_LIBUUID) \
> > +	       $(PROFILED_LIBE2P) $(LIBINTL) $(LIBMAGIC) $(SYSLIBS)
> > +PROFILED_DEPLIBS= $(DEPPROFILED_LIBSUPPORT) $(PROFILED_LIBEXT2FS) \
> > +		  $(DEPPROFILED_LIBCOM_ERR) $(DEPPROFILED_LIBBLKID) \
> > +		  $(DEPPROFILED_LIBUUID) $(DEPPROFILED_LIBE2P)
> > +
> > +COMPILE_ET=	_ET_DIR_OVERRIDE=$(srcdir)/../lib/et/et ../lib/et/compile_et
> > +
> > +.c.o:
> > +	$(E) "	CC $<"
> > +	$(Q) $(CC) -c $(ALL_CFLAGS) $< -o $@
> > +	$(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
> > +	$(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
> > +@PROFILE_CMT@	$(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/$*.o -c $<
> > +
> > +#
> > +# Flags for doing mtrace --- uncomment to produce mtracing e2spacey
> > +# 	Note:  The optimization flags must include -g
> > +#
> > +#MTRACE=	-DMTRACE
> > +#MTRACE_OBJ= mtrace.o
> > +#MTRACE_SRC= $(srcdir)/mtrace.c
> > +#OPT= -g
> > +
> > +#
> > +# Flags for doing mcheck --- uncomment to produce mchecking e2spacey
> > +# 	Note:  The optimization flags must include -g
> > +#
> > +#MCHECK= -DMCHECK
> > +
> > +OBJS= main.o
> > +
> > +PROFILED_OBJS= profiled/main.o
> > +
> > +SRCS= $(srcdir)/main.o
> > +
> > +all:: profiled $(PROGS) $(MANPAGES)
> > +
> > +@PROFILE_CMT@all:: e2spacey.profiled
> > +
> > +e2spacey: $(OBJS)  $(DEPLIBS)
> > +	$(E) "	LD $@"
> > +	$(Q) $(LD) $(ALL_LDFLAGS) $(RDYNAMIC) -o e2spacey $(OBJS) $(LIBS)
> > +
> > +e2spacey.static: $(OBJS) $(STATIC_DEPLIBS)
> > +	$(E) "	LD $@"
> > +	$(Q) $(LD) $(LDFLAGS_STATIC) -o e2spacey.static $(OBJS) $(STATIC_LIBS) -lpthread
> > +
> > +e2spacey.profiled: $(OBJS)  $(PROFILED_DEPLIBS)
> > +	$(E) "	LD $@"
> > +	$(Q) $(LD) $(ALL_LDFLAGS) -g -pg -o e2spacey.profiled $(PROFILED_OBJS) \
> > +		$(PROFILED_LIBS) -lpthread
> > +
> > +test_profile: $(srcdir)/profile.c profile_helpers.o argv_parse.o \
> > +		prof_err.o profile.h $(DEPSTATIC_LIBCOM_ERR)
> > +	$(E) "	LD $@"
> > +	$(Q) $(CC) -o test_profile -DDEBUG_PROGRAM $(srcdir)/profile.c prof_err.o \
> > +		profile_helpers.o argv_parse.o $(STATIC_LIBCOM_ERR) \
> > +		$(ALL_CFLAGS)
> > +
> > +profiled:
> > +@PROFILE_CMT@	$(E) "	MKDIR $@"
> > +@PROFILE_CMT@	$(Q) mkdir profiled
> > +
> > +e2spacey.8: $(DEP_SUBSTITUTE) $(srcdir)/e2spacey.8.in
> > +	$(E) "	SUBST $@"
> > +	$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2spacey.8.in e2spacey.8
> > +
> > +installdirs:
> > +	$(E) "	MKINSTALLDIRS $(root_sbindir) $(man8dir)"
> > +	$(Q) $(MKINSTALLDIRS) $(DESTDIR)$(root_sbindir) \
> > +		$(DESTDIR)$(man8dir) $(DESTDIR)$(man5dir)
> > +
> > +install: $(PROGS) $(MANPAGES) $(FMANPAGES) installdirs
> > +	$(Q) for i in $(PROGS); do \
> > +		$(ES) "	INSTALL $(root_sbindir)/$$i"; \
> > +		$(INSTALL_PROGRAM) $$i $(DESTDIR)$(root_sbindir)/$$i; \
> > +	done
> > +	$(Q) for i in $(MANPAGES); do \
> > +		for j in $(COMPRESS_EXT); do \
> > +			$(RM) -f $(DESTDIR)$(man8dir)/$$i.$$j; \
> > +		done; \
> > +		$(ES) "	INSTALL_DATA $(man8dir)/$$i"; \
> > +		$(INSTALL_DATA) $$i $(DESTDIR)$(man8dir)/$$i; \
> > +	done
> > +
> > +install-strip: install
> > +	$(Q) for i in $(PROGS); do \
> > +		$(ES) "	STRIP $(root_sbindir)/$$i"; \
> > +		$(STRIP) $(DESTDIR)$(root_sbindir)/$$i; \
> > +	done
> > +
> > +uninstall:
> > +	for i in $(PROGS); do \
> > +		$(RM) -f $(DESTDIR)$(root_sbindir)/$$i; \
> > +	done
> > +	for i in $(MANPAGES); do \
> > +		$(RM) -f $(DESTDIR)$(man8dir)/$$i; \
> > +	done
> > +
> > +clean::
> > +	$(RM) -f $(PROGS)
> > +	$(RM) -rf profiled
> > +
> > +mostlyclean: clean
> > +distclean: clean
> > +	$(RM) -f .depend Makefile $(srcdir)/TAGS $(srcdir)/Makefile.in.old
> > +
> > +# +++ Dependency line eater +++
> > +#
> > +# Makefile dependencies follow.  This must be the last section in
> > +# the Makefile.in file
> > +#
> > +main.o: $(srcdir)/main.c $(top_builddir)/lib/config.h \
> > + $(top_builddir)/lib/dirpaths.h $(srcdir)/fsmap.h \
> > + $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
> > + $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
> > + $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
> > + $(top_builddir)/lib/ext2fs/ext2_err.h \
> > + $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
> > + $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \
> > + $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \
> > + $(top_srcdir)/lib/support/quotaio_tree.h
> > diff --git a/spacey/e2spacey.8.in b/spacey/e2spacey.8.in
> > new file mode 100644
> > index 0000000..f4956fc
> > --- /dev/null
> > +++ b/spacey/e2spacey.8.in
> > @@ -0,0 +1,65 @@
> > +.TH E2SPACEY 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
> > +.SH NAME
> > +e2spacey \- show free space information about an ext4 filesystem
> > +.SH SYNOPSIS
> > +.B e2spacey
> > +[
> > +.B \-srg
> > +]
> > +[
> > +.B \-b
> > +|
> > +.B \-e
> > +.I bsize
> > +|
> > +.B \-h
> > +.I h1
> > +[
> > +.B \-m
> > +.I bmult
> > +]
> > +]
> > +[
> > +.B \-a
> > +.I group
> > +]
> > +.I mountpoint
> > +.br
> > +.B e2spacey \-V
> > +.SH DESCRIPTION
> > +.B e2spacey
> > +reports and controls free space usage in an ext4 filesystem.
> > +When the
> > +.B flex_bg
> > +feature is enabled, the free space information is grouped by flex block groups
> > +instead of regular block groups.
> > +This enables reporting of free space extents that span multiple block groups.
> > +
> > +.SH OPTIONS
> > +.TP 1.0i
> > +.BI \-a " group"
> > +Only query the specified block group's free space information.
> > +Multiple options may be provided.
> > +.TP
> > +.B \-b
> > +Establish histogram bins sized in successive powers of two.
> > +.TP
> > +.B \-e
> > +Fix the histogram bin size to a specific value.
> > +.TP
> > +.B \-g
> > +Instead of printing a histogram, simply report the number of free extents
> > +and number of free blocks per block group.
> > +.TP
> > +.BI \-h " hist"
> > +Fix the histogram bin size to a specific initial value.
> > +Use this in comination with the
> > +.B \-m
> > +option to specify a custom histgram bin size growth function.
> > +.TP
> > +.BI \-m " mult"
> > +The size of each histogram bin should be computed by multiplying the
> > +previous bin's size by this quantity.
> > +.TP
> > +.B \-s
> > +Print a summary of the free space before exiting.
> > diff --git a/spacey/fsmap.h b/spacey/fsmap.h
> > new file mode 100644
> > index 0000000..3c5084c
> > --- /dev/null
> > +++ b/spacey/fsmap.h
> > @@ -0,0 +1,89 @@
> > +/*
> > + * 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.
> > + *
> > + * 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
> > + */
> > +#ifndef FSMAP_H_
> > +#define FSMAP_H_
> > +
> > +/* FS_IOC_GETFSMAP ioctl definitions */
> > +#ifndef FS_IOC_GETFSMAP
> > +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 FS_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 /* FS_IOC_GETFSMAP */
> > +
> > +#endif
> > diff --git a/spacey/main.c b/spacey/main.c
> > new file mode 100644
> > index 0000000..009a965
> > --- /dev/null
> > +++ b/spacey/main.c
> > @@ -0,0 +1,456 @@
> > +/*
> > + * 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.
> > + *
> > + * 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 "config.h"
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <libgen.h>
> > +#include <unistd.h>
> > +#include <sys/ioctl.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +#include <errno.h>
> > +#include <mntent.h>
> > +#include <limits.h>
> > +#include "ext2fs/ext2_types.h"
> > +#include "ext2fs/ext2fs.h"
> > +#include "fsmap.h"
> > +#include "ext2fs/ext2_fs.h"
> > +
> > +#include "../version.h"
> > +#include "support/nls-enable.h"
> > +
> > +static const char *progname = "e2spaceman";
> > +
> > +struct histent
> > +{
> > +	blk64_t		low;
> > +	blk64_t		high;
> > +	size_t		count;
> > +	blk64_t		blocks;
> > +};
> > +
> > +static struct ext4_fsop_geom fsgeo;
> > +static struct ext4_fsop_geom flexgeo;
> > +
> > +static struct histent *hist;
> > +static size_t histcount;
> > +
> > +static dgrp_t *bglist;
> > +static size_t bgcount;
> > +
> > +static blk64_t totblocks;
> > +static long long totexts;
> > +
> > +static int equalsize;
> > +static int multsize;
> > +
> > +static int seen1;
> > +static int dumpflag;
> > +static int gflag;
> > +static const char *filename;
> > +static dev_t datadev;
> > +
> > +static inline dgrp_t f2b(dgrp_t fgroup)
> > +{
> > +	return fsgeo.efg_flexbgsize ? fgroup * fsgeo.efg_flexbgsize : fgroup;
> > +}
> > +
> > +static inline dgrp_t b2f(dgrp_t group)
> > +{
> > +	return fsgeo.efg_flexbgsize ? group / fsgeo.efg_flexbgsize : group;
> > +}
> > +
> > +static void usage(void)
> > +{
> > +	fprintf(stderr, _(
> > +"Usage: %s [options] mountpoint\n\n\
> > +	-V          print version information\n"),
> > +		progname);
> > +	exit(2);
> > +}
> > +
> > +#define PROC_MOUNTS	"/proc/mounts"
> > +int find_datadev(const char *arg, dev_t *datadev, char *mntpoint)
> > +{
> > +	struct mntent *mnt;
> > +	FILE *mtp;
> > +	char *mtab_file;
> > +	char rmnt_fsname[PATH_MAX], rmnt_dir[PATH_MAX];
> > +	struct stat sbuf;
> > +	dev_t fd_dev;
> > +
> > +	if (stat(arg, &sbuf) < 0)
> > +		return errno;
> > +	/*
> > +	 * We want to match st_rdev if the path provided is a device
> > +	 * special file.  Otherwise we are looking for the the
> > +	 * device id for the containing filesystem, in st_dev.
> > +	 */
> > +	if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode))
> > +		fd_dev = sbuf.st_rdev;
> > +	else
> > +		fd_dev = sbuf.st_dev;
> > +
> > +	mtab_file = PROC_MOUNTS;
> > +	if (access(mtab_file, R_OK) != 0)
> > +		mtab_file = MOUNTED;
> > +
> > +	if ((mtp = setmntent(mtab_file, "r")) == NULL)
> > +		return ENOENT;
> > +
> > +	while ((mnt = getmntent(mtp)) != NULL) {
> > +		if (!realpath(mnt->mnt_dir, rmnt_dir))
> > +			continue;
> > +		if (!realpath(mnt->mnt_fsname, rmnt_fsname))
> > +			continue;
> > +
> > +		if (stat(rmnt_fsname, &sbuf) < 0)
> > +			continue;
> > +		if (sbuf.st_rdev == fd_dev) {
> > +			*datadev = fd_dev;
> > +			strncpy(mntpoint, rmnt_dir, PATH_MAX);
> > +			break;
> > +		}
> > +	}
> > +	endmntent(mtp);
> > +	return 0;
> > +}
> > +
> > +static void addhistent(blk64_t h)
> > +{
> > +	hist = realloc(hist, (histcount + 1) * sizeof(*hist));
> > +	if (!hist) {
> > +		perror("addhistent");
> > +		exit(2);
> > +	}
> > +	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(dgrp_t group, blk64_t fsb, blk64_t len)
> > +{
> > +	size_t i;
> > +
> > +	if (dumpflag)
> > +		printf("%8u %8llu %8llu\n", group, fsb, 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 ((struct histent *)a)->low - ((struct histent *)b)->low;
> > +}
> > +
> > +static void histinit(blk64_t maxlen)
> > +{
> > +	blk64_t 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)
> > +{
> > +	size_t i;
> > +
> > +	printf("%7s %7s %7s %7s %6s\n",
> > +		_("from"), _("to"), _("extents"), _("blocks"), _("pct"));
> > +	for (i = 0; i < histcount; i++) {
> > +		if (hist[i].count)
> > +			printf("%7llu %7llu %7Zu %7llu %6.2f\n", hist[i].low,
> > +				hist[i].high, hist[i].count, hist[i].blocks,
> > +				hist[i].blocks * 100.0 / totblocks);
> > +	}
> > +}
> > +
> > +static int inbglist(dgrp_t fgroup)
> > +{
> > +	size_t i;
> > +
> > +	if (bgcount == 0)
> > +		return 1;
> > +	for (i = 0; i < bgcount; i++)
> > +		if (b2f(bglist[i]) == fgroup)
> > +			return 1;
> > +	return 0;
> > +}
> > +
> > +#define NR_EXTENTS 1024
> > +
> > +static void scan_bg(int fd, dgrp_t fgroup)
> > +{
> > +	struct fsmap_head *fsmap;
> > +	struct fsmap *extent;
> > +	struct fsmap *l, *h;
> > +	struct fsmap *p;
> > +	off64_t blocksize = flexgeo.efg_blocksize;
> > +	off64_t bytes_per_bg;
> > +	off64_t len;
> > +	blk64_t fsb;
> > +	blk64_t freeblks = 0;
> > +	blk64_t freeexts = 0;
> > +	int ret;
> > +	int i;
> > +
> > +	bytes_per_bg = (off64_t)flexgeo.efg_bgblocks * blocksize;
> > +
> > +	fsmap = malloc(fsmap_sizeof(NR_EXTENTS));
> > +	if (!fsmap) {
> > +		fprintf(stderr, _("%s: fsmap malloc failed.\n"), progname);
> > +		exit(1);
> > +	}
> > +
> > +	memset(fsmap, 0, sizeof(*fsmap));
> > +	fsmap->fmh_count = NR_EXTENTS;
> > +	l = fsmap->fmh_keys;
> > +	h = fsmap->fmh_keys + 1;
> > +	l->fmr_physical = fgroup * bytes_per_bg;
> > +	h->fmr_physical = ((fgroup + 1) * bytes_per_bg) - 1;
> > +	l->fmr_device = h->fmr_device = datadev;
> > +	h->fmr_owner = ULLONG_MAX;
> > +	h->fmr_flags = UINT_MAX;
> > +	h->fmr_offset = ULLONG_MAX;
> > +
> > +	while (1) {
> > +		ret = ioctl(fd, FS_IOC_GETFSMAP, fsmap);
> > +		if (ret < 0) {
> > +			fprintf(stderr,
> > +_("%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n"),
> > +				progname, filename, strerror(errno));
> > +			free(fsmap);
> > +			exit(1);
> > +		}
> > +
> > +		/* 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 != FMR_OWN_FREE)
> > +				continue;
> > +
> > +			fsb = extent->fmr_physical / blocksize;
> > +			len = extent->fmr_length / blocksize;
> > +			freeblks += len;
> > +			freeexts++;
> > +
> > +			addtohist(f2b(fgroup), fsb, len);
> > +		}
> > +
> > +		p = &fsmap->fmh_recs[fsmap->fmh_entries - 1];
> > +		if (p->fmr_flags & FMR_OF_LAST)
> > +			break;
> > +		fsmap_advance(fsmap);
> > +	}
> > +
> > +	if (gflag)
> > +		printf(_("%10u %10llu %10llu\n"), f2b(fgroup), freeexts,
> > +		       freeblks);
> > +}
> > +
> > +static void bglistadd(char *a)
> > +{
> > +	bglist = realloc(bglist, (bgcount + 1) * sizeof(*bglist));
> > +	bglist[bgcount] = (dgrp_t)atoi(a);
> > +	bgcount++;
> > +}
> > +
> > +
> > +static void setup_fsgeo(int fd)
> > +{
> > +	/* Get the current filesystem size & geometry */
> > +	if (ioctl(fd, EXT4_IOC_FSGEOMETRY, &fsgeo) < 0) {
> > +		fprintf(stderr, _(
> > +			"%s: cannot determine geometry of ext4 filesystem"
> > +			" mounted at %s.\n"),
> > +			progname, filename);
> > +		exit(1);
> > +	}
> > +
> > +	/*
> > +	 * Refactor the geometry so that a "group" is the size of the smallest
> > +	 * number of BGs required to contain the longest free extent possible.
> > +	 *
> > +	 * (IOWs, we handle everything in terms of flexbgs.)
> > +	 */
> > +	flexgeo = fsgeo;
> > +	if (fsgeo.efg_flexbgsize) {
> > +		flexgeo.efg_bgblocks *= fsgeo.efg_flexbgsize;
> > +		flexgeo.efg_bgcount = (fsgeo.efg_bgcount +
> > +				       fsgeo.efg_flexbgsize - 1) /
> > +				      fsgeo.efg_flexbgsize;
> > +		flexgeo.efg_bg_iblocks *= fsgeo.efg_flexbgsize;
> > +		flexgeo.efg_flexbgsize = 0;
> > +	}
> > +}
> > +
> > +int main(int argc, char **argv)
> > +{
> > +	char *progname;
> > +	int fd;
> > +	int c;
> > +	char mntpoint[PATH_MAX];
> > +	blk64_t max_extent;
> > +	int speced, summaryflag;
> > +	dgrp_t fgroup;
> > +
> > +	speced = dumpflag = summaryflag = gflag = 0;
> > +
> > +	progname = basename(argv[0]);
> > +#ifdef ENABLE_NLS
> > +	setlocale(LC_ALL, "");
> > +	bindtextdomain(PACKAGE, LOCALEDIR);
> > +	textdomain(PACKAGE);
> > +#endif
> > +
> > +	while ((c = getopt(argc, argv, "a:bde:gh:m:sV")) != EOF) {
> > +		switch (c) {
> > +		case 'a':
> > +			bglistadd(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 'g':
> > +			histcount = 0;
> > +			gflag++;
> > +			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 's':
> > +			summaryflag = 1;
> > +			break;
> > +		case 'V':
> > +			printf(_("%s version %s\n"), progname, VERSION);
> > +			exit(0);
> > +		case '?':
> > +		default:
> > +			usage();
> > +		}
> > +	}
> > +	if (argc - optind != 1)
> > +		usage();
> > +
> > +	filename = argv[optind];
> > +	fd = open(argv[optind], O_RDONLY);
> > +	if (fd < 0) {
> > +		perror(argv[optind]);
> > +		return 1;
> > +	}
> > +
> > +	if (find_datadev(argv[optind], &datadev, mntpoint)) {
> > +		perror("find_datadev");
> > +		exit(1);
> > +	}
> > +
> > +	close(fd);
> > +	fd = open(mntpoint, O_RDONLY);
> > +	if (fd < 0) {
> > +		perror(mntpoint);
> > +		return 1;
> > +	}
> > +
> > +	setup_fsgeo(fd);
> > +
> > +	/* Set up histogram */
> > +	max_extent = flexgeo.efg_bgblocks;
> > +
> > +	if (!speced)
> > +		multsize = 2;
> > +	histinit(max_extent);
> > +
> > +	/* Collect data and print */
> > +	if (gflag)
> > +		printf(_("        AG    extents     blocks\n"));
> > +	for (fgroup = 0; fgroup < flexgeo.efg_bgcount; fgroup++)  {
> > +		if (inbglist(fgroup))
> > +			scan_bg(fd, fgroup);
> > +	}
> > +	if (histcount && !gflag)
> > +		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 (bglist)
> > +		free(bglist);
> > +	if (hist)
> > +		free(hist);
> > +	close(fd);
> > +
> > +	return 0;
> > +}
> > 
> 
> 
> Cheers, Andreas
> 
> 
> 
> 
> 

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

* Re: [PATCH 2/3] e2info: create a tool to display ext4 fs geometry online
  2017-03-02 19:49   ` Andreas Dilger
@ 2017-03-02 21:50     ` Darrick J. Wong
  2017-03-02 22:05       ` Andreas Dilger
  0 siblings, 1 reply; 11+ messages in thread
From: Darrick J. Wong @ 2017-03-02 21:50 UTC (permalink / raw)
  To: Andreas Dilger; +Cc: tytso, linux-ext4

On Thu, Mar 02, 2017 at 12:49:46PM -0700, Andreas Dilger wrote:
> On Mar 1, 2017, at 9:52 PM, Darrick J. Wong <darrick.wong@oracle.com> wrote:
> > 
> > From: Darrick J. Wong <darrick.wong@oracle.com>
> > 
> > Create e2info, which reports the fs geometry of an online ext4 filesystem.
> 
> Besides providing a place to call the new EXT4_IOC_FSGEOMETRY ioctl, I
> don't see how this is much different from "dumpe2fs -h"?

Eh, screw it, I'm walking away from this whole FSGEOMETRY ioctl patchset.
Too much uphill friction, insufficient motivation...

--D

> 
> Cheers, Andreas
> 
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> > configure            |    4 +
> > configure.ac         |    3 +
> > lib/ext2fs/ext2_fs.h |   34 ++++++++
> > misc/Makefile.in     |   30 ++++++-
> > misc/e2info.8.in     |   64 ++++++++++++++++
> > misc/e2info.c        |  205 ++++++++++++++++++++++++++++++++++++++++++++++++++
> > 6 files changed, 336 insertions(+), 4 deletions(-)
> > create mode 100644 misc/e2info.8.in
> > create mode 100644 misc/e2info.c
> > 
> > 
> > diff --git a/configure b/configure
> > index 5f7b429..b553da1 100755
> > --- a/configure
> > +++ b/configure
> > @@ -642,6 +642,7 @@ root_prefix
> > UNIX_CMT
> > CYGWIN_CMT
> > LINUX_CMT
> > +E2INFO_CMT
> > UNI_DIFF_OPTS
> > SEM_INIT_LIB
> > FUSE_CMT
> > @@ -13663,13 +13664,16 @@ fi
> > { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UNI_DIFF_OPTS" >&5
> > $as_echo "$UNI_DIFF_OPTS" >&6; }
> > 
> > +E2INFO_CMT="#"
> > case "$host_os" in
> > linux*)
> > 
> > $as_echo "#define HAVE_EXT2_IOCTLS 1" >>confdefs.h
> > 
> > +	E2INFO_CMT=
> > 	;;
> > esac
> > +
> > LINUX_CMT="#"
> > CYGWIN_CMT="#"
> > UNIX_CMT=
> > diff --git a/configure.ac b/configure.ac
> > index 9da7b86..bf613fd 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -1260,11 +1260,14 @@ AC_SUBST(UNI_DIFF_OPTS)
> > dnl
> > dnl We use the EXT2 ioctls only under Linux
> > dnl
> > +E2INFO_CMT="#"
> > case "$host_os" in
> > linux*)
> > 	AC_DEFINE(HAVE_EXT2_IOCTLS, 1, [Define to 1 if Ext2 ioctls present])
> > +	E2INFO_CMT=
> > 	;;
> > esac
> > +AC_SUBST(E2INFO_CMT)
> > dnl
> > dnl OS-specific uncomment control
> > dnl
> > diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> > index 27a7d3a..bad7648 100644
> > --- a/lib/ext2fs/ext2_fs.h
> > +++ b/lib/ext2fs/ext2_fs.h
> > @@ -372,6 +372,40 @@ struct ext4_new_group_input {
> > #define EXT4_IOC_GROUP_ADD		_IOW('f', 8,struct ext4_new_group_input)
> > #define EXT4_IOC_RESIZE_FS		_IOW('f', 16, __u64)
> > 
> > +/* ext4 fs geometry. */
> > +struct ext4_fsop_geom {
> > +	__u32		efg_blocksize;	/* filesystem (data) block size */
> > +	__u32		efg_bgblocks;	/* fsblocks in an AG		*/
> > +	__u32		efg_bgcount;	/* number of allocation groups	*/
> > +	__u32		efg_logblocks;	/* fsblocks in the log		*/
> > +	__u32		efg_resvblocks;	/* number of reserved blocks	*/
> > +	__u32		efg_inodesize;	/* inode size in bytes		*/
> > +	__u32		efg_bg_iblocks;	/* inode blocks per AG		*/
> > +	__u32		efg_flags;	/* superblock version flags	*/
> > +	__u64		efg_inodecount;	/* inode count			*/
> > +	__u64		efg_blockcount;	/* fsblocks in filesystem	*/
> > +	unsigned char	efg_uuid[16];	/* unique id of the filesystem	*/
> > +	__u32		efg_sunit;	/* stripe unit, fsblocks	*/
> > +	__u32		efg_swidth;	/* stripe width, fsblocks	*/
> > +	__u32		efg_clustersize;/* fs cluster size		*/
> > +	__u32		efg_flexbgsize;	/* number of bg's in a flexbg	*/
> > +	__u64		efg_resv[6];
> > +};
> > +
> > +#define EXT4_FSOP_GEOM_FLAGS_ATTR	0x00001	/* extended attr in use	 */
> > +#define EXT4_FSOP_GEOM_FLAGS_NLINK	0x00002	/* 32-bit nlink values	 */
> > +#define EXT4_FSOP_GEOM_FLAGS_QUOTA	0x00004	/* quotas enabled	 */
> > +#define EXT4_FSOP_GEOM_FLAGS_PROJQ	0x00008	/* project quotas	 */
> > +#define EXT4_FSOP_GEOM_FLAGS_META_CSUM	0x00010	/* metadata checksums	 */
> > +#define EXT4_FSOP_GEOM_FLAGS_FTYPE	0x00020	/* inode directory types */
> > +#define EXT4_FSOP_GEOM_FLAGS_64BIT	0x00040	/* 64-bit support	 */
> > +#define EXT4_FSOP_GEOM_FLAGS_INLINEDATA	0x00080	/* inline data		 */
> > +#define EXT4_FSOP_GEOM_FLAGS_ENCRYPT	0x00100	/* encrypted files	 */
> > +#define EXT4_FSOP_GEOM_FLAGS_LARGEDIR	0x00200	/* large directories	 */
> > +#define EXT4_FSOP_GEOM_FLAGS_EXTENTS	0x00400	/* extents		 */
> > +
> > +#define EXT4_IOC_FSGEOMETRY		_IOR ('f', 19, struct ext4_fsop_geom)
> > +
> > /*
> >  * Structure of an inode on the disk
> >  */
> > diff --git a/misc/Makefile.in b/misc/Makefile.in
> > index 467c15d..311aa57 100644
> > --- a/misc/Makefile.in
> > +++ b/misc/Makefile.in
> > @@ -32,14 +32,19 @@ INSTALL = @INSTALL@
> > 
> > @FUSE_CMT@FUSE_PROG= fuse2fs
> > 
> > +@E2INFO_CMT@E2INFO_PROG= e2info
> > +@E2INFO_CMT@E2INFO_MAN= e2info.8
> > +
> > SPROGS=		mke2fs badblocks tune2fs dumpe2fs $(BLKID_PROG) logsave \
> > 			$(E2IMAGE_PROG) @FSCK_PROG@ e2undo
> > USPROGS=	mklost+found filefrag e2freefrag $(UUIDD_PROG) \
> > -			$(E4DEFRAG_PROG) $(E4CRYPT_PROG) $(FUSE_PROG)
> > +			$(E4DEFRAG_PROG) $(E4CRYPT_PROG) $(FUSE_PROG) \
> > +			$(E2INFO_PROG)
> > SMANPAGES=	tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \
> > 			e2label.8 $(FINDFS_MAN) $(BLKID_MAN) $(E2IMAGE_MAN) \
> > 			logsave.8 filefrag.8 e2freefrag.8 e2undo.8 \
> > -			$(UUIDD_MAN) $(E4DEFRAG_MAN) $(E4CRYPT_MAN) @FSCK_MAN@
> > +			$(UUIDD_MAN) $(E4DEFRAG_MAN) $(E4CRYPT_MAN) @FSCK_MAN@ \
> > +			$(E2INFO_MAN)
> > FMANPAGES=	mke2fs.conf.5 ext4.5
> > 
> > UPROGS=		chattr lsattr @UUID_CMT@ uuidgen
> > @@ -68,6 +73,7 @@ E4CRYPT_OBJS=   e4crypt.o
> > E2FREEFRAG_OBJS= e2freefrag.o
> > E2FUZZ_OBJS=	e2fuzz.o
> > FUSE2FS_OBJS=	fuse2fs.o journal.o recovery.o revoke.o
> > +E2INFO_OBJS=	e2info.o
> > 
> > PROFILED_TUNE2FS_OBJS=	profiled/tune2fs.o profiled/util.o
> > PROFILED_MKLPF_OBJS=	profiled/mklost+found.o
> > @@ -90,8 +96,9 @@ PROFILED_E2FREEFRAG_OBJS= profiled/e2freefrag.o
> > PROFILED_E2UNDO_OBJS=	profiled/e2undo.o
> > PROFILED_E4DEFRAG_OBJS=	profiled/e4defrag.o
> > PROFILED_E4CRYPT_OBJS=	profiled/e4crypt.o
> > -PROFILED_FUSE2FS_OJBS=	profiled/fuse2fs.o profiled/journal.o \
> > +PROFILED_FUSE2FS_OBJS=	profiled/fuse2fs.o profiled/journal.o \
> > 			profiled/recovery.o profiled/revoke.o
> > +PROFILED_E2INFO_OBJS=	profiled/e2info.o
> > 
> > SRCS=	$(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c $(srcdir)/mk_hugefiles.c \
> > 		$(srcdir)/chattr.c $(srcdir)/lsattr.c $(srcdir)/dumpe2fs.c \
> > @@ -102,7 +109,7 @@ SRCS=	$(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c $(srcdir)/
> > 		$(srcdir)/e2freefrag.c $(srcdir)/create_inode.c \
> > 		$(srcdir)/fuse2fs.c \
> > 		$(srcdir)/../debugfs/journal.c $(srcdir)/../e2fsck/revoke.c \
> > -		$(srcdir)/../e2fsck/recovery.c
> > +		$(srcdir)/../e2fsck/recovery.c $(srcdir)/e2info.c
> > 
> > LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBSUPPORT)
> > DEPLIBS= $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBSUPPORT)
> > @@ -391,6 +398,11 @@ fuse2fs: $(FUSE2FS_OBJS) $(DEPLIBS) $(DEPLIBBLKID) $(DEPLIBUUID) \
> > 		$(LIBFUSE) $(LIBBLKID) $(LIBUUID) $(LIBEXT2FS) $(LIBINTL) \
> > 		$(CLOCK_GETTIME_LIB) $(SYSLIBS)
> > 
> > +e2info: $(E2INFO_OBJS) $(DEPLIBS)
> > +	$(E) "	LD $@"
> > +	$(Q) $(CC) $(ALL_LDFLAGS) -o e2info $(E2INFO_OBJS) $(LIBINTL) \
> > +		$(SYSLIBS)
> > +
> > journal.o: $(srcdir)/../debugfs/journal.c
> > 	$(E) "	CC $@"
> > 	$(Q) $(CC) -c $(JOURNAL_CFLAGS) -I$(srcdir) \
> > @@ -411,6 +423,10 @@ tst_ismounted: $(srcdir)/ismounted.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
> > 	$(CC) -o tst_ismounted $(srcdir)/ismounted.c -DDEBUG $(ALL_CFLAGS) \
> > 		$(LIBCOM_ERR) $(SYSLIBS)
> > 
> > +e2info.8: $(DEP_SUBSTITUTE) $(srcdir)/e2info.8.in
> > +	$(E) "	SUBST $@"
> > +	$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2info.8.in e2info.8
> > +
> > tune2fs.8: $(DEP_SUBSTITUTE) $(srcdir)/tune2fs.8.in
> > 	$(E) "	SUBST $@"
> > 	$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/tune2fs.8.in tune2fs.8
> > @@ -844,3 +860,9 @@ recovery.o: $(srcdir)/../e2fsck/recovery.c $(srcdir)/../e2fsck/jfs_user.h \
> >  $(top_srcdir)/lib/support/quotaio_tree.h \
> >  $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \
> >  $(top_srcdir)/lib/ext2fs/kernel-list.h
> > +e2info.o: $(srcdir)/e2info.c $(top_builddir)/lib/config.h \
> > + $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
> > + $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
> > + $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
> > + $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
> > + $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h
> > diff --git a/misc/e2info.8.in b/misc/e2info.8.in
> > new file mode 100644
> > index 0000000..c7f580f
> > --- /dev/null
> > +++ b/misc/e2info.8.in
> > @@ -0,0 +1,64 @@
> > +.\" -*- nroff -*-
> > +.\" Copyright 2017 Oracle Inc.  All Rights Reserved.
> > +.\" This file may be copied under the terms of the GNU Public License.
> > +.\"
> > +.\" Verbatim blocks taken from openssl req manpage content
> > +.de Vb \" Begin verbatim text
> > +.ft CW
> > +.nf
> > +.ne \\$1
> > +..
> > +.de Ve \" End verbatim text
> > +.ft R
> > +.fi
> > +..
> > +
> > +.TH E2INFO 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
> > +.SH NAME
> > +e2info \- Display information about a mounted ext4 filesystem
> > +.SH SYNOPSIS
> > +.B e2info
> > +.I mount-point
> > +.br
> > +.B e2info \-V
> > +.SH DESCRIPTION
> > +Prints the filesystem geometry of an ext4 filesystem.  If the mounted
> > +filesystem is an ext2 or ext3 filesystem mounted with the ext4 driver,
> > +the geometry will be displayed.
> > +.SH "EXAMPLES"
> > +
> > +Understanding e2info output.
> > +.PP
> > +Suppose one has the following "e2info /dev/sda" output:
> > +.PP
> > +.RS 2
> > +.Vb
> > +\&meta-data=/dev/loop0             isize=256    bgcount=14808 bgsize=32768 blks
> > +\&         =                       attr=1       quota=0 pquota=0
> > +\&         =                       crc=0        64bit=0 inlinedata=0 extents=1
> > +\&         =                       flexbg=16
> > +\&data     =                       bsize=4096   blocks=485198848 bg_iblocks=512
> > +\&         =                       sunit=32     swidth=128 blks clustersize=0
> > +\&         =                       encrypt=0
> > +\&naming   =                       bsize=4096   largedir=0 ftype=1 nlink=1
> > +\&log      =                       bsize=4096   blocks=32768
> > +.Ve
> > +.RE
> > +.PP
> > +
> > +Here, the data section of the output indicates "bsize=4096",
> > +meaning the data block size for this filesystem is 4096 bytes.
> > +This section also shows "sunit=32 swidth=128 blks", which means
> > +the stripe unit is 32*4096 bytes = 128 kibibytes and the stripe
> > +width is 128*4096 bytes = 512 kibibytes.
> > +A single stripe of this filesystem therefore consists
> > +of four stripe units (128 blocks / 32 blocks per unit).
> > +Note also that "flexbg=16", which means that this filesystem has
> > +512MB flex block groups.
> > +That is the upper limit of how much physical disk space can be mapped
> > +into a file.
> > +.SH SEE ALSO
> > +.BR mkfs.ext4 (8),
> > +.BR md (4),
> > +.BR lvm (8),
> > +.BR mount (8).
> > diff --git a/misc/e2info.c b/misc/e2info.c
> > new file mode 100644
> > index 0000000..675f005
> > --- /dev/null
> > +++ b/misc/e2info.c
> > @@ -0,0 +1,205 @@
> > +/*
> > + * 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 "config.h"
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <libgen.h>
> > +#include <unistd.h>
> > +#include <sys/ioctl.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +#include <errno.h>
> > +#include <mntent.h>
> > +#include <limits.h>
> > +
> > +#include "ext2fs/ext2_fs.h"
> > +
> > +#include "../version.h"
> > +#include "support/nls-enable.h"
> > +
> > +static const char *progname = "e2info";
> > +
> > +static void
> > +usage(void)
> > +{
> > +	fprintf(stderr, _(
> > +"Usage: %s [options] mountpoint\n\n\
> > +	-V          print version information\n"),
> > +		progname);
> > +	exit(2);
> > +}
> > +
> > +#define PROC_MOUNTS	"/proc/mounts"
> > +int
> > +find_datadev(
> > +	const char	*arg,
> > +	char		*datadev,
> > +	char		*mntpoint)
> > +{
> > +	struct mntent	*mnt;
> > +	FILE		*mtp;
> > +	char		*mtab_file;
> > +	char		rmnt_fsname[PATH_MAX], rmnt_dir[PATH_MAX];
> > +	struct stat	sbuf;
> > +	dev_t		fd_dev;
> > +
> > +	if (stat(arg, &sbuf) < 0)
> > +		return errno;
> > +	/*
> > +	 * We want to match st_rdev if the path provided is a device
> > +	 * special file.  Otherwise we are looking for the the
> > +	 * device id for the containing filesystem, in st_dev.
> > +	 */
> > +	if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode))
> > +		fd_dev = sbuf.st_rdev;
> > +	else
> > +		fd_dev = sbuf.st_dev;
> > +
> > +	mtab_file = PROC_MOUNTS;
> > +	if (access(mtab_file, R_OK) != 0)
> > +		mtab_file = MOUNTED;
> > +
> > +	if ((mtp = setmntent(mtab_file, "r")) == NULL)
> > +		return ENOENT;
> > +
> > +	while ((mnt = getmntent(mtp)) != NULL) {
> > +		if (!realpath(mnt->mnt_dir, rmnt_dir))
> > +			continue;
> > +		if (!realpath(mnt->mnt_fsname, rmnt_fsname))
> > +			continue;
> > +
> > +		if (stat(rmnt_fsname, &sbuf) < 0)
> > +			continue;
> > +		if (sbuf.st_rdev == fd_dev) {
> > +			strncpy(datadev, rmnt_fsname, PATH_MAX);
> > +			strncpy(mntpoint, rmnt_dir, PATH_MAX);
> > +			break;
> > +		}
> > +	}
> > +	endmntent(mtp);
> > +	return 0;
> > +}
> > +
> > +int
> > +main(int argc, char **argv)
> > +{
> > +	struct ext4_fsop_geom	geo;
> > +	char			*progname;
> > +	int			fd;
> > +	int			c;
> > +	int			attr_enabled;
> > +	int			nlink_enabled;
> > +	int			quota_enabled;
> > +	int			projquota_enabled;
> > +	int			metacrc_enabled;
> > +	int			ftype_enabled;
> > +	int			is_64bit;
> > +	int			inlinedata_enabled;
> > +	int			encrypt_enabled;
> > +	int			largedir_enabled;
> > +	int			extents_enabled;
> > +	char			datadev[PATH_MAX];
> > +	char			mntpoint[PATH_MAX];
> > +
> > +	progname = basename(argv[0]);
> > +#ifdef ENABLE_NLS
> > +	setlocale(LC_ALL, "");
> > +	bindtextdomain(PACKAGE, LOCALEDIR);
> > +	textdomain(PACKAGE);
> > +#endif
> > +
> > +	while ((c = getopt(argc, argv, "V")) != EOF) {
> > +		switch (c) {
> > +		case 'V':
> > +			printf(_("%s version %s\n"), progname, VERSION);
> > +			exit(0);
> > +		case '?':
> > +		default:
> > +			usage();
> > +		}
> > +	}
> > +	if (argc - optind != 1)
> > +		usage();
> > +
> > +	fd = open(argv[optind], O_RDONLY);
> > +	if (fd < 0) {
> > +		perror(argv[optind]);
> > +		return 1;
> > +	}
> > +
> > +	if (find_datadev(argv[optind], datadev, mntpoint)) {
> > +		perror("find_datadev");
> > +		strncpy(datadev, argv[optind], PATH_MAX);
> > +		strncpy(mntpoint, argv[optind], PATH_MAX);
> > +	}
> > +
> > +	close(fd);
> > +	fd = open(mntpoint, O_RDONLY);
> > +	if (fd < 0) {
> > +		perror(mntpoint);
> > +		return 1;
> > +	}
> > +
> > +	/* get the current filesystem size & geometry */
> > +	if (ioctl(fd, EXT4_IOC_FSGEOMETRY, &geo) < 0) {
> > +		fprintf(stderr, _(
> > +			"%s: cannot determine geometry of filesystem"
> > +			" mounted at %s: %s\n"),
> > +			progname, argv[optind], strerror(errno));
> > +		exit(1);
> > +	}
> > +
> > +	attr_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_ATTR ? 1 : 0;
> > +	nlink_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_NLINK ? 1 : 0;
> > +	quota_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_QUOTA ? 1 : 0;
> > +	projquota_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_PROJQ ? 1 : 0;
> > +	metacrc_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_META_CSUM ? 1 : 0;
> > +	ftype_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_FTYPE ? 1 : 0;
> > +	is_64bit = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_64BIT ? 1 : 0;
> > +	inlinedata_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_INLINEDATA ? 1 : 0;
> > +	encrypt_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_ENCRYPT ? 1 : 0;
> > +	largedir_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_LARGEDIR ? 1 : 0;
> > +	extents_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_EXTENTS ? 1 : 0;
> > +
> > +	printf(_(
> > +	    "meta-data=%-22s isize=%-6u bgcount=%u bgsize=%u blks\n"
> > +	    "         =%-22s attr=%-7u quota=%u pquota=%u\n"
> > +	    "         =%-22s crc=%-8u 64bit=%u inlinedata=%u extents=%u\n"
> > +	    "         =%-22s flexbg=%u\n"
> > +	    "data     =%-22s bsize=%-6u blocks=%llu bg_iblocks=%u\n"
> > +	    "         =%-22s sunit=%-6u swidth=%u blks clustersize=%u\n"
> > +	    "         =%-22s encrypt=%u\n"
> > +	    "naming   =%-22s bsize=%-6u largedir=%d ftype=%d nlink=%u\n"
> > +	    "log      =%-22s bsize=%-6u blocks=%u\n"),
> > +		datadev, geo.efg_inodesize, geo.efg_bgcount, geo.efg_bgblocks,
> > +		"", attr_enabled, quota_enabled, projquota_enabled,
> > +		"", metacrc_enabled, is_64bit, inlinedata_enabled,
> > +			extents_enabled,
> > +		"", geo.efg_flexbgsize,
> > +		"", geo.efg_blocksize, (unsigned long long)geo.efg_blockcount,
> > +			geo.efg_bg_iblocks,
> > +		"", geo.efg_sunit, geo.efg_swidth, geo.efg_clustersize,
> > +		"", encrypt_enabled,
> > +		"", geo.efg_blocksize, largedir_enabled, ftype_enabled,
> > +			nlink_enabled,
> > +		"", geo.efg_blocksize, geo.efg_logblocks);
> > +
> > +	exit(0);
> > +}
> > 
> 
> 
> Cheers, Andreas
> 
> 
> 
> 
> 

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

* Re: [PATCH 2/3] e2info: create a tool to display ext4 fs geometry online
  2017-03-02 21:50     ` Darrick J. Wong
@ 2017-03-02 22:05       ` Andreas Dilger
       [not found]         ` <20170302224413.GN26319@birch.djwong.org>
  0 siblings, 1 reply; 11+ messages in thread
From: Andreas Dilger @ 2017-03-02 22:05 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: tytso, linux-ext4

[-- Attachment #1: Type: text/plain, Size: 18756 bytes --]


> On Mar 2, 2017, at 2:50 PM, Darrick J. Wong <darrick.wong@oracle.com> wrote:
> 
> On Thu, Mar 02, 2017 at 12:49:46PM -0700, Andreas Dilger wrote:
>> On Mar 1, 2017, at 9:52 PM, Darrick J. Wong <darrick.wong@oracle.com> wrote:
>>> 
>>> From: Darrick J. Wong <darrick.wong@oracle.com>
>>> 
>>> Create e2info, which reports the fs geometry of an online ext4 filesystem.
>> 
>> Besides providing a place to call the new EXT4_IOC_FSGEOMETRY ioctl, I
>> don't see how this is much different from "dumpe2fs -h"?
> 
> Eh, screw it, I'm walking away from this whole FSGEOMETRY ioctl patchset.
> Too much uphill friction, insufficient motivation...

I can see the FSGEOMETRY ioctl could be useful for applications, especially
if this is common across filesystems.  My main objection was to having a new
tool in e2fsprogs for the sole purpose of calling the ioctl.

Cheers, Andreas

>> 
>>> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
>>> ---
>>> configure            |    4 +
>>> configure.ac         |    3 +
>>> lib/ext2fs/ext2_fs.h |   34 ++++++++
>>> misc/Makefile.in     |   30 ++++++-
>>> misc/e2info.8.in     |   64 ++++++++++++++++
>>> misc/e2info.c        |  205 ++++++++++++++++++++++++++++++++++++++++++++++++++
>>> 6 files changed, 336 insertions(+), 4 deletions(-)
>>> create mode 100644 misc/e2info.8.in
>>> create mode 100644 misc/e2info.c
>>> 
>>> 
>>> diff --git a/configure b/configure
>>> index 5f7b429..b553da1 100755
>>> --- a/configure
>>> +++ b/configure
>>> @@ -642,6 +642,7 @@ root_prefix
>>> UNIX_CMT
>>> CYGWIN_CMT
>>> LINUX_CMT
>>> +E2INFO_CMT
>>> UNI_DIFF_OPTS
>>> SEM_INIT_LIB
>>> FUSE_CMT
>>> @@ -13663,13 +13664,16 @@ fi
>>> { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UNI_DIFF_OPTS" >&5
>>> $as_echo "$UNI_DIFF_OPTS" >&6; }
>>> 
>>> +E2INFO_CMT="#"
>>> case "$host_os" in
>>> linux*)
>>> 
>>> $as_echo "#define HAVE_EXT2_IOCTLS 1" >>confdefs.h
>>> 
>>> +	E2INFO_CMT=
>>> 	;;
>>> esac
>>> +
>>> LINUX_CMT="#"
>>> CYGWIN_CMT="#"
>>> UNIX_CMT=
>>> diff --git a/configure.ac b/configure.ac
>>> index 9da7b86..bf613fd 100644
>>> --- a/configure.ac
>>> +++ b/configure.ac
>>> @@ -1260,11 +1260,14 @@ AC_SUBST(UNI_DIFF_OPTS)
>>> dnl
>>> dnl We use the EXT2 ioctls only under Linux
>>> dnl
>>> +E2INFO_CMT="#"
>>> case "$host_os" in
>>> linux*)
>>> 	AC_DEFINE(HAVE_EXT2_IOCTLS, 1, [Define to 1 if Ext2 ioctls present])
>>> +	E2INFO_CMT=
>>> 	;;
>>> esac
>>> +AC_SUBST(E2INFO_CMT)
>>> dnl
>>> dnl OS-specific uncomment control
>>> dnl
>>> diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
>>> index 27a7d3a..bad7648 100644
>>> --- a/lib/ext2fs/ext2_fs.h
>>> +++ b/lib/ext2fs/ext2_fs.h
>>> @@ -372,6 +372,40 @@ struct ext4_new_group_input {
>>> #define EXT4_IOC_GROUP_ADD		_IOW('f', 8,struct ext4_new_group_input)
>>> #define EXT4_IOC_RESIZE_FS		_IOW('f', 16, __u64)
>>> 
>>> +/* ext4 fs geometry. */
>>> +struct ext4_fsop_geom {
>>> +	__u32		efg_blocksize;	/* filesystem (data) block size */
>>> +	__u32		efg_bgblocks;	/* fsblocks in an AG		*/
>>> +	__u32		efg_bgcount;	/* number of allocation groups	*/
>>> +	__u32		efg_logblocks;	/* fsblocks in the log		*/
>>> +	__u32		efg_resvblocks;	/* number of reserved blocks	*/
>>> +	__u32		efg_inodesize;	/* inode size in bytes		*/
>>> +	__u32		efg_bg_iblocks;	/* inode blocks per AG		*/
>>> +	__u32		efg_flags;	/* superblock version flags	*/
>>> +	__u64		efg_inodecount;	/* inode count			*/
>>> +	__u64		efg_blockcount;	/* fsblocks in filesystem	*/
>>> +	unsigned char	efg_uuid[16];	/* unique id of the filesystem	*/
>>> +	__u32		efg_sunit;	/* stripe unit, fsblocks	*/
>>> +	__u32		efg_swidth;	/* stripe width, fsblocks	*/
>>> +	__u32		efg_clustersize;/* fs cluster size		*/
>>> +	__u32		efg_flexbgsize;	/* number of bg's in a flexbg	*/
>>> +	__u64		efg_resv[6];
>>> +};
>>> +
>>> +#define EXT4_FSOP_GEOM_FLAGS_ATTR	0x00001	/* extended attr in use	 */
>>> +#define EXT4_FSOP_GEOM_FLAGS_NLINK	0x00002	/* 32-bit nlink values	 */
>>> +#define EXT4_FSOP_GEOM_FLAGS_QUOTA	0x00004	/* quotas enabled	 */
>>> +#define EXT4_FSOP_GEOM_FLAGS_PROJQ	0x00008	/* project quotas	 */
>>> +#define EXT4_FSOP_GEOM_FLAGS_META_CSUM	0x00010	/* metadata checksums	 */
>>> +#define EXT4_FSOP_GEOM_FLAGS_FTYPE	0x00020	/* inode directory types */
>>> +#define EXT4_FSOP_GEOM_FLAGS_64BIT	0x00040	/* 64-bit support	 */
>>> +#define EXT4_FSOP_GEOM_FLAGS_INLINEDATA	0x00080	/* inline data		 */
>>> +#define EXT4_FSOP_GEOM_FLAGS_ENCRYPT	0x00100	/* encrypted files	 */
>>> +#define EXT4_FSOP_GEOM_FLAGS_LARGEDIR	0x00200	/* large directories	 */
>>> +#define EXT4_FSOP_GEOM_FLAGS_EXTENTS	0x00400	/* extents		 */
>>> +
>>> +#define EXT4_IOC_FSGEOMETRY		_IOR ('f', 19, struct ext4_fsop_geom)
>>> +
>>> /*
>>> * Structure of an inode on the disk
>>> */
>>> diff --git a/misc/Makefile.in b/misc/Makefile.in
>>> index 467c15d..311aa57 100644
>>> --- a/misc/Makefile.in
>>> +++ b/misc/Makefile.in
>>> @@ -32,14 +32,19 @@ INSTALL = @INSTALL@
>>> 
>>> @FUSE_CMT@FUSE_PROG= fuse2fs
>>> 
>>> +@E2INFO_CMT@E2INFO_PROG= e2info
>>> +@E2INFO_CMT@E2INFO_MAN= e2info.8
>>> +
>>> SPROGS=		mke2fs badblocks tune2fs dumpe2fs $(BLKID_PROG) logsave \
>>> 			$(E2IMAGE_PROG) @FSCK_PROG@ e2undo
>>> USPROGS=	mklost+found filefrag e2freefrag $(UUIDD_PROG) \
>>> -			$(E4DEFRAG_PROG) $(E4CRYPT_PROG) $(FUSE_PROG)
>>> +			$(E4DEFRAG_PROG) $(E4CRYPT_PROG) $(FUSE_PROG) \
>>> +			$(E2INFO_PROG)
>>> SMANPAGES=	tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \
>>> 			e2label.8 $(FINDFS_MAN) $(BLKID_MAN) $(E2IMAGE_MAN) \
>>> 			logsave.8 filefrag.8 e2freefrag.8 e2undo.8 \
>>> -			$(UUIDD_MAN) $(E4DEFRAG_MAN) $(E4CRYPT_MAN) @FSCK_MAN@
>>> +			$(UUIDD_MAN) $(E4DEFRAG_MAN) $(E4CRYPT_MAN) @FSCK_MAN@ \
>>> +			$(E2INFO_MAN)
>>> FMANPAGES=	mke2fs.conf.5 ext4.5
>>> 
>>> UPROGS=		chattr lsattr @UUID_CMT@ uuidgen
>>> @@ -68,6 +73,7 @@ E4CRYPT_OBJS=   e4crypt.o
>>> E2FREEFRAG_OBJS= e2freefrag.o
>>> E2FUZZ_OBJS=	e2fuzz.o
>>> FUSE2FS_OBJS=	fuse2fs.o journal.o recovery.o revoke.o
>>> +E2INFO_OBJS=	e2info.o
>>> 
>>> PROFILED_TUNE2FS_OBJS=	profiled/tune2fs.o profiled/util.o
>>> PROFILED_MKLPF_OBJS=	profiled/mklost+found.o
>>> @@ -90,8 +96,9 @@ PROFILED_E2FREEFRAG_OBJS= profiled/e2freefrag.o
>>> PROFILED_E2UNDO_OBJS=	profiled/e2undo.o
>>> PROFILED_E4DEFRAG_OBJS=	profiled/e4defrag.o
>>> PROFILED_E4CRYPT_OBJS=	profiled/e4crypt.o
>>> -PROFILED_FUSE2FS_OJBS=	profiled/fuse2fs.o profiled/journal.o \
>>> +PROFILED_FUSE2FS_OBJS=	profiled/fuse2fs.o profiled/journal.o \
>>> 			profiled/recovery.o profiled/revoke.o
>>> +PROFILED_E2INFO_OBJS=	profiled/e2info.o
>>> 
>>> SRCS=	$(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c $(srcdir)/mk_hugefiles.c \
>>> 		$(srcdir)/chattr.c $(srcdir)/lsattr.c $(srcdir)/dumpe2fs.c \
>>> @@ -102,7 +109,7 @@ SRCS=	$(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c $(srcdir)/
>>> 		$(srcdir)/e2freefrag.c $(srcdir)/create_inode.c \
>>> 		$(srcdir)/fuse2fs.c \
>>> 		$(srcdir)/../debugfs/journal.c $(srcdir)/../e2fsck/revoke.c \
>>> -		$(srcdir)/../e2fsck/recovery.c
>>> +		$(srcdir)/../e2fsck/recovery.c $(srcdir)/e2info.c
>>> 
>>> LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBSUPPORT)
>>> DEPLIBS= $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBSUPPORT)
>>> @@ -391,6 +398,11 @@ fuse2fs: $(FUSE2FS_OBJS) $(DEPLIBS) $(DEPLIBBLKID) $(DEPLIBUUID) \
>>> 		$(LIBFUSE) $(LIBBLKID) $(LIBUUID) $(LIBEXT2FS) $(LIBINTL) \
>>> 		$(CLOCK_GETTIME_LIB) $(SYSLIBS)
>>> 
>>> +e2info: $(E2INFO_OBJS) $(DEPLIBS)
>>> +	$(E) "	LD $@"
>>> +	$(Q) $(CC) $(ALL_LDFLAGS) -o e2info $(E2INFO_OBJS) $(LIBINTL) \
>>> +		$(SYSLIBS)
>>> +
>>> journal.o: $(srcdir)/../debugfs/journal.c
>>> 	$(E) "	CC $@"
>>> 	$(Q) $(CC) -c $(JOURNAL_CFLAGS) -I$(srcdir) \
>>> @@ -411,6 +423,10 @@ tst_ismounted: $(srcdir)/ismounted.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
>>> 	$(CC) -o tst_ismounted $(srcdir)/ismounted.c -DDEBUG $(ALL_CFLAGS) \
>>> 		$(LIBCOM_ERR) $(SYSLIBS)
>>> 
>>> +e2info.8: $(DEP_SUBSTITUTE) $(srcdir)/e2info.8.in
>>> +	$(E) "	SUBST $@"
>>> +	$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2info.8.in e2info.8
>>> +
>>> tune2fs.8: $(DEP_SUBSTITUTE) $(srcdir)/tune2fs.8.in
>>> 	$(E) "	SUBST $@"
>>> 	$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/tune2fs.8.in tune2fs.8
>>> @@ -844,3 +860,9 @@ recovery.o: $(srcdir)/../e2fsck/recovery.c $(srcdir)/../e2fsck/jfs_user.h \
>>> $(top_srcdir)/lib/support/quotaio_tree.h \
>>> $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \
>>> $(top_srcdir)/lib/ext2fs/kernel-list.h
>>> +e2info.o: $(srcdir)/e2info.c $(top_builddir)/lib/config.h \
>>> + $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
>>> + $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
>>> + $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
>>> + $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
>>> + $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h
>>> diff --git a/misc/e2info.8.in b/misc/e2info.8.in
>>> new file mode 100644
>>> index 0000000..c7f580f
>>> --- /dev/null
>>> +++ b/misc/e2info.8.in
>>> @@ -0,0 +1,64 @@
>>> +.\" -*- nroff -*-
>>> +.\" Copyright 2017 Oracle Inc.  All Rights Reserved.
>>> +.\" This file may be copied under the terms of the GNU Public License.
>>> +.\"
>>> +.\" Verbatim blocks taken from openssl req manpage content
>>> +.de Vb \" Begin verbatim text
>>> +.ft CW
>>> +.nf
>>> +.ne \\$1
>>> +..
>>> +.de Ve \" End verbatim text
>>> +.ft R
>>> +.fi
>>> +..
>>> +
>>> +.TH E2INFO 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
>>> +.SH NAME
>>> +e2info \- Display information about a mounted ext4 filesystem
>>> +.SH SYNOPSIS
>>> +.B e2info
>>> +.I mount-point
>>> +.br
>>> +.B e2info \-V
>>> +.SH DESCRIPTION
>>> +Prints the filesystem geometry of an ext4 filesystem.  If the mounted
>>> +filesystem is an ext2 or ext3 filesystem mounted with the ext4 driver,
>>> +the geometry will be displayed.
>>> +.SH "EXAMPLES"
>>> +
>>> +Understanding e2info output.
>>> +.PP
>>> +Suppose one has the following "e2info /dev/sda" output:
>>> +.PP
>>> +.RS 2
>>> +.Vb
>>> +\&meta-data=/dev/loop0             isize=256    bgcount=14808 bgsize=32768 blks
>>> +\&         =                       attr=1       quota=0 pquota=0
>>> +\&         =                       crc=0        64bit=0 inlinedata=0 extents=1
>>> +\&         =                       flexbg=16
>>> +\&data     =                       bsize=4096   blocks=485198848 bg_iblocks=512
>>> +\&         =                       sunit=32     swidth=128 blks clustersize=0
>>> +\&         =                       encrypt=0
>>> +\&naming   =                       bsize=4096   largedir=0 ftype=1 nlink=1
>>> +\&log      =                       bsize=4096   blocks=32768
>>> +.Ve
>>> +.RE
>>> +.PP
>>> +
>>> +Here, the data section of the output indicates "bsize=4096",
>>> +meaning the data block size for this filesystem is 4096 bytes.
>>> +This section also shows "sunit=32 swidth=128 blks", which means
>>> +the stripe unit is 32*4096 bytes = 128 kibibytes and the stripe
>>> +width is 128*4096 bytes = 512 kibibytes.
>>> +A single stripe of this filesystem therefore consists
>>> +of four stripe units (128 blocks / 32 blocks per unit).
>>> +Note also that "flexbg=16", which means that this filesystem has
>>> +512MB flex block groups.
>>> +That is the upper limit of how much physical disk space can be mapped
>>> +into a file.
>>> +.SH SEE ALSO
>>> +.BR mkfs.ext4 (8),
>>> +.BR md (4),
>>> +.BR lvm (8),
>>> +.BR mount (8).
>>> diff --git a/misc/e2info.c b/misc/e2info.c
>>> new file mode 100644
>>> index 0000000..675f005
>>> --- /dev/null
>>> +++ b/misc/e2info.c
>>> @@ -0,0 +1,205 @@
>>> +/*
>>> + * 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 "config.h"
>>> +#include <stdio.h>
>>> +#include <stdlib.h>
>>> +#include <string.h>
>>> +#include <libgen.h>
>>> +#include <unistd.h>
>>> +#include <sys/ioctl.h>
>>> +#include <sys/types.h>
>>> +#include <sys/stat.h>
>>> +#include <fcntl.h>
>>> +#include <errno.h>
>>> +#include <mntent.h>
>>> +#include <limits.h>
>>> +
>>> +#include "ext2fs/ext2_fs.h"
>>> +
>>> +#include "../version.h"
>>> +#include "support/nls-enable.h"
>>> +
>>> +static const char *progname = "e2info";
>>> +
>>> +static void
>>> +usage(void)
>>> +{
>>> +	fprintf(stderr, _(
>>> +"Usage: %s [options] mountpoint\n\n\
>>> +	-V          print version information\n"),
>>> +		progname);
>>> +	exit(2);
>>> +}
>>> +
>>> +#define PROC_MOUNTS	"/proc/mounts"
>>> +int
>>> +find_datadev(
>>> +	const char	*arg,
>>> +	char		*datadev,
>>> +	char		*mntpoint)
>>> +{
>>> +	struct mntent	*mnt;
>>> +	FILE		*mtp;
>>> +	char		*mtab_file;
>>> +	char		rmnt_fsname[PATH_MAX], rmnt_dir[PATH_MAX];
>>> +	struct stat	sbuf;
>>> +	dev_t		fd_dev;
>>> +
>>> +	if (stat(arg, &sbuf) < 0)
>>> +		return errno;
>>> +	/*
>>> +	 * We want to match st_rdev if the path provided is a device
>>> +	 * special file.  Otherwise we are looking for the the
>>> +	 * device id for the containing filesystem, in st_dev.
>>> +	 */
>>> +	if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode))
>>> +		fd_dev = sbuf.st_rdev;
>>> +	else
>>> +		fd_dev = sbuf.st_dev;
>>> +
>>> +	mtab_file = PROC_MOUNTS;
>>> +	if (access(mtab_file, R_OK) != 0)
>>> +		mtab_file = MOUNTED;
>>> +
>>> +	if ((mtp = setmntent(mtab_file, "r")) == NULL)
>>> +		return ENOENT;
>>> +
>>> +	while ((mnt = getmntent(mtp)) != NULL) {
>>> +		if (!realpath(mnt->mnt_dir, rmnt_dir))
>>> +			continue;
>>> +		if (!realpath(mnt->mnt_fsname, rmnt_fsname))
>>> +			continue;
>>> +
>>> +		if (stat(rmnt_fsname, &sbuf) < 0)
>>> +			continue;
>>> +		if (sbuf.st_rdev == fd_dev) {
>>> +			strncpy(datadev, rmnt_fsname, PATH_MAX);
>>> +			strncpy(mntpoint, rmnt_dir, PATH_MAX);
>>> +			break;
>>> +		}
>>> +	}
>>> +	endmntent(mtp);
>>> +	return 0;
>>> +}
>>> +
>>> +int
>>> +main(int argc, char **argv)
>>> +{
>>> +	struct ext4_fsop_geom	geo;
>>> +	char			*progname;
>>> +	int			fd;
>>> +	int			c;
>>> +	int			attr_enabled;
>>> +	int			nlink_enabled;
>>> +	int			quota_enabled;
>>> +	int			projquota_enabled;
>>> +	int			metacrc_enabled;
>>> +	int			ftype_enabled;
>>> +	int			is_64bit;
>>> +	int			inlinedata_enabled;
>>> +	int			encrypt_enabled;
>>> +	int			largedir_enabled;
>>> +	int			extents_enabled;
>>> +	char			datadev[PATH_MAX];
>>> +	char			mntpoint[PATH_MAX];
>>> +
>>> +	progname = basename(argv[0]);
>>> +#ifdef ENABLE_NLS
>>> +	setlocale(LC_ALL, "");
>>> +	bindtextdomain(PACKAGE, LOCALEDIR);
>>> +	textdomain(PACKAGE);
>>> +#endif
>>> +
>>> +	while ((c = getopt(argc, argv, "V")) != EOF) {
>>> +		switch (c) {
>>> +		case 'V':
>>> +			printf(_("%s version %s\n"), progname, VERSION);
>>> +			exit(0);
>>> +		case '?':
>>> +		default:
>>> +			usage();
>>> +		}
>>> +	}
>>> +	if (argc - optind != 1)
>>> +		usage();
>>> +
>>> +	fd = open(argv[optind], O_RDONLY);
>>> +	if (fd < 0) {
>>> +		perror(argv[optind]);
>>> +		return 1;
>>> +	}
>>> +
>>> +	if (find_datadev(argv[optind], datadev, mntpoint)) {
>>> +		perror("find_datadev");
>>> +		strncpy(datadev, argv[optind], PATH_MAX);
>>> +		strncpy(mntpoint, argv[optind], PATH_MAX);
>>> +	}
>>> +
>>> +	close(fd);
>>> +	fd = open(mntpoint, O_RDONLY);
>>> +	if (fd < 0) {
>>> +		perror(mntpoint);
>>> +		return 1;
>>> +	}
>>> +
>>> +	/* get the current filesystem size & geometry */
>>> +	if (ioctl(fd, EXT4_IOC_FSGEOMETRY, &geo) < 0) {
>>> +		fprintf(stderr, _(
>>> +			"%s: cannot determine geometry of filesystem"
>>> +			" mounted at %s: %s\n"),
>>> +			progname, argv[optind], strerror(errno));
>>> +		exit(1);
>>> +	}
>>> +
>>> +	attr_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_ATTR ? 1 : 0;
>>> +	nlink_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_NLINK ? 1 : 0;
>>> +	quota_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_QUOTA ? 1 : 0;
>>> +	projquota_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_PROJQ ? 1 : 0;
>>> +	metacrc_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_META_CSUM ? 1 : 0;
>>> +	ftype_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_FTYPE ? 1 : 0;
>>> +	is_64bit = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_64BIT ? 1 : 0;
>>> +	inlinedata_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_INLINEDATA ? 1 : 0;
>>> +	encrypt_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_ENCRYPT ? 1 : 0;
>>> +	largedir_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_LARGEDIR ? 1 : 0;
>>> +	extents_enabled = geo.efg_flags & EXT4_FSOP_GEOM_FLAGS_EXTENTS ? 1 : 0;
>>> +
>>> +	printf(_(
>>> +	    "meta-data=%-22s isize=%-6u bgcount=%u bgsize=%u blks\n"
>>> +	    "         =%-22s attr=%-7u quota=%u pquota=%u\n"
>>> +	    "         =%-22s crc=%-8u 64bit=%u inlinedata=%u extents=%u\n"
>>> +	    "         =%-22s flexbg=%u\n"
>>> +	    "data     =%-22s bsize=%-6u blocks=%llu bg_iblocks=%u\n"
>>> +	    "         =%-22s sunit=%-6u swidth=%u blks clustersize=%u\n"
>>> +	    "         =%-22s encrypt=%u\n"
>>> +	    "naming   =%-22s bsize=%-6u largedir=%d ftype=%d nlink=%u\n"
>>> +	    "log      =%-22s bsize=%-6u blocks=%u\n"),
>>> +		datadev, geo.efg_inodesize, geo.efg_bgcount, geo.efg_bgblocks,
>>> +		"", attr_enabled, quota_enabled, projquota_enabled,
>>> +		"", metacrc_enabled, is_64bit, inlinedata_enabled,
>>> +			extents_enabled,
>>> +		"", geo.efg_flexbgsize,
>>> +		"", geo.efg_blocksize, (unsigned long long)geo.efg_blockcount,
>>> +			geo.efg_bg_iblocks,
>>> +		"", geo.efg_sunit, geo.efg_swidth, geo.efg_clustersize,
>>> +		"", encrypt_enabled,
>>> +		"", geo.efg_blocksize, largedir_enabled, ftype_enabled,
>>> +			nlink_enabled,
>>> +		"", geo.efg_blocksize, geo.efg_logblocks);
>>> +
>>> +	exit(0);
>>> +}
>>> 
>> 
>> 
>> Cheers, Andreas
>> 
>> 
>> 
>> 
>> 
> 
> 


Cheers, Andreas






[-- Attachment #2: Message signed with OpenPGP --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

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

* Re: [PATCH 2/3] e2info: create a tool to display ext4 fs geometry online
       [not found]         ` <20170302224413.GN26319@birch.djwong.org>
@ 2017-03-03  5:12           ` Theodore Ts'o
  0 siblings, 0 replies; 11+ messages in thread
From: Theodore Ts'o @ 2017-03-03  5:12 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: Andreas Dilger, linux-ext4

On Thu, Mar 02, 2017 at 02:44:13PM -0800, Darrick J. Wong wrote:
> That's true.  You're right in pointing out that dumpe2fs ought to be the
> sole ext4 header dumping tool... but then there'll be complaints that
> the online mode doesn't print the group descriptor information like the
> offline mode does; also if I want to replicate dumpe2fs -h's output then
> I basically have to export the whole ext4 superblock via ioctl (which
> binds userspace to the ext4 superblock so dumpe2fs is likely to be the
> only program ever to use it) to avoid complaints about the output
> missing header fields; and finally combine that with the various
> suggestions that I try to come up with some sort of generic fs geometry
> ioctl, which (IMO) doesn't make enough sense to justify all the
> inevitable fsdevel bikeshedding...

Well, one advantage of using the ioctl is that it won't require
special (root) privileges.  So if we only use it when the block device
can't be opened directly, it might still be useful, even if we don't
return all of the information as dumpe2fs -h.


> ...at that point I decided I just don't care anymore.  I'll leave it to
> whomever actually /does/ want this, since the original justification
> (being able to hook up xfs_spaceman's reporting tools to ext4) is never
> going to happen anyway.

I'll take a look at this when I have a chance.  I agree that
integrating these two programs with e2freefrag and dumpe2fs makes the
most amount of sense.

						- Ted

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

* Re: [PATCH 1/3] misc: fix all the compiler warnings
  2017-03-02  4:52 ` [PATCH 1/3] misc: fix all the compiler warnings Darrick J. Wong
@ 2017-03-03 15:04   ` Theodore Ts'o
  0 siblings, 0 replies; 11+ messages in thread
From: Theodore Ts'o @ 2017-03-03 15:04 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-ext4

On Wed, Mar 01, 2017 at 08:52:12PM -0800, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Fix the various compiler warnings that have crept in, and only define
> __bitwise if the system headers haven't already done so.  Linux 4.10
> changes the __bitwise definition so that our redefinition here is
> just different enough that gcc complains.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>

Applied, thanks!!

						- Ted

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

end of thread, other threads:[~2017-03-03 15:04 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-02  4:52 [PATCH 0/3] e2fsprogs: new tools e2info/e2spacey Darrick J. Wong
2017-03-02  4:52 ` [PATCH 1/3] misc: fix all the compiler warnings Darrick J. Wong
2017-03-03 15:04   ` Theodore Ts'o
2017-03-02  4:52 ` [PATCH 2/3] e2info: create a tool to display ext4 fs geometry online Darrick J. Wong
2017-03-02 19:49   ` Andreas Dilger
2017-03-02 21:50     ` Darrick J. Wong
2017-03-02 22:05       ` Andreas Dilger
     [not found]         ` <20170302224413.GN26319@birch.djwong.org>
2017-03-03  5:12           ` Theodore Ts'o
2017-03-02  4:52 ` [PATCH 3/3] e2spacey: create a program to use getfsmap to profile free space Darrick J. Wong
2017-03-02 19:45   ` Andreas Dilger
2017-03-02 21:27     ` Darrick J. Wong

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.