* [PATCH 01/10] xfs: introduce the XFS_IOC_GETFSMAP ioctl
2017-06-02 19:51 [PATCH v8 00/10] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
@ 2017-06-02 19:51 ` Darrick J. Wong
2017-06-02 19:51 ` [PATCH 02/10] xfs_io: refactor numlen into a library function Darrick J. Wong
` (8 subsequent siblings)
9 siblings, 0 replies; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-02 19:51 UTC (permalink / raw)
To: sandeen, darrick.wong; +Cc: linux-xfs
From: Darrick J. Wong <darrick.wong@oracle.com>
Introduce a new ioctl that uses the reverse mapping btree to return
information about the physical layout of the filesystem.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
[sandeen: rework to have less autoconf magic]
Modified-by: Eric Sandeen <sandeen@redhat.com>
---
v3: rework the whole mess to have less autoconf magic; now we only
track if the system headers actually define getfsmap.
v2: shorten the device field to u32 since that's all we need for
dev_t. Support reporting reverse mapping information for all the
devices that XFS supports (data, log).
---
configure.ac | 1
include/builddefs.in | 4 ++
include/linux.h | 103 +++++++++++++++++++++++++++++++++++++++++++++++++
m4/package_libcdev.m4 | 20 ++++++++++
4 files changed, 128 insertions(+)
diff --git a/configure.ac b/configure.ac
index aa102e4..9534986 100644
--- a/configure.ac
+++ b/configure.ac
@@ -142,6 +142,7 @@ AC_HAVE_READDIR
AC_HAVE_FSETXATTR
AC_HAVE_MREMAP
AC_NEED_INTERNAL_FSXATTR
+AC_HAVE_GETFSMAP
if test "$enable_blkid" = yes; then
AC_HAVE_BLKID_TOPO
diff --git a/include/builddefs.in b/include/builddefs.in
index 4d6bb2d..ec630bd 100644
--- a/include/builddefs.in
+++ b/include/builddefs.in
@@ -112,6 +112,7 @@ HAVE_FLS = @have_fls@
HAVE_FSETXATTR = @have_fsetxattr@
HAVE_MREMAP = @have_mremap@
NEED_INTERNAL_FSXATTR = @need_internal_fsxattr@
+HAVE_GETFSMAP = @have_getfsmap@
GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
# -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
@@ -150,6 +151,9 @@ endif
ifeq ($(NEED_INTERNAL_FSXATTR),yes)
PCFLAGS+= -DOVERRIDE_SYSTEM_FSXATTR
endif
+ifeq ($(HAVE_GETFSMAP),yes)
+PCFLAGS+= -DHAVE_GETFSMAP
+endif
GCFLAGS = $(DEBUG) \
diff --git a/include/linux.h b/include/linux.h
index 6a676ca..38969d1 100644
--- a/include/linux.h
+++ b/include/linux.h
@@ -222,4 +222,107 @@ struct fsxattr {
#define FS_XFLAG_COWEXTSIZE 0x00010000 /* CoW extent size allocator hint */
#endif
+#ifndef HAVE_GETFSMAP
+/*
+ * Structure for FS_IOC_GETFSMAP.
+ *
+ * The memory layout for this call are the scalar values defined in
+ * struct fsmap_head, followed by two struct fsmap that describe
+ * the lower and upper bound of mappings to return, followed by an
+ * array of struct fsmap mappings.
+ *
+ * fmh_iflags control the output of the call, whereas fmh_oflags report
+ * on the overall record output. fmh_count should be set to the
+ * length of the fmh_recs array, and fmh_entries will be set to the
+ * number of entries filled out during each call. If fmh_count is
+ * zero, the number of reverse mappings will be returned in
+ * fmh_entries, though no mappings will be returned. fmh_reserved
+ * must be set to zero.
+ *
+ * The two elements in the fmh_keys array are used to constrain the
+ * output. The first element in the array should represent the
+ * lowest disk mapping ("low key") that the user wants to learn
+ * about. If this value is all zeroes, the filesystem will return
+ * the first entry it knows about. For a subsequent call, the
+ * contents of fsmap_head.fmh_recs[fsmap_head.fmh_count - 1] should be
+ * copied into fmh_keys[0] to have the kernel start where it left off.
+ *
+ * The second element in the fmh_keys array should represent the
+ * highest disk mapping ("high key") that the user wants to learn
+ * about. If this value is all ones, the filesystem will not stop
+ * until it runs out of mapping to return or runs out of space in
+ * fmh_recs.
+ *
+ * fmr_device can be either a 32-bit cookie representing a device, or
+ * a 32-bit dev_t if the FMH_OF_DEV_T flag is set. fmr_physical,
+ * fmr_offset, and fmr_length are expressed in units of bytes.
+ * fmr_owner is either an inode number, or a special value if
+ * FMR_OF_SPECIAL_OWNER is set in fmr_flags.
+ */
+struct fsmap {
+ __u32 fmr_device; /* device id */
+ __u32 fmr_flags; /* mapping flags */
+ __u64 fmr_physical; /* device offset of segment */
+ __u64 fmr_owner; /* owner id */
+ __u64 fmr_offset; /* file offset of segment */
+ __u64 fmr_length; /* length of segment */
+ __u64 fmr_reserved[3]; /* must be zero */
+};
+
+struct fsmap_head {
+ __u32 fmh_iflags; /* control flags */
+ __u32 fmh_oflags; /* output flags */
+ __u32 fmh_count; /* # of entries in array incl. input */
+ __u32 fmh_entries; /* # of entries filled in (output). */
+ __u64 fmh_reserved[6]; /* must be zero */
+
+ struct fsmap fmh_keys[2]; /* low and high keys for the mapping search */
+ struct fsmap fmh_recs[]; /* returned records */
+};
+
+/* Size of an fsmap_head with room for nr records. */
+static inline size_t
+fsmap_sizeof(
+ unsigned int nr)
+{
+ return sizeof(struct fsmap_head) + nr * sizeof(struct fsmap);
+}
+
+/* Start the next fsmap query at the end of the current query results. */
+static inline void
+fsmap_advance(
+ struct fsmap_head *head)
+{
+ head->fmh_keys[0] = head->fmh_recs[head->fmh_entries - 1];
+}
+
+/* fmh_iflags values - set by XFS_IOC_GETFSMAP caller in the header. */
+/* no flags defined yet */
+#define FMH_IF_VALID 0
+
+/* fmh_oflags values - returned in the header segment only. */
+#define FMH_OF_DEV_T 0x1 /* fmr_device values will be dev_t */
+
+/* fmr_flags values - returned for each non-header segment */
+#define FMR_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */
+#define FMR_OF_ATTR_FORK 0x2 /* segment = attribute fork */
+#define FMR_OF_EXTENT_MAP 0x4 /* segment = extent map */
+#define FMR_OF_SHARED 0x8 /* segment = shared with another file */
+#define FMR_OF_SPECIAL_OWNER 0x10 /* owner is a special value */
+#define FMR_OF_LAST 0x20 /* segment is the last in the FS */
+
+/* Each FS gets to define its own special owner codes. */
+#define FMR_OWNER(type, code) (((__u64)type << 32) | \
+ ((__u64)code & 0xFFFFFFFFULL))
+#define FMR_OWNER_TYPE(owner) ((__u32)((__u64)owner >> 32))
+#define FMR_OWNER_CODE(owner) ((__u32)(((__u64)owner & 0xFFFFFFFFULL)))
+#define FMR_OWN_FREE FMR_OWNER(0, 1) /* free space */
+#define FMR_OWN_UNKNOWN FMR_OWNER(0, 2) /* unknown owner */
+#define FMR_OWN_METADATA FMR_OWNER(0, 3) /* metadata */
+
+#define FS_IOC_GETFSMAP _IOWR('X', 59, struct fsmap_head)
+
+#define HAVE_GETFSMAP
+#endif /* HAVE_GETFSMAP */
+
#endif /* __XFS_LINUX_H__ */
diff --git a/m4/package_libcdev.m4 b/m4/package_libcdev.m4
index bc3b4ce..fa5b639 100644
--- a/m4/package_libcdev.m4
+++ b/m4/package_libcdev.m4
@@ -277,3 +277,23 @@ AC_DEFUN([AC_NEED_INTERNAL_FSXATTR],
)
AC_SUBST(need_internal_fsxattr)
])
+
+#
+# Check if we have a FS_IOC_GETFSMAP ioctl (Linux)
+#
+AC_DEFUN([AC_HAVE_GETFSMAP],
+ [ AC_MSG_CHECKING([for GETFSMAP])
+ AC_TRY_LINK([
+#define _GNU_SOURCE
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <linux/fs.h>
+#include <linux/fsmap.h>
+ ], [
+ unsigned long x = FS_IOC_GETFSMAP;
+ struct fsmap_head fh;
+ ], have_getfsmap=yes
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no))
+ AC_SUBST(have_getfsmap)
+ ])
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 02/10] xfs_io: refactor numlen into a library function
2017-06-02 19:51 [PATCH v8 00/10] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
2017-06-02 19:51 ` [PATCH 01/10] xfs: introduce the XFS_IOC_GETFSMAP ioctl Darrick J. Wong
@ 2017-06-02 19:51 ` Darrick J. Wong
2017-06-13 21:09 ` Eric Sandeen
2017-06-02 19:51 ` [PATCH 03/10] xfs_io: support the new getfsmap ioctl Darrick J. Wong
` (7 subsequent siblings)
9 siblings, 1 reply; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-02 19:51 UTC (permalink / raw)
To: sandeen, darrick.wong; +Cc: linux-xfs
From: Darrick J. Wong <darrick.wong@oracle.com>
Refactor the competing numlen implementations into a single library function.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
include/input.h | 1 +
io/bmap.c | 19 ++++---------------
io/fiemap.c | 14 +-------------
libxcmd/input.c | 13 +++++++++++++
4 files changed, 19 insertions(+), 28 deletions(-)
diff --git a/include/input.h b/include/input.h
index 221678e..82cd2f4 100644
--- a/include/input.h
+++ b/include/input.h
@@ -28,6 +28,7 @@ extern char **breakline(char *input, int *count);
extern void doneline(char *input, char **vec);
extern char *fetchline(void);
+extern size_t numlen(uint64_t val, size_t base);
extern long long cvtnum(size_t blocksize, size_t sectorsize, char *s);
extern void cvtstr(double value, char *str, size_t sz);
extern unsigned long cvttime(char *s);
diff --git a/io/bmap.c b/io/bmap.c
index 2333244..2e4ff7b 100644
--- a/io/bmap.c
+++ b/io/bmap.c
@@ -18,6 +18,7 @@
#include "platform_defs.h"
#include "command.h"
+#include "input.h"
#include "init.h"
#include "io.h"
@@ -53,18 +54,6 @@ bmap_help(void)
"\n"));
}
-static int
-numlen(
- off64_t val)
-{
- off64_t tmp;
- int len;
-
- for (len = 0, tmp = val; tmp > 0; tmp = tmp/10)
- len++;
- return (len == 0 ? 1 : len);
-}
-
int
bmap_f(
int argc,
@@ -323,7 +312,7 @@ bmap_f(
if (map[i + 1].bmv_block == -1) {
foff_w = max(foff_w, strlen(rbuf));
tot_w = max(tot_w,
- numlen(map[i+1].bmv_length));
+ numlen(map[i+1].bmv_length, 10));
} else {
snprintf(bbuf, sizeof(bbuf), "%lld..%lld",
(long long) map[i + 1].bmv_block,
@@ -344,10 +333,10 @@ bmap_f(
aoff_w = 0;
foff_w = max(foff_w, strlen(rbuf));
tot_w = max(tot_w,
- numlen(map[i+1].bmv_length));
+ numlen(map[i+1].bmv_length, 10));
}
}
- agno_w = is_rt ? 0 : max(MINAG_WIDTH, numlen(fsgeo.agcount));
+ agno_w = is_rt ? 0 : max(MINAG_WIDTH, numlen(fsgeo.agcount, 10));
printf("%4s: %-*s %-*s %*s %-*s %*s%s\n",
_("EXT"),
foff_w, _("FILE-OFFSET"),
diff --git a/io/fiemap.c b/io/fiemap.c
index bcbae49..75e8820 100644
--- a/io/fiemap.c
+++ b/io/fiemap.c
@@ -18,6 +18,7 @@
#include "platform_defs.h"
#include "command.h"
+#include "input.h"
#include <linux/fiemap.h>
#include "init.h"
#include "io.h"
@@ -48,19 +49,6 @@ fiemap_help(void)
"\n"));
}
-static int
-numlen(
- __u64 val,
- int base)
-{
- __u64 tmp;
- int len;
-
- for (len = 0, tmp = val; tmp > 0; tmp = tmp/base)
- len++;
- return (len == 0 ? 1 : len);
-}
-
static void
print_verbose(
struct fiemap_extent *extent,
diff --git a/libxcmd/input.c b/libxcmd/input.c
index 8aeb3b0..9437be3 100644
--- a/libxcmd/input.c
+++ b/libxcmd/input.c
@@ -136,6 +136,19 @@ doneline(
free(vec);
}
+size_t
+numlen(
+ uint64_t val,
+ size_t base)
+{
+ uint64_t tmp;
+ size_t len;
+
+ for (len = 0, tmp = val; tmp > 0; tmp = tmp / base)
+ len++;
+ return len == 0 ? 1 : len;
+}
+
#define EXABYTES(x) ((long long)(x) << 60)
#define PETABYTES(x) ((long long)(x) << 50)
#define TERABYTES(x) ((long long)(x) << 40)
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 02/10] xfs_io: refactor numlen into a library function
2017-06-02 19:51 ` [PATCH 02/10] xfs_io: refactor numlen into a library function Darrick J. Wong
@ 2017-06-13 21:09 ` Eric Sandeen
0 siblings, 0 replies; 29+ messages in thread
From: Eric Sandeen @ 2017-06-13 21:09 UTC (permalink / raw)
To: Darrick J. Wong, sandeen; +Cc: linux-xfs
On 6/2/17 2:51 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
>
> Refactor the competing numlen implementations into a single library function.
>
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
yay!
Reviewed-by: Eric Sandeen <sandeen@redhat.com>
> ---
> include/input.h | 1 +
> io/bmap.c | 19 ++++---------------
> io/fiemap.c | 14 +-------------
> libxcmd/input.c | 13 +++++++++++++
> 4 files changed, 19 insertions(+), 28 deletions(-)
>
>
> diff --git a/include/input.h b/include/input.h
> index 221678e..82cd2f4 100644
> --- a/include/input.h
> +++ b/include/input.h
> @@ -28,6 +28,7 @@ extern char **breakline(char *input, int *count);
> extern void doneline(char *input, char **vec);
> extern char *fetchline(void);
>
> +extern size_t numlen(uint64_t val, size_t base);
> extern long long cvtnum(size_t blocksize, size_t sectorsize, char *s);
> extern void cvtstr(double value, char *str, size_t sz);
> extern unsigned long cvttime(char *s);
> diff --git a/io/bmap.c b/io/bmap.c
> index 2333244..2e4ff7b 100644
> --- a/io/bmap.c
> +++ b/io/bmap.c
> @@ -18,6 +18,7 @@
>
> #include "platform_defs.h"
> #include "command.h"
> +#include "input.h"
> #include "init.h"
> #include "io.h"
>
> @@ -53,18 +54,6 @@ bmap_help(void)
> "\n"));
> }
>
> -static int
> -numlen(
> - off64_t val)
> -{
> - off64_t tmp;
> - int len;
> -
> - for (len = 0, tmp = val; tmp > 0; tmp = tmp/10)
> - len++;
> - return (len == 0 ? 1 : len);
> -}
> -
> int
> bmap_f(
> int argc,
> @@ -323,7 +312,7 @@ bmap_f(
> if (map[i + 1].bmv_block == -1) {
> foff_w = max(foff_w, strlen(rbuf));
> tot_w = max(tot_w,
> - numlen(map[i+1].bmv_length));
> + numlen(map[i+1].bmv_length, 10));
> } else {
> snprintf(bbuf, sizeof(bbuf), "%lld..%lld",
> (long long) map[i + 1].bmv_block,
> @@ -344,10 +333,10 @@ bmap_f(
> aoff_w = 0;
> foff_w = max(foff_w, strlen(rbuf));
> tot_w = max(tot_w,
> - numlen(map[i+1].bmv_length));
> + numlen(map[i+1].bmv_length, 10));
> }
> }
> - agno_w = is_rt ? 0 : max(MINAG_WIDTH, numlen(fsgeo.agcount));
> + agno_w = is_rt ? 0 : max(MINAG_WIDTH, numlen(fsgeo.agcount, 10));
> printf("%4s: %-*s %-*s %*s %-*s %*s%s\n",
> _("EXT"),
> foff_w, _("FILE-OFFSET"),
> diff --git a/io/fiemap.c b/io/fiemap.c
> index bcbae49..75e8820 100644
> --- a/io/fiemap.c
> +++ b/io/fiemap.c
> @@ -18,6 +18,7 @@
>
> #include "platform_defs.h"
> #include "command.h"
> +#include "input.h"
> #include <linux/fiemap.h>
> #include "init.h"
> #include "io.h"
> @@ -48,19 +49,6 @@ fiemap_help(void)
> "\n"));
> }
>
> -static int
> -numlen(
> - __u64 val,
> - int base)
> -{
> - __u64 tmp;
> - int len;
> -
> - for (len = 0, tmp = val; tmp > 0; tmp = tmp/base)
> - len++;
> - return (len == 0 ? 1 : len);
> -}
> -
> static void
> print_verbose(
> struct fiemap_extent *extent,
> diff --git a/libxcmd/input.c b/libxcmd/input.c
> index 8aeb3b0..9437be3 100644
> --- a/libxcmd/input.c
> +++ b/libxcmd/input.c
> @@ -136,6 +136,19 @@ doneline(
> free(vec);
> }
>
> +size_t
> +numlen(
> + uint64_t val,
> + size_t base)
> +{
> + uint64_t tmp;
> + size_t len;
> +
> + for (len = 0, tmp = val; tmp > 0; tmp = tmp / base)
> + len++;
> + return len == 0 ? 1 : len;
> +}
> +
> #define EXABYTES(x) ((long long)(x) << 60)
> #define PETABYTES(x) ((long long)(x) << 50)
> #define TERABYTES(x) ((long long)(x) << 40)
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 03/10] xfs_io: support the new getfsmap ioctl
2017-06-02 19:51 [PATCH v8 00/10] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
2017-06-02 19:51 ` [PATCH 01/10] xfs: introduce the XFS_IOC_GETFSMAP ioctl Darrick J. Wong
2017-06-02 19:51 ` [PATCH 02/10] xfs_io: refactor numlen into a library function Darrick J. Wong
@ 2017-06-02 19:51 ` Darrick J. Wong
2017-06-13 22:20 ` Eric Sandeen
2017-06-02 19:51 ` [PATCH 04/10] xfs_repair: replace rmap_compare with libxfs version Darrick J. Wong
` (6 subsequent siblings)
9 siblings, 1 reply; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-02 19:51 UTC (permalink / raw)
To: sandeen, darrick.wong; +Cc: linux-xfs
From: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
io/Makefile | 7 +
io/copy_file_range.c | 2
io/encrypt.c | 1
io/fsmap.c | 549 ++++++++++++++++++++++++++++++++++++++++++++++++++
io/init.c | 8 +
io/io.h | 14 +
io/open.c | 21 ++
io/pwrite.c | 2
io/reflink.c | 4
io/sendfile.c | 2
man/man8/xfs_io.8 | 66 ++++++
11 files changed, 663 insertions(+), 13 deletions(-)
create mode 100644 io/fsmap.c
diff --git a/io/Makefile b/io/Makefile
index 435ccff..47b0a66 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -99,6 +99,13 @@ ifeq ($(HAVE_MREMAP),yes)
LCFLAGS += -DHAVE_MREMAP
endif
+# On linux we get fsmap from the system or define it ourselves
+# so include this based on platform type. If this reverts to only
+# the autoconf check w/o local definition, change to testing HAVE_GETFSMAP
+ifeq ($(PKG_PLATFORM),linux)
+CFILES += fsmap.c
+endif
+
default: depend $(LTCOMMAND)
include $(BUILDRULES)
diff --git a/io/copy_file_range.c b/io/copy_file_range.c
index 249c649..d1dfc5a 100644
--- a/io/copy_file_range.c
+++ b/io/copy_file_range.c
@@ -121,7 +121,7 @@ copy_range_f(int argc, char **argv)
if (optind != argc - 1)
return command_usage(©_range_cmd);
- fd = openfile(argv[optind], NULL, IO_READONLY, 0);
+ fd = openfile(argv[optind], NULL, IO_READONLY, 0, NULL);
if (fd < 0)
return 0;
diff --git a/io/encrypt.c b/io/encrypt.c
index d844c5e..26ab97c 100644
--- a/io/encrypt.c
+++ b/io/encrypt.c
@@ -20,6 +20,7 @@
#include "platform_defs.h"
#include "command.h"
#include "init.h"
+#include "path.h"
#include "io.h"
#ifndef ARRAY_SIZE
diff --git a/io/fsmap.c b/io/fsmap.c
new file mode 100644
index 0000000..1f4de81
--- /dev/null
+++ b/io/fsmap.c
@@ -0,0 +1,549 @@
+/*
+ * Copyright (C) 2017 Oracle. All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "platform_defs.h"
+#include "command.h"
+#include "init.h"
+#include "path.h"
+#include "io.h"
+#include "input.h"
+
+static cmdinfo_t fsmap_cmd;
+static dev_t xfs_data_dev;
+
+static void
+fsmap_help(void)
+{
+ printf(_(
+"\n"
+" Prints the block mapping for a filesystem"
+"\n"
+" Example:\n"
+" 'fsmap [-d|-l|-r] [-v] [-n nr] [startoff] [endoff]' - tabular format verbose map, including unwritten extents\n"
+"\n"
+" fsmap prints the map of disk blocks used by the whole filesystem.\n"
+" When possible, owner and offset information will be included in the\n"
+" sapce report.\n"
+"\n"
+" By default, each line of the listing takes the following form:\n"
+" extent: [startoffset..endoffset] owner startblock..endblock\n"
+" The owner field is either an inode number or a special value.\n"
+" All the file offsets and disk blocks are in units of 512-byte blocks.\n"
+" -d -- query only the data device.\n"
+" -l -- query only the log device.\n"
+" -r -- query only the realtime device.\n"
+" -n -- query n extents.\n"
+" -v -- Verbose information, specify ag info. Show flags legend on 2nd -v\n"
+"\n"));
+}
+
+#define OWNER_BUF_SZ 32
+static const char *
+special_owner(
+ int64_t owner,
+ char *buf)
+{
+ switch (owner) {
+ case XFS_FMR_OWN_FREE:
+ return _("free space");
+ case XFS_FMR_OWN_UNKNOWN:
+ return _("unknown");
+ case XFS_FMR_OWN_FS:
+ return _("static fs metadata");
+ case XFS_FMR_OWN_LOG:
+ return _("journalling log");
+ case XFS_FMR_OWN_AG:
+ return _("per-AG metadata");
+ case XFS_FMR_OWN_INOBT:
+ return _("inode btree");
+ case XFS_FMR_OWN_INODES:
+ return _("inodes");
+ case XFS_FMR_OWN_REFC:
+ return _("refcount btree");
+ case XFS_FMR_OWN_COW:
+ return _("cow reservation");
+ case XFS_FMR_OWN_DEFECTIVE:
+ return _("defective");
+ default:
+ snprintf(buf, OWNER_BUF_SZ, _("special %u:%u"),
+ FMR_OWNER_TYPE(owner), FMR_OWNER_CODE(owner));
+ return buf;
+ }
+}
+
+static void
+dump_map(
+ unsigned long long *nr,
+ struct fsmap_head *head)
+{
+ unsigned long long i;
+ struct fsmap *p;
+ char owner[OWNER_BUF_SZ];
+
+ for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) {
+ printf("\t%llu: %u:%u [%lld..%lld]: ", i + (*nr),
+ major(p->fmr_device), minor(p->fmr_device),
+ (long long)BTOBBT(p->fmr_physical),
+ (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1));
+ if (p->fmr_flags & FMR_OF_SPECIAL_OWNER)
+ printf("%s", special_owner(p->fmr_owner, owner));
+ else if (p->fmr_flags & FMR_OF_EXTENT_MAP)
+ printf(_("inode %lld extent map"),
+ (long long) p->fmr_owner);
+ else
+ printf(_("inode %lld %lld..%lld"),
+ (long long)p->fmr_owner,
+ (long long)BTOBBT(p->fmr_offset),
+ (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1));
+ printf(_(" %lld blocks\n"),
+ (long long)BTOBBT(p->fmr_length));
+ }
+
+ (*nr) += head->fmh_entries;
+}
+
+/*
+ * Verbose mode displays:
+ * extent: major:minor [startblock..endblock]: startoffset..endoffset \
+ * ag# (agoffset..agendoffset) totalbbs flags
+ */
+#define MINRANGE_WIDTH 16
+#define MINAG_WIDTH 2
+#define MINTOT_WIDTH 5
+#define NFLG 7 /* count of flags */
+#define FLG_NULL 00000000 /* Null flag */
+#define FLG_ATTR_FORK 01000000 /* attribute fork */
+#define FLG_SHARED 00100000 /* shared extent */
+#define FLG_PRE 00010000 /* Unwritten extent */
+#define FLG_BSU 00001000 /* Not on begin of stripe unit */
+#define FLG_ESU 00000100 /* Not on end of stripe unit */
+#define FLG_BSW 00000010 /* Not on begin of stripe width */
+#define FLG_ESW 00000001 /* Not on end of stripe width */
+static void
+dump_map_verbose(
+ unsigned long long *nr,
+ struct fsmap_head *head,
+ bool *dumped_flags,
+ struct xfs_fsop_geom *fsgeo)
+{
+ unsigned long long i;
+ struct fsmap *p;
+ int agno;
+ off64_t agoff, bperag;
+ int foff_w, boff_w, aoff_w, tot_w, agno_w, own_w;
+ int nr_w, dev_w;
+ char rbuf[32], bbuf[32], abuf[32], obuf[32];
+ char nbuf[32], dbuf[32], gbuf[32];
+ char owner[OWNER_BUF_SZ];
+ int sunit, swidth;
+ int flg = 0;
+
+ foff_w = boff_w = aoff_w = own_w = MINRANGE_WIDTH;
+ dev_w = 3;
+ nr_w = 4;
+ tot_w = MINTOT_WIDTH;
+ bperag = (off64_t)fsgeo->agblocks *
+ (off64_t)fsgeo->blocksize;
+ sunit = (fsgeo->sunit * fsgeo->blocksize);
+ swidth = (fsgeo->swidth * fsgeo->blocksize);
+
+ /*
+ * Go through the extents and figure out the width
+ * needed for all columns.
+ */
+ for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) {
+ if (p->fmr_flags & FMR_OF_PREALLOC ||
+ p->fmr_flags & FMR_OF_ATTR_FORK ||
+ p->fmr_flags & FMR_OF_SHARED)
+ flg = 1;
+ if (sunit &&
+ (p->fmr_physical % sunit != 0 ||
+ ((p->fmr_physical + p->fmr_length) % sunit) != 0 ||
+ p->fmr_physical % swidth != 0 ||
+ ((p->fmr_physical + p->fmr_length) % swidth) != 0))
+ flg = 1;
+ if (flg)
+ *dumped_flags = true;
+ snprintf(nbuf, sizeof(nbuf), "%llu", (*nr) + i);
+ nr_w = max(nr_w, strlen(nbuf));
+ if (head->fmh_oflags & FMH_OF_DEV_T)
+ snprintf(dbuf, sizeof(dbuf), "%u:%u",
+ major(p->fmr_device),
+ minor(p->fmr_device));
+ else
+ snprintf(dbuf, sizeof(dbuf), "0x%x", p->fmr_device);
+ dev_w = max(dev_w, strlen(dbuf));
+ snprintf(bbuf, sizeof(bbuf), "[%lld..%lld]:",
+ (long long)BTOBBT(p->fmr_physical),
+ (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1));
+ boff_w = max(boff_w, strlen(bbuf));
+ if (p->fmr_flags & FMR_OF_SPECIAL_OWNER)
+ own_w = max(own_w, strlen(
+ special_owner(p->fmr_owner, owner)));
+ else {
+ snprintf(obuf, sizeof(obuf), "%lld",
+ (long long)p->fmr_owner);
+ own_w = max(own_w, strlen(obuf));
+ }
+ if (p->fmr_flags & FMR_OF_EXTENT_MAP)
+ foff_w = max(foff_w, strlen(_("extent_map")));
+ else if (p->fmr_flags & FMR_OF_SPECIAL_OWNER)
+ ;
+ else {
+ snprintf(rbuf, sizeof(rbuf), "%lld..%lld",
+ (long long)BTOBBT(p->fmr_offset),
+ (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1));
+ foff_w = max(foff_w, strlen(rbuf));
+ }
+ if (p->fmr_device == xfs_data_dev) {
+ agno = p->fmr_physical / bperag;
+ agoff = p->fmr_physical - (agno * bperag);
+ snprintf(abuf, sizeof(abuf),
+ "(%lld..%lld)",
+ (long long)BTOBBT(agoff),
+ (long long)BTOBBT(agoff + p->fmr_length - 1));
+ } else
+ abuf[0] = 0;
+ aoff_w = max(aoff_w, strlen(abuf));
+ tot_w = max(tot_w,
+ numlen(BTOBBT(p->fmr_length), 10));
+ }
+ agno_w = max(MINAG_WIDTH, numlen(fsgeo->agcount, 10));
+ if (nr == 0)
+ printf("%*s: %-*s %-*s %-*s %-*s %*s %-*s %*s%s\n",
+ nr_w, _("EXT"),
+ dev_w, _("DEV"),
+ boff_w, _("BLOCK-RANGE"),
+ own_w, _("OWNER"),
+ foff_w, _("FILE-OFFSET"),
+ agno_w, _("AG"),
+ aoff_w, _("AG-OFFSET"),
+ tot_w, _("TOTAL"),
+ flg ? _(" FLAGS") : "");
+ for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) {
+ flg = FLG_NULL;
+ if (p->fmr_flags & FMR_OF_PREALLOC)
+ flg |= FLG_PRE;
+ if (p->fmr_flags & FMR_OF_ATTR_FORK)
+ flg |= FLG_ATTR_FORK;
+ if (p->fmr_flags & FMR_OF_SHARED)
+ flg |= FLG_SHARED;
+ /*
+ * If striping enabled, determine if extent starts/ends
+ * on a stripe unit boundary.
+ */
+ if (sunit) {
+ if (p->fmr_physical % sunit != 0)
+ flg |= FLG_BSU;
+ if (((p->fmr_physical +
+ p->fmr_length ) % sunit ) != 0)
+ flg |= FLG_ESU;
+ if (p->fmr_physical % swidth != 0)
+ flg |= FLG_BSW;
+ if (((p->fmr_physical +
+ p->fmr_length ) % swidth ) != 0)
+ flg |= FLG_ESW;
+ }
+ if (head->fmh_oflags & FMH_OF_DEV_T)
+ snprintf(dbuf, sizeof(dbuf), "%u:%u",
+ major(p->fmr_device),
+ minor(p->fmr_device));
+ else
+ snprintf(dbuf, sizeof(dbuf), "0x%x", p->fmr_device);
+ snprintf(bbuf, sizeof(bbuf), "[%lld..%lld]:",
+ (long long)BTOBBT(p->fmr_physical),
+ (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1));
+ if (p->fmr_flags & FMR_OF_SPECIAL_OWNER) {
+ snprintf(obuf, sizeof(obuf), "%s",
+ special_owner(p->fmr_owner, owner));
+ snprintf(rbuf, sizeof(rbuf), " ");
+ } else {
+ snprintf(obuf, sizeof(obuf), "%lld",
+ (long long)p->fmr_owner);
+ snprintf(rbuf, sizeof(rbuf), "%lld..%lld",
+ (long long)BTOBBT(p->fmr_offset),
+ (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1));
+ }
+ if (p->fmr_device == xfs_data_dev) {
+ agno = p->fmr_physical / bperag;
+ agoff = p->fmr_physical - (agno * bperag);
+ snprintf(abuf, sizeof(abuf),
+ "(%lld..%lld)",
+ (long long)BTOBBT(agoff),
+ (long long)BTOBBT(agoff + p->fmr_length - 1));
+ snprintf(gbuf, sizeof(gbuf),
+ "%lld",
+ (long long)agno);
+ } else {
+ abuf[0] = 0;
+ gbuf[0] = 0;
+ }
+ if (p->fmr_flags & FMR_OF_EXTENT_MAP)
+ printf("%*llu: %-*s %-*s %-*s %-*s %-*s %-*s %*lld\n",
+ nr_w, (*nr) + i,
+ dev_w, dbuf,
+ boff_w, bbuf,
+ own_w, obuf,
+ foff_w, _("extent map"),
+ agno_w, gbuf,
+ aoff_w, abuf,
+ tot_w, (long long)BTOBBT(p->fmr_length));
+ else {
+ printf("%*llu: %-*s %-*s %-*s %-*s", nr_w, (*nr) + i,
+ dev_w, dbuf, boff_w, bbuf, own_w, obuf,
+ foff_w, rbuf);
+ printf(" %-*s %-*s", agno_w, gbuf,
+ aoff_w, abuf);
+ printf(" %*lld", tot_w,
+ (long long)BTOBBT(p->fmr_length));
+ if (flg == FLG_NULL)
+ printf("\n");
+ else
+ printf(" %-*.*o\n", NFLG, NFLG, flg);
+ }
+ }
+
+ (*nr) += head->fmh_entries;
+}
+
+static void
+dump_verbose_key(void)
+{
+ printf(_(" FLAG Values:\n"));
+ printf(_(" %*.*o Attribute fork\n"),
+ NFLG+1, NFLG+1, FLG_ATTR_FORK);
+ printf(_(" %*.*o Shared extent\n"),
+ NFLG+1, NFLG+1, FLG_SHARED);
+ printf(_(" %*.*o Unwritten preallocated extent\n"),
+ NFLG+1, NFLG+1, FLG_PRE);
+ printf(_(" %*.*o Doesn't begin on stripe unit\n"),
+ NFLG+1, NFLG+1, FLG_BSU);
+ printf(_(" %*.*o Doesn't end on stripe unit\n"),
+ NFLG+1, NFLG+1, FLG_ESU);
+ printf(_(" %*.*o Doesn't begin on stripe width\n"),
+ NFLG+1, NFLG+1, FLG_BSW);
+ printf(_(" %*.*o Doesn't end on stripe width\n"),
+ NFLG+1, NFLG+1, FLG_ESW);
+}
+
+int
+fsmap_f(
+ int argc,
+ char **argv)
+{
+ struct fsmap *p;
+ struct fsmap_head *nhead;
+ struct fsmap_head *head;
+ struct fsmap *l, *h;
+ struct xfs_fsop_geom fsgeo;
+ long long start = 0;
+ long long end = -1;
+ int nmap_size;
+ int map_size;
+ int nflag = 0;
+ int vflag = 0;
+ int i = 0;
+ int c;
+ unsigned long long nr = 0;
+ size_t fsblocksize, fssectsize;
+ struct fs_path *fs;
+ static bool tab_init;
+ bool dumped_flags = false;
+ int dflag, lflag, rflag;
+
+ init_cvtnum(&fsblocksize, &fssectsize);
+
+ dflag = lflag = rflag = 0;
+ while ((c = getopt(argc, argv, "dln:rv")) != EOF) {
+ switch (c) {
+ case 'd': /* data device */
+ dflag = 1;
+ break;
+ case 'l': /* log device */
+ lflag = 1;
+ break;
+ case 'n': /* number of extents specified */
+ nflag = atoi(optarg);
+ break;
+ case 'r': /* rt device */
+ rflag = 1;
+ break;
+ case 'v': /* Verbose output */
+ vflag++;
+ break;
+ default:
+ return command_usage(&fsmap_cmd);
+ }
+ }
+
+ if (dflag + lflag + rflag > 1)
+ return command_usage(&fsmap_cmd);
+
+ if (argc > optind && dflag + lflag + rflag == 0)
+ return command_usage(&fsmap_cmd);
+
+ if (argc > optind) {
+ start = cvtnum(fsblocksize, fssectsize, argv[optind]);
+ if (start < 0) {
+ fprintf(stderr,
+ _("Bad rmap start_bblock %s.\n"),
+ argv[optind]);
+ return 0;
+ }
+ start <<= BBSHIFT;
+ }
+
+ if (argc > optind + 1) {
+ end = cvtnum(fsblocksize, fssectsize, argv[optind + 1]);
+ if (end < 0) {
+ fprintf(stderr,
+ _("Bad rmap end_bblock %s.\n"),
+ argv[optind + 1]);
+ return 0;
+ }
+ end <<= BBSHIFT;
+ }
+
+ if (vflag) {
+ c = ioctl(file->fd, XFS_IOC_FSGEOMETRY, &fsgeo);
+ if (c < 0) {
+ fprintf(stderr,
+ _("%s: can't get geometry [\"%s\"]: %s\n"),
+ progname, file->name, strerror(errno));
+ exitcode = 1;
+ return 0;
+ }
+ }
+
+ map_size = nflag ? nflag : 131072 / sizeof(struct fsmap);
+ head = malloc(fsmap_sizeof(map_size));
+ if (head == NULL) {
+ fprintf(stderr, _("%s: malloc of %zu bytes failed.\n"),
+ progname, fsmap_sizeof(map_size));
+ exitcode = 1;
+ return 0;
+ }
+
+ memset(head, 0, sizeof(*head));
+ l = head->fmh_keys;
+ h = head->fmh_keys + 1;
+ if (dflag) {
+ l->fmr_device = h->fmr_device = file->fs_path.fs_datadev;
+ } else if (lflag) {
+ l->fmr_device = h->fmr_device = file->fs_path.fs_logdev;
+ } else if (rflag) {
+ l->fmr_device = h->fmr_device = file->fs_path.fs_rtdev;
+ } else {
+ l->fmr_device = 0;
+ h->fmr_device = UINT_MAX;
+ }
+ l->fmr_physical = start;
+ h->fmr_physical = end;
+ h->fmr_owner = ULLONG_MAX;
+ h->fmr_flags = UINT_MAX;
+ h->fmr_offset = ULLONG_MAX;
+
+ /* Count mappings */
+ if (!nflag) {
+ head->fmh_count = 0;
+ i = ioctl(file->fd, FS_IOC_GETFSMAP, head);
+ if (i < 0) {
+ fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETFSMAP)"
+ " iflags=0x%x [\"%s\"]: %s\n"),
+ progname, head->fmh_iflags, file->name,
+ strerror(errno));
+ free(head);
+ exitcode = 1;
+ return 0;
+ }
+ if (head->fmh_entries > map_size + 2) {
+ map_size = 11ULL * head->fmh_entries / 10;
+ nmap_size = map_size > (1 << 24) ? (1 << 24) : map_size;
+ nhead = realloc(head, fsmap_sizeof(nmap_size));
+ if (nhead == NULL) {
+ fprintf(stderr,
+ _("%s: cannot realloc %zu bytes\n"),
+ progname, fsmap_sizeof(nmap_size));
+ } else {
+ head = nhead;
+ map_size = nmap_size;
+ }
+ }
+ }
+
+ /*
+ * If this is an XFS filesystem, remember the data device.
+ * (We report AG number/block for data device extents on XFS).
+ */
+ if (!tab_init) {
+ fs_table_initialise(0, NULL, 0, NULL);
+ tab_init = true;
+ }
+ fs = fs_table_lookup(file->name, FS_MOUNT_POINT);
+ xfs_data_dev = fs ? fs->fs_datadev : 0;
+
+ head->fmh_count = map_size;
+ do {
+ /* Get some extents */
+ i = ioctl(file->fd, FS_IOC_GETFSMAP, head);
+ if (i < 0) {
+ fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETFSMAP)"
+ " iflags=0x%x [\"%s\"]: %s\n"),
+ progname, head->fmh_iflags, file->name,
+ strerror(errno));
+ free(head);
+ exitcode = 1;
+ return 0;
+ }
+
+ if (head->fmh_entries == 0)
+ break;
+
+ if (!vflag)
+ dump_map(&nr, head);
+ else
+ dump_map_verbose(&nr, head, &dumped_flags, &fsgeo);
+
+ p = &head->fmh_recs[head->fmh_entries - 1];
+ if (p->fmr_flags & FMR_OF_LAST)
+ break;
+ fsmap_advance(head);
+ } while (true);
+
+ if (dumped_flags)
+ dump_verbose_key();
+
+ free(head);
+ return 0;
+}
+
+void
+fsmap_init(void)
+{
+ fsmap_cmd.name = "fsmap";
+ fsmap_cmd.cfunc = fsmap_f;
+ fsmap_cmd.argmin = 0;
+ fsmap_cmd.argmax = -1;
+ fsmap_cmd.flags = CMD_NOMAP_OK | CMD_FLAG_FOREIGN_OK;
+ fsmap_cmd.args = _("[-d|-l|-r] [-v] [-n nx] [start] [end]");
+ fsmap_cmd.oneline = _("print filesystem mapping for a range of blocks");
+ fsmap_cmd.help = fsmap_help;
+
+ add_command(&fsmap_cmd);
+}
diff --git a/io/init.c b/io/init.c
index c15a1e1..20d5f80 100644
--- a/io/init.c
+++ b/io/init.c
@@ -66,6 +66,7 @@ init_commands(void)
file_init();
flink_init();
freeze_init();
+ fsmap_init();
fsync_init();
getrusage_init();
help_init();
@@ -139,6 +140,7 @@ init(
char *sp;
mode_t mode = 0600;
xfs_fsop_geom_t geometry = { 0 };
+ struct fs_path fsp;
progname = basename(argv[0]);
setlocale(LC_ALL, "");
@@ -148,6 +150,7 @@ init(
pagesize = getpagesize();
gettimeofday(&stopwatch, NULL);
+ fs_table_initialise(0, NULL, 0, NULL);
while ((c = getopt(argc, argv, "ac:C:dFfim:p:nrRstTVx")) != EOF) {
switch (c) {
case 'a':
@@ -212,11 +215,12 @@ init(
}
while (optind < argc) {
- if ((c = openfile(argv[optind], &geometry, flags, mode)) < 0)
+ c = openfile(argv[optind], &geometry, flags, mode, &fsp);
+ if (c < 0)
exit(1);
if (!platform_test_xfs_fd(c))
flags |= IO_FOREIGN;
- if (addfile(argv[optind], c, &geometry, flags) < 0)
+ if (addfile(argv[optind], c, &geometry, flags, &fsp) < 0)
exit(1);
optind++;
}
diff --git a/io/io.h b/io/io.h
index 952bdb8..6a0fe65 100644
--- a/io/io.h
+++ b/io/io.h
@@ -17,6 +17,7 @@
*/
#include "xfs.h"
+#include "path.h"
/*
* Read/write patterns (default is always "forward")
@@ -47,6 +48,7 @@ typedef struct fileio {
int flags; /* flags describing file state */
char *name; /* file name at time of open */
xfs_fsop_geom_t geom; /* XFS filesystem geometry */
+ struct fs_path fs_path; /* XFS path information */
} fileio_t;
extern fileio_t *filetable; /* open file table */
@@ -76,8 +78,10 @@ extern void *check_mapping_range(mmap_region_t *, off64_t, size_t, int);
*/
extern off64_t filesize(void);
-extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t);
-extern int addfile(char *, int , xfs_fsop_geom_t *, int);
+extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t,
+ struct fs_path *);
+extern int addfile(char *, int , xfs_fsop_geom_t *, int,
+ struct fs_path *);
extern void printxattr(uint, int, int, const char *, int, int);
extern unsigned int recurse_all;
@@ -174,3 +178,9 @@ extern void readdir_init(void);
extern void reflink_init(void);
extern void cowextsize_init(void);
+
+#ifdef HAVE_GETFSMAP
+extern void fsmap_init(void);
+#else
+# define fsmap_init() do { } while (0)
+#endif
diff --git a/io/open.c b/io/open.c
index 2ed55cf..b50f068 100644
--- a/io/open.c
+++ b/io/open.c
@@ -52,8 +52,10 @@ openfile(
char *path,
xfs_fsop_geom_t *geom,
int flags,
- mode_t mode)
+ mode_t mode,
+ struct fs_path *fs_path)
{
+ struct fs_path *fsp;
int fd;
int oflags;
@@ -118,6 +120,14 @@ openfile(
}
}
}
+
+ if (fs_path) {
+ fsp = fs_table_lookup(path, FS_MOUNT_POINT);
+ if (!fsp)
+ memset(fs_path, 0, sizeof(*fs_path));
+ else
+ *fs_path = *fsp;
+ }
return fd;
}
@@ -126,7 +136,8 @@ addfile(
char *name,
int fd,
xfs_fsop_geom_t *geometry,
- int flags)
+ int flags,
+ struct fs_path *fs_path)
{
char *filename;
@@ -154,6 +165,7 @@ addfile(
file->flags = flags;
file->name = filename;
file->geom = *geometry;
+ file->fs_path = *fs_path;
return 0;
}
@@ -195,6 +207,7 @@ open_f(
char *sp;
mode_t mode = 0600;
xfs_fsop_geom_t geometry = { 0 };
+ struct fs_path fsp;
if (argc == 1) {
if (file)
@@ -257,14 +270,14 @@ open_f(
return -1;
}
- fd = openfile(argv[optind], &geometry, flags, mode);
+ fd = openfile(argv[optind], &geometry, flags, mode, &fsp);
if (fd < 0)
return 0;
if (!platform_test_xfs_fd(fd))
flags |= IO_FOREIGN;
- addfile(argv[optind], fd, &geometry, flags);
+ addfile(argv[optind], fd, &geometry, flags, &fsp);
return 0;
}
diff --git a/io/pwrite.c b/io/pwrite.c
index 7c0bb7f..1c5dfca 100644
--- a/io/pwrite.c
+++ b/io/pwrite.c
@@ -357,7 +357,7 @@ pwrite_f(
return 0;
c = IO_READONLY | (dflag ? IO_DIRECT : 0);
- if (infile && ((fd = openfile(infile, NULL, c, 0)) < 0))
+ if (infile && ((fd = openfile(infile, NULL, c, 0, NULL)) < 0))
return 0;
gettimeofday(&t1, NULL);
diff --git a/io/reflink.c b/io/reflink.c
index fe05d1e..f584e8f 100644
--- a/io/reflink.c
+++ b/io/reflink.c
@@ -154,7 +154,7 @@ dedupe_f(
return 0;
}
- fd = openfile(infile, NULL, IO_READONLY, 0);
+ fd = openfile(infile, NULL, IO_READONLY, 0, NULL);
if (fd < 0)
return 0;
@@ -278,7 +278,7 @@ reflink_f(
}
clone_all:
- fd = openfile(infile, NULL, IO_READONLY, 0);
+ fd = openfile(infile, NULL, IO_READONLY, 0, NULL);
if (fd < 0)
return 0;
diff --git a/io/sendfile.c b/io/sendfile.c
index edd31c9..063fa7f 100644
--- a/io/sendfile.c
+++ b/io/sendfile.c
@@ -115,7 +115,7 @@ sendfile_f(
if (!infile)
fd = filetable[fd].fd;
- else if ((fd = openfile(infile, NULL, IO_READONLY, 0)) < 0)
+ else if ((fd = openfile(infile, NULL, IO_READONLY, 0, NULL)) < 0)
return 0;
if (optind == argc - 2) {
diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
index 29a036c..bd8af47 100644
--- a/man/man8/xfs_io.8
+++ b/man/man8/xfs_io.8
@@ -301,6 +301,72 @@ ioctl. Options behave as described in the
.BR xfs_bmap (8)
manual page.
.TP
+.BI "fsmap [ \-d | \-l | \-r ] [ \-v ] [ \-n " nx " ] [ " start " ] [ " end " ]
+Prints the mapping of disk blocks used by a filesystem.
+The map lists each extent used by files, allocation group metadata,
+journalling logs, and static filesystem metadata, as well as any
+regions that are unused.
+Each line of the listings takes the following form:
+.PP
+.RS
+.IR extent ": " major ":" minor " [" startblock .. endblock "]: " owner " " startoffset .. endoffset " " length
+.PP
+Static filesystem metadata, allocation group metadata, btrees,
+journalling logs, and free space are marked by replacing the
+.IR startoffset .. endoffset
+with the appropriate marker.
+All blocks, offsets, and lengths are specified in units of 512-byte
+blocks, no matter what the filesystem's block size is.
+The optional
+.I start
+and
+.I end
+arguments can be used to constrain the output to a particular range of
+disk blocks.
+.RE
+.RS 1.0i
+.PD 0
+.TP
+.BI \-d
+Display only extents from the data device.
+This option only applies for XFS filesystems.
+.TP
+.BI \-l
+Display only extents from the external log device.
+This option only applies to XFS filesystems.
+.TP
+.BI \-r
+Display only extents from the realtime device.
+This option only applies to XFS filesystems.
+.TP
+.BI \-n " num_extents"
+If this option is given,
+.B xfs_fsmap
+obtains the extent list of the file in groups of
+.I num_extents
+extents.
+In the absence of
+.BR \-n ", " xfs_fsmap
+queries the system for the number of extents in the filesystem and uses
+that value to compute the group size.
+.TP
+.B \-v
+Shows verbose information.
+When this flag is specified, additional AG specific information is
+appended to each line in the following form:
+.IP
+.RS 1.2i
+.IR agno " (" startagblock .. endagblock ") " nblocks " " flags
+.RE
+.IP
+A second
+.B \-v
+option will print out the
+.I flags
+legend.
+.RE
+.PD
+.TP
.BI "extsize [ \-R | \-D ] [ " value " ]"
Display and/or modify the preferred extent size used when allocating
space for the currently open file. If the
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 03/10] xfs_io: support the new getfsmap ioctl
2017-06-02 19:51 ` [PATCH 03/10] xfs_io: support the new getfsmap ioctl Darrick J. Wong
@ 2017-06-13 22:20 ` Eric Sandeen
2017-06-14 0:23 ` Darrick J. Wong
0 siblings, 1 reply; 29+ messages in thread
From: Eric Sandeen @ 2017-06-13 22:20 UTC (permalink / raw)
To: Darrick J. Wong, sandeen; +Cc: linux-xfs
On 6/2/17 2:51 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
>
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Sorry Darrick, lots more here that I missed the first time around.
> ---
> io/Makefile | 7 +
> io/copy_file_range.c | 2
> io/encrypt.c | 1
> io/fsmap.c | 549 ++++++++++++++++++++++++++++++++++++++++++++++++++
> io/init.c | 8 +
> io/io.h | 14 +
> io/open.c | 21 ++
> io/pwrite.c | 2
> io/reflink.c | 4
> io/sendfile.c | 2
> man/man8/xfs_io.8 | 66 ++++++
> 11 files changed, 663 insertions(+), 13 deletions(-)
> create mode 100644 io/fsmap.c
>
>
> diff --git a/io/Makefile b/io/Makefile
> index 435ccff..47b0a66 100644
> --- a/io/Makefile
> +++ b/io/Makefile
> @@ -99,6 +99,13 @@ ifeq ($(HAVE_MREMAP),yes)
> LCFLAGS += -DHAVE_MREMAP
> endif
>
> +# On linux we get fsmap from the system or define it ourselves
> +# so include this based on platform type. If this reverts to only
> +# the autoconf check w/o local definition, change to testing HAVE_GETFSMAP
> +ifeq ($(PKG_PLATFORM),linux)
> +CFILES += fsmap.c
> +endif
> +
> default: depend $(LTCOMMAND)
>
> include $(BUILDRULES)
> diff --git a/io/copy_file_range.c b/io/copy_file_range.c
> index 249c649..d1dfc5a 100644
> --- a/io/copy_file_range.c
> +++ b/io/copy_file_range.c
> @@ -121,7 +121,7 @@ copy_range_f(int argc, char **argv)
> if (optind != argc - 1)
> return command_usage(©_range_cmd);
>
> - fd = openfile(argv[optind], NULL, IO_READONLY, 0);
> + fd = openfile(argv[optind], NULL, IO_READONLY, 0, NULL);
> if (fd < 0)
> return 0;
>
> diff --git a/io/encrypt.c b/io/encrypt.c
> index d844c5e..26ab97c 100644
> --- a/io/encrypt.c
> +++ b/io/encrypt.c
> @@ -20,6 +20,7 @@
> #include "platform_defs.h"
> #include "command.h"
> #include "init.h"
> +#include "path.h"
> #include "io.h"
>
> #ifndef ARRAY_SIZE
> diff --git a/io/fsmap.c b/io/fsmap.c
> new file mode 100644
> index 0000000..1f4de81
> --- /dev/null
> +++ b/io/fsmap.c
> @@ -0,0 +1,549 @@
> +/*
> + * Copyright (C) 2017 Oracle. All Rights Reserved.
> + *
> + * Author: Darrick J. Wong <darrick.wong@oracle.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation,
> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
> + */
> +#include "platform_defs.h"
> +#include "command.h"
> +#include "init.h"
> +#include "path.h"
> +#include "io.h"
> +#include "input.h"
> +
> +static cmdinfo_t fsmap_cmd;
> +static dev_t xfs_data_dev;
> +
> +static void
> +fsmap_help(void)
> +{
> + printf(_(
> +"\n"
> +" Prints the block mapping for a filesystem"
> +"\n"
> +" Example:\n"
> +" 'fsmap [-d|-l|-r] [-v] [-n nr] [startoff] [endoff]' - tabular format verbose map, including unwritten extents\n"
Whoops, I missed this the first time, that's a restatement of all options,
not an example.
(Or I'd probably just drop it, I don't think an example is needed
or useful, but as you like it... I guess it's modeled on fiemap)
> +"\n"
> +" fsmap prints the map of disk blocks used by the whole filesystem.\n"
> +" When possible, owner and offset information will be included in the\n"
> +" sapce report.\n"
> +"\n"
> +" By default, each line of the listing takes the following form:\n"
> +" extent: [startoffset..endoffset] owner startblock..endblock\n"
Hm, no:
0: 8:17 [0..1175]: unknown 1176 blocks
1: 8:17 [1176..1183]: free space 8 blocks
manpage gets it right:
extent: major:minor [startblock..endblock]: owner startoffset..endoffset length
(I might drop the last "blocks"... is it useful? fiemap doesn't use it)
Sigh, sorry for missing stuff on the first round.
OK fiemap prints a header with -v ...
# io/xfs_io -c "fiemap -v" /mnt/test/junk
/mnt/test/junk:
EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS
0: [0..7]: hole 8
1: [8..39]: 5936..5967 32 0x0
I think that'd be useful here, too ... oh, bug. see below. (s/nr == 0/*nr == 0/)
> +" The owner field is either an inode number or a special value.\n"
> +" All the file offsets and disk blocks are in units of 512-byte blocks.\n"
> +" -d -- query only the data device.\n"
(this is the default, yes?)
> +" -l -- query only the log device.\n"
Hm, with an external log I get:
xfs_io> fsmap -l
0: 7:7 [0..2097151]: journalling log 2097152 blocks
but an internal log does not show those blocks in the output, should it?
> +" -r -- query only the realtime device.\n"
> +" -n -- query n extents.\n"
-n doesn't seem to work as described:
# io/xfs_io -c "fsmap -n 2" /mnt/test
0: 8:17 [0..1175]: unknown 1176 blocks
1: 8:17 [1176..1183]: free space 8 blocks
2: 8:17 [1184..1327]: unknown 144 blocks
3: 8:17 [1328..1343]: free space 16 blocks
Oh, it's "at a time" - so help text needs to be fixed to reflect that it's
the size of each query, not the total number queried.
> +" -v -- Verbose information, specify ag info. Show flags legend on 2nd -v\n"
(and FILE-OFFSET of each owner?)
There are no flags printed AFAICT, and no different behavior with -vv...
but that seems broken somewhere.
Oh, it looks like if no flags are (will be?) printed we skip the column
and the legend. That seems a little odd to me... is it intentional?
> +"\n"));
> +}
> +
> +#define OWNER_BUF_SZ 32
> +static const char *
> +special_owner(
> + int64_t owner,
> + char *buf)
> +{
> + switch (owner) {
> + case XFS_FMR_OWN_FREE:
> + return _("free space");
(Aside: I wonder if there's any way to avoid spaces in the owner field,
so that awk can easily parse the result...? Not sure how that'd look,
but it'd make it a lot more useful when presented with thousands of
records)
> + case XFS_FMR_OWN_UNKNOWN:
> + return _("unknown");
> + case XFS_FMR_OWN_FS:
> + return _("static fs metadata");
> + case XFS_FMR_OWN_LOG:
> + return _("journalling log");
> + case XFS_FMR_OWN_AG:
> + return _("per-AG metadata");
> + case XFS_FMR_OWN_INOBT:
> + return _("inode btree");
> + case XFS_FMR_OWN_INODES:
> + return _("inodes");
> + case XFS_FMR_OWN_REFC:
> + return _("refcount btree");
> + case XFS_FMR_OWN_COW:
> + return _("cow reservation");
> + case XFS_FMR_OWN_DEFECTIVE:
> + return _("defective");
> + default:
> + snprintf(buf, OWNER_BUF_SZ, _("special %u:%u"),
> + FMR_OWNER_TYPE(owner), FMR_OWNER_CODE(owner));
> + return buf;
> + }
> +}
> +
> +static void
> +dump_map(
> + unsigned long long *nr,
> + struct fsmap_head *head)
> +{
> + unsigned long long i;
> + struct fsmap *p;
> + char owner[OWNER_BUF_SZ];
> +
> + for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) {
> + printf("\t%llu: %u:%u [%lld..%lld]: ", i + (*nr),
> + major(p->fmr_device), minor(p->fmr_device),
> + (long long)BTOBBT(p->fmr_physical),
> + (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1));
> + if (p->fmr_flags & FMR_OF_SPECIAL_OWNER)
> + printf("%s", special_owner(p->fmr_owner, owner));
> + else if (p->fmr_flags & FMR_OF_EXTENT_MAP)
> + printf(_("inode %lld extent map"),
> + (long long) p->fmr_owner);
> + else
> + printf(_("inode %lld %lld..%lld"),
> + (long long)p->fmr_owner,
> + (long long)BTOBBT(p->fmr_offset),
> + (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1));
> + printf(_(" %lld blocks\n"),
> + (long long)BTOBBT(p->fmr_length));
> + }
> +
> + (*nr) += head->fmh_entries;
> +}
> +
> +/*
> + * Verbose mode displays:
> + * extent: major:minor [startblock..endblock]: startoffset..endoffset \
> + * ag# (agoffset..agendoffset) totalbbs flags
> + */
> +#define MINRANGE_WIDTH 16
> +#define MINAG_WIDTH 2
> +#define MINTOT_WIDTH 5
> +#define NFLG 7 /* count of flags */
> +#define FLG_NULL 00000000 /* Null flag */
> +#define FLG_ATTR_FORK 01000000 /* attribute fork */
> +#define FLG_SHARED 00100000 /* shared extent */
> +#define FLG_PRE 00010000 /* Unwritten extent */
> +#define FLG_BSU 00001000 /* Not on begin of stripe unit */
> +#define FLG_ESU 00000100 /* Not on end of stripe unit */
> +#define FLG_BSW 00000010 /* Not on begin of stripe width */
> +#define FLG_ESW 00000001 /* Not on end of stripe width */
> +static void
> +dump_map_verbose(
> + unsigned long long *nr,
> + struct fsmap_head *head,
> + bool *dumped_flags,
> + struct xfs_fsop_geom *fsgeo)
> +{
> + unsigned long long i;
> + struct fsmap *p;
> + int agno;
> + off64_t agoff, bperag;
> + int foff_w, boff_w, aoff_w, tot_w, agno_w, own_w;
> + int nr_w, dev_w;
> + char rbuf[32], bbuf[32], abuf[32], obuf[32];
> + char nbuf[32], dbuf[32], gbuf[32];
> + char owner[OWNER_BUF_SZ];
> + int sunit, swidth;
> + int flg = 0;
> +
> + foff_w = boff_w = aoff_w = own_w = MINRANGE_WIDTH;
> + dev_w = 3;
> + nr_w = 4;
> + tot_w = MINTOT_WIDTH;
> + bperag = (off64_t)fsgeo->agblocks *
> + (off64_t)fsgeo->blocksize;
> + sunit = (fsgeo->sunit * fsgeo->blocksize);
> + swidth = (fsgeo->swidth * fsgeo->blocksize);
> +
> + /*
> + * Go through the extents and figure out the width
> + * needed for all columns.
> + */
> + for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) {
> + if (p->fmr_flags & FMR_OF_PREALLOC ||
> + p->fmr_flags & FMR_OF_ATTR_FORK ||
> + p->fmr_flags & FMR_OF_SHARED)
> + flg = 1;
> + if (sunit &&
> + (p->fmr_physical % sunit != 0 ||
> + ((p->fmr_physical + p->fmr_length) % sunit) != 0 ||
> + p->fmr_physical % swidth != 0 ||
> + ((p->fmr_physical + p->fmr_length) % swidth) != 0))
> + flg = 1;
> + if (flg)
> + *dumped_flags = true;
> + snprintf(nbuf, sizeof(nbuf), "%llu", (*nr) + i);
> + nr_w = max(nr_w, strlen(nbuf));
> + if (head->fmh_oflags & FMH_OF_DEV_T)
> + snprintf(dbuf, sizeof(dbuf), "%u:%u",
> + major(p->fmr_device),
> + minor(p->fmr_device));
> + else
> + snprintf(dbuf, sizeof(dbuf), "0x%x", p->fmr_device);
> + dev_w = max(dev_w, strlen(dbuf));
> + snprintf(bbuf, sizeof(bbuf), "[%lld..%lld]:",
> + (long long)BTOBBT(p->fmr_physical),
> + (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1));
> + boff_w = max(boff_w, strlen(bbuf));
> + if (p->fmr_flags & FMR_OF_SPECIAL_OWNER)
> + own_w = max(own_w, strlen(
> + special_owner(p->fmr_owner, owner)));
> + else {
> + snprintf(obuf, sizeof(obuf), "%lld",
> + (long long)p->fmr_owner);
> + own_w = max(own_w, strlen(obuf));
> + }
> + if (p->fmr_flags & FMR_OF_EXTENT_MAP)
> + foff_w = max(foff_w, strlen(_("extent_map")));
> + else if (p->fmr_flags & FMR_OF_SPECIAL_OWNER)
> + ;
> + else {
> + snprintf(rbuf, sizeof(rbuf), "%lld..%lld",
> + (long long)BTOBBT(p->fmr_offset),
> + (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1));
> + foff_w = max(foff_w, strlen(rbuf));
> + }
> + if (p->fmr_device == xfs_data_dev) {
> + agno = p->fmr_physical / bperag;
> + agoff = p->fmr_physical - (agno * bperag);
> + snprintf(abuf, sizeof(abuf),
> + "(%lld..%lld)",
> + (long long)BTOBBT(agoff),
> + (long long)BTOBBT(agoff + p->fmr_length - 1));
> + } else
> + abuf[0] = 0;
> + aoff_w = max(aoff_w, strlen(abuf));
> + tot_w = max(tot_w,
> + numlen(BTOBBT(p->fmr_length), 10));
> + }
> + agno_w = max(MINAG_WIDTH, numlen(fsgeo->agcount, 10));
> + if (nr == 0)
if (*nr == 0)
> + printf("%*s: %-*s %-*s %-*s %-*s %*s %-*s %*s%s\n",
> + nr_w, _("EXT"),
> + dev_w, _("DEV"),
> + boff_w, _("BLOCK-RANGE"),
> + own_w, _("OWNER"),
> + foff_w, _("FILE-OFFSET"),
> + agno_w, _("AG"),
> + aoff_w, _("AG-OFFSET"),
> + tot_w, _("TOTAL"),
> + flg ? _(" FLAGS") : "");
> + for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) {
> + flg = FLG_NULL;
> + if (p->fmr_flags & FMR_OF_PREALLOC)
> + flg |= FLG_PRE;
> + if (p->fmr_flags & FMR_OF_ATTR_FORK)
> + flg |= FLG_ATTR_FORK;
> + if (p->fmr_flags & FMR_OF_SHARED)
> + flg |= FLG_SHARED;
> + /*
> + * If striping enabled, determine if extent starts/ends
> + * on a stripe unit boundary.
> + */
> + if (sunit) {
> + if (p->fmr_physical % sunit != 0)
> + flg |= FLG_BSU;
> + if (((p->fmr_physical +
> + p->fmr_length ) % sunit ) != 0)
> + flg |= FLG_ESU;
> + if (p->fmr_physical % swidth != 0)
> + flg |= FLG_BSW;
> + if (((p->fmr_physical +
> + p->fmr_length ) % swidth ) != 0)
> + flg |= FLG_ESW;
> + }
> + if (head->fmh_oflags & FMH_OF_DEV_T)
> + snprintf(dbuf, sizeof(dbuf), "%u:%u",
> + major(p->fmr_device),
> + minor(p->fmr_device));
> + else
> + snprintf(dbuf, sizeof(dbuf), "0x%x", p->fmr_device);
> + snprintf(bbuf, sizeof(bbuf), "[%lld..%lld]:",
> + (long long)BTOBBT(p->fmr_physical),
> + (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1));
> + if (p->fmr_flags & FMR_OF_SPECIAL_OWNER) {
> + snprintf(obuf, sizeof(obuf), "%s",
> + special_owner(p->fmr_owner, owner));
> + snprintf(rbuf, sizeof(rbuf), " ");
> + } else {
> + snprintf(obuf, sizeof(obuf), "%lld",
> + (long long)p->fmr_owner);
> + snprintf(rbuf, sizeof(rbuf), "%lld..%lld",
> + (long long)BTOBBT(p->fmr_offset),
> + (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1));
> + }
> + if (p->fmr_device == xfs_data_dev) {
> + agno = p->fmr_physical / bperag;
> + agoff = p->fmr_physical - (agno * bperag);
> + snprintf(abuf, sizeof(abuf),
> + "(%lld..%lld)",
> + (long long)BTOBBT(agoff),
> + (long long)BTOBBT(agoff + p->fmr_length - 1));
> + snprintf(gbuf, sizeof(gbuf),
> + "%lld",
> + (long long)agno);
> + } else {
> + abuf[0] = 0;
> + gbuf[0] = 0;
> + }
> + if (p->fmr_flags & FMR_OF_EXTENT_MAP)
> + printf("%*llu: %-*s %-*s %-*s %-*s %-*s %-*s %*lld\n",
> + nr_w, (*nr) + i,
> + dev_w, dbuf,
> + boff_w, bbuf,
> + own_w, obuf,
> + foff_w, _("extent map"),
> + agno_w, gbuf,
> + aoff_w, abuf,
> + tot_w, (long long)BTOBBT(p->fmr_length));
> + else {
> + printf("%*llu: %-*s %-*s %-*s %-*s", nr_w, (*nr) + i,
> + dev_w, dbuf, boff_w, bbuf, own_w, obuf,
> + foff_w, rbuf);
> + printf(" %-*s %-*s", agno_w, gbuf,
> + aoff_w, abuf);
> + printf(" %*lld", tot_w,
> + (long long)BTOBBT(p->fmr_length));
> + if (flg == FLG_NULL)
> + printf("\n");
> + else
> + printf(" %-*.*o\n", NFLG, NFLG, flg);
> + }
> + }
> +
> + (*nr) += head->fmh_entries;
> +}
> +
> +static void
> +dump_verbose_key(void)
> +{
> + printf(_(" FLAG Values:\n"));
> + printf(_(" %*.*o Attribute fork\n"),
> + NFLG+1, NFLG+1, FLG_ATTR_FORK);
> + printf(_(" %*.*o Shared extent\n"),
> + NFLG+1, NFLG+1, FLG_SHARED);
> + printf(_(" %*.*o Unwritten preallocated extent\n"),
> + NFLG+1, NFLG+1, FLG_PRE);
> + printf(_(" %*.*o Doesn't begin on stripe unit\n"),
> + NFLG+1, NFLG+1, FLG_BSU);
> + printf(_(" %*.*o Doesn't end on stripe unit\n"),
> + NFLG+1, NFLG+1, FLG_ESU);
> + printf(_(" %*.*o Doesn't begin on stripe width\n"),
> + NFLG+1, NFLG+1, FLG_BSW);
> + printf(_(" %*.*o Doesn't end on stripe width\n"),
> + NFLG+1, NFLG+1, FLG_ESW);
> +}
> +
> +int
> +fsmap_f(
> + int argc,
> + char **argv)
> +{
> + struct fsmap *p;
> + struct fsmap_head *nhead;
> + struct fsmap_head *head;
> + struct fsmap *l, *h;
> + struct xfs_fsop_geom fsgeo;
> + long long start = 0;
> + long long end = -1;
> + int nmap_size;
> + int map_size;
> + int nflag = 0;
> + int vflag = 0;
> + int i = 0;
> + int c;
> + unsigned long long nr = 0;
> + size_t fsblocksize, fssectsize;
> + struct fs_path *fs;
> + static bool tab_init;
> + bool dumped_flags = false;
> + int dflag, lflag, rflag;
> +
> + init_cvtnum(&fsblocksize, &fssectsize);
> +
> + dflag = lflag = rflag = 0;
> + while ((c = getopt(argc, argv, "dln:rv")) != EOF) {
> + switch (c) {
> + case 'd': /* data device */
> + dflag = 1;
> + break;
> + case 'l': /* log device */
> + lflag = 1;
> + break;
> + case 'n': /* number of extents specified */
> + nflag = atoi(optarg);
> + break;
> + case 'r': /* rt device */
> + rflag = 1;
> + break;
> + case 'v': /* Verbose output */
> + vflag++;
> + break;
> + default:
> + return command_usage(&fsmap_cmd);
> + }
> + }
> +
> + if (dflag + lflag + rflag > 1)
> + return command_usage(&fsmap_cmd);
> +
> + if (argc > optind && dflag + lflag + rflag == 0)
> + return command_usage(&fsmap_cmd);
> +
> + if (argc > optind) {
> + start = cvtnum(fsblocksize, fssectsize, argv[optind]);
> + if (start < 0) {
> + fprintf(stderr,
> + _("Bad rmap start_bblock %s.\n"),
> + argv[optind]);
> + return 0;
> + }
> + start <<= BBSHIFT;
> + }
> +
> + if (argc > optind + 1) {
> + end = cvtnum(fsblocksize, fssectsize, argv[optind + 1]);
> + if (end < 0) {
> + fprintf(stderr,
> + _("Bad rmap end_bblock %s.\n"),
> + argv[optind + 1]);
> + return 0;
> + }
> + end <<= BBSHIFT;
> + }
> +
> + if (vflag) {
> + c = ioctl(file->fd, XFS_IOC_FSGEOMETRY, &fsgeo);
> + if (c < 0) {
> + fprintf(stderr,
> + _("%s: can't get geometry [\"%s\"]: %s\n"),
> + progname, file->name, strerror(errno));
> + exitcode = 1;
> + return 0;
> + }
> + }
> +
> + map_size = nflag ? nflag : 131072 / sizeof(struct fsmap);
Manpage, below:
"In the absence of -n, xfs_fsmap queries the system for the number of extents in the filesystem
and uses that value to compute the group size."
Looks hard-coded to 131072, no?
> + head = malloc(fsmap_sizeof(map_size));
> + if (head == NULL) {
> + fprintf(stderr, _("%s: malloc of %zu bytes failed.\n"),
> + progname, fsmap_sizeof(map_size));
> + exitcode = 1;
> + return 0;
> + }
> +
> + memset(head, 0, sizeof(*head));
> + l = head->fmh_keys;
> + h = head->fmh_keys + 1;
> + if (dflag) {
> + l->fmr_device = h->fmr_device = file->fs_path.fs_datadev;
> + } else if (lflag) {
> + l->fmr_device = h->fmr_device = file->fs_path.fs_logdev;
> + } else if (rflag) {
> + l->fmr_device = h->fmr_device = file->fs_path.fs_rtdev;
> + } else {
> + l->fmr_device = 0;
> + h->fmr_device = UINT_MAX;
> + }
> + l->fmr_physical = start;
> + h->fmr_physical = end;
> + h->fmr_owner = ULLONG_MAX;
> + h->fmr_flags = UINT_MAX;
> + h->fmr_offset = ULLONG_MAX;
> +
> + /* Count mappings */
> + if (!nflag) {
> + head->fmh_count = 0;
> + i = ioctl(file->fd, FS_IOC_GETFSMAP, head);
> + if (i < 0) {
> + fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETFSMAP)"
> + " iflags=0x%x [\"%s\"]: %s\n"),
> + progname, head->fmh_iflags, file->name,
> + strerror(errno));
> + free(head);
> + exitcode = 1;
> + return 0;
> + }
> + if (head->fmh_entries > map_size + 2) {
> + map_size = 11ULL * head->fmh_entries / 10;
> + nmap_size = map_size > (1 << 24) ? (1 << 24) : map_size;
> + nhead = realloc(head, fsmap_sizeof(nmap_size));
> + if (nhead == NULL) {
> + fprintf(stderr,
> + _("%s: cannot realloc %zu bytes\n"),
> + progname, fsmap_sizeof(nmap_size));
> + } else {
> + head = nhead;
> + map_size = nmap_size;
> + }
> + }
> + }
> +
> + /*
> + * If this is an XFS filesystem, remember the data device.
> + * (We report AG number/block for data device extents on XFS).
> + */
> + if (!tab_init) {
> + fs_table_initialise(0, NULL, 0, NULL);
> + tab_init = true;
> + }
> + fs = fs_table_lookup(file->name, FS_MOUNT_POINT);
> + xfs_data_dev = fs ? fs->fs_datadev : 0;
> +
> + head->fmh_count = map_size;
> + do {
> + /* Get some extents */
> + i = ioctl(file->fd, FS_IOC_GETFSMAP, head);
> + if (i < 0) {
> + fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETFSMAP)"
> + " iflags=0x%x [\"%s\"]: %s\n"),
> + progname, head->fmh_iflags, file->name,
> + strerror(errno));
> + free(head);
> + exitcode = 1;
> + return 0;
> + }
> +
> + if (head->fmh_entries == 0)
> + break;
> +
> + if (!vflag)
> + dump_map(&nr, head);
> + else
> + dump_map_verbose(&nr, head, &dumped_flags, &fsgeo);
> +
> + p = &head->fmh_recs[head->fmh_entries - 1];
> + if (p->fmr_flags & FMR_OF_LAST)
> + break;
> + fsmap_advance(head);
> + } while (true);
> +
> + if (dumped_flags)
> + dump_verbose_key();
> +
> + free(head);
> + return 0;
> +}
> +
> +void
> +fsmap_init(void)
> +{
> + fsmap_cmd.name = "fsmap";
> + fsmap_cmd.cfunc = fsmap_f;
> + fsmap_cmd.argmin = 0;
> + fsmap_cmd.argmax = -1;
> + fsmap_cmd.flags = CMD_NOMAP_OK | CMD_FLAG_FOREIGN_OK;
> + fsmap_cmd.args = _("[-d|-l|-r] [-v] [-n nx] [start] [end]");
> + fsmap_cmd.oneline = _("print filesystem mapping for a range of blocks");
> + fsmap_cmd.help = fsmap_help;
> +
> + add_command(&fsmap_cmd);
> +}
> diff --git a/io/init.c b/io/init.c
> index c15a1e1..20d5f80 100644
> --- a/io/init.c
> +++ b/io/init.c
> @@ -66,6 +66,7 @@ init_commands(void)
> file_init();
> flink_init();
> freeze_init();
> + fsmap_init();
> fsync_init();
> getrusage_init();
> help_init();
> @@ -139,6 +140,7 @@ init(
> char *sp;
> mode_t mode = 0600;
> xfs_fsop_geom_t geometry = { 0 };
> + struct fs_path fsp;
>
> progname = basename(argv[0]);
> setlocale(LC_ALL, "");
> @@ -148,6 +150,7 @@ init(
> pagesize = getpagesize();
> gettimeofday(&stopwatch, NULL);
>
> + fs_table_initialise(0, NULL, 0, NULL);
> while ((c = getopt(argc, argv, "ac:C:dFfim:p:nrRstTVx")) != EOF) {
> switch (c) {
> case 'a':
> @@ -212,11 +215,12 @@ init(
> }
>
> while (optind < argc) {
> - if ((c = openfile(argv[optind], &geometry, flags, mode)) < 0)
> + c = openfile(argv[optind], &geometry, flags, mode, &fsp);
> + if (c < 0)
> exit(1);
> if (!platform_test_xfs_fd(c))
> flags |= IO_FOREIGN;
> - if (addfile(argv[optind], c, &geometry, flags) < 0)
> + if (addfile(argv[optind], c, &geometry, flags, &fsp) < 0)
> exit(1);
> optind++;
> }
> diff --git a/io/io.h b/io/io.h
> index 952bdb8..6a0fe65 100644
> --- a/io/io.h
> +++ b/io/io.h
> @@ -17,6 +17,7 @@
> */
>
> #include "xfs.h"
> +#include "path.h"
>
> /*
> * Read/write patterns (default is always "forward")
> @@ -47,6 +48,7 @@ typedef struct fileio {
> int flags; /* flags describing file state */
> char *name; /* file name at time of open */
> xfs_fsop_geom_t geom; /* XFS filesystem geometry */
> + struct fs_path fs_path; /* XFS path information */
> } fileio_t;
>
> extern fileio_t *filetable; /* open file table */
> @@ -76,8 +78,10 @@ extern void *check_mapping_range(mmap_region_t *, off64_t, size_t, int);
> */
>
> extern off64_t filesize(void);
> -extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t);
> -extern int addfile(char *, int , xfs_fsop_geom_t *, int);
> +extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t,
> + struct fs_path *);
> +extern int addfile(char *, int , xfs_fsop_geom_t *, int,
> + struct fs_path *);
> extern void printxattr(uint, int, int, const char *, int, int);
>
> extern unsigned int recurse_all;
> @@ -174,3 +178,9 @@ extern void readdir_init(void);
> extern void reflink_init(void);
>
> extern void cowextsize_init(void);
> +
> +#ifdef HAVE_GETFSMAP
> +extern void fsmap_init(void);
> +#else
> +# define fsmap_init() do { } while (0)
> +#endif
> diff --git a/io/open.c b/io/open.c
> index 2ed55cf..b50f068 100644
> --- a/io/open.c
> +++ b/io/open.c
> @@ -52,8 +52,10 @@ openfile(
> char *path,
> xfs_fsop_geom_t *geom,
> int flags,
> - mode_t mode)
> + mode_t mode,
> + struct fs_path *fs_path)
> {
> + struct fs_path *fsp;
> int fd;
> int oflags;
>
> @@ -118,6 +120,14 @@ openfile(
> }
> }
> }
> +
> + if (fs_path) {
> + fsp = fs_table_lookup(path, FS_MOUNT_POINT);
> + if (!fsp)
> + memset(fs_path, 0, sizeof(*fs_path));
> + else
> + *fs_path = *fsp;
> + }
> return fd;
> }
>
> @@ -126,7 +136,8 @@ addfile(
> char *name,
> int fd,
> xfs_fsop_geom_t *geometry,
> - int flags)
> + int flags,
> + struct fs_path *fs_path)
> {
> char *filename;
>
> @@ -154,6 +165,7 @@ addfile(
> file->flags = flags;
> file->name = filename;
> file->geom = *geometry;
> + file->fs_path = *fs_path;
> return 0;
> }
>
> @@ -195,6 +207,7 @@ open_f(
> char *sp;
> mode_t mode = 0600;
> xfs_fsop_geom_t geometry = { 0 };
> + struct fs_path fsp;
>
> if (argc == 1) {
> if (file)
> @@ -257,14 +270,14 @@ open_f(
> return -1;
> }
>
> - fd = openfile(argv[optind], &geometry, flags, mode);
> + fd = openfile(argv[optind], &geometry, flags, mode, &fsp);
> if (fd < 0)
> return 0;
>
> if (!platform_test_xfs_fd(fd))
> flags |= IO_FOREIGN;
>
> - addfile(argv[optind], fd, &geometry, flags);
> + addfile(argv[optind], fd, &geometry, flags, &fsp);
> return 0;
> }
>
> diff --git a/io/pwrite.c b/io/pwrite.c
> index 7c0bb7f..1c5dfca 100644
> --- a/io/pwrite.c
> +++ b/io/pwrite.c
> @@ -357,7 +357,7 @@ pwrite_f(
> return 0;
>
> c = IO_READONLY | (dflag ? IO_DIRECT : 0);
> - if (infile && ((fd = openfile(infile, NULL, c, 0)) < 0))
> + if (infile && ((fd = openfile(infile, NULL, c, 0, NULL)) < 0))
> return 0;
>
> gettimeofday(&t1, NULL);
> diff --git a/io/reflink.c b/io/reflink.c
> index fe05d1e..f584e8f 100644
> --- a/io/reflink.c
> +++ b/io/reflink.c
> @@ -154,7 +154,7 @@ dedupe_f(
> return 0;
> }
>
> - fd = openfile(infile, NULL, IO_READONLY, 0);
> + fd = openfile(infile, NULL, IO_READONLY, 0, NULL);
> if (fd < 0)
> return 0;
>
> @@ -278,7 +278,7 @@ reflink_f(
> }
>
> clone_all:
> - fd = openfile(infile, NULL, IO_READONLY, 0);
> + fd = openfile(infile, NULL, IO_READONLY, 0, NULL);
> if (fd < 0)
> return 0;
>
> diff --git a/io/sendfile.c b/io/sendfile.c
> index edd31c9..063fa7f 100644
> --- a/io/sendfile.c
> +++ b/io/sendfile.c
> @@ -115,7 +115,7 @@ sendfile_f(
>
> if (!infile)
> fd = filetable[fd].fd;
> - else if ((fd = openfile(infile, NULL, IO_READONLY, 0)) < 0)
> + else if ((fd = openfile(infile, NULL, IO_READONLY, 0, NULL)) < 0)
> return 0;
>
> if (optind == argc - 2) {
> diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
> index 29a036c..bd8af47 100644
> --- a/man/man8/xfs_io.8
> +++ b/man/man8/xfs_io.8
> @@ -301,6 +301,72 @@ ioctl. Options behave as described in the
> .BR xfs_bmap (8)
> manual page.
> .TP
> +.BI "fsmap [ \-d | \-l | \-r ] [ \-v ] [ \-n " nx " ] [ " start " ] [ " end " ]
> +Prints the mapping of disk blocks used by a filesystem.
> +The map lists each extent used by files, allocation group metadata,
> +journalling logs, and static filesystem metadata, as well as any
> +regions that are unused.
> +Each line of the listings takes the following form:
> +.PP
> +.RS
> +.IR extent ": " major ":" minor " [" startblock .. endblock "]: " owner " " startoffset .. endoffset " " length
> +.PP
> +Static filesystem metadata, allocation group metadata, btrees,
> +journalling logs, and free space are marked by replacing the
> +.IR startoffset .. endoffset
> +with the appropriate marker.
> +All blocks, offsets, and lengths are specified in units of 512-byte
> +blocks, no matter what the filesystem's block size is.
> +The optional
> +.I start
> +and
> +.I end
> +arguments can be used to constrain the output to a particular range of
> +disk blocks.
> +.RE
> +.RS 1.0i
> +.PD 0
> +.TP
> +.BI \-d
> +Display only extents from the data device.
> +This option only applies for XFS filesystems.
> +.TP
> +.BI \-l
> +Display only extents from the external log device.
> +This option only applies to XFS filesystems.
> +.TP
> +.BI \-r
> +Display only extents from the realtime device.
> +This option only applies to XFS filesystems.
> +.TP
> +.BI \-n " num_extents"
> +If this option is given,
> +.B xfs_fsmap
> +obtains the extent list of the file in groups of
> +.I num_extents
> +extents.
> +In the absence of
> +.BR \-n ", " xfs_fsmap
> +queries the system for the number of extents in the filesystem and uses
> +that value to compute the group size.
> +.TP
> +.B \-v
> +Shows verbose information.
> +When this flag is specified, additional AG specific information is
> +appended to each line in the following form:
> +.IP
> +.RS 1.2i
> +.IR agno " (" startagblock .. endagblock ") " nblocks " " flags
> +.RE
> +.IP
> +A second
> +.B \-v
> +option will print out the
> +.I flags
> +legend.
> +.RE
> +.PD
> +.TP
> .BI "extsize [ \-R | \-D ] [ " value " ]"
> Display and/or modify the preferred extent size used when allocating
> space for the currently open file. If the
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 03/10] xfs_io: support the new getfsmap ioctl
2017-06-13 22:20 ` Eric Sandeen
@ 2017-06-14 0:23 ` Darrick J. Wong
0 siblings, 0 replies; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-14 0:23 UTC (permalink / raw)
To: Eric Sandeen; +Cc: sandeen, linux-xfs
On Tue, Jun 13, 2017 at 05:20:28PM -0500, Eric Sandeen wrote:
> On 6/2/17 2:51 PM, Darrick J. Wong wrote:
> > From: Darrick J. Wong <darrick.wong@oracle.com>
> >
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
>
> Sorry Darrick, lots more here that I missed the first time around.
>
> > ---
> > io/Makefile | 7 +
> > io/copy_file_range.c | 2
> > io/encrypt.c | 1
> > io/fsmap.c | 549 ++++++++++++++++++++++++++++++++++++++++++++++++++
> > io/init.c | 8 +
> > io/io.h | 14 +
> > io/open.c | 21 ++
> > io/pwrite.c | 2
> > io/reflink.c | 4
> > io/sendfile.c | 2
> > man/man8/xfs_io.8 | 66 ++++++
> > 11 files changed, 663 insertions(+), 13 deletions(-)
> > create mode 100644 io/fsmap.c
> >
> >
> > diff --git a/io/Makefile b/io/Makefile
> > index 435ccff..47b0a66 100644
> > --- a/io/Makefile
> > +++ b/io/Makefile
> > @@ -99,6 +99,13 @@ ifeq ($(HAVE_MREMAP),yes)
> > LCFLAGS += -DHAVE_MREMAP
> > endif
> >
> > +# On linux we get fsmap from the system or define it ourselves
> > +# so include this based on platform type. If this reverts to only
> > +# the autoconf check w/o local definition, change to testing HAVE_GETFSMAP
> > +ifeq ($(PKG_PLATFORM),linux)
> > +CFILES += fsmap.c
> > +endif
> > +
> > default: depend $(LTCOMMAND)
> >
> > include $(BUILDRULES)
> > diff --git a/io/copy_file_range.c b/io/copy_file_range.c
> > index 249c649..d1dfc5a 100644
> > --- a/io/copy_file_range.c
> > +++ b/io/copy_file_range.c
> > @@ -121,7 +121,7 @@ copy_range_f(int argc, char **argv)
> > if (optind != argc - 1)
> > return command_usage(©_range_cmd);
> >
> > - fd = openfile(argv[optind], NULL, IO_READONLY, 0);
> > + fd = openfile(argv[optind], NULL, IO_READONLY, 0, NULL);
> > if (fd < 0)
> > return 0;
> >
> > diff --git a/io/encrypt.c b/io/encrypt.c
> > index d844c5e..26ab97c 100644
> > --- a/io/encrypt.c
> > +++ b/io/encrypt.c
> > @@ -20,6 +20,7 @@
> > #include "platform_defs.h"
> > #include "command.h"
> > #include "init.h"
> > +#include "path.h"
> > #include "io.h"
> >
> > #ifndef ARRAY_SIZE
> > diff --git a/io/fsmap.c b/io/fsmap.c
> > new file mode 100644
> > index 0000000..1f4de81
> > --- /dev/null
> > +++ b/io/fsmap.c
> > @@ -0,0 +1,549 @@
> > +/*
> > + * Copyright (C) 2017 Oracle. All Rights Reserved.
> > + *
> > + * Author: Darrick J. Wong <darrick.wong@oracle.com>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation; either version 2
> > + * of the License, or (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it would be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write the Free Software Foundation,
> > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
> > + */
> > +#include "platform_defs.h"
> > +#include "command.h"
> > +#include "init.h"
> > +#include "path.h"
> > +#include "io.h"
> > +#include "input.h"
> > +
> > +static cmdinfo_t fsmap_cmd;
> > +static dev_t xfs_data_dev;
> > +
> > +static void
> > +fsmap_help(void)
> > +{
> > + printf(_(
> > +"\n"
> > +" Prints the block mapping for a filesystem"
> > +"\n"
> > +" Example:\n"
> > +" 'fsmap [-d|-l|-r] [-v] [-n nr] [startoff] [endoff]' - tabular format verbose map, including unwritten extents\n"
>
> Whoops, I missed this the first time, that's a restatement of all options,
> not an example.
>
> (Or I'd probably just drop it, I don't think an example is needed
> or useful, but as you like it... I guess it's modeled on fiemap)
Yeah, it's unnecessary and redundant. I'll remove it.
> > +"\n"
> > +" fsmap prints the map of disk blocks used by the whole filesystem.\n"
> > +" When possible, owner and offset information will be included in the\n"
> > +" sapce report.\n"
> > +"\n"
> > +" By default, each line of the listing takes the following form:\n"
> > +" extent: [startoffset..endoffset] owner startblock..endblock\n"
>
> Hm, no:
>
> 0: 8:17 [0..1175]: unknown 1176 blocks
> 1: 8:17 [1176..1183]: free space 8 blocks
>
> manpage gets it right:
>
> extent: major:minor [startblock..endblock]: owner startoffset..endoffset length
>
> (I might drop the last "blocks"... is it useful? fiemap doesn't use it)
Probably came from the bmap command, but yes, it's redundant since we
already state that the numbers are in units of blocks.
I'll update the help screen to list the correct fields.
> Sigh, sorry for missing stuff on the first round.
>
> OK fiemap prints a header with -v ...
>
> # io/xfs_io -c "fiemap -v" /mnt/test/junk
> /mnt/test/junk:
> EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS
> 0: [0..7]: hole 8
> 1: [8..39]: 5936..5967 32 0x0
>
> I think that'd be useful here, too ... oh, bug. see below. (s/nr == 0/*nr == 0/)
Got it.
> > +" The owner field is either an inode number or a special value.\n"
> > +" All the file offsets and disk blocks are in units of 512-byte blocks.\n"
> > +" -d -- query only the data device.\n"
>
> (this is the default, yes?)
Yes.
> > +" -l -- query only the log device.\n"
>
> Hm, with an external log I get:
>
> xfs_io> fsmap -l
> 0: 7:7 [0..2097151]: journalling log 2097152 blocks
>
> but an internal log does not show those blocks in the output, should it?
It will if you have rmapbt=1. Maybe the kernel should report the owner
of an external log as 'unknown' if the caller doesn't have
CAP_SYS_ADMIN, similar to how we don't report specific owners for the
data device.
> > +" -r -- query only the realtime device.\n"
> > +" -n -- query n extents.\n"
>
> -n doesn't seem to work as described:
>
> # io/xfs_io -c "fsmap -n 2" /mnt/test
> 0: 8:17 [0..1175]: unknown 1176 blocks
> 1: 8:17 [1176..1183]: free space 8 blocks
> 2: 8:17 [1184..1327]: unknown 144 blocks
> 3: 8:17 [1328..1343]: free space 16 blocks
>
> Oh, it's "at a time" - so help text needs to be fixed to reflect that it's
> the size of each query, not the total number queried.
Yes. Will fix the documentation.
> > +" -v -- Verbose information, specify ag info. Show flags legend on 2nd -v\n"
>
> (and FILE-OFFSET of each owner?)
>
> There are no flags printed AFAICT, and no different behavior with -vv...
> but that seems broken somewhere.
>
> Oh, it looks like if no flags are (will be?) printed we skip the column
> and the legend. That seems a little odd to me... is it intentional?
bmap doesn't show the legend unless any of the flags are used, so fsmap
behaves similarly.
> > +"\n"));
> > +}
> > +
> > +#define OWNER_BUF_SZ 32
> > +static const char *
> > +special_owner(
> > + int64_t owner,
> > + char *buf)
> > +{
> > + switch (owner) {
> > + case XFS_FMR_OWN_FREE:
> > + return _("free space");
>
> (Aside: I wonder if there's any way to avoid spaces in the owner field,
> so that awk can easily parse the result...? Not sure how that'd look,
> but it'd make it a lot more useful when presented with thousands of
> records)
Well, a few options come to mind -- adding a machine-friendly format,
enclosing the owner names with spaces for easier parsing, or stuffing
in weird nonbreaking space sequences (yuck). I'm partial to the second.
> > + case XFS_FMR_OWN_UNKNOWN:
> > + return _("unknown");
> > + case XFS_FMR_OWN_FS:
> > + return _("static fs metadata");
> > + case XFS_FMR_OWN_LOG:
> > + return _("journalling log");
> > + case XFS_FMR_OWN_AG:
> > + return _("per-AG metadata");
> > + case XFS_FMR_OWN_INOBT:
> > + return _("inode btree");
> > + case XFS_FMR_OWN_INODES:
> > + return _("inodes");
> > + case XFS_FMR_OWN_REFC:
> > + return _("refcount btree");
> > + case XFS_FMR_OWN_COW:
> > + return _("cow reservation");
> > + case XFS_FMR_OWN_DEFECTIVE:
> > + return _("defective");
> > + default:
> > + snprintf(buf, OWNER_BUF_SZ, _("special %u:%u"),
> > + FMR_OWNER_TYPE(owner), FMR_OWNER_CODE(owner));
> > + return buf;
> > + }
> > +}
> > +
> > +static void
> > +dump_map(
> > + unsigned long long *nr,
> > + struct fsmap_head *head)
> > +{
> > + unsigned long long i;
> > + struct fsmap *p;
> > + char owner[OWNER_BUF_SZ];
> > +
> > + for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) {
> > + printf("\t%llu: %u:%u [%lld..%lld]: ", i + (*nr),
> > + major(p->fmr_device), minor(p->fmr_device),
> > + (long long)BTOBBT(p->fmr_physical),
> > + (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1));
> > + if (p->fmr_flags & FMR_OF_SPECIAL_OWNER)
> > + printf("%s", special_owner(p->fmr_owner, owner));
> > + else if (p->fmr_flags & FMR_OF_EXTENT_MAP)
> > + printf(_("inode %lld extent map"),
> > + (long long) p->fmr_owner);
> > + else
> > + printf(_("inode %lld %lld..%lld"),
> > + (long long)p->fmr_owner,
> > + (long long)BTOBBT(p->fmr_offset),
> > + (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1));
> > + printf(_(" %lld blocks\n"),
> > + (long long)BTOBBT(p->fmr_length));
> > + }
> > +
> > + (*nr) += head->fmh_entries;
> > +}
> > +
> > +/*
> > + * Verbose mode displays:
> > + * extent: major:minor [startblock..endblock]: startoffset..endoffset \
> > + * ag# (agoffset..agendoffset) totalbbs flags
> > + */
> > +#define MINRANGE_WIDTH 16
> > +#define MINAG_WIDTH 2
> > +#define MINTOT_WIDTH 5
> > +#define NFLG 7 /* count of flags */
> > +#define FLG_NULL 00000000 /* Null flag */
> > +#define FLG_ATTR_FORK 01000000 /* attribute fork */
> > +#define FLG_SHARED 00100000 /* shared extent */
> > +#define FLG_PRE 00010000 /* Unwritten extent */
> > +#define FLG_BSU 00001000 /* Not on begin of stripe unit */
> > +#define FLG_ESU 00000100 /* Not on end of stripe unit */
> > +#define FLG_BSW 00000010 /* Not on begin of stripe width */
> > +#define FLG_ESW 00000001 /* Not on end of stripe width */
> > +static void
> > +dump_map_verbose(
> > + unsigned long long *nr,
> > + struct fsmap_head *head,
> > + bool *dumped_flags,
> > + struct xfs_fsop_geom *fsgeo)
> > +{
> > + unsigned long long i;
> > + struct fsmap *p;
> > + int agno;
> > + off64_t agoff, bperag;
> > + int foff_w, boff_w, aoff_w, tot_w, agno_w, own_w;
> > + int nr_w, dev_w;
> > + char rbuf[32], bbuf[32], abuf[32], obuf[32];
> > + char nbuf[32], dbuf[32], gbuf[32];
> > + char owner[OWNER_BUF_SZ];
> > + int sunit, swidth;
> > + int flg = 0;
> > +
> > + foff_w = boff_w = aoff_w = own_w = MINRANGE_WIDTH;
> > + dev_w = 3;
> > + nr_w = 4;
> > + tot_w = MINTOT_WIDTH;
> > + bperag = (off64_t)fsgeo->agblocks *
> > + (off64_t)fsgeo->blocksize;
> > + sunit = (fsgeo->sunit * fsgeo->blocksize);
> > + swidth = (fsgeo->swidth * fsgeo->blocksize);
> > +
> > + /*
> > + * Go through the extents and figure out the width
> > + * needed for all columns.
> > + */
> > + for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) {
> > + if (p->fmr_flags & FMR_OF_PREALLOC ||
> > + p->fmr_flags & FMR_OF_ATTR_FORK ||
> > + p->fmr_flags & FMR_OF_SHARED)
> > + flg = 1;
> > + if (sunit &&
> > + (p->fmr_physical % sunit != 0 ||
> > + ((p->fmr_physical + p->fmr_length) % sunit) != 0 ||
> > + p->fmr_physical % swidth != 0 ||
> > + ((p->fmr_physical + p->fmr_length) % swidth) != 0))
> > + flg = 1;
> > + if (flg)
> > + *dumped_flags = true;
> > + snprintf(nbuf, sizeof(nbuf), "%llu", (*nr) + i);
> > + nr_w = max(nr_w, strlen(nbuf));
> > + if (head->fmh_oflags & FMH_OF_DEV_T)
> > + snprintf(dbuf, sizeof(dbuf), "%u:%u",
> > + major(p->fmr_device),
> > + minor(p->fmr_device));
> > + else
> > + snprintf(dbuf, sizeof(dbuf), "0x%x", p->fmr_device);
> > + dev_w = max(dev_w, strlen(dbuf));
> > + snprintf(bbuf, sizeof(bbuf), "[%lld..%lld]:",
> > + (long long)BTOBBT(p->fmr_physical),
> > + (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1));
> > + boff_w = max(boff_w, strlen(bbuf));
> > + if (p->fmr_flags & FMR_OF_SPECIAL_OWNER)
> > + own_w = max(own_w, strlen(
> > + special_owner(p->fmr_owner, owner)));
> > + else {
> > + snprintf(obuf, sizeof(obuf), "%lld",
> > + (long long)p->fmr_owner);
> > + own_w = max(own_w, strlen(obuf));
> > + }
> > + if (p->fmr_flags & FMR_OF_EXTENT_MAP)
> > + foff_w = max(foff_w, strlen(_("extent_map")));
> > + else if (p->fmr_flags & FMR_OF_SPECIAL_OWNER)
> > + ;
> > + else {
> > + snprintf(rbuf, sizeof(rbuf), "%lld..%lld",
> > + (long long)BTOBBT(p->fmr_offset),
> > + (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1));
> > + foff_w = max(foff_w, strlen(rbuf));
> > + }
> > + if (p->fmr_device == xfs_data_dev) {
> > + agno = p->fmr_physical / bperag;
> > + agoff = p->fmr_physical - (agno * bperag);
> > + snprintf(abuf, sizeof(abuf),
> > + "(%lld..%lld)",
> > + (long long)BTOBBT(agoff),
> > + (long long)BTOBBT(agoff + p->fmr_length - 1));
> > + } else
> > + abuf[0] = 0;
> > + aoff_w = max(aoff_w, strlen(abuf));
> > + tot_w = max(tot_w,
> > + numlen(BTOBBT(p->fmr_length), 10));
> > + }
> > + agno_w = max(MINAG_WIDTH, numlen(fsgeo->agcount, 10));
> > + if (nr == 0)
>
> if (*nr == 0)
Oops, fixed.
> > + printf("%*s: %-*s %-*s %-*s %-*s %*s %-*s %*s%s\n",
> > + nr_w, _("EXT"),
> > + dev_w, _("DEV"),
> > + boff_w, _("BLOCK-RANGE"),
> > + own_w, _("OWNER"),
> > + foff_w, _("FILE-OFFSET"),
> > + agno_w, _("AG"),
> > + aoff_w, _("AG-OFFSET"),
> > + tot_w, _("TOTAL"),
> > + flg ? _(" FLAGS") : "");
> > + for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) {
> > + flg = FLG_NULL;
> > + if (p->fmr_flags & FMR_OF_PREALLOC)
> > + flg |= FLG_PRE;
> > + if (p->fmr_flags & FMR_OF_ATTR_FORK)
> > + flg |= FLG_ATTR_FORK;
> > + if (p->fmr_flags & FMR_OF_SHARED)
> > + flg |= FLG_SHARED;
> > + /*
> > + * If striping enabled, determine if extent starts/ends
> > + * on a stripe unit boundary.
> > + */
> > + if (sunit) {
> > + if (p->fmr_physical % sunit != 0)
> > + flg |= FLG_BSU;
> > + if (((p->fmr_physical +
> > + p->fmr_length ) % sunit ) != 0)
> > + flg |= FLG_ESU;
> > + if (p->fmr_physical % swidth != 0)
> > + flg |= FLG_BSW;
> > + if (((p->fmr_physical +
> > + p->fmr_length ) % swidth ) != 0)
> > + flg |= FLG_ESW;
> > + }
> > + if (head->fmh_oflags & FMH_OF_DEV_T)
> > + snprintf(dbuf, sizeof(dbuf), "%u:%u",
> > + major(p->fmr_device),
> > + minor(p->fmr_device));
> > + else
> > + snprintf(dbuf, sizeof(dbuf), "0x%x", p->fmr_device);
> > + snprintf(bbuf, sizeof(bbuf), "[%lld..%lld]:",
> > + (long long)BTOBBT(p->fmr_physical),
> > + (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1));
> > + if (p->fmr_flags & FMR_OF_SPECIAL_OWNER) {
> > + snprintf(obuf, sizeof(obuf), "%s",
> > + special_owner(p->fmr_owner, owner));
> > + snprintf(rbuf, sizeof(rbuf), " ");
> > + } else {
> > + snprintf(obuf, sizeof(obuf), "%lld",
> > + (long long)p->fmr_owner);
> > + snprintf(rbuf, sizeof(rbuf), "%lld..%lld",
> > + (long long)BTOBBT(p->fmr_offset),
> > + (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1));
> > + }
> > + if (p->fmr_device == xfs_data_dev) {
> > + agno = p->fmr_physical / bperag;
> > + agoff = p->fmr_physical - (agno * bperag);
> > + snprintf(abuf, sizeof(abuf),
> > + "(%lld..%lld)",
> > + (long long)BTOBBT(agoff),
> > + (long long)BTOBBT(agoff + p->fmr_length - 1));
> > + snprintf(gbuf, sizeof(gbuf),
> > + "%lld",
> > + (long long)agno);
> > + } else {
> > + abuf[0] = 0;
> > + gbuf[0] = 0;
> > + }
> > + if (p->fmr_flags & FMR_OF_EXTENT_MAP)
> > + printf("%*llu: %-*s %-*s %-*s %-*s %-*s %-*s %*lld\n",
> > + nr_w, (*nr) + i,
> > + dev_w, dbuf,
> > + boff_w, bbuf,
> > + own_w, obuf,
> > + foff_w, _("extent map"),
> > + agno_w, gbuf,
> > + aoff_w, abuf,
> > + tot_w, (long long)BTOBBT(p->fmr_length));
> > + else {
> > + printf("%*llu: %-*s %-*s %-*s %-*s", nr_w, (*nr) + i,
> > + dev_w, dbuf, boff_w, bbuf, own_w, obuf,
> > + foff_w, rbuf);
> > + printf(" %-*s %-*s", agno_w, gbuf,
> > + aoff_w, abuf);
> > + printf(" %*lld", tot_w,
> > + (long long)BTOBBT(p->fmr_length));
> > + if (flg == FLG_NULL)
> > + printf("\n");
> > + else
> > + printf(" %-*.*o\n", NFLG, NFLG, flg);
> > + }
> > + }
> > +
> > + (*nr) += head->fmh_entries;
> > +}
> > +
> > +static void
> > +dump_verbose_key(void)
> > +{
> > + printf(_(" FLAG Values:\n"));
> > + printf(_(" %*.*o Attribute fork\n"),
> > + NFLG+1, NFLG+1, FLG_ATTR_FORK);
> > + printf(_(" %*.*o Shared extent\n"),
> > + NFLG+1, NFLG+1, FLG_SHARED);
> > + printf(_(" %*.*o Unwritten preallocated extent\n"),
> > + NFLG+1, NFLG+1, FLG_PRE);
> > + printf(_(" %*.*o Doesn't begin on stripe unit\n"),
> > + NFLG+1, NFLG+1, FLG_BSU);
> > + printf(_(" %*.*o Doesn't end on stripe unit\n"),
> > + NFLG+1, NFLG+1, FLG_ESU);
> > + printf(_(" %*.*o Doesn't begin on stripe width\n"),
> > + NFLG+1, NFLG+1, FLG_BSW);
> > + printf(_(" %*.*o Doesn't end on stripe width\n"),
> > + NFLG+1, NFLG+1, FLG_ESW);
> > +}
> > +
> > +int
> > +fsmap_f(
> > + int argc,
> > + char **argv)
> > +{
> > + struct fsmap *p;
> > + struct fsmap_head *nhead;
> > + struct fsmap_head *head;
> > + struct fsmap *l, *h;
> > + struct xfs_fsop_geom fsgeo;
> > + long long start = 0;
> > + long long end = -1;
> > + int nmap_size;
> > + int map_size;
> > + int nflag = 0;
> > + int vflag = 0;
> > + int i = 0;
> > + int c;
> > + unsigned long long nr = 0;
> > + size_t fsblocksize, fssectsize;
> > + struct fs_path *fs;
> > + static bool tab_init;
> > + bool dumped_flags = false;
> > + int dflag, lflag, rflag;
> > +
> > + init_cvtnum(&fsblocksize, &fssectsize);
> > +
> > + dflag = lflag = rflag = 0;
> > + while ((c = getopt(argc, argv, "dln:rv")) != EOF) {
> > + switch (c) {
> > + case 'd': /* data device */
> > + dflag = 1;
> > + break;
> > + case 'l': /* log device */
> > + lflag = 1;
> > + break;
> > + case 'n': /* number of extents specified */
> > + nflag = atoi(optarg);
> > + break;
> > + case 'r': /* rt device */
> > + rflag = 1;
> > + break;
> > + case 'v': /* Verbose output */
> > + vflag++;
> > + break;
> > + default:
> > + return command_usage(&fsmap_cmd);
> > + }
> > + }
> > +
> > + if (dflag + lflag + rflag > 1)
> > + return command_usage(&fsmap_cmd);
> > +
> > + if (argc > optind && dflag + lflag + rflag == 0)
> > + return command_usage(&fsmap_cmd);
> > +
> > + if (argc > optind) {
> > + start = cvtnum(fsblocksize, fssectsize, argv[optind]);
> > + if (start < 0) {
> > + fprintf(stderr,
> > + _("Bad rmap start_bblock %s.\n"),
> > + argv[optind]);
> > + return 0;
> > + }
> > + start <<= BBSHIFT;
> > + }
> > +
> > + if (argc > optind + 1) {
> > + end = cvtnum(fsblocksize, fssectsize, argv[optind + 1]);
> > + if (end < 0) {
> > + fprintf(stderr,
> > + _("Bad rmap end_bblock %s.\n"),
> > + argv[optind + 1]);
> > + return 0;
> > + }
> > + end <<= BBSHIFT;
> > + }
> > +
> > + if (vflag) {
> > + c = ioctl(file->fd, XFS_IOC_FSGEOMETRY, &fsgeo);
> > + if (c < 0) {
> > + fprintf(stderr,
> > + _("%s: can't get geometry [\"%s\"]: %s\n"),
> > + progname, file->name, strerror(errno));
> > + exitcode = 1;
> > + return 0;
> > + }
> > + }
> > +
> > + map_size = nflag ? nflag : 131072 / sizeof(struct fsmap);
>
> Manpage, below:
>
> "In the absence of -n, xfs_fsmap queries the system for the number of extents in the filesystem
> and uses that value to compute the group size."
>
> Looks hard-coded to 131072, no?
Yes. It used to behave as specified, but it was very slow to rake every
rmap record in the system twice, so I changed it to 131072 and evidently
forgot to update the manpage.
--D
> > + head = malloc(fsmap_sizeof(map_size));
> > + if (head == NULL) {
> > + fprintf(stderr, _("%s: malloc of %zu bytes failed.\n"),
> > + progname, fsmap_sizeof(map_size));
> > + exitcode = 1;
> > + return 0;
> > + }
> > +
> > + memset(head, 0, sizeof(*head));
> > + l = head->fmh_keys;
> > + h = head->fmh_keys + 1;
> > + if (dflag) {
> > + l->fmr_device = h->fmr_device = file->fs_path.fs_datadev;
> > + } else if (lflag) {
> > + l->fmr_device = h->fmr_device = file->fs_path.fs_logdev;
> > + } else if (rflag) {
> > + l->fmr_device = h->fmr_device = file->fs_path.fs_rtdev;
> > + } else {
> > + l->fmr_device = 0;
> > + h->fmr_device = UINT_MAX;
> > + }
> > + l->fmr_physical = start;
> > + h->fmr_physical = end;
> > + h->fmr_owner = ULLONG_MAX;
> > + h->fmr_flags = UINT_MAX;
> > + h->fmr_offset = ULLONG_MAX;
> > +
> > + /* Count mappings */
> > + if (!nflag) {
> > + head->fmh_count = 0;
> > + i = ioctl(file->fd, FS_IOC_GETFSMAP, head);
> > + if (i < 0) {
> > + fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETFSMAP)"
> > + " iflags=0x%x [\"%s\"]: %s\n"),
> > + progname, head->fmh_iflags, file->name,
> > + strerror(errno));
> > + free(head);
> > + exitcode = 1;
> > + return 0;
> > + }
> > + if (head->fmh_entries > map_size + 2) {
> > + map_size = 11ULL * head->fmh_entries / 10;
> > + nmap_size = map_size > (1 << 24) ? (1 << 24) : map_size;
> > + nhead = realloc(head, fsmap_sizeof(nmap_size));
> > + if (nhead == NULL) {
> > + fprintf(stderr,
> > + _("%s: cannot realloc %zu bytes\n"),
> > + progname, fsmap_sizeof(nmap_size));
> > + } else {
> > + head = nhead;
> > + map_size = nmap_size;
> > + }
> > + }
> > + }
> > +
> > + /*
> > + * If this is an XFS filesystem, remember the data device.
> > + * (We report AG number/block for data device extents on XFS).
> > + */
> > + if (!tab_init) {
> > + fs_table_initialise(0, NULL, 0, NULL);
> > + tab_init = true;
> > + }
> > + fs = fs_table_lookup(file->name, FS_MOUNT_POINT);
> > + xfs_data_dev = fs ? fs->fs_datadev : 0;
> > +
> > + head->fmh_count = map_size;
> > + do {
> > + /* Get some extents */
> > + i = ioctl(file->fd, FS_IOC_GETFSMAP, head);
> > + if (i < 0) {
> > + fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETFSMAP)"
> > + " iflags=0x%x [\"%s\"]: %s\n"),
> > + progname, head->fmh_iflags, file->name,
> > + strerror(errno));
> > + free(head);
> > + exitcode = 1;
> > + return 0;
> > + }
> > +
> > + if (head->fmh_entries == 0)
> > + break;
> > +
> > + if (!vflag)
> > + dump_map(&nr, head);
> > + else
> > + dump_map_verbose(&nr, head, &dumped_flags, &fsgeo);
> > +
> > + p = &head->fmh_recs[head->fmh_entries - 1];
> > + if (p->fmr_flags & FMR_OF_LAST)
> > + break;
> > + fsmap_advance(head);
> > + } while (true);
> > +
> > + if (dumped_flags)
> > + dump_verbose_key();
> > +
> > + free(head);
> > + return 0;
> > +}
> > +
> > +void
> > +fsmap_init(void)
> > +{
> > + fsmap_cmd.name = "fsmap";
> > + fsmap_cmd.cfunc = fsmap_f;
> > + fsmap_cmd.argmin = 0;
> > + fsmap_cmd.argmax = -1;
> > + fsmap_cmd.flags = CMD_NOMAP_OK | CMD_FLAG_FOREIGN_OK;
> > + fsmap_cmd.args = _("[-d|-l|-r] [-v] [-n nx] [start] [end]");
> > + fsmap_cmd.oneline = _("print filesystem mapping for a range of blocks");
> > + fsmap_cmd.help = fsmap_help;
> > +
> > + add_command(&fsmap_cmd);
> > +}
> > diff --git a/io/init.c b/io/init.c
> > index c15a1e1..20d5f80 100644
> > --- a/io/init.c
> > +++ b/io/init.c
> > @@ -66,6 +66,7 @@ init_commands(void)
> > file_init();
> > flink_init();
> > freeze_init();
> > + fsmap_init();
> > fsync_init();
> > getrusage_init();
> > help_init();
> > @@ -139,6 +140,7 @@ init(
> > char *sp;
> > mode_t mode = 0600;
> > xfs_fsop_geom_t geometry = { 0 };
> > + struct fs_path fsp;
> >
> > progname = basename(argv[0]);
> > setlocale(LC_ALL, "");
> > @@ -148,6 +150,7 @@ init(
> > pagesize = getpagesize();
> > gettimeofday(&stopwatch, NULL);
> >
> > + fs_table_initialise(0, NULL, 0, NULL);
> > while ((c = getopt(argc, argv, "ac:C:dFfim:p:nrRstTVx")) != EOF) {
> > switch (c) {
> > case 'a':
> > @@ -212,11 +215,12 @@ init(
> > }
> >
> > while (optind < argc) {
> > - if ((c = openfile(argv[optind], &geometry, flags, mode)) < 0)
> > + c = openfile(argv[optind], &geometry, flags, mode, &fsp);
> > + if (c < 0)
> > exit(1);
> > if (!platform_test_xfs_fd(c))
> > flags |= IO_FOREIGN;
> > - if (addfile(argv[optind], c, &geometry, flags) < 0)
> > + if (addfile(argv[optind], c, &geometry, flags, &fsp) < 0)
> > exit(1);
> > optind++;
> > }
> > diff --git a/io/io.h b/io/io.h
> > index 952bdb8..6a0fe65 100644
> > --- a/io/io.h
> > +++ b/io/io.h
> > @@ -17,6 +17,7 @@
> > */
> >
> > #include "xfs.h"
> > +#include "path.h"
> >
> > /*
> > * Read/write patterns (default is always "forward")
> > @@ -47,6 +48,7 @@ typedef struct fileio {
> > int flags; /* flags describing file state */
> > char *name; /* file name at time of open */
> > xfs_fsop_geom_t geom; /* XFS filesystem geometry */
> > + struct fs_path fs_path; /* XFS path information */
> > } fileio_t;
> >
> > extern fileio_t *filetable; /* open file table */
> > @@ -76,8 +78,10 @@ extern void *check_mapping_range(mmap_region_t *, off64_t, size_t, int);
> > */
> >
> > extern off64_t filesize(void);
> > -extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t);
> > -extern int addfile(char *, int , xfs_fsop_geom_t *, int);
> > +extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t,
> > + struct fs_path *);
> > +extern int addfile(char *, int , xfs_fsop_geom_t *, int,
> > + struct fs_path *);
> > extern void printxattr(uint, int, int, const char *, int, int);
> >
> > extern unsigned int recurse_all;
> > @@ -174,3 +178,9 @@ extern void readdir_init(void);
> > extern void reflink_init(void);
> >
> > extern void cowextsize_init(void);
> > +
> > +#ifdef HAVE_GETFSMAP
> > +extern void fsmap_init(void);
> > +#else
> > +# define fsmap_init() do { } while (0)
> > +#endif
> > diff --git a/io/open.c b/io/open.c
> > index 2ed55cf..b50f068 100644
> > --- a/io/open.c
> > +++ b/io/open.c
> > @@ -52,8 +52,10 @@ openfile(
> > char *path,
> > xfs_fsop_geom_t *geom,
> > int flags,
> > - mode_t mode)
> > + mode_t mode,
> > + struct fs_path *fs_path)
> > {
> > + struct fs_path *fsp;
> > int fd;
> > int oflags;
> >
> > @@ -118,6 +120,14 @@ openfile(
> > }
> > }
> > }
> > +
> > + if (fs_path) {
> > + fsp = fs_table_lookup(path, FS_MOUNT_POINT);
> > + if (!fsp)
> > + memset(fs_path, 0, sizeof(*fs_path));
> > + else
> > + *fs_path = *fsp;
> > + }
> > return fd;
> > }
> >
> > @@ -126,7 +136,8 @@ addfile(
> > char *name,
> > int fd,
> > xfs_fsop_geom_t *geometry,
> > - int flags)
> > + int flags,
> > + struct fs_path *fs_path)
> > {
> > char *filename;
> >
> > @@ -154,6 +165,7 @@ addfile(
> > file->flags = flags;
> > file->name = filename;
> > file->geom = *geometry;
> > + file->fs_path = *fs_path;
> > return 0;
> > }
> >
> > @@ -195,6 +207,7 @@ open_f(
> > char *sp;
> > mode_t mode = 0600;
> > xfs_fsop_geom_t geometry = { 0 };
> > + struct fs_path fsp;
> >
> > if (argc == 1) {
> > if (file)
> > @@ -257,14 +270,14 @@ open_f(
> > return -1;
> > }
> >
> > - fd = openfile(argv[optind], &geometry, flags, mode);
> > + fd = openfile(argv[optind], &geometry, flags, mode, &fsp);
> > if (fd < 0)
> > return 0;
> >
> > if (!platform_test_xfs_fd(fd))
> > flags |= IO_FOREIGN;
> >
> > - addfile(argv[optind], fd, &geometry, flags);
> > + addfile(argv[optind], fd, &geometry, flags, &fsp);
> > return 0;
> > }
> >
> > diff --git a/io/pwrite.c b/io/pwrite.c
> > index 7c0bb7f..1c5dfca 100644
> > --- a/io/pwrite.c
> > +++ b/io/pwrite.c
> > @@ -357,7 +357,7 @@ pwrite_f(
> > return 0;
> >
> > c = IO_READONLY | (dflag ? IO_DIRECT : 0);
> > - if (infile && ((fd = openfile(infile, NULL, c, 0)) < 0))
> > + if (infile && ((fd = openfile(infile, NULL, c, 0, NULL)) < 0))
> > return 0;
> >
> > gettimeofday(&t1, NULL);
> > diff --git a/io/reflink.c b/io/reflink.c
> > index fe05d1e..f584e8f 100644
> > --- a/io/reflink.c
> > +++ b/io/reflink.c
> > @@ -154,7 +154,7 @@ dedupe_f(
> > return 0;
> > }
> >
> > - fd = openfile(infile, NULL, IO_READONLY, 0);
> > + fd = openfile(infile, NULL, IO_READONLY, 0, NULL);
> > if (fd < 0)
> > return 0;
> >
> > @@ -278,7 +278,7 @@ reflink_f(
> > }
> >
> > clone_all:
> > - fd = openfile(infile, NULL, IO_READONLY, 0);
> > + fd = openfile(infile, NULL, IO_READONLY, 0, NULL);
> > if (fd < 0)
> > return 0;
> >
> > diff --git a/io/sendfile.c b/io/sendfile.c
> > index edd31c9..063fa7f 100644
> > --- a/io/sendfile.c
> > +++ b/io/sendfile.c
> > @@ -115,7 +115,7 @@ sendfile_f(
> >
> > if (!infile)
> > fd = filetable[fd].fd;
> > - else if ((fd = openfile(infile, NULL, IO_READONLY, 0)) < 0)
> > + else if ((fd = openfile(infile, NULL, IO_READONLY, 0, NULL)) < 0)
> > return 0;
> >
> > if (optind == argc - 2) {
> > diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
> > index 29a036c..bd8af47 100644
> > --- a/man/man8/xfs_io.8
> > +++ b/man/man8/xfs_io.8
> > @@ -301,6 +301,72 @@ ioctl. Options behave as described in the
> > .BR xfs_bmap (8)
> > manual page.
> > .TP
> > +.BI "fsmap [ \-d | \-l | \-r ] [ \-v ] [ \-n " nx " ] [ " start " ] [ " end " ]
> > +Prints the mapping of disk blocks used by a filesystem.
> > +The map lists each extent used by files, allocation group metadata,
> > +journalling logs, and static filesystem metadata, as well as any
> > +regions that are unused.
> > +Each line of the listings takes the following form:
> > +.PP
> > +.RS
> > +.IR extent ": " major ":" minor " [" startblock .. endblock "]: " owner " " startoffset .. endoffset " " length
> > +.PP
> > +Static filesystem metadata, allocation group metadata, btrees,
> > +journalling logs, and free space are marked by replacing the
> > +.IR startoffset .. endoffset
> > +with the appropriate marker.
> > +All blocks, offsets, and lengths are specified in units of 512-byte
> > +blocks, no matter what the filesystem's block size is.
> > +The optional
> > +.I start
> > +and
> > +.I end
> > +arguments can be used to constrain the output to a particular range of
> > +disk blocks.
> > +.RE
> > +.RS 1.0i
> > +.PD 0
> > +.TP
> > +.BI \-d
> > +Display only extents from the data device.
> > +This option only applies for XFS filesystems.
> > +.TP
> > +.BI \-l
> > +Display only extents from the external log device.
> > +This option only applies to XFS filesystems.
> > +.TP
> > +.BI \-r
> > +Display only extents from the realtime device.
> > +This option only applies to XFS filesystems.
> > +.TP
> > +.BI \-n " num_extents"
> > +If this option is given,
> > +.B xfs_fsmap
> > +obtains the extent list of the file in groups of
> > +.I num_extents
> > +extents.
> > +In the absence of
> > +.BR \-n ", " xfs_fsmap
> > +queries the system for the number of extents in the filesystem and uses
> > +that value to compute the group size.
> > +.TP
> > +.B \-v
> > +Shows verbose information.
> > +When this flag is specified, additional AG specific information is
> > +appended to each line in the following form:
> > +.IP
> > +.RS 1.2i
> > +.IR agno " (" startagblock .. endagblock ") " nblocks " " flags
> > +.RE
> > +.IP
> > +A second
> > +.B \-v
> > +option will print out the
> > +.I flags
> > +legend.
> > +.RE
> > +.PD
> > +.TP
> > .BI "extsize [ \-R | \-D ] [ " value " ]"
> > Display and/or modify the preferred extent size used when allocating
> > space for the currently open file. If the
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 04/10] xfs_repair: replace rmap_compare with libxfs version
2017-06-02 19:51 [PATCH v8 00/10] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
` (2 preceding siblings ...)
2017-06-02 19:51 ` [PATCH 03/10] xfs_io: support the new getfsmap ioctl Darrick J. Wong
@ 2017-06-02 19:51 ` Darrick J. Wong
2017-06-13 22:34 ` Eric Sandeen
2017-06-02 19:51 ` [PATCH 05/10] xfs_spaceman: space management tool Darrick J. Wong
` (5 subsequent siblings)
9 siblings, 1 reply; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-02 19:51 UTC (permalink / raw)
To: sandeen, darrick.wong; +Cc: linux-xfs
From: Darrick J. Wong <darrick.wong@oracle.com>
Now that libxfs has a function to compare rmaps, replace xfs_repair's
helper function with that.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
libxfs/libxfs_api_defs.h | 1 +
repair/rmap.c | 32 ++------------------------------
2 files changed, 3 insertions(+), 30 deletions(-)
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index 31239ca..2d8d9c8 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -144,5 +144,6 @@
#define xfs_refcount_get_rec libxfs_refcount_get_rec
#define xfs_rmap_lookup_le_range libxfs_rmap_lookup_le_range
#define xfs_refc_block libxfs_refc_block
+#define xfs_rmap_compare libxfs_rmap_compare
#endif /* __LIBXFS_API_DEFS_H__ */
diff --git a/repair/rmap.c b/repair/rmap.c
index 7508973..ab6e583 100644
--- a/repair/rmap.c
+++ b/repair/rmap.c
@@ -49,37 +49,9 @@ static struct xfs_ag_rmap *ag_rmaps;
static bool rmapbt_suspect;
static bool refcbt_suspect;
-/*
- * Compare rmap observations for array sorting.
- */
-static int
-rmap_compare(
- const void *a,
- const void *b)
+static inline int rmap_compare(const void *a, const void *b)
{
- const struct xfs_rmap_irec *pa;
- const struct xfs_rmap_irec *pb;
- __u64 oa;
- __u64 ob;
-
- pa = a; pb = b;
- oa = libxfs_rmap_irec_offset_pack(pa);
- ob = libxfs_rmap_irec_offset_pack(pb);
-
- if (pa->rm_startblock < pb->rm_startblock)
- return -1;
- else if (pa->rm_startblock > pb->rm_startblock)
- return 1;
- else if (pa->rm_owner < pb->rm_owner)
- return -1;
- else if (pa->rm_owner > pb->rm_owner)
- return 1;
- else if (oa < ob)
- return -1;
- else if (oa > ob)
- return 1;
- else
- return 0;
+ return libxfs_rmap_compare(a, b);
}
/*
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 04/10] xfs_repair: replace rmap_compare with libxfs version
2017-06-02 19:51 ` [PATCH 04/10] xfs_repair: replace rmap_compare with libxfs version Darrick J. Wong
@ 2017-06-13 22:34 ` Eric Sandeen
0 siblings, 0 replies; 29+ messages in thread
From: Eric Sandeen @ 2017-06-13 22:34 UTC (permalink / raw)
To: Darrick J. Wong, sandeen; +Cc: linux-xfs
On 6/2/17 2:51 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
>
> Now that libxfs has a function to compare rmaps, replace xfs_repair's
> helper function with that.
>
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
reviewed-by: Eric Sandeen <sandeen@redhat.com>
> ---
> libxfs/libxfs_api_defs.h | 1 +
> repair/rmap.c | 32 ++------------------------------
> 2 files changed, 3 insertions(+), 30 deletions(-)
>
>
> diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
> index 31239ca..2d8d9c8 100644
> --- a/libxfs/libxfs_api_defs.h
> +++ b/libxfs/libxfs_api_defs.h
> @@ -144,5 +144,6 @@
> #define xfs_refcount_get_rec libxfs_refcount_get_rec
> #define xfs_rmap_lookup_le_range libxfs_rmap_lookup_le_range
> #define xfs_refc_block libxfs_refc_block
> +#define xfs_rmap_compare libxfs_rmap_compare
>
> #endif /* __LIBXFS_API_DEFS_H__ */
> diff --git a/repair/rmap.c b/repair/rmap.c
> index 7508973..ab6e583 100644
> --- a/repair/rmap.c
> +++ b/repair/rmap.c
> @@ -49,37 +49,9 @@ static struct xfs_ag_rmap *ag_rmaps;
> static bool rmapbt_suspect;
> static bool refcbt_suspect;
>
> -/*
> - * Compare rmap observations for array sorting.
> - */
> -static int
> -rmap_compare(
> - const void *a,
> - const void *b)
> +static inline int rmap_compare(const void *a, const void *b)
> {
> - const struct xfs_rmap_irec *pa;
> - const struct xfs_rmap_irec *pb;
> - __u64 oa;
> - __u64 ob;
> -
> - pa = a; pb = b;
> - oa = libxfs_rmap_irec_offset_pack(pa);
> - ob = libxfs_rmap_irec_offset_pack(pb);
> -
> - if (pa->rm_startblock < pb->rm_startblock)
> - return -1;
> - else if (pa->rm_startblock > pb->rm_startblock)
> - return 1;
> - else if (pa->rm_owner < pb->rm_owner)
> - return -1;
> - else if (pa->rm_owner > pb->rm_owner)
> - return 1;
> - else if (oa < ob)
> - return -1;
> - else if (oa > ob)
> - return 1;
> - else
> - return 0;
> + return libxfs_rmap_compare(a, b);
> }
>
> /*
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 05/10] xfs_spaceman: space management tool
2017-06-02 19:51 [PATCH v8 00/10] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
` (3 preceding siblings ...)
2017-06-02 19:51 ` [PATCH 04/10] xfs_repair: replace rmap_compare with libxfs version Darrick J. Wong
@ 2017-06-02 19:51 ` Darrick J. Wong
2017-06-14 14:15 ` Eric Sandeen
2017-06-02 19:51 ` [PATCH 06/10] xfs_spaceman: add FITRIM support Darrick J. Wong
` (4 subsequent siblings)
9 siblings, 1 reply; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-02 19:51 UTC (permalink / raw)
To: sandeen, darrick.wong; +Cc: linux-xfs, Dave Chinner
From: Dave Chinner <dchinner@redhat.com>
xfs_spaceman is intended as a diagnostic and control tool for space
management operations within XFS. Operations like examining free
space, managing allocation policies, issuing block discards on free
space, etc.
The tool is modelled on the xfs_io interface, allowing both
interactive and command line control of the tool, enabling it to be
used in scripts and automated management tools.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
[darrick: change xfsctl to ioctl]
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
Makefile | 3 +
spaceman/Makefile | 33 ++++++++++++
spaceman/file.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++
spaceman/init.c | 114 +++++++++++++++++++++++++++++++++++++++++
spaceman/init.h | 23 ++++++++
spaceman/space.h | 36 +++++++++++++
6 files changed, 357 insertions(+), 1 deletion(-)
create mode 100644 spaceman/Makefile
create mode 100644 spaceman/file.c
create mode 100644 spaceman/init.c
create mode 100644 spaceman/init.h
create mode 100644 spaceman/space.h
diff --git a/Makefile b/Makefile
index ba87327..72d0044 100644
--- a/Makefile
+++ b/Makefile
@@ -47,7 +47,7 @@ HDR_SUBDIRS = include libxfs
DLIB_SUBDIRS = libxlog libxcmd libhandle
LIB_SUBDIRS = libxfs $(DLIB_SUBDIRS)
TOOL_SUBDIRS = copy db estimate fsck growfs io logprint mkfs quota \
- mdrestore repair rtcp m4 man doc debian
+ mdrestore repair rtcp m4 man doc debian spaceman
ifneq ("$(PKG_PLATFORM)","darwin")
TOOL_SUBDIRS += fsr
@@ -88,6 +88,7 @@ quota: libxcmd
repair: libxlog libxcmd
copy: libxlog
mkfs: libxcmd
+spaceman: libxcmd
ifeq ($(HAVE_BUILDDEFS), yes)
include $(BUILDRULES)
diff --git a/spaceman/Makefile b/spaceman/Makefile
new file mode 100644
index 0000000..df59edf
--- /dev/null
+++ b/spaceman/Makefile
@@ -0,0 +1,33 @@
+#
+# Copyright (c) 2012 Red Hat, Inc. All Rights Reserved.
+#
+
+TOPDIR = ..
+include $(TOPDIR)/include/builddefs
+
+LTCOMMAND = xfs_spaceman
+HFILES = init.h space.h
+CFILES = init.c file.c
+
+LLDLIBS = $(LIBXCMD)
+LTDEPENDENCIES = $(LIBXCMD)
+LLDFLAGS = -static
+
+ifeq ($(ENABLE_READLINE),yes)
+LLDLIBS += $(LIBREADLINE) $(LIBTERMCAP)
+endif
+
+ifeq ($(ENABLE_EDITLINE),yes)
+LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP)
+endif
+
+default: depend $(LTCOMMAND)
+
+include $(BUILDRULES)
+
+install: default
+ $(INSTALL) -m 755 -d $(PKG_SBIN_DIR)
+ $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR)
+install-dev:
+
+-include .dep
diff --git a/spaceman/file.c b/spaceman/file.c
new file mode 100644
index 0000000..9356066
--- /dev/null
+++ b/spaceman/file.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2004-2005 Silicon Graphics, Inc.
+ * Copyright (c) 2012 Red Hat, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libxfs.h"
+#include <sys/mman.h>
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "space.h"
+
+static cmdinfo_t print_cmd;
+
+fileio_t *filetable;
+int filecount;
+fileio_t *file;
+
+static void
+print_fileio(
+ fileio_t *file,
+ int index,
+ int braces)
+{
+ printf(_("%c%03d%c %-14s (%s,%s,%s%s%s)\n"),
+ braces? '[' : ' ', index, braces? ']' : ' ', file->name,
+ file->flags & O_SYNC ? _("sync") : _("non-sync"),
+ file->flags & O_DIRECT ? _("direct") : _("non-direct"),
+ file->flags & O_RDONLY ? _("read-only") : _("read-write"),
+ file->flags & O_APPEND ? _(",append-only") : "",
+ file->flags & O_NONBLOCK ? _(",non-block") : "");
+}
+
+int
+filelist_f(void)
+{
+ int i;
+
+ for (i = 0; i < filecount; i++)
+ print_fileio(&filetable[i], i, &filetable[i] == file);
+ return 0;
+}
+
+static int
+print_f(
+ int argc,
+ char **argv)
+{
+ filelist_f();
+ return 0;
+}
+
+int
+openfile(
+ char *path,
+ xfs_fsop_geom_t *geom,
+ int flags,
+ mode_t mode)
+{
+ int fd;
+
+ fd = open(path, flags, mode);
+ if (fd < 0) {
+ if ((errno == EISDIR) && (flags & O_RDWR)) {
+ /* make it as if we asked for O_RDONLY & try again */
+ flags &= ~O_RDWR;
+ flags |= O_RDONLY;
+ fd = open(path, flags, mode);
+ if (fd < 0) {
+ perror(path);
+ return -1;
+ }
+ } else {
+ perror(path);
+ return -1;
+ }
+ }
+
+ if (ioctl(fd, XFS_IOC_FSGEOMETRY, geom) < 0) {
+ perror("XFS_IOC_FSGEOMETRY");
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+int
+addfile(
+ char *name,
+ int fd,
+ xfs_fsop_geom_t *geometry,
+ int flags)
+{
+ char *filename;
+
+ filename = strdup(name);
+ if (!filename) {
+ perror("strdup");
+ close(fd);
+ return -1;
+ }
+
+ /* Extend the table of currently open files */
+ filetable = (fileio_t *)realloc(filetable, /* growing */
+ ++filecount * sizeof(fileio_t));
+ if (!filetable) {
+ perror("realloc");
+ filecount = 0;
+ free(filename);
+ close(fd);
+ return -1;
+ }
+
+ /* Finally, make this the new active open file */
+ file = &filetable[filecount - 1];
+ file->fd = fd;
+ file->flags = flags;
+ file->name = filename;
+ file->geom = *geometry;
+ return 0;
+}
+
+void
+file_init(void)
+{
+ print_cmd.name = "print";
+ print_cmd.altname = "p";
+ print_cmd.cfunc = print_f;
+ print_cmd.argmin = 0;
+ print_cmd.argmax = 0;
+ print_cmd.flags = CMD_FLAG_ONESHOT;
+ print_cmd.oneline = _("list current open files");
+
+ add_command(&print_cmd);
+}
diff --git a/spaceman/init.c b/spaceman/init.c
new file mode 100644
index 0000000..5dbaef2
--- /dev/null
+++ b/spaceman/init.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2012 Red Hat, Inc
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libxfs.h"
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "space.h"
+
+char *progname;
+int exitcode;
+
+void
+usage(void)
+{
+ fprintf(stderr,
+ _("Usage: %s [-c cmd] file\n"),
+ progname);
+ exit(1);
+}
+
+static void
+init_commands(void)
+{
+ file_init();
+ help_init();
+ quit_init();
+}
+
+static int
+init_args_command(
+ int index)
+{
+ if (index >= filecount)
+ return 0;
+ file = &filetable[index++];
+ return index;
+}
+
+static int
+init_check_command(
+ const cmdinfo_t *ct)
+{
+ if (!(ct->flags & CMD_FLAG_ONESHOT))
+ return 0;
+ return 1;
+}
+
+void
+init(
+ int argc,
+ char **argv)
+{
+ int c, flags = 0;
+ mode_t mode = 0600;
+ xfs_fsop_geom_t geometry = { 0 };
+
+ progname = basename(argv[0]);
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+
+ while ((c = getopt(argc, argv, "c:V")) != EOF) {
+ switch (c) {
+ case 'c':
+ add_user_command(optarg);
+ break;
+ case 'V':
+ printf(_("%s version %s\n"), progname, VERSION);
+ exit(0);
+ default:
+ usage();
+ }
+ }
+
+ if (optind != argc - 1)
+ usage();
+
+ if ((c = openfile(argv[optind], &geometry, flags, mode)) < 0)
+ exit(1);
+ if (!platform_test_xfs_fd(c))
+ printf(_("Not an XFS filesystem!\n"));
+ if (addfile(argv[optind], c, &geometry, flags) < 0)
+ exit(1);
+
+ init_commands();
+ add_command_iterator(init_args_command);
+ add_check_command(init_check_command);
+}
+
+int
+main(
+ int argc,
+ char **argv)
+{
+ init(argc, argv);
+ command_loop();
+ return exitcode;
+}
diff --git a/spaceman/init.h b/spaceman/init.h
new file mode 100644
index 0000000..165e4f5
--- /dev/null
+++ b/spaceman/init.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2012 Red Hat, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+extern char *progname;
+extern int exitcode;
+
+#define min(a,b) (((a)<(b))?(a):(b))
+#define max(a,b) (((a)>(b))?(a):(b))
diff --git a/spaceman/space.h b/spaceman/space.h
new file mode 100644
index 0000000..6e1bc52
--- /dev/null
+++ b/spaceman/space.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012 Red Hat, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+typedef struct fileio {
+ int fd; /* open file descriptor */
+ int flags; /* flags describing file state */
+ char *name; /* file name at time of open */
+ xfs_fsop_geom_t geom; /* XFS filesystem geometry */
+} fileio_t;
+
+extern fileio_t *filetable; /* open file table */
+extern int filecount; /* number of open files */
+extern fileio_t *file; /* active file in file table */
+extern int filelist_f(void);
+
+extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t);
+extern int addfile(char *, int , xfs_fsop_geom_t *, int);
+
+extern void file_init(void);
+extern void help_init(void);
+extern void quit_init(void);
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 05/10] xfs_spaceman: space management tool
2017-06-02 19:51 ` [PATCH 05/10] xfs_spaceman: space management tool Darrick J. Wong
@ 2017-06-14 14:15 ` Eric Sandeen
2017-06-14 16:16 ` Darrick J. Wong
0 siblings, 1 reply; 29+ messages in thread
From: Eric Sandeen @ 2017-06-14 14:15 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs, Dave Chinner
On 6/2/17 2:51 PM, Darrick J. Wong wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> xfs_spaceman is intended as a diagnostic and control tool for space
> management operations within XFS. Operations like examining free
> space, managing allocation policies, issuing block discards on free
> space, etc.
>
> The tool is modelled on the xfs_io interface, allowing both
> interactive and command line control of the tool, enabling it to be
> used in scripts and automated management tools.
>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> [darrick: change xfsctl to ioctl]
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
> Makefile | 3 +
> spaceman/Makefile | 33 ++++++++++++
> spaceman/file.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> spaceman/init.c | 114 +++++++++++++++++++++++++++++++++++++++++
> spaceman/init.h | 23 ++++++++
> spaceman/space.h | 36 +++++++++++++
> 6 files changed, 357 insertions(+), 1 deletion(-)
> create mode 100644 spaceman/Makefile
> create mode 100644 spaceman/file.c
> create mode 100644 spaceman/init.c
> create mode 100644 spaceman/init.h
> create mode 100644 spaceman/space.h
>
>
> diff --git a/Makefile b/Makefile
> index ba87327..72d0044 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -47,7 +47,7 @@ HDR_SUBDIRS = include libxfs
> DLIB_SUBDIRS = libxlog libxcmd libhandle
> LIB_SUBDIRS = libxfs $(DLIB_SUBDIRS)
> TOOL_SUBDIRS = copy db estimate fsck growfs io logprint mkfs quota \
> - mdrestore repair rtcp m4 man doc debian
> + mdrestore repair rtcp m4 man doc debian spaceman
>
> ifneq ("$(PKG_PLATFORM)","darwin")
> TOOL_SUBDIRS += fsr
> @@ -88,6 +88,7 @@ quota: libxcmd
> repair: libxlog libxcmd
> copy: libxlog
> mkfs: libxcmd
> +spaceman: libxcmd
>
> ifeq ($(HAVE_BUILDDEFS), yes)
> include $(BUILDRULES)
> diff --git a/spaceman/Makefile b/spaceman/Makefile
> new file mode 100644
> index 0000000..df59edf
> --- /dev/null
> +++ b/spaceman/Makefile
> @@ -0,0 +1,33 @@
> +#
> +# Copyright (c) 2012 Red Hat, Inc. All Rights Reserved.
> +#
> +
> +TOPDIR = ..
> +include $(TOPDIR)/include/builddefs
> +
> +LTCOMMAND = xfs_spaceman
> +HFILES = init.h space.h
> +CFILES = init.c file.c
> +
> +LLDLIBS = $(LIBXCMD)
> +LTDEPENDENCIES = $(LIBXCMD)
> +LLDFLAGS = -static
> +
> +ifeq ($(ENABLE_READLINE),yes)
> +LLDLIBS += $(LIBREADLINE) $(LIBTERMCAP)
> +endif
> +
> +ifeq ($(ENABLE_EDITLINE),yes)
> +LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP)
> +endif
> +
> +default: depend $(LTCOMMAND)
> +
> +include $(BUILDRULES)
> +
> +install: default
> + $(INSTALL) -m 755 -d $(PKG_SBIN_DIR)
> + $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR)
> +install-dev:
> +
> +-include .dep
> diff --git a/spaceman/file.c b/spaceman/file.c
> new file mode 100644
> index 0000000..9356066
> --- /dev/null
> +++ b/spaceman/file.c
> @@ -0,0 +1,149 @@
> +/*
> + * Copyright (c) 2004-2005 Silicon Graphics, Inc.
> + * Copyright (c) 2012 Red Hat, Inc.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation,
> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "libxfs.h"
> +#include <sys/mman.h>
> +#include "command.h"
> +#include "input.h"
> +#include "init.h"
> +#include "space.h"
> +
> +static cmdinfo_t print_cmd;
> +
> +fileio_t *filetable;
> +int filecount;
> +fileio_t *file;
> +
> +static void
> +print_fileio(
> + fileio_t *file,
> + int index,
> + int braces)
> +{
> + printf(_("%c%03d%c %-14s (%s,%s,%s%s%s)\n"),
> + braces? '[' : ' ', index, braces? ']' : ' ', file->name,
> + file->flags & O_SYNC ? _("sync") : _("non-sync"),
Ok, my question last round about this didn't get answered:
[xfsprogs-fsmap]# spaceman/xfs_spaceman -c print mnt/
[000] mnt/ (non-sync,non-direct,read-write)
[xfsprogs-fsmap]# mount -o remount,ro mnt
[xfsprogs-fsmap]# spaceman/xfs_spaceman -c print mnt/
[000] mnt/ (non-sync,non-direct,read-write)
I don't see that these flags have any meaning; indeed, the flags argument
to openfile() and addfile() is initialized to 0 and never changed. Should
it just be removed?
If you want to get things merged and clean stuff up with a later patch,
that's ok by me, or we could remove them now. It's not really a functionality
problem so I'm not too bothered.
> + file->flags & O_DIRECT ? _("direct") : _("non-direct"),
> + file->flags & O_RDONLY ? _("read-only") : _("read-write"),
> + file->flags & O_APPEND ? _(",append-only") : "",
> + file->flags & O_NONBLOCK ? _(",non-block") : "");
> +}
> +
> +int
> +filelist_f(void)
> +{
> + int i;
> +
> + for (i = 0; i < filecount; i++)
> + print_fileio(&filetable[i], i, &filetable[i] == file);
> + return 0;
> +}
> +
> +static int
> +print_f(
> + int argc,
> + char **argv)
> +{
> + filelist_f();
No need for the separate filelist_f, just put the guts here, it has no other
caller.
Hm, actually ... for consistency with xfs_io should we have both "file" and "print?"
file [ N ]
Display a list of all open files and (optionally) switch to an alternate current open file.
print Display a list of all open files and memory mapped regions. The current file and current mapping are distinguishable from any others.
Again not overly concerned about this, just pointing it out - if it's modeled on xfs_io behavior, let's keep it as similar as possible.
(If this gets changed, don't forget the manpage)
> + return 0;
> +}
> +
> +int
> +openfile(
> + char *path,
> + xfs_fsop_geom_t *geom,
> + int flags,
flags is always called with flags == 0, so all the flag testing below is pointless -
and probably doesn't relate to filesystem-wide operations anyway.
> + mode_t mode)
> +{
> + int fd;
> +
> + fd = open(path, flags, mode);
> + if (fd < 0) {
> + if ((errno == EISDIR) && (flags & O_RDWR)) {
> + /* make it as if we asked for O_RDONLY & try again */
> + flags &= ~O_RDWR;
> + flags |= O_RDONLY;
> + fd = open(path, flags, mode);
> + if (fd < 0) {
> + perror(path);
> + return -1;
> + }
> + } else {
> + perror(path);
> + return -1;
> + }
> + }
> +
> + if (ioctl(fd, XFS_IOC_FSGEOMETRY, geom) < 0) {
> + perror("XFS_IOC_FSGEOMETRY");
> + close(fd);
> + return -1;
> + }
> + return fd;
> +}
> +
> +int
> +addfile(
> + char *name,
> + int fd,
> + xfs_fsop_geom_t *geometry,
> + int flags)
> +{
> + char *filename;
> +
> + filename = strdup(name);
> + if (!filename) {
> + perror("strdup");
> + close(fd);
> + return -1;
> + }
> +
> + /* Extend the table of currently open files */
> + filetable = (fileio_t *)realloc(filetable, /* growing */
> + ++filecount * sizeof(fileio_t));
Are you keeping all the filetable stuff with the thought that maybe some
day we'll allow operation on multiple filesystems? Probably a good idea.
> + if (!filetable) {
> + perror("realloc");
> + filecount = 0;
> + free(filename);
> + close(fd);
> + return -1;
> + }
> +
> + /* Finally, make this the new active open file */
> + file = &filetable[filecount - 1];
> + file->fd = fd;
> + file->flags = flags;
> + file->name = filename;
> + file->geom = *geometry;
> + return 0;
> +}
> +
> +void
> +file_init(void)
> +{
file_init setting up print_cmd is confusing - unless you want both ala xfs_io,
I'd go consistently with either "print" or "file" but not a mishmash.
> + print_cmd.name = "print";
> + print_cmd.altname = "p";
> + print_cmd.cfunc = print_f;
> + print_cmd.argmin = 0;
> + print_cmd.argmax = 0;
> + print_cmd.flags = CMD_FLAG_ONESHOT;
> + print_cmd.oneline = _("list current open files");
> +
> + add_command(&print_cmd);
> +}
> diff --git a/spaceman/init.c b/spaceman/init.c
> new file mode 100644
> index 0000000..5dbaef2
> --- /dev/null
> +++ b/spaceman/init.c
> @@ -0,0 +1,114 @@
> +/*
> + * Copyright (c) 2012 Red Hat, Inc
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation,
> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "libxfs.h"
> +#include "command.h"
> +#include "input.h"
> +#include "init.h"
> +#include "space.h"
> +
> +char *progname;
> +int exitcode;
> +
> +void
> +usage(void)
> +{
> + fprintf(stderr,
> + _("Usage: %s [-c cmd] file\n"),
> + progname);
> + exit(1);
> +}
> +
> +static void
> +init_commands(void)
> +{
> + file_init();
> + help_init();
> + quit_init();
> +}
> +
> +static int
> +init_args_command(
> + int index)
> +{
> + if (index >= filecount)
> + return 0;
> + file = &filetable[index++];
> + return index;
> +}
> +
> +static int
> +init_check_command(
> + const cmdinfo_t *ct)
> +{
> + if (!(ct->flags & CMD_FLAG_ONESHOT))
> + return 0;
> + return 1;
> +}
> +
> +void
> +init(
> + int argc,
> + char **argv)
> +{
> + int c, flags = 0;
> + mode_t mode = 0600;
> + xfs_fsop_geom_t geometry = { 0 };
> +
> + progname = basename(argv[0]);
> + setlocale(LC_ALL, "");
> + bindtextdomain(PACKAGE, LOCALEDIR);
> + textdomain(PACKAGE);
> +
> + while ((c = getopt(argc, argv, "c:V")) != EOF) {
> + switch (c) {
> + case 'c':
> + add_user_command(optarg);
> + break;
> + case 'V':
> + printf(_("%s version %s\n"), progname, VERSION);
> + exit(0);
> + default:
> + usage();
> + }
> + }
> +
> + if (optind != argc - 1)
> + usage();
> +
> + if ((c = openfile(argv[optind], &geometry, flags, mode)) < 0)
> + exit(1);
> + if (!platform_test_xfs_fd(c))
> + printf(_("Not an XFS filesystem!\n"));
> + if (addfile(argv[optind], c, &geometry, flags) < 0)
> + exit(1);
> +
> + init_commands();
> + add_command_iterator(init_args_command);
> + add_check_command(init_check_command);
> +}
> +
> +int
> +main(
> + int argc,
> + char **argv)
> +{
> + init(argc, argv);
> + command_loop();
> + return exitcode;
> +}
> diff --git a/spaceman/init.h b/spaceman/init.h
> new file mode 100644
> index 0000000..165e4f5
> --- /dev/null
> +++ b/spaceman/init.h
> @@ -0,0 +1,23 @@
> +/*
> + * Copyright (c) 2012 Red Hat, Inc.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation,
> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +extern char *progname;
> +extern int exitcode;
> +
> +#define min(a,b) (((a)<(b))?(a):(b))
> +#define max(a,b) (((a)>(b))?(a):(b))
these aren't actually used, FWIW.
> diff --git a/spaceman/space.h b/spaceman/space.h
> new file mode 100644
> index 0000000..6e1bc52
> --- /dev/null
> +++ b/spaceman/space.h
> @@ -0,0 +1,36 @@
> +/*
> + * Copyright (c) 2012 Red Hat, Inc.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation,
> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +typedef struct fileio {
> + int fd; /* open file descriptor */
> + int flags; /* flags describing file state */
This is never used, really - always 0.
> + char *name; /* file name at time of open */
> + xfs_fsop_geom_t geom; /* XFS filesystem geometry */
> +} fileio_t;
> +
> +extern fileio_t *filetable; /* open file table */
> +extern int filecount; /* number of open files */
> +extern fileio_t *file; /* active file in file table */
> +extern int filelist_f(void);
> +
> +extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t);
> +extern int addfile(char *, int , xfs_fsop_geom_t *, int);
> +
> +extern void file_init(void);
> +extern void help_init(void);
> +extern void quit_init(void);
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 05/10] xfs_spaceman: space management tool
2017-06-14 14:15 ` Eric Sandeen
@ 2017-06-14 16:16 ` Darrick J. Wong
0 siblings, 0 replies; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-14 16:16 UTC (permalink / raw)
To: Eric Sandeen; +Cc: linux-xfs, Dave Chinner
On Wed, Jun 14, 2017 at 09:15:49AM -0500, Eric Sandeen wrote:
> On 6/2/17 2:51 PM, Darrick J. Wong wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> >
> > xfs_spaceman is intended as a diagnostic and control tool for space
> > management operations within XFS. Operations like examining free
> > space, managing allocation policies, issuing block discards on free
> > space, etc.
> >
> > The tool is modelled on the xfs_io interface, allowing both
> > interactive and command line control of the tool, enabling it to be
> > used in scripts and automated management tools.
> >
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > [darrick: change xfsctl to ioctl]
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> > Makefile | 3 +
> > spaceman/Makefile | 33 ++++++++++++
> > spaceman/file.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> > spaceman/init.c | 114 +++++++++++++++++++++++++++++++++++++++++
> > spaceman/init.h | 23 ++++++++
> > spaceman/space.h | 36 +++++++++++++
> > 6 files changed, 357 insertions(+), 1 deletion(-)
> > create mode 100644 spaceman/Makefile
> > create mode 100644 spaceman/file.c
> > create mode 100644 spaceman/init.c
> > create mode 100644 spaceman/init.h
> > create mode 100644 spaceman/space.h
> >
> >
> > diff --git a/Makefile b/Makefile
> > index ba87327..72d0044 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -47,7 +47,7 @@ HDR_SUBDIRS = include libxfs
> > DLIB_SUBDIRS = libxlog libxcmd libhandle
> > LIB_SUBDIRS = libxfs $(DLIB_SUBDIRS)
> > TOOL_SUBDIRS = copy db estimate fsck growfs io logprint mkfs quota \
> > - mdrestore repair rtcp m4 man doc debian
> > + mdrestore repair rtcp m4 man doc debian spaceman
> >
> > ifneq ("$(PKG_PLATFORM)","darwin")
> > TOOL_SUBDIRS += fsr
> > @@ -88,6 +88,7 @@ quota: libxcmd
> > repair: libxlog libxcmd
> > copy: libxlog
> > mkfs: libxcmd
> > +spaceman: libxcmd
> >
> > ifeq ($(HAVE_BUILDDEFS), yes)
> > include $(BUILDRULES)
> > diff --git a/spaceman/Makefile b/spaceman/Makefile
> > new file mode 100644
> > index 0000000..df59edf
> > --- /dev/null
> > +++ b/spaceman/Makefile
> > @@ -0,0 +1,33 @@
> > +#
> > +# Copyright (c) 2012 Red Hat, Inc. All Rights Reserved.
> > +#
> > +
> > +TOPDIR = ..
> > +include $(TOPDIR)/include/builddefs
> > +
> > +LTCOMMAND = xfs_spaceman
> > +HFILES = init.h space.h
> > +CFILES = init.c file.c
> > +
> > +LLDLIBS = $(LIBXCMD)
> > +LTDEPENDENCIES = $(LIBXCMD)
> > +LLDFLAGS = -static
> > +
> > +ifeq ($(ENABLE_READLINE),yes)
> > +LLDLIBS += $(LIBREADLINE) $(LIBTERMCAP)
> > +endif
> > +
> > +ifeq ($(ENABLE_EDITLINE),yes)
> > +LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP)
> > +endif
> > +
> > +default: depend $(LTCOMMAND)
> > +
> > +include $(BUILDRULES)
> > +
> > +install: default
> > + $(INSTALL) -m 755 -d $(PKG_SBIN_DIR)
> > + $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR)
> > +install-dev:
> > +
> > +-include .dep
> > diff --git a/spaceman/file.c b/spaceman/file.c
> > new file mode 100644
> > index 0000000..9356066
> > --- /dev/null
> > +++ b/spaceman/file.c
> > @@ -0,0 +1,149 @@
> > +/*
> > + * Copyright (c) 2004-2005 Silicon Graphics, Inc.
> > + * Copyright (c) 2012 Red Hat, Inc.
> > + * All Rights Reserved.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License as
> > + * published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it would be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write the Free Software Foundation,
> > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> > + */
> > +
> > +#include "libxfs.h"
> > +#include <sys/mman.h>
> > +#include "command.h"
> > +#include "input.h"
> > +#include "init.h"
> > +#include "space.h"
> > +
> > +static cmdinfo_t print_cmd;
> > +
> > +fileio_t *filetable;
> > +int filecount;
> > +fileio_t *file;
> > +
> > +static void
> > +print_fileio(
> > + fileio_t *file,
> > + int index,
> > + int braces)
> > +{
> > + printf(_("%c%03d%c %-14s (%s,%s,%s%s%s)\n"),
> > + braces? '[' : ' ', index, braces? ']' : ' ', file->name,
> > + file->flags & O_SYNC ? _("sync") : _("non-sync"),
>
> Ok, my question last round about this didn't get answered:
>
> [xfsprogs-fsmap]# spaceman/xfs_spaceman -c print mnt/
> [000] mnt/ (non-sync,non-direct,read-write)
>
> [xfsprogs-fsmap]# mount -o remount,ro mnt
>
> [xfsprogs-fsmap]# spaceman/xfs_spaceman -c print mnt/
> [000] mnt/ (non-sync,non-direct,read-write)
>
> I don't see that these flags have any meaning; indeed, the flags argument
> to openfile() and addfile() is initialized to 0 and never changed. Should
> it just be removed?
>
> If you want to get things merged and clean stuff up with a later patch,
> that's ok by me, or we could remove them now. It's not really a functionality
> problem so I'm not too bothered.
I don't think any of these flags matter for spaceman, I'll just remove
the fd flags reporting.
> > + file->flags & O_DIRECT ? _("direct") : _("non-direct"),
> > + file->flags & O_RDONLY ? _("read-only") : _("read-write"),
FWIW I'm not sure how this /ever/ works, since "#define O_RDONLY 0".
> > + file->flags & O_APPEND ? _(",append-only") : "",
> > + file->flags & O_NONBLOCK ? _(",non-block") : "");
> > +}
> > +
> > +int
> > +filelist_f(void)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < filecount; i++)
> > + print_fileio(&filetable[i], i, &filetable[i] == file);
> > + return 0;
> > +}
> > +
> > +static int
> > +print_f(
> > + int argc,
> > + char **argv)
> > +{
> > + filelist_f();
>
> No need for the separate filelist_f, just put the guts here, it has no other
> caller.
>
> Hm, actually ... for consistency with xfs_io should we have both "file" and "print?"
>
> file [ N ]
> Display a list of all open files and (optionally) switch to an alternate current open file.
>
> print Display a list of all open files and memory mapped regions. The current file and current mapping are distinguishable from any others.
>
> Again not overly concerned about this, just pointing it out - if it's modeled on xfs_io behavior, let's keep it as similar as possible.
>
> (If this gets changed, don't forget the manpage)
I'll just get rid of the weird print_f -> filelist_f indirection since
spaceman doesn't have a 'file' command anymore anyway.
>
> > + return 0;
> > +}
> > +
> > +int
> > +openfile(
> > + char *path,
> > + xfs_fsop_geom_t *geom,
> > + int flags,
>
> flags is always called with flags == 0, so all the flag testing below is pointless -
> and probably doesn't relate to filesystem-wide operations anyway.
I'll get rid of mode too, since we don't use it either.
>
> > + mode_t mode)
> > +{
> > + int fd;
> > +
> > + fd = open(path, flags, mode);
> > + if (fd < 0) {
> > + if ((errno == EISDIR) && (flags & O_RDWR)) {
> > + /* make it as if we asked for O_RDONLY & try again */
> > + flags &= ~O_RDWR;
> > + flags |= O_RDONLY;
> > + fd = open(path, flags, mode);
> > + if (fd < 0) {
> > + perror(path);
> > + return -1;
> > + }
> > + } else {
> > + perror(path);
> > + return -1;
> > + }
> > + }
> > +
> > + if (ioctl(fd, XFS_IOC_FSGEOMETRY, geom) < 0) {
> > + perror("XFS_IOC_FSGEOMETRY");
> > + close(fd);
> > + return -1;
> > + }
> > + return fd;
> > +}
> > +
> > +int
> > +addfile(
> > + char *name,
> > + int fd,
> > + xfs_fsop_geom_t *geometry,
> > + int flags)
> > +{
> > + char *filename;
> > +
> > + filename = strdup(name);
> > + if (!filename) {
> > + perror("strdup");
> > + close(fd);
> > + return -1;
> > + }
> > +
> > + /* Extend the table of currently open files */
> > + filetable = (fileio_t *)realloc(filetable, /* growing */
> > + ++filecount * sizeof(fileio_t));
>
> Are you keeping all the filetable stuff with the thought that maybe some
> day we'll allow operation on multiple filesystems? Probably a good idea.
Yes.
> > + if (!filetable) {
> > + perror("realloc");
> > + filecount = 0;
> > + free(filename);
> > + close(fd);
> > + return -1;
> > + }
> > +
> > + /* Finally, make this the new active open file */
> > + file = &filetable[filecount - 1];
> > + file->fd = fd;
> > + file->flags = flags;
> > + file->name = filename;
> > + file->geom = *geometry;
> > + return 0;
> > +}
> > +
> > +void
> > +file_init(void)
> > +{
>
> file_init setting up print_cmd is confusing - unless you want both ala xfs_io,
> I'd go consistently with either "print" or "file" but not a mishmash.
Ok, print_init it is.
>
> > + print_cmd.name = "print";
> > + print_cmd.altname = "p";
> > + print_cmd.cfunc = print_f;
> > + print_cmd.argmin = 0;
> > + print_cmd.argmax = 0;
> > + print_cmd.flags = CMD_FLAG_ONESHOT;
> > + print_cmd.oneline = _("list current open files");
> > +
> > + add_command(&print_cmd);
> > +}
> > diff --git a/spaceman/init.c b/spaceman/init.c
> > new file mode 100644
> > index 0000000..5dbaef2
> > --- /dev/null
> > +++ b/spaceman/init.c
> > @@ -0,0 +1,114 @@
> > +/*
> > + * Copyright (c) 2012 Red Hat, Inc
> > + * All Rights Reserved.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License as
> > + * published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it would be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write the Free Software Foundation,
> > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> > + */
> > +
> > +#include "libxfs.h"
> > +#include "command.h"
> > +#include "input.h"
> > +#include "init.h"
> > +#include "space.h"
> > +
> > +char *progname;
> > +int exitcode;
> > +
> > +void
> > +usage(void)
> > +{
> > + fprintf(stderr,
> > + _("Usage: %s [-c cmd] file\n"),
> > + progname);
> > + exit(1);
> > +}
> > +
> > +static void
> > +init_commands(void)
> > +{
> > + file_init();
> > + help_init();
> > + quit_init();
> > +}
> > +
> > +static int
> > +init_args_command(
> > + int index)
> > +{
> > + if (index >= filecount)
> > + return 0;
> > + file = &filetable[index++];
> > + return index;
> > +}
> > +
> > +static int
> > +init_check_command(
> > + const cmdinfo_t *ct)
> > +{
> > + if (!(ct->flags & CMD_FLAG_ONESHOT))
> > + return 0;
> > + return 1;
> > +}
> > +
> > +void
> > +init(
> > + int argc,
> > + char **argv)
> > +{
> > + int c, flags = 0;
> > + mode_t mode = 0600;
> > + xfs_fsop_geom_t geometry = { 0 };
> > +
> > + progname = basename(argv[0]);
> > + setlocale(LC_ALL, "");
> > + bindtextdomain(PACKAGE, LOCALEDIR);
> > + textdomain(PACKAGE);
> > +
> > + while ((c = getopt(argc, argv, "c:V")) != EOF) {
> > + switch (c) {
> > + case 'c':
> > + add_user_command(optarg);
> > + break;
> > + case 'V':
> > + printf(_("%s version %s\n"), progname, VERSION);
> > + exit(0);
> > + default:
> > + usage();
> > + }
> > + }
> > +
> > + if (optind != argc - 1)
> > + usage();
> > +
> > + if ((c = openfile(argv[optind], &geometry, flags, mode)) < 0)
> > + exit(1);
> > + if (!platform_test_xfs_fd(c))
> > + printf(_("Not an XFS filesystem!\n"));
> > + if (addfile(argv[optind], c, &geometry, flags) < 0)
> > + exit(1);
> > +
> > + init_commands();
> > + add_command_iterator(init_args_command);
> > + add_check_command(init_check_command);
> > +}
> > +
> > +int
> > +main(
> > + int argc,
> > + char **argv)
> > +{
> > + init(argc, argv);
> > + command_loop();
> > + return exitcode;
> > +}
> > diff --git a/spaceman/init.h b/spaceman/init.h
> > new file mode 100644
> > index 0000000..165e4f5
> > --- /dev/null
> > +++ b/spaceman/init.h
> > @@ -0,0 +1,23 @@
> > +/*
> > + * Copyright (c) 2012 Red Hat, Inc.
> > + * All Rights Reserved.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License as
> > + * published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it would be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write the Free Software Foundation,
> > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> > + */
> > +
> > +extern char *progname;
> > +extern int exitcode;
> > +
> > +#define min(a,b) (((a)<(b))?(a):(b))
> > +#define max(a,b) (((a)>(b))?(a):(b))
>
> these aren't actually used, FWIW.
Deleted.
Also realizing that these header files don't have ifndef guards; will
add those too.
> > diff --git a/spaceman/space.h b/spaceman/space.h
> > new file mode 100644
> > index 0000000..6e1bc52
> > --- /dev/null
> > +++ b/spaceman/space.h
> > @@ -0,0 +1,36 @@
> > +/*
> > + * Copyright (c) 2012 Red Hat, Inc.
> > + * All Rights Reserved.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License as
> > + * published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it would be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write the Free Software Foundation,
> > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> > + */
> > +
> > +typedef struct fileio {
> > + int fd; /* open file descriptor */
> > + int flags; /* flags describing file state */
>
> This is never used, really - always 0.
Deleted.
--D
>
> > + char *name; /* file name at time of open */
> > + xfs_fsop_geom_t geom; /* XFS filesystem geometry */
> > +} fileio_t;
> > +
> > +extern fileio_t *filetable; /* open file table */
> > +extern int filecount; /* number of open files */
> > +extern fileio_t *file; /* active file in file table */
> > +extern int filelist_f(void);
> > +
> > +extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t);
> > +extern int addfile(char *, int , xfs_fsop_geom_t *, int);
> > +
> > +extern void file_init(void);
> > +extern void help_init(void);
> > +extern void quit_init(void);
> >
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 06/10] xfs_spaceman: add FITRIM support
2017-06-02 19:51 [PATCH v8 00/10] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
` (4 preceding siblings ...)
2017-06-02 19:51 ` [PATCH 05/10] xfs_spaceman: space management tool Darrick J. Wong
@ 2017-06-02 19:51 ` Darrick J. Wong
2017-06-14 15:32 ` Eric Sandeen
2017-06-02 19:51 ` [PATCH 07/10] xfs_spaceman: add new speculative prealloc control Darrick J. Wong
` (3 subsequent siblings)
9 siblings, 1 reply; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-02 19:51 UTC (permalink / raw)
To: sandeen, darrick.wong; +Cc: linux-xfs, Dave Chinner
From: Dave Chinner <dchinner@redhat.com>
Add support for discarding free space extents via the FITRIM
command. Make it easy to discard a single range, an entire AG or all
the freespace in the filesystem.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
spaceman/Makefile | 2 -
spaceman/init.c | 1
spaceman/space.h | 1
spaceman/trim.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 130 insertions(+), 1 deletion(-)
create mode 100644 spaceman/trim.c
diff --git a/spaceman/Makefile b/spaceman/Makefile
index df59edf..c63a4fc 100644
--- a/spaceman/Makefile
+++ b/spaceman/Makefile
@@ -7,7 +7,7 @@ include $(TOPDIR)/include/builddefs
LTCOMMAND = xfs_spaceman
HFILES = init.h space.h
-CFILES = init.c file.c
+CFILES = init.c file.c trim.c
LLDLIBS = $(LIBXCMD)
LTDEPENDENCIES = $(LIBXCMD)
diff --git a/spaceman/init.c b/spaceman/init.c
index 5dbaef2..0958377 100644
--- a/spaceman/init.c
+++ b/spaceman/init.c
@@ -40,6 +40,7 @@ init_commands(void)
file_init();
help_init();
quit_init();
+ trim_init();
}
static int
diff --git a/spaceman/space.h b/spaceman/space.h
index 6e1bc52..7b4f034 100644
--- a/spaceman/space.h
+++ b/spaceman/space.h
@@ -34,3 +34,4 @@ extern int addfile(char *, int , xfs_fsop_geom_t *, int);
extern void file_init(void);
extern void help_init(void);
extern void quit_init(void);
+extern void trim_init(void);
diff --git a/spaceman/trim.c b/spaceman/trim.c
new file mode 100644
index 0000000..d58f6d1
--- /dev/null
+++ b/spaceman/trim.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2012 Red Hat, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libxfs.h"
+#include <linux/fs.h>
+#include "command.h"
+#include "init.h"
+#include "space.h"
+#include "input.h"
+
+static cmdinfo_t trim_cmd;
+
+/*
+ * Trim unused space in xfs filesystem.
+ */
+static int
+trim_f(
+ int argc,
+ char **argv)
+{
+ struct fstrim_range trim = {0};
+ xfs_agnumber_t agno = 0;
+ off64_t offset = 0;
+ ssize_t length = 0;
+ ssize_t minlen = 0;
+ int aflag = 0;
+ int fflag = 0;
+ int ret;
+ int c;
+
+ while ((c = getopt(argc, argv, "a:fm:")) != EOF) {
+ switch (c) {
+ case 'a':
+ aflag = 1;
+ agno = atoi(optarg);
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'm':
+ minlen = cvtnum(file->geom.blocksize,
+ file->geom.sectsize, argv[optind]);
+ break;
+ default:
+ return command_usage(&trim_cmd);
+ }
+ }
+
+ if (aflag && fflag)
+ return command_usage(&trim_cmd);
+
+ if (optind != argc - 2 && !(aflag || fflag))
+ return command_usage(&trim_cmd);
+ if (optind != argc) {
+ offset = cvtnum(file->geom.blocksize, file->geom.sectsize,
+ argv[optind]);
+ length = cvtnum(file->geom.blocksize, file->geom.sectsize,
+ argv[optind + 1]);
+ } else if (agno) {
+ offset = agno * file->geom.agblocks * file->geom.blocksize;
+ length = file->geom.agblocks * file->geom.blocksize;
+ } else {
+ offset = 0;
+ length = file->geom.datablocks * file->geom.blocksize;
+ }
+
+ trim.start = offset;
+ trim.len = length;
+ trim.minlen = minlen;
+
+ ret = ioctl(file->fd, FITRIM, (unsigned long)&trim);
+ if (ret < 0) {
+ fprintf(stderr, "%s: ioctl(FITRIM) [\"%s\"]: "
+ "%s\n", progname, file->name, strerror(errno));
+ exitcode = 1;
+ }
+ return 0;
+}
+
+static void
+trim_help(void)
+{
+ printf(_(
+"\n"
+"Discard filesystem free space\n"
+"\n"
+"Options: [-m minlen] [-f]|[-a agno]|[offset length]\n"
+"\n"
+" -m minlen -- skip freespace extents smaller than minlen\n"
+" -f -- trim all the freespace in the entire filesystem\n"
+" -a agno -- trim all the freespace in the given AG agno\n"
+" offset length -- trim the freespace in the range {offset, length}\n"
+"\n"));
+
+}
+
+void
+trim_init(void)
+{
+ trim_cmd.name = "trim";
+ trim_cmd.altname = "tr";
+ trim_cmd.cfunc = trim_f;
+ trim_cmd.argmin = 1;
+ trim_cmd.argmax = 4;
+ trim_cmd.args = "[-m minlen] [-f]|[-a agno]|[offset length]";
+ trim_cmd.flags = CMD_FLAG_ONESHOT;
+ trim_cmd.oneline = _("Discard filesystem free space");
+ trim_cmd.help = trim_help;
+
+ add_command(&trim_cmd);
+}
+
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 06/10] xfs_spaceman: add FITRIM support
2017-06-02 19:51 ` [PATCH 06/10] xfs_spaceman: add FITRIM support Darrick J. Wong
@ 2017-06-14 15:32 ` Eric Sandeen
2017-06-14 16:32 ` Darrick J. Wong
0 siblings, 1 reply; 29+ messages in thread
From: Eric Sandeen @ 2017-06-14 15:32 UTC (permalink / raw)
To: Darrick J. Wong, sandeen; +Cc: linux-xfs, Dave Chinner
On 6/2/17 2:51 PM, Darrick J. Wong wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> Add support for discarding free space extents via the FITRIM
> command. Make it easy to discard a single range, an entire AG or all
> the freespace in the filesystem.
>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
> spaceman/Makefile | 2 -
> spaceman/init.c | 1
> spaceman/space.h | 1
> spaceman/trim.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 130 insertions(+), 1 deletion(-)
> create mode 100644 spaceman/trim.c
>
>
> diff --git a/spaceman/Makefile b/spaceman/Makefile
> index df59edf..c63a4fc 100644
> --- a/spaceman/Makefile
> +++ b/spaceman/Makefile
> @@ -7,7 +7,7 @@ include $(TOPDIR)/include/builddefs
>
> LTCOMMAND = xfs_spaceman
> HFILES = init.h space.h
> -CFILES = init.c file.c
> +CFILES = init.c file.c trim.c
>
> LLDLIBS = $(LIBXCMD)
> LTDEPENDENCIES = $(LIBXCMD)
> diff --git a/spaceman/init.c b/spaceman/init.c
> index 5dbaef2..0958377 100644
> --- a/spaceman/init.c
> +++ b/spaceman/init.c
> @@ -40,6 +40,7 @@ init_commands(void)
> file_init();
> help_init();
> quit_init();
> + trim_init();
> }
>
> static int
> diff --git a/spaceman/space.h b/spaceman/space.h
> index 6e1bc52..7b4f034 100644
> --- a/spaceman/space.h
> +++ b/spaceman/space.h
> @@ -34,3 +34,4 @@ extern int addfile(char *, int , xfs_fsop_geom_t *, int);
> extern void file_init(void);
> extern void help_init(void);
> extern void quit_init(void);
> +extern void trim_init(void);
> diff --git a/spaceman/trim.c b/spaceman/trim.c
> new file mode 100644
> index 0000000..d58f6d1
> --- /dev/null
> +++ b/spaceman/trim.c
> @@ -0,0 +1,127 @@
> +/*
> + * Copyright (c) 2012 Red Hat, Inc.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation,
> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "libxfs.h"
> +#include <linux/fs.h>
> +#include "command.h"
> +#include "init.h"
> +#include "space.h"
> +#include "input.h"
> +
> +static cmdinfo_t trim_cmd;
> +
> +/*
> + * Trim unused space in xfs filesystem.
> + */
> +static int
> +trim_f(
> + int argc,
> + char **argv)
> +{
> + struct fstrim_range trim = {0};
> + xfs_agnumber_t agno = 0;
> + off64_t offset = 0;
> + ssize_t length = 0;
> + ssize_t minlen = 0;
> + int aflag = 0;
> + int fflag = 0;
> + int ret;
> + int c;
> +
> + while ((c = getopt(argc, argv, "a:fm:")) != EOF) {
> + switch (c) {
> + case 'a':
> + aflag = 1;
> + agno = atoi(optarg);
(do we want to detect errors with strtol?) *shrug*
> + break;
> + case 'f':
> + fflag = 1;
> + break;
> + case 'm':
> + minlen = cvtnum(file->geom.blocksize,
> + file->geom.sectsize, argv[optind]);
s/argtv[optind]/optarg/ (see below)
> + break;
> + default:
> + return command_usage(&trim_cmd);
> + }
> + }
> +
> + if (aflag && fflag)
> + return command_usage(&trim_cmd);
> +
> + if (optind != argc - 2 && !(aflag || fflag))
> + return command_usage(&trim_cmd);
> + if (optind != argc) {
> + offset = cvtnum(file->geom.blocksize, file->geom.sectsize,
> + argv[optind]);
> + length = cvtnum(file->geom.blocksize, file->geom.sectsize,
> + argv[optind + 1]);
> + } else if (agno) {
> + offset = agno * file->geom.agblocks * file->geom.blocksize;
> + length = file->geom.agblocks * file->geom.blocksize;
> + } else {
> + offset = 0;
> + length = file->geom.datablocks * file->geom.blocksize;
> + }
> +
> + trim.start = offset;
> + trim.len = length;
> + trim.minlen = minlen;
> +
> + ret = ioctl(file->fd, FITRIM, (unsigned long)&trim);
> + if (ret < 0) {
> + fprintf(stderr, "%s: ioctl(FITRIM) [\"%s\"]: "
> + "%s\n", progname, file->name, strerror(errno));
> + exitcode = 1;
> + }
> + return 0;
> +}
> +
> +static void
> +trim_help(void)
> +{
> + printf(_(
> +"\n"
> +"Discard filesystem free space\n"
> +"\n"
> +"Options: [-m minlen] [-f]|[-a agno]|[offset length]\n"
Don't restate the Options, that comes out already from
the cmd args:
xfs_spaceman> help trim
trim [-m minlen] [-f]|[-a agno]|[offset length] -- Discard filesystem free space
Discard filesystem free space
Options: [-m minlen] [-f]|[-a agno]|[offset length]
> +"\n"
> +" -m minlen -- skip freespace extents smaller than minlen\n"
> +" -f -- trim all the freespace in the entire filesystem\n"
> +" -a agno -- trim all the freespace in the given AG agno\n"
> +" offset length -- trim the freespace in the range {offset, length}\n"
> +"\n"));
> +
> +}
> +
> +void
> +trim_init(void)
> +{
> + trim_cmd.name = "trim";
> + trim_cmd.altname = "tr";
> + trim_cmd.cfunc = trim_f;
> + trim_cmd.argmin = 1;
> + trim_cmd.argmax = 4;
> + trim_cmd.args = "[-m minlen] [-f]|[-a agno]|[offset length]";
I found myself wondering if any of these were default, and testing shows
that nope, one is of the last 3 or'd options is required. Is the above
the standard way to represent that?
/me checks http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html
Meh, not sure. If it were in a SYNOPSIS it would be 3 separate lines
for each of the 3 modes (-f / -a / offset length)
is:
trim_cmd.args = "-f|-a agno|offset length [-m minlen] ";
any better? Not sure there is a standard way to show mutually exclusive
but required options on a single line.
> + trim_cmd.flags = CMD_FLAG_ONESHOT;
> + trim_cmd.oneline = _("Discard filesystem free space");
> + trim_cmd.help = trim_help;
> +
> + add_command(&trim_cmd);
> +}
> +
A little testing....
xfs_spaceman> trim -m 16k
Segmentation fault
(sadface)
ahah:
case 'm':
minlen = cvtnum(file->geom.blocksize,
- file->geom.sectsize, argv[optind]);
+ file->geom.sectsize, optarg);
Ok, also, am I forgetting how getopt works?
xfs_spaceman> trim -f -m
trim: option requires an argument -- 'm'
trim [-m minlen] [-f]|[-a agno]|[offset length] -- Discard filesystem free space
xfs_spaceman> trim -m -f
trim [-m minlen] [-f]|[-a agno]|[offset length] -- Discard filesystem free space
xfs_spaceman>
getopt is interpreting "-f" as the required argument for "-m?"
I didn't know it did that ....
xfs_spaceman> trim -m -derp -f
xfs_spaceman: ioctl(FITRIM) ["mnt/"]: Invalid argument
hm maybe we do want something better than atoi()...
-Eric
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 06/10] xfs_spaceman: add FITRIM support
2017-06-14 15:32 ` Eric Sandeen
@ 2017-06-14 16:32 ` Darrick J. Wong
0 siblings, 0 replies; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-14 16:32 UTC (permalink / raw)
To: Eric Sandeen; +Cc: sandeen, linux-xfs, Dave Chinner
On Wed, Jun 14, 2017 at 10:32:53AM -0500, Eric Sandeen wrote:
> On 6/2/17 2:51 PM, Darrick J. Wong wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> >
> > Add support for discarding free space extents via the FITRIM
> > command. Make it easy to discard a single range, an entire AG or all
> > the freespace in the filesystem.
> >
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> > spaceman/Makefile | 2 -
> > spaceman/init.c | 1
> > spaceman/space.h | 1
> > spaceman/trim.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> > 4 files changed, 130 insertions(+), 1 deletion(-)
> > create mode 100644 spaceman/trim.c
> >
> >
> > diff --git a/spaceman/Makefile b/spaceman/Makefile
> > index df59edf..c63a4fc 100644
> > --- a/spaceman/Makefile
> > +++ b/spaceman/Makefile
> > @@ -7,7 +7,7 @@ include $(TOPDIR)/include/builddefs
> >
> > LTCOMMAND = xfs_spaceman
> > HFILES = init.h space.h
> > -CFILES = init.c file.c
> > +CFILES = init.c file.c trim.c
> >
> > LLDLIBS = $(LIBXCMD)
> > LTDEPENDENCIES = $(LIBXCMD)
> > diff --git a/spaceman/init.c b/spaceman/init.c
> > index 5dbaef2..0958377 100644
> > --- a/spaceman/init.c
> > +++ b/spaceman/init.c
> > @@ -40,6 +40,7 @@ init_commands(void)
> > file_init();
> > help_init();
> > quit_init();
> > + trim_init();
> > }
> >
> > static int
> > diff --git a/spaceman/space.h b/spaceman/space.h
> > index 6e1bc52..7b4f034 100644
> > --- a/spaceman/space.h
> > +++ b/spaceman/space.h
> > @@ -34,3 +34,4 @@ extern int addfile(char *, int , xfs_fsop_geom_t *, int);
> > extern void file_init(void);
> > extern void help_init(void);
> > extern void quit_init(void);
> > +extern void trim_init(void);
> > diff --git a/spaceman/trim.c b/spaceman/trim.c
> > new file mode 100644
> > index 0000000..d58f6d1
> > --- /dev/null
> > +++ b/spaceman/trim.c
> > @@ -0,0 +1,127 @@
> > +/*
> > + * Copyright (c) 2012 Red Hat, Inc.
> > + * All Rights Reserved.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License as
> > + * published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it would be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write the Free Software Foundation,
> > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> > + */
> > +
> > +#include "libxfs.h"
> > +#include <linux/fs.h>
> > +#include "command.h"
> > +#include "init.h"
> > +#include "space.h"
> > +#include "input.h"
> > +
> > +static cmdinfo_t trim_cmd;
> > +
> > +/*
> > + * Trim unused space in xfs filesystem.
> > + */
> > +static int
> > +trim_f(
> > + int argc,
> > + char **argv)
> > +{
> > + struct fstrim_range trim = {0};
> > + xfs_agnumber_t agno = 0;
> > + off64_t offset = 0;
> > + ssize_t length = 0;
> > + ssize_t minlen = 0;
> > + int aflag = 0;
> > + int fflag = 0;
> > + int ret;
> > + int c;
> > +
> > + while ((c = getopt(argc, argv, "a:fm:")) != EOF) {
> > + switch (c) {
> > + case 'a':
> > + aflag = 1;
> > + agno = atoi(optarg);
>
> (do we want to detect errors with strtol?) *shrug*
strtoul, since it's an AG number.
Some of the xfsprogs code still uses atoi, maybe they ought to be converted?
$ grep atoi.*optarg */*.c -n
db/freesp.c:170: equalsize = atoi(optarg);
db/freesp.c:176: addhistent(atoi(optarg));
db/freesp.c:182: multsize = atoi(optarg);
fsr/xfs_fsr.c:273: howlong = atoi(optarg);
fsr/xfs_fsr.c:282: argv_blksz_dio = atoi(optarg);
fsr/xfs_fsr.c:285: npasses = atoi(optarg);
fsr/xfs_fsr.c:290: nfrags = atoi(optarg);
growfs/xfs_growfs.c:169: maxpct = atoi(optarg);
io/bmap.c:97: nflag = atoi(optarg);
io/fiemap.c:230: max_extents = atoi(optarg);
io/fsmap.c:379: nflag = atoi(optarg);
logprint/logprint.c:197: print_start = atoi(optarg);
quota/project.c:290: recurse_depth = atoi(optarg);
quota/report.c:225: lower = (uint)atoi(optarg);
quota/report.c:228: upper = (uint)atoi(optarg);
quota/report.c:717: lower = (uint)atoi(optarg);
quota/report.c:721: upper = (uint)atoi(optarg);
rtcp/xfs_rtcp.c:49: extsize = atoi(optarg);
Separate patch, though...
>
> > + break;
> > + case 'f':
> > + fflag = 1;
> > + break;
> > + case 'm':
> > + minlen = cvtnum(file->geom.blocksize,
> > + file->geom.sectsize, argv[optind]);
>
> s/argtv[optind]/optarg/ (see below)
Fixed.
>
> > + break;
> > + default:
> > + return command_usage(&trim_cmd);
> > + }
> > + }
> > +
> > + if (aflag && fflag)
> > + return command_usage(&trim_cmd);
> > +
> > + if (optind != argc - 2 && !(aflag || fflag))
> > + return command_usage(&trim_cmd);
> > + if (optind != argc) {
> > + offset = cvtnum(file->geom.blocksize, file->geom.sectsize,
> > + argv[optind]);
> > + length = cvtnum(file->geom.blocksize, file->geom.sectsize,
> > + argv[optind + 1]);
> > + } else if (agno) {
> > + offset = agno * file->geom.agblocks * file->geom.blocksize;
> > + length = file->geom.agblocks * file->geom.blocksize;
> > + } else {
> > + offset = 0;
> > + length = file->geom.datablocks * file->geom.blocksize;
> > + }
> > +
> > + trim.start = offset;
> > + trim.len = length;
> > + trim.minlen = minlen;
> > +
> > + ret = ioctl(file->fd, FITRIM, (unsigned long)&trim);
> > + if (ret < 0) {
> > + fprintf(stderr, "%s: ioctl(FITRIM) [\"%s\"]: "
> > + "%s\n", progname, file->name, strerror(errno));
> > + exitcode = 1;
> > + }
> > + return 0;
> > +}
> > +
> > +static void
> > +trim_help(void)
> > +{
> > + printf(_(
> > +"\n"
> > +"Discard filesystem free space\n"
> > +"\n"
> > +"Options: [-m minlen] [-f]|[-a agno]|[offset length]\n"
>
> Don't restate the Options, that comes out already from
> the cmd args:
>
> xfs_spaceman> help trim
> trim [-m minlen] [-f]|[-a agno]|[offset length] -- Discard filesystem free space
>
> Discard filesystem free space
>
> Options: [-m minlen] [-f]|[-a agno]|[offset length]
Fixed.
> > +"\n"
> > +" -m minlen -- skip freespace extents smaller than minlen\n"
> > +" -f -- trim all the freespace in the entire filesystem\n"
> > +" -a agno -- trim all the freespace in the given AG agno\n"
> > +" offset length -- trim the freespace in the range {offset, length}\n"
> > +"\n"));
> > +
> > +}
> > +
> > +void
> > +trim_init(void)
> > +{
> > + trim_cmd.name = "trim";
> > + trim_cmd.altname = "tr";
> > + trim_cmd.cfunc = trim_f;
> > + trim_cmd.argmin = 1;
> > + trim_cmd.argmax = 4;
> > + trim_cmd.args = "[-m minlen] [-f]|[-a agno]|[offset length]";
>
> I found myself wondering if any of these were default, and testing shows
> that nope, one is of the last 3 or'd options is required. Is the above
> the standard way to represent that?
>
> /me checks http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html
>
> Meh, not sure. If it were in a SYNOPSIS it would be 3 separate lines
> for each of the 3 modes (-f / -a / offset length)
>
> is:
>
> trim_cmd.args = "-f|-a agno|offset length [-m minlen] ";
>
> any better? Not sure there is a standard way to show mutually exclusive
> but required options on a single line.
ISTR seeing (in DOS land) people using:
(-a agno|-f|offset length)
to communicate that exactly one of the options has to be specified.
It's familiar at least to the extent that egrep uses the same syntax
to find any of the three options, and unfamiliar in that we're using
it here to mean XOR whereas egrep uses it for OR.
For now I'll amend the help text to state that exactly one of -a, -f,
or the offset/length pair are required.
> > + trim_cmd.flags = CMD_FLAG_ONESHOT;
> > + trim_cmd.oneline = _("Discard filesystem free space");
> > + trim_cmd.help = trim_help;
> > +
> > + add_command(&trim_cmd);
> > +}
> > +
>
> A little testing....
>
> xfs_spaceman> trim -m 16k
> Segmentation fault
>
> (sadface)
>
> ahah:
> case 'm':
> minlen = cvtnum(file->geom.blocksize,
> - file->geom.sectsize, argv[optind]);
> + file->geom.sectsize, optarg);
Fixed.
> Ok, also, am I forgetting how getopt works?
>
> xfs_spaceman> trim -f -m
> trim: option requires an argument -- 'm'
> trim [-m minlen] [-f]|[-a agno]|[offset length] -- Discard filesystem free space
>
> xfs_spaceman> trim -m -f
> trim [-m minlen] [-f]|[-a agno]|[offset length] -- Discard filesystem free space
> xfs_spaceman>
>
> getopt is interpreting "-f" as the required argument for "-m?"
> I didn't know it did that ....
Yep, it does that. getopt("f:m") means that the next arg after -f is sucked
in as -f's argument even if it matches something else in the getopt string.
For all it knows, -m /is/ a valid input to -f.
> xfs_spaceman> trim -m -derp -f
> xfs_spaceman: ioctl(FITRIM) ["mnt/"]: Invalid argument
>
> hm maybe we do want something better than atoi()...
strtoul, as mentioned above.
--D
>
> -Eric
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 07/10] xfs_spaceman: add new speculative prealloc control
2017-06-02 19:51 [PATCH v8 00/10] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
` (5 preceding siblings ...)
2017-06-02 19:51 ` [PATCH 06/10] xfs_spaceman: add FITRIM support Darrick J. Wong
@ 2017-06-02 19:51 ` Darrick J. Wong
2017-06-14 15:05 ` Eric Sandeen
2017-06-02 19:52 ` [PATCH 08/10] xfs_spaceman: Free space mapping command Darrick J. Wong
` (2 subsequent siblings)
9 siblings, 1 reply; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-02 19:51 UTC (permalink / raw)
To: sandeen, darrick.wong; +Cc: linux-xfs, Dave Chinner
From: Dave Chinner <dchinner@redhat.com>
Add an control interface for purging speculative
preallocation via the new ioctls.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
[darrick: change xfsctl to ioctl]
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
spaceman/Makefile | 2 -
spaceman/init.c | 1
spaceman/prealloc.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++
spaceman/space.h | 1
4 files changed, 114 insertions(+), 1 deletion(-)
create mode 100644 spaceman/prealloc.c
diff --git a/spaceman/Makefile b/spaceman/Makefile
index c63a4fc..6aad746 100644
--- a/spaceman/Makefile
+++ b/spaceman/Makefile
@@ -7,7 +7,7 @@ include $(TOPDIR)/include/builddefs
LTCOMMAND = xfs_spaceman
HFILES = init.h space.h
-CFILES = init.c file.c trim.c
+CFILES = init.c file.c prealloc.c trim.c
LLDLIBS = $(LIBXCMD)
LTDEPENDENCIES = $(LIBXCMD)
diff --git a/spaceman/init.c b/spaceman/init.c
index 0958377..93a8a1e 100644
--- a/spaceman/init.c
+++ b/spaceman/init.c
@@ -39,6 +39,7 @@ init_commands(void)
{
file_init();
help_init();
+ prealloc_init();
quit_init();
trim_init();
}
diff --git a/spaceman/prealloc.c b/spaceman/prealloc.c
new file mode 100644
index 0000000..71c0d80
--- /dev/null
+++ b/spaceman/prealloc.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2012 Red Hat, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libxfs.h"
+#include "command.h"
+#include "input.h"
+#include "init.h"
+#include "space.h"
+
+static cmdinfo_t prealloc_cmd;
+
+/*
+ * Control preallocation amounts.
+ */
+static int
+prealloc_f(
+ int argc,
+ char **argv)
+{
+ struct xfs_fs_eofblocks eofb = {0};
+ int c;
+
+ eofb.eof_version = XFS_EOFBLOCKS_VERSION;
+
+ while ((c = getopt(argc, argv, "g:m:p:su:")) != EOF) {
+ switch (c) {
+ case 'g':
+ eofb.eof_flags |= XFS_EOF_FLAGS_GID;
+ eofb.eof_gid = atoi(optarg);
+ break;
+ case 'u':
+ eofb.eof_flags |= XFS_EOF_FLAGS_UID;
+ eofb.eof_uid = atoi(optarg);
+ break;
+ case 'p':
+ eofb.eof_flags |= XFS_EOF_FLAGS_PRID;
+ eofb.eof_prid = atoi(optarg);
+ break;
+ case 's':
+ eofb.eof_flags |= XFS_EOF_FLAGS_SYNC;
+ break;
+ case 'm':
+ eofb.eof_flags |= XFS_EOF_FLAGS_MINFILESIZE;
+ eofb.eof_min_file_size = cvtnum(file->geom.blocksize,
+ file->geom.sectsize,
+ optarg);
+ break;
+ case '?':
+ default:
+ return command_usage(&prealloc_cmd);
+ }
+ }
+ if (optind != argc)
+ return command_usage(&prealloc_cmd);
+
+ if (ioctl(file->fd, XFS_IOC_FREE_EOFBLOCKS, &eofb) < 0) {
+ fprintf(stderr, _("%s: XFS_IOC_FREE_EOFBLOCKS on %s: %s\n"),
+ progname, file->name, strerror(errno));
+ }
+ return 0;
+}
+
+static void
+prealloc_help(void)
+{
+ printf(_(
+"\n"
+"Control speculative preallocation\n"
+"\n"
+"Options: [-s] [-ugp id] [-m minlen]\n"
+"\n"
+" -s -- wait for removal to complete\n"
+" -u uid -- remove prealloc on files matching user <uid>\n"
+" -g gid -- remove prealloc on files matching group <gid>\n"
+" -p prid -- remove prealloc on files matching project <prid>\n"
+" -m minlen -- only consider files larger than <minlen>\n"
+"\n"));
+
+}
+
+void
+prealloc_init(void)
+{
+ prealloc_cmd.name = "prealloc";
+ prealloc_cmd.altname = "prealloc";
+ prealloc_cmd.cfunc = prealloc_f;
+ prealloc_cmd.argmin = 1;
+ prealloc_cmd.argmax = -1;
+ prealloc_cmd.args = "[-s] [-ugp id] [-m minlen]";
+ prealloc_cmd.flags = CMD_FLAG_ONESHOT;
+ prealloc_cmd.oneline = _("Control speculative preallocation");
+ prealloc_cmd.help = prealloc_help;
+
+ add_command(&prealloc_cmd);
+}
+
diff --git a/spaceman/space.h b/spaceman/space.h
index 7b4f034..0ae3116 100644
--- a/spaceman/space.h
+++ b/spaceman/space.h
@@ -33,5 +33,6 @@ extern int addfile(char *, int , xfs_fsop_geom_t *, int);
extern void file_init(void);
extern void help_init(void);
+extern void prealloc_init(void);
extern void quit_init(void);
extern void trim_init(void);
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 07/10] xfs_spaceman: add new speculative prealloc control
2017-06-02 19:51 ` [PATCH 07/10] xfs_spaceman: add new speculative prealloc control Darrick J. Wong
@ 2017-06-14 15:05 ` Eric Sandeen
2017-06-14 16:39 ` Darrick J. Wong
0 siblings, 1 reply; 29+ messages in thread
From: Eric Sandeen @ 2017-06-14 15:05 UTC (permalink / raw)
To: Darrick J. Wong, sandeen; +Cc: linux-xfs, Dave Chinner
On 6/2/17 2:51 PM, Darrick J. Wong wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> Add an control interface for purging speculative
> preallocation via the new ioctls.
>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> [darrick: change xfsctl to ioctl]
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
> spaceman/Makefile | 2 -
> spaceman/init.c | 1
> spaceman/prealloc.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++
> spaceman/space.h | 1
> 4 files changed, 114 insertions(+), 1 deletion(-)
> create mode 100644 spaceman/prealloc.c
>
>
> diff --git a/spaceman/Makefile b/spaceman/Makefile
> index c63a4fc..6aad746 100644
> --- a/spaceman/Makefile
> +++ b/spaceman/Makefile
> @@ -7,7 +7,7 @@ include $(TOPDIR)/include/builddefs
>
> LTCOMMAND = xfs_spaceman
> HFILES = init.h space.h
> -CFILES = init.c file.c trim.c
> +CFILES = init.c file.c prealloc.c trim.c
>
> LLDLIBS = $(LIBXCMD)
> LTDEPENDENCIES = $(LIBXCMD)
> diff --git a/spaceman/init.c b/spaceman/init.c
> index 0958377..93a8a1e 100644
> --- a/spaceman/init.c
> +++ b/spaceman/init.c
> @@ -39,6 +39,7 @@ init_commands(void)
> {
> file_init();
> help_init();
> + prealloc_init();
> quit_init();
> trim_init();
> }
> diff --git a/spaceman/prealloc.c b/spaceman/prealloc.c
> new file mode 100644
> index 0000000..71c0d80
> --- /dev/null
> +++ b/spaceman/prealloc.c
> @@ -0,0 +1,111 @@
> +/*
> + * Copyright (c) 2012 Red Hat, Inc.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation,
> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "libxfs.h"
> +#include "command.h"
> +#include "input.h"
> +#include "init.h"
> +#include "space.h"
> +
> +static cmdinfo_t prealloc_cmd;
> +
> +/*
> + * Control preallocation amounts.
> + */
> +static int
> +prealloc_f(
> + int argc,
> + char **argv)
> +{
> + struct xfs_fs_eofblocks eofb = {0};
> + int c;
> +
> + eofb.eof_version = XFS_EOFBLOCKS_VERSION;
> +
> + while ((c = getopt(argc, argv, "g:m:p:su:")) != EOF) {
> + switch (c) {
> + case 'g':
> + eofb.eof_flags |= XFS_EOF_FLAGS_GID;
> + eofb.eof_gid = atoi(optarg);
> + break;
> + case 'u':
> + eofb.eof_flags |= XFS_EOF_FLAGS_UID;
> + eofb.eof_uid = atoi(optarg);
> + break;
> + case 'p':
> + eofb.eof_flags |= XFS_EOF_FLAGS_PRID;
> + eofb.eof_prid = atoi(optarg);
> + break;
> + case 's':
> + eofb.eof_flags |= XFS_EOF_FLAGS_SYNC;
> + break;
> + case 'm':
> + eofb.eof_flags |= XFS_EOF_FLAGS_MINFILESIZE;
> + eofb.eof_min_file_size = cvtnum(file->geom.blocksize,
> + file->geom.sectsize,
> + optarg);
> + break;
> + case '?':
> + default:
> + return command_usage(&prealloc_cmd);
> + }
> + }
> + if (optind != argc)
> + return command_usage(&prealloc_cmd);
> +
> + if (ioctl(file->fd, XFS_IOC_FREE_EOFBLOCKS, &eofb) < 0) {
> + fprintf(stderr, _("%s: XFS_IOC_FREE_EOFBLOCKS on %s: %s\n"),
> + progname, file->name, strerror(errno));
> + }
> + return 0;
> +}
> +
> +static void
> +prealloc_help(void)
> +{
> + printf(_(
> +"\n"
> +"Control speculative preallocation\n"
> +"\n"
> +"Options: [-s] [-ugp id] [-m minlen]\n"
No need to restate Options: because that comes out already with help,
from the args in the cmd struct:
xfs_spaceman> help prealloc
prealloc [-s] [-ugp id] [-m minlen] -- Control speculative preallocation
Control speculative preallocation
Options: [-s] [-ugp id] [-m minlen]
> +"\n"
> +" -s -- wait for removal to complete\n"
> +" -u uid -- remove prealloc on files matching user <uid>\n"
> +" -g gid -- remove prealloc on files matching group <gid>\n"
> +" -p prid -- remove prealloc on files matching project <prid>\n"
> +" -m minlen -- only consider files larger than <minlen>\n"
units? (bytes?) Probably should mention that suffixes are accepted,
in the manpage.
> +"\n"));
I guess with no -u, -g, or -p it removes speculative prealloc for all ids?
That'd be good to add to the manpage.
> +
> +}
> +
> +void
> +prealloc_init(void)
> +{
> + prealloc_cmd.name = "prealloc";
> + prealloc_cmd.altname = "prealloc";
> + prealloc_cmd.cfunc = prealloc_f;
> + prealloc_cmd.argmin = 1;
> + prealloc_cmd.argmax = -1;
> + prealloc_cmd.args = "[-s] [-ugp id] [-m minlen]";
This help is a little confusing:
xfs_spaceman> prealloc -ugp 0
prealloc [-s] [-ugp id] [-m minlen] -- Control speculative preallocation
xfs_spaceman> prealloc -u 0 -g 0 -p 0
xfs_spaceman>
should probably be:
prealloc [-s] [-u id] [-g id] [-p id] [-m minlen] -- Control speculative preallocation
> + prealloc_cmd.flags = CMD_FLAG_ONESHOT;
> + prealloc_cmd.oneline = _("Control speculative preallocation");
> + prealloc_cmd.help = prealloc_help;
> +
> + add_command(&prealloc_cmd);
> +}
> +
> diff --git a/spaceman/space.h b/spaceman/space.h
> index 7b4f034..0ae3116 100644
> --- a/spaceman/space.h
> +++ b/spaceman/space.h
> @@ -33,5 +33,6 @@ extern int addfile(char *, int , xfs_fsop_geom_t *, int);
>
> extern void file_init(void);
> extern void help_init(void);
> +extern void prealloc_init(void);
> extern void quit_init(void);
> extern void trim_init(void);
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 07/10] xfs_spaceman: add new speculative prealloc control
2017-06-14 15:05 ` Eric Sandeen
@ 2017-06-14 16:39 ` Darrick J. Wong
0 siblings, 0 replies; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-14 16:39 UTC (permalink / raw)
To: Eric Sandeen; +Cc: sandeen, linux-xfs, Dave Chinner
On Wed, Jun 14, 2017 at 10:05:33AM -0500, Eric Sandeen wrote:
> On 6/2/17 2:51 PM, Darrick J. Wong wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> >
> > Add an control interface for purging speculative
> > preallocation via the new ioctls.
> >
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > [darrick: change xfsctl to ioctl]
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> > spaceman/Makefile | 2 -
> > spaceman/init.c | 1
> > spaceman/prealloc.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++
> > spaceman/space.h | 1
> > 4 files changed, 114 insertions(+), 1 deletion(-)
> > create mode 100644 spaceman/prealloc.c
> >
> >
> > diff --git a/spaceman/Makefile b/spaceman/Makefile
> > index c63a4fc..6aad746 100644
> > --- a/spaceman/Makefile
> > +++ b/spaceman/Makefile
> > @@ -7,7 +7,7 @@ include $(TOPDIR)/include/builddefs
> >
> > LTCOMMAND = xfs_spaceman
> > HFILES = init.h space.h
> > -CFILES = init.c file.c trim.c
> > +CFILES = init.c file.c prealloc.c trim.c
> >
> > LLDLIBS = $(LIBXCMD)
> > LTDEPENDENCIES = $(LIBXCMD)
> > diff --git a/spaceman/init.c b/spaceman/init.c
> > index 0958377..93a8a1e 100644
> > --- a/spaceman/init.c
> > +++ b/spaceman/init.c
> > @@ -39,6 +39,7 @@ init_commands(void)
> > {
> > file_init();
> > help_init();
> > + prealloc_init();
> > quit_init();
> > trim_init();
> > }
> > diff --git a/spaceman/prealloc.c b/spaceman/prealloc.c
> > new file mode 100644
> > index 0000000..71c0d80
> > --- /dev/null
> > +++ b/spaceman/prealloc.c
> > @@ -0,0 +1,111 @@
> > +/*
> > + * Copyright (c) 2012 Red Hat, Inc.
> > + * All Rights Reserved.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License as
> > + * published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it would be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write the Free Software Foundation,
> > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> > + */
> > +
> > +#include "libxfs.h"
> > +#include "command.h"
> > +#include "input.h"
> > +#include "init.h"
> > +#include "space.h"
> > +
> > +static cmdinfo_t prealloc_cmd;
> > +
> > +/*
> > + * Control preallocation amounts.
> > + */
> > +static int
> > +prealloc_f(
> > + int argc,
> > + char **argv)
> > +{
> > + struct xfs_fs_eofblocks eofb = {0};
> > + int c;
> > +
> > + eofb.eof_version = XFS_EOFBLOCKS_VERSION;
> > +
> > + while ((c = getopt(argc, argv, "g:m:p:su:")) != EOF) {
> > + switch (c) {
> > + case 'g':
> > + eofb.eof_flags |= XFS_EOF_FLAGS_GID;
> > + eofb.eof_gid = atoi(optarg);
> > + break;
> > + case 'u':
> > + eofb.eof_flags |= XFS_EOF_FLAGS_UID;
> > + eofb.eof_uid = atoi(optarg);
> > + break;
> > + case 'p':
> > + eofb.eof_flags |= XFS_EOF_FLAGS_PRID;
> > + eofb.eof_prid = atoi(optarg);
> > + break;
> > + case 's':
> > + eofb.eof_flags |= XFS_EOF_FLAGS_SYNC;
> > + break;
> > + case 'm':
> > + eofb.eof_flags |= XFS_EOF_FLAGS_MINFILESIZE;
> > + eofb.eof_min_file_size = cvtnum(file->geom.blocksize,
> > + file->geom.sectsize,
> > + optarg);
> > + break;
> > + case '?':
> > + default:
> > + return command_usage(&prealloc_cmd);
> > + }
> > + }
> > + if (optind != argc)
> > + return command_usage(&prealloc_cmd);
> > +
> > + if (ioctl(file->fd, XFS_IOC_FREE_EOFBLOCKS, &eofb) < 0) {
> > + fprintf(stderr, _("%s: XFS_IOC_FREE_EOFBLOCKS on %s: %s\n"),
> > + progname, file->name, strerror(errno));
> > + }
> > + return 0;
> > +}
> > +
> > +static void
> > +prealloc_help(void)
> > +{
> > + printf(_(
> > +"\n"
> > +"Control speculative preallocation\n"
> > +"\n"
> > +"Options: [-s] [-ugp id] [-m minlen]\n"
>
> No need to restate Options: because that comes out already with help,
> from the args in the cmd struct:
>
> xfs_spaceman> help prealloc
> prealloc [-s] [-ugp id] [-m minlen] -- Control speculative preallocation
>
> Control speculative preallocation
>
> Options: [-s] [-ugp id] [-m minlen]
>
>
> > +"\n"
> > +" -s -- wait for removal to complete\n"
> > +" -u uid -- remove prealloc on files matching user <uid>\n"
> > +" -g gid -- remove prealloc on files matching group <gid>\n"
> > +" -p prid -- remove prealloc on files matching project <prid>\n"
> > +" -m minlen -- only consider files larger than <minlen>\n"
>
> units? (bytes?) Probably should mention that suffixes are accepted,
> in the manpage.
>
> > +"\n"));
>
> I guess with no -u, -g, or -p it removes speculative prealloc for all ids?
> That'd be good to add to the manpage.
Will do.
> > +
> > +}
> > +
> > +void
> > +prealloc_init(void)
> > +{
> > + prealloc_cmd.name = "prealloc";
> > + prealloc_cmd.altname = "prealloc";
> > + prealloc_cmd.cfunc = prealloc_f;
> > + prealloc_cmd.argmin = 1;
> > + prealloc_cmd.argmax = -1;
> > + prealloc_cmd.args = "[-s] [-ugp id] [-m minlen]";
>
> This help is a little confusing:
>
> xfs_spaceman> prealloc -ugp 0
> prealloc [-s] [-ugp id] [-m minlen] -- Control speculative preallocation
>
> xfs_spaceman> prealloc -u 0 -g 0 -p 0
> xfs_spaceman>
>
> should probably be:
>
> prealloc [-s] [-u id] [-g id] [-p id] [-m minlen] -- Control speculative preallocation
Fixed.
--D
> > + prealloc_cmd.flags = CMD_FLAG_ONESHOT;
> > + prealloc_cmd.oneline = _("Control speculative preallocation");
> > + prealloc_cmd.help = prealloc_help;
> > +
> > + add_command(&prealloc_cmd);
> > +}
> > +
> > diff --git a/spaceman/space.h b/spaceman/space.h
> > index 7b4f034..0ae3116 100644
> > --- a/spaceman/space.h
> > +++ b/spaceman/space.h
> > @@ -33,5 +33,6 @@ extern int addfile(char *, int , xfs_fsop_geom_t *, int);
> >
> > extern void file_init(void);
> > extern void help_init(void);
> > +extern void prealloc_init(void);
> > extern void quit_init(void);
> > extern void trim_init(void);
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 08/10] xfs_spaceman: Free space mapping command
2017-06-02 19:51 [PATCH v8 00/10] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
` (6 preceding siblings ...)
2017-06-02 19:51 ` [PATCH 07/10] xfs_spaceman: add new speculative prealloc control Darrick J. Wong
@ 2017-06-02 19:52 ` Darrick J. Wong
2017-06-14 15:43 ` Eric Sandeen
2017-06-14 16:04 ` Eric Sandeen
2017-06-02 19:52 ` [PATCH 09/10] xfs_spaceman: add a man page Darrick J. Wong
2017-06-02 19:52 ` [PATCH 10/10] xfs_spaceman: add group summary mode Darrick J. Wong
9 siblings, 2 replies; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-02 19:52 UTC (permalink / raw)
To: sandeen, darrick.wong; +Cc: linux-xfs, Dave Chinner
From: Dave Chinner <dchinner@redhat.com>
Add freespace mapping tool modelled on the xfs_db freesp command.
The advantage of this command over xfs_db is that it can be done
online and is coherent with concurrent modifications to the
filesystem.
This requires the kernel to support the XFS_IOC_GETFSMAP ioctl to map
free space indexes.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
[darrick: port from FIEMAPFS to GETFSMAP]
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
spaceman/Makefile | 7 +
spaceman/file.c | 19 ++-
spaceman/freesp.c | 367 +++++++++++++++++++++++++++++++++++++++++++++++++++
spaceman/init.c | 8 +
spaceman/prealloc.c | 1
spaceman/space.h | 12 +-
spaceman/trim.c | 1
7 files changed, 409 insertions(+), 6 deletions(-)
create mode 100644 spaceman/freesp.c
diff --git a/spaceman/Makefile b/spaceman/Makefile
index 6aad746..95ec3c0 100644
--- a/spaceman/Makefile
+++ b/spaceman/Makefile
@@ -21,6 +21,13 @@ ifeq ($(ENABLE_EDITLINE),yes)
LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP)
endif
+# On linux we get fsmap from the system or define it ourselves
+# so include this based on platform type. If this reverts to only
+# the autoconf check w/o local definition, change to testing HAVE_GETFSMAP
+ifeq ($(PKG_PLATFORM),linux)
+CFILES += freesp.c
+endif
+
default: depend $(LTCOMMAND)
include $(BUILDRULES)
diff --git a/spaceman/file.c b/spaceman/file.c
index 9356066..46b8826 100644
--- a/spaceman/file.c
+++ b/spaceman/file.c
@@ -22,6 +22,7 @@
#include "command.h"
#include "input.h"
#include "init.h"
+#include "path.h"
#include "space.h"
static cmdinfo_t print_cmd;
@@ -69,8 +70,10 @@ openfile(
char *path,
xfs_fsop_geom_t *geom,
int flags,
- mode_t mode)
+ mode_t mode,
+ struct fs_path *fs_path)
{
+ struct fs_path *fsp;
int fd;
fd = open(path, flags, mode);
@@ -95,6 +98,16 @@ openfile(
close(fd);
return -1;
}
+
+ if (fs_path) {
+ fsp = fs_table_lookup(path, FS_MOUNT_POINT);
+ if (!fsp) {
+ fprintf(stderr, _("%s: cannot find mount point."),
+ path);
+ return -1;
+ }
+ memcpy(fs_path, fsp, sizeof(struct fs_path));
+ }
return fd;
}
@@ -103,7 +116,8 @@ addfile(
char *name,
int fd,
xfs_fsop_geom_t *geometry,
- int flags)
+ int flags,
+ struct fs_path *fs_path)
{
char *filename;
@@ -131,6 +145,7 @@ addfile(
file->flags = flags;
file->name = filename;
file->geom = *geometry;
+ memcpy(&file->fs_path, fs_path, sizeof(file->fs_path));
return 0;
}
diff --git a/spaceman/freesp.c b/spaceman/freesp.c
new file mode 100644
index 0000000..2290a5e
--- /dev/null
+++ b/spaceman/freesp.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
+ * Copyright (c) 2012 Red Hat, Inc.
+ * Copyright (c) 2017 Oracle.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libxfs.h"
+#include <linux/fiemap.h>
+#include "command.h"
+#include "init.h"
+#include "path.h"
+#include "space.h"
+
+typedef struct histent
+{
+ int low;
+ int high;
+ long long count;
+ long long blocks;
+} histent_t;
+
+static int agcount;
+static xfs_agnumber_t *aglist;
+static int dumpflag;
+static int equalsize;
+static histent_t *hist;
+static int histcount;
+static int multsize;
+static int seen1;
+static int summaryflag;
+static bool rtflag;
+static long long totblocks;
+static long long totexts;
+
+static cmdinfo_t freesp_cmd;
+
+static void
+addhistent(
+ int h)
+{
+ hist = realloc(hist, (histcount + 1) * sizeof(*hist));
+ if (h == 0)
+ h = 1;
+ hist[histcount].low = h;
+ hist[histcount].count = hist[histcount].blocks = 0;
+ histcount++;
+ if (h == 1)
+ seen1 = 1;
+}
+
+static void
+addtohist(
+ xfs_agnumber_t agno,
+ xfs_agblock_t agbno,
+ off64_t len)
+{
+ int i;
+
+ if (dumpflag)
+ printf("%8d %8d %8"PRId64"\n", agno, agbno, len);
+ totexts++;
+ totblocks += len;
+ for (i = 0; i < histcount; i++) {
+ if (hist[i].high >= len) {
+ hist[i].count++;
+ hist[i].blocks += len;
+ break;
+ }
+ }
+}
+
+static int
+hcmp(
+ const void *a,
+ const void *b)
+{
+ return ((histent_t *)a)->low - ((histent_t *)b)->low;
+}
+
+static void
+histinit(
+ int maxlen)
+{
+ int i;
+
+ if (equalsize) {
+ for (i = 1; i < maxlen; i += equalsize)
+ addhistent(i);
+ } else if (multsize) {
+ for (i = 1; i < maxlen; i *= multsize)
+ addhistent(i);
+ } else {
+ if (!seen1)
+ addhistent(1);
+ qsort(hist, histcount, sizeof(*hist), hcmp);
+ }
+ for (i = 0; i < histcount; i++) {
+ if (i < histcount - 1)
+ hist[i].high = hist[i + 1].low - 1;
+ else
+ hist[i].high = maxlen;
+ }
+}
+
+static void
+printhist(void)
+{
+ int i;
+
+ printf("%7s %7s %7s %7s %6s\n",
+ _("from"), _("to"), _("extents"), _("blocks"), _("pct"));
+ for (i = 0; i < histcount; i++) {
+ if (hist[i].count)
+ printf("%7d %7d %7lld %7lld %6.2f\n", hist[i].low,
+ hist[i].high, hist[i].count, hist[i].blocks,
+ hist[i].blocks * 100.0 / totblocks);
+ }
+}
+
+static int
+inaglist(
+ xfs_agnumber_t agno)
+{
+ int i;
+
+ if (agcount == 0)
+ return 1;
+ for (i = 0; i < agcount; i++)
+ if (aglist[i] == agno)
+ return 1;
+ return 0;
+}
+
+#define NR_EXTENTS 128
+
+static void
+scan_ag(
+ xfs_agnumber_t agno)
+{
+ struct fsmap_head *fsmap;
+ struct fsmap *extent;
+ struct fsmap *l, *h;
+ struct fsmap *p;
+ off64_t blocksize = file->geom.blocksize;
+ off64_t bperag;
+ off64_t aglen;
+ xfs_agblock_t agbno;
+ int ret;
+ int i;
+
+ bperag = (off64_t)file->geom.agblocks * blocksize;
+
+ fsmap = malloc(fsmap_sizeof(NR_EXTENTS));
+ if (!fsmap) {
+ fprintf(stderr, _("%s: fsmap malloc failed.\n"), progname);
+ exitcode = 1;
+ return;
+ }
+
+ memset(fsmap, 0, sizeof(*fsmap));
+ fsmap->fmh_count = NR_EXTENTS;
+ l = fsmap->fmh_keys;
+ h = fsmap->fmh_keys + 1;
+ if (agno != NULLAGNUMBER) {
+ l->fmr_physical = agno * bperag;
+ h->fmr_physical = ((agno + 1) * bperag) - 1;
+ l->fmr_device = h->fmr_device = file->fs_path.fs_datadev;
+ } else {
+ l->fmr_physical = 0;
+ h->fmr_physical = ULLONG_MAX;
+ l->fmr_device = h->fmr_device = file->fs_path.fs_rtdev;
+ }
+ h->fmr_owner = ULLONG_MAX;
+ h->fmr_flags = UINT_MAX;
+ h->fmr_offset = ULLONG_MAX;
+
+ while (true) {
+ ret = ioctl(file->fd, FS_IOC_GETFSMAP, fsmap);
+ if (ret < 0) {
+ fprintf(stderr, _("%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n"),
+ progname, file->name, strerror(errno));
+ free(fsmap);
+ exitcode = 1;
+ return;
+ }
+
+ /* No more extents to map, exit */
+ if (!fsmap->fmh_entries)
+ break;
+
+ for (i = 0, extent = fsmap->fmh_recs;
+ i < fsmap->fmh_entries;
+ i++, extent++) {
+ if (!(extent->fmr_flags & FMR_OF_SPECIAL_OWNER) ||
+ extent->fmr_owner != XFS_FMR_OWN_FREE)
+ continue;
+ agbno = (extent->fmr_physical - (bperag * agno)) /
+ blocksize;
+ aglen = extent->fmr_length / blocksize;
+
+ addtohist(agno, agbno, aglen);
+ }
+
+ p = &fsmap->fmh_recs[fsmap->fmh_entries - 1];
+ if (p->fmr_flags & FMR_OF_LAST)
+ break;
+ fsmap_advance(fsmap);
+ }
+}
+static void
+aglistadd(
+ char *a)
+{
+ aglist = realloc(aglist, (agcount + 1) * sizeof(*aglist));
+ aglist[agcount] = (xfs_agnumber_t)atoi(a);
+ agcount++;
+}
+
+static int
+init(
+ int argc,
+ char **argv)
+{
+ int c;
+ int speced = 0;
+
+ agcount = dumpflag = equalsize = multsize = optind = 0;
+ histcount = seen1 = summaryflag = 0;
+ totblocks = totexts = 0;
+ aglist = NULL;
+ hist = NULL;
+ rtflag = false;
+ while ((c = getopt(argc, argv, "a:bde:h:m:rs")) != EOF) {
+ switch (c) {
+ case 'a':
+ aglistadd(optarg);
+ break;
+ case 'b':
+ if (speced)
+ return 0;
+ multsize = 2;
+ speced = 1;
+ break;
+ case 'd':
+ dumpflag = 1;
+ break;
+ case 'e':
+ if (speced)
+ return 0;
+ equalsize = atoi(optarg);
+ speced = 1;
+ break;
+ case 'h':
+ if (speced && !histcount)
+ return 0;
+ addhistent(atoi(optarg));
+ speced = 1;
+ break;
+ case 'm':
+ if (speced)
+ return 0;
+ multsize = atoi(optarg);
+ speced = 1;
+ break;
+ case 'r':
+ rtflag = true;
+ break;
+ case 's':
+ summaryflag = 1;
+ break;
+ case '?':
+ return 0;
+ }
+ }
+ if (optind != argc)
+ return 0;
+ if (!speced)
+ multsize = 2;
+ histinit(file->geom.agblocks);
+ return 1;
+}
+
+/*
+ * Report on freespace usage in xfs filesystem.
+ */
+static int
+freesp_f(
+ int argc,
+ char **argv)
+{
+ xfs_agnumber_t agno;
+
+ if (!init(argc, argv))
+ return 0;
+ if (rtflag)
+ scan_ag(NULLAGNUMBER);
+ for (agno = 0; !rtflag && agno < file->geom.agcount; agno++) {
+ if (inaglist(agno))
+ scan_ag(agno);
+ }
+ if (histcount)
+ printhist();
+ if (summaryflag) {
+ printf(_("total free extents %lld\n"), totexts);
+ printf(_("total free blocks %lld\n"), totblocks);
+ printf(_("average free extent size %g\n"),
+ (double)totblocks / (double)totexts);
+ }
+ if (aglist)
+ free(aglist);
+ if (hist)
+ free(hist);
+ return 0;
+}
+
+static void
+freesp_help(void)
+{
+ printf(_(
+"\n"
+"Examine filesystem free space\n"
+"\n"
+"Options: [-bdsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n"
+"\n"
+" -a agno -- Scan only the given AG agno.\n"
+" -b -- binary histogram bin size\n"
+" -d -- debug output\n"
+" -e bsize -- Use fixed histogram bin size of bsize\n"
+" -h hbsz -- Use custom histogram bin size of h1.\n"
+" Multiple specifications are allowed.\n"
+" -m bmult -- Use histogram bin size multiplier of bmult.\n"
+" -r -- Display realtime device free space information.\n"
+" -s -- Emit freespace summary information.\n"
+"\n"));
+
+}
+
+void
+freesp_init(void)
+{
+ freesp_cmd.name = "freesp";
+ freesp_cmd.altname = "fsp";
+ freesp_cmd.cfunc = freesp_f;
+ freesp_cmd.argmin = 0;
+ freesp_cmd.argmax = -1;
+ freesp_cmd.args = "[-bdsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]";
+ freesp_cmd.flags = CMD_FLAG_ONESHOT;
+ freesp_cmd.oneline = _("Examine filesystem free space");
+ freesp_cmd.help = freesp_help;
+
+ add_command(&freesp_cmd);
+}
+
diff --git a/spaceman/init.c b/spaceman/init.c
index 93a8a1e..f3c93c3 100644
--- a/spaceman/init.c
+++ b/spaceman/init.c
@@ -20,6 +20,7 @@
#include "command.h"
#include "input.h"
#include "init.h"
+#include "path.h"
#include "space.h"
char *progname;
@@ -38,6 +39,7 @@ static void
init_commands(void)
{
file_init();
+ freesp_init();
help_init();
prealloc_init();
quit_init();
@@ -71,12 +73,14 @@ init(
int c, flags = 0;
mode_t mode = 0600;
xfs_fsop_geom_t geometry = { 0 };
+ struct fs_path fsp;
progname = basename(argv[0]);
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
+ fs_table_initialise(0, NULL, 0, NULL);
while ((c = getopt(argc, argv, "c:V")) != EOF) {
switch (c) {
case 'c':
@@ -93,11 +97,11 @@ init(
if (optind != argc - 1)
usage();
- if ((c = openfile(argv[optind], &geometry, flags, mode)) < 0)
+ if ((c = openfile(argv[optind], &geometry, flags, mode, &fsp)) < 0)
exit(1);
if (!platform_test_xfs_fd(c))
printf(_("Not an XFS filesystem!\n"));
- if (addfile(argv[optind], c, &geometry, flags) < 0)
+ if (addfile(argv[optind], c, &geometry, flags, &fsp) < 0)
exit(1);
init_commands();
diff --git a/spaceman/prealloc.c b/spaceman/prealloc.c
index 71c0d80..55b85ed 100644
--- a/spaceman/prealloc.c
+++ b/spaceman/prealloc.c
@@ -20,6 +20,7 @@
#include "command.h"
#include "input.h"
#include "init.h"
+#include "path.h"
#include "space.h"
static cmdinfo_t prealloc_cmd;
diff --git a/spaceman/space.h b/spaceman/space.h
index 0ae3116..bf9a2df 100644
--- a/spaceman/space.h
+++ b/spaceman/space.h
@@ -21,6 +21,7 @@ typedef struct fileio {
int flags; /* flags describing file state */
char *name; /* file name at time of open */
xfs_fsop_geom_t geom; /* XFS filesystem geometry */
+ struct fs_path fs_path; /* XFS path information */
} fileio_t;
extern fileio_t *filetable; /* open file table */
@@ -28,11 +29,18 @@ extern int filecount; /* number of open files */
extern fileio_t *file; /* active file in file table */
extern int filelist_f(void);
-extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t);
-extern int addfile(char *, int , xfs_fsop_geom_t *, int);
+extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t,
+ struct fs_path *);
+extern int addfile(char *, int , xfs_fsop_geom_t *, int, struct fs_path *);
extern void file_init(void);
extern void help_init(void);
extern void prealloc_init(void);
extern void quit_init(void);
extern void trim_init(void);
+
+#ifdef HAVE_GETFSMAP
+extern void freesp_init(void);
+#else
+# define freesp_init() do { } while (0)
+#endif
diff --git a/spaceman/trim.c b/spaceman/trim.c
index d58f6d1..b5908cc 100644
--- a/spaceman/trim.c
+++ b/spaceman/trim.c
@@ -20,6 +20,7 @@
#include <linux/fs.h>
#include "command.h"
#include "init.h"
+#include "path.h"
#include "space.h"
#include "input.h"
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 08/10] xfs_spaceman: Free space mapping command
2017-06-02 19:52 ` [PATCH 08/10] xfs_spaceman: Free space mapping command Darrick J. Wong
@ 2017-06-14 15:43 ` Eric Sandeen
2017-06-14 16:43 ` Darrick J. Wong
2017-06-14 16:04 ` Eric Sandeen
1 sibling, 1 reply; 29+ messages in thread
From: Eric Sandeen @ 2017-06-14 15:43 UTC (permalink / raw)
To: Darrick J. Wong, sandeen; +Cc: linux-xfs, Dave Chinner
On 6/2/17 2:52 PM, Darrick J. Wong wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> Add freespace mapping tool modelled on the xfs_db freesp command.
> The advantage of this command over xfs_db is that it can be done
> online and is coherent with concurrent modifications to the
> filesystem.
>
> This requires the kernel to support the XFS_IOC_GETFSMAP ioctl to map
> free space indexes.
>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> [darrick: port from FIEMAPFS to GETFSMAP]
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
> spaceman/Makefile | 7 +
> spaceman/file.c | 19 ++-
> spaceman/freesp.c | 367 +++++++++++++++++++++++++++++++++++++++++++++++++++
> spaceman/init.c | 8 +
> spaceman/prealloc.c | 1
> spaceman/space.h | 12 +-
> spaceman/trim.c | 1
> 7 files changed, 409 insertions(+), 6 deletions(-)
> create mode 100644 spaceman/freesp.c
>
>
> diff --git a/spaceman/Makefile b/spaceman/Makefile
> index 6aad746..95ec3c0 100644
> --- a/spaceman/Makefile
> +++ b/spaceman/Makefile
> @@ -21,6 +21,13 @@ ifeq ($(ENABLE_EDITLINE),yes)
> LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP)
> endif
>
> +# On linux we get fsmap from the system or define it ourselves
> +# so include this based on platform type. If this reverts to only
> +# the autoconf check w/o local definition, change to testing HAVE_GETFSMAP
> +ifeq ($(PKG_PLATFORM),linux)
> +CFILES += freesp.c
> +endif
> +
> default: depend $(LTCOMMAND)
>
> include $(BUILDRULES)
> diff --git a/spaceman/file.c b/spaceman/file.c
> index 9356066..46b8826 100644
> --- a/spaceman/file.c
> +++ b/spaceman/file.c
> @@ -22,6 +22,7 @@
> #include "command.h"
> #include "input.h"
> #include "init.h"
> +#include "path.h"
> #include "space.h"
>
> static cmdinfo_t print_cmd;
> @@ -69,8 +70,10 @@ openfile(
> char *path,
> xfs_fsop_geom_t *geom,
> int flags,
> - mode_t mode)
> + mode_t mode,
> + struct fs_path *fs_path)
> {
> + struct fs_path *fsp;
> int fd;
>
> fd = open(path, flags, mode);
> @@ -95,6 +98,16 @@ openfile(
> close(fd);
> return -1;
> }
> +
> + if (fs_path) {
> + fsp = fs_table_lookup(path, FS_MOUNT_POINT);
> + if (!fsp) {
> + fprintf(stderr, _("%s: cannot find mount point."),
> + path);
> + return -1;
> + }
> + memcpy(fs_path, fsp, sizeof(struct fs_path));
> + }
> return fd;
> }
>
> @@ -103,7 +116,8 @@ addfile(
> char *name,
> int fd,
> xfs_fsop_geom_t *geometry,
> - int flags)
> + int flags,
> + struct fs_path *fs_path)
> {
> char *filename;
>
> @@ -131,6 +145,7 @@ addfile(
> file->flags = flags;
> file->name = filename;
> file->geom = *geometry;
> + memcpy(&file->fs_path, fs_path, sizeof(file->fs_path));
> return 0;
> }
>
> diff --git a/spaceman/freesp.c b/spaceman/freesp.c
> new file mode 100644
> index 0000000..2290a5e
> --- /dev/null
> +++ b/spaceman/freesp.c
> @@ -0,0 +1,367 @@
> +/*
> + * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
> + * Copyright (c) 2012 Red Hat, Inc.
> + * Copyright (c) 2017 Oracle.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation,
> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "libxfs.h"
> +#include <linux/fiemap.h>
> +#include "command.h"
> +#include "init.h"
> +#include "path.h"
> +#include "space.h"
> +
> +typedef struct histent
> +{
> + int low;
> + int high;
> + long long count;
> + long long blocks;
> +} histent_t;
> +
> +static int agcount;
> +static xfs_agnumber_t *aglist;
> +static int dumpflag;
> +static int equalsize;
> +static histent_t *hist;
> +static int histcount;
> +static int multsize;
> +static int seen1;
> +static int summaryflag;
> +static bool rtflag;
> +static long long totblocks;
> +static long long totexts;
> +
> +static cmdinfo_t freesp_cmd;
> +
> +static void
> +addhistent(
> + int h)
> +{
> + hist = realloc(hist, (histcount + 1) * sizeof(*hist));
> + if (h == 0)
> + h = 1;
> + hist[histcount].low = h;
> + hist[histcount].count = hist[histcount].blocks = 0;
> + histcount++;
> + if (h == 1)
> + seen1 = 1;
> +}
> +
> +static void
> +addtohist(
> + xfs_agnumber_t agno,
> + xfs_agblock_t agbno,
> + off64_t len)
> +{
> + int i;
> +
> + if (dumpflag)
> + printf("%8d %8d %8"PRId64"\n", agno, agbno, len);
> + totexts++;
> + totblocks += len;
> + for (i = 0; i < histcount; i++) {
> + if (hist[i].high >= len) {
> + hist[i].count++;
> + hist[i].blocks += len;
> + break;
> + }
> + }
> +}
> +
> +static int
> +hcmp(
> + const void *a,
> + const void *b)
> +{
> + return ((histent_t *)a)->low - ((histent_t *)b)->low;
> +}
> +
> +static void
> +histinit(
> + int maxlen)
> +{
> + int i;
> +
> + if (equalsize) {
> + for (i = 1; i < maxlen; i += equalsize)
> + addhistent(i);
> + } else if (multsize) {
> + for (i = 1; i < maxlen; i *= multsize)
> + addhistent(i);
> + } else {
> + if (!seen1)
> + addhistent(1);
> + qsort(hist, histcount, sizeof(*hist), hcmp);
> + }
> + for (i = 0; i < histcount; i++) {
> + if (i < histcount - 1)
> + hist[i].high = hist[i + 1].low - 1;
> + else
> + hist[i].high = maxlen;
> + }
> +}
> +
> +static void
> +printhist(void)
> +{
> + int i;
> +
> + printf("%7s %7s %7s %7s %6s\n",
> + _("from"), _("to"), _("extents"), _("blocks"), _("pct"));
> + for (i = 0; i < histcount; i++) {
> + if (hist[i].count)
> + printf("%7d %7d %7lld %7lld %6.2f\n", hist[i].low,
> + hist[i].high, hist[i].count, hist[i].blocks,
> + hist[i].blocks * 100.0 / totblocks);
> + }
> +}
> +
> +static int
> +inaglist(
> + xfs_agnumber_t agno)
> +{
> + int i;
> +
> + if (agcount == 0)
> + return 1;
> + for (i = 0; i < agcount; i++)
> + if (aglist[i] == agno)
> + return 1;
> + return 0;
> +}
> +
> +#define NR_EXTENTS 128
> +
> +static void
> +scan_ag(
> + xfs_agnumber_t agno)
> +{
> + struct fsmap_head *fsmap;
> + struct fsmap *extent;
> + struct fsmap *l, *h;
> + struct fsmap *p;
> + off64_t blocksize = file->geom.blocksize;
> + off64_t bperag;
> + off64_t aglen;
> + xfs_agblock_t agbno;
> + int ret;
> + int i;
> +
> + bperag = (off64_t)file->geom.agblocks * blocksize;
> +
> + fsmap = malloc(fsmap_sizeof(NR_EXTENTS));
> + if (!fsmap) {
> + fprintf(stderr, _("%s: fsmap malloc failed.\n"), progname);
> + exitcode = 1;
> + return;
> + }
> +
> + memset(fsmap, 0, sizeof(*fsmap));
> + fsmap->fmh_count = NR_EXTENTS;
> + l = fsmap->fmh_keys;
> + h = fsmap->fmh_keys + 1;
> + if (agno != NULLAGNUMBER) {
> + l->fmr_physical = agno * bperag;
> + h->fmr_physical = ((agno + 1) * bperag) - 1;
> + l->fmr_device = h->fmr_device = file->fs_path.fs_datadev;
> + } else {
> + l->fmr_physical = 0;
> + h->fmr_physical = ULLONG_MAX;
> + l->fmr_device = h->fmr_device = file->fs_path.fs_rtdev;
> + }
> + h->fmr_owner = ULLONG_MAX;
> + h->fmr_flags = UINT_MAX;
> + h->fmr_offset = ULLONG_MAX;
> +
> + while (true) {
> + ret = ioctl(file->fd, FS_IOC_GETFSMAP, fsmap);
> + if (ret < 0) {
> + fprintf(stderr, _("%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n"),
> + progname, file->name, strerror(errno));
> + free(fsmap);
> + exitcode = 1;
> + return;
> + }
> +
> + /* No more extents to map, exit */
> + if (!fsmap->fmh_entries)
> + break;
> +
> + for (i = 0, extent = fsmap->fmh_recs;
> + i < fsmap->fmh_entries;
> + i++, extent++) {
> + if (!(extent->fmr_flags & FMR_OF_SPECIAL_OWNER) ||
> + extent->fmr_owner != XFS_FMR_OWN_FREE)
> + continue;
> + agbno = (extent->fmr_physical - (bperag * agno)) /
> + blocksize;
> + aglen = extent->fmr_length / blocksize;
> +
> + addtohist(agno, agbno, aglen);
> + }
> +
> + p = &fsmap->fmh_recs[fsmap->fmh_entries - 1];
> + if (p->fmr_flags & FMR_OF_LAST)
> + break;
> + fsmap_advance(fsmap);
> + }
> +}
> +static void
> +aglistadd(
> + char *a)
> +{
> + aglist = realloc(aglist, (agcount + 1) * sizeof(*aglist));
> + aglist[agcount] = (xfs_agnumber_t)atoi(a);
> + agcount++;
> +}
> +
> +static int
> +init(
> + int argc,
> + char **argv)
> +{
> + int c;
> + int speced = 0;
> +
> + agcount = dumpflag = equalsize = multsize = optind = 0;
> + histcount = seen1 = summaryflag = 0;
> + totblocks = totexts = 0;
> + aglist = NULL;
> + hist = NULL;
> + rtflag = false;
> + while ((c = getopt(argc, argv, "a:bde:h:m:rs")) != EOF) {
> + switch (c) {
> + case 'a':
> + aglistadd(optarg);
> + break;
> + case 'b':
> + if (speced)
> + return 0;
> + multsize = 2;
> + speced = 1;
> + break;
> + case 'd':
> + dumpflag = 1;
> + break;
> + case 'e':
> + if (speced)
> + return 0;
> + equalsize = atoi(optarg);
> + speced = 1;
> + break;
> + case 'h':
> + if (speced && !histcount)
> + return 0;
> + addhistent(atoi(optarg));
> + speced = 1;
> + break;
> + case 'm':
> + if (speced)
> + return 0;
> + multsize = atoi(optarg);
> + speced = 1;
> + break;
> + case 'r':
> + rtflag = true;
> + break;
> + case 's':
> + summaryflag = 1;
> + break;
> + case '?':
> + return 0;
> + }
> + }
> + if (optind != argc)
> + return 0;
> + if (!speced)
> + multsize = 2;
> + histinit(file->geom.agblocks);
> + return 1;
> +}
> +
> +/*
> + * Report on freespace usage in xfs filesystem.
> + */
> +static int
> +freesp_f(
> + int argc,
> + char **argv)
> +{
> + xfs_agnumber_t agno;
> +
> + if (!init(argc, argv))
> + return 0;
> + if (rtflag)
> + scan_ag(NULLAGNUMBER);
> + for (agno = 0; !rtflag && agno < file->geom.agcount; agno++) {
> + if (inaglist(agno))
> + scan_ag(agno);
> + }
> + if (histcount)
> + printhist();
> + if (summaryflag) {
> + printf(_("total free extents %lld\n"), totexts);
> + printf(_("total free blocks %lld\n"), totblocks);
> + printf(_("average free extent size %g\n"),
> + (double)totblocks / (double)totexts);
> + }
> + if (aglist)
> + free(aglist);
> + if (hist)
> + free(hist);
> + return 0;
> +}
> +
> +static void
> +freesp_help(void)
> +{
> + printf(_(
> +"\n"
> +"Examine filesystem free space\n"
> +"\n"
> +"Options: [-bdsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n"
don't restate options ...
> +"\n"
> +" -a agno -- Scan only the given AG agno.\n"
> +" -b -- binary histogram bin size\n"
> +" -d -- debug output\n"
> +" -e bsize -- Use fixed histogram bin size of bsize\n"
> +" -h hbsz -- Use custom histogram bin size of h1.\n"
> +" Multiple specifications are allowed.\n"
> +" -m bmult -- Use histogram bin size multiplier of bmult.\n"
> +" -r -- Display realtime device free space information.\n"
> +" -s -- Emit freespace summary information.\n"
> +"\n"));
> +
> +}
> +
> +void
> +freesp_init(void)
> +{
> + freesp_cmd.name = "freesp";
> + freesp_cmd.altname = "fsp";
> + freesp_cmd.cfunc = freesp_f;
> + freesp_cmd.argmin = 0;
> + freesp_cmd.argmax = -1;
> + freesp_cmd.args = "[-bdsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]";
[-a agno]... right? Multiple allowed?
> + freesp_cmd.flags = CMD_FLAG_ONESHOT;
> + freesp_cmd.oneline = _("Examine filesystem free space");
> + freesp_cmd.help = freesp_help;
> +
> + add_command(&freesp_cmd);
> +}
> +
> diff --git a/spaceman/init.c b/spaceman/init.c
> index 93a8a1e..f3c93c3 100644
> --- a/spaceman/init.c
> +++ b/spaceman/init.c
> @@ -20,6 +20,7 @@
> #include "command.h"
> #include "input.h"
> #include "init.h"
> +#include "path.h"
> #include "space.h"
>
> char *progname;
> @@ -38,6 +39,7 @@ static void
> init_commands(void)
> {
> file_init();
> + freesp_init();
> help_init();
> prealloc_init();
> quit_init();
> @@ -71,12 +73,14 @@ init(
> int c, flags = 0;
> mode_t mode = 0600;
> xfs_fsop_geom_t geometry = { 0 };
> + struct fs_path fsp;
>
> progname = basename(argv[0]);
> setlocale(LC_ALL, "");
> bindtextdomain(PACKAGE, LOCALEDIR);
> textdomain(PACKAGE);
>
> + fs_table_initialise(0, NULL, 0, NULL);
> while ((c = getopt(argc, argv, "c:V")) != EOF) {
> switch (c) {
> case 'c':
> @@ -93,11 +97,11 @@ init(
> if (optind != argc - 1)
> usage();
>
> - if ((c = openfile(argv[optind], &geometry, flags, mode)) < 0)
> + if ((c = openfile(argv[optind], &geometry, flags, mode, &fsp)) < 0)
> exit(1);
> if (!platform_test_xfs_fd(c))
> printf(_("Not an XFS filesystem!\n"));
> - if (addfile(argv[optind], c, &geometry, flags) < 0)
> + if (addfile(argv[optind], c, &geometry, flags, &fsp) < 0)
> exit(1);
>
> init_commands();
> diff --git a/spaceman/prealloc.c b/spaceman/prealloc.c
> index 71c0d80..55b85ed 100644
> --- a/spaceman/prealloc.c
> +++ b/spaceman/prealloc.c
> @@ -20,6 +20,7 @@
> #include "command.h"
> #include "input.h"
> #include "init.h"
> +#include "path.h"
> #include "space.h"
>
> static cmdinfo_t prealloc_cmd;
> diff --git a/spaceman/space.h b/spaceman/space.h
> index 0ae3116..bf9a2df 100644
> --- a/spaceman/space.h
> +++ b/spaceman/space.h
> @@ -21,6 +21,7 @@ typedef struct fileio {
> int flags; /* flags describing file state */
> char *name; /* file name at time of open */
> xfs_fsop_geom_t geom; /* XFS filesystem geometry */
> + struct fs_path fs_path; /* XFS path information */
> } fileio_t;
>
> extern fileio_t *filetable; /* open file table */
> @@ -28,11 +29,18 @@ extern int filecount; /* number of open files */
> extern fileio_t *file; /* active file in file table */
> extern int filelist_f(void);
>
> -extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t);
> -extern int addfile(char *, int , xfs_fsop_geom_t *, int);
> +extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t,
> + struct fs_path *);
> +extern int addfile(char *, int , xfs_fsop_geom_t *, int, struct fs_path *);
>
> extern void file_init(void);
> extern void help_init(void);
> extern void prealloc_init(void);
> extern void quit_init(void);
> extern void trim_init(void);
> +
> +#ifdef HAVE_GETFSMAP
> +extern void freesp_init(void);
> +#else
> +# define freesp_init() do { } while (0)
> +#endif
> diff --git a/spaceman/trim.c b/spaceman/trim.c
> index d58f6d1..b5908cc 100644
> --- a/spaceman/trim.c
> +++ b/spaceman/trim.c
> @@ -20,6 +20,7 @@
> #include <linux/fs.h>
> #include "command.h"
> #include "init.h"
> +#include "path.h"
> #include "space.h"
> #include "input.h"
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 08/10] xfs_spaceman: Free space mapping command
2017-06-14 15:43 ` Eric Sandeen
@ 2017-06-14 16:43 ` Darrick J. Wong
0 siblings, 0 replies; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-14 16:43 UTC (permalink / raw)
To: Eric Sandeen; +Cc: sandeen, linux-xfs, Dave Chinner
On Wed, Jun 14, 2017 at 10:43:06AM -0500, Eric Sandeen wrote:
> On 6/2/17 2:52 PM, Darrick J. Wong wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> >
> > Add freespace mapping tool modelled on the xfs_db freesp command.
> > The advantage of this command over xfs_db is that it can be done
> > online and is coherent with concurrent modifications to the
> > filesystem.
> >
> > This requires the kernel to support the XFS_IOC_GETFSMAP ioctl to map
> > free space indexes.
> >
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > [darrick: port from FIEMAPFS to GETFSMAP]
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> > spaceman/Makefile | 7 +
> > spaceman/file.c | 19 ++-
> > spaceman/freesp.c | 367 +++++++++++++++++++++++++++++++++++++++++++++++++++
> > spaceman/init.c | 8 +
> > spaceman/prealloc.c | 1
> > spaceman/space.h | 12 +-
> > spaceman/trim.c | 1
> > 7 files changed, 409 insertions(+), 6 deletions(-)
> > create mode 100644 spaceman/freesp.c
> >
> >
> > diff --git a/spaceman/Makefile b/spaceman/Makefile
> > index 6aad746..95ec3c0 100644
> > --- a/spaceman/Makefile
> > +++ b/spaceman/Makefile
> > @@ -21,6 +21,13 @@ ifeq ($(ENABLE_EDITLINE),yes)
> > LLDLIBS += $(LIBEDITLINE) $(LIBTERMCAP)
> > endif
> >
> > +# On linux we get fsmap from the system or define it ourselves
> > +# so include this based on platform type. If this reverts to only
> > +# the autoconf check w/o local definition, change to testing HAVE_GETFSMAP
> > +ifeq ($(PKG_PLATFORM),linux)
> > +CFILES += freesp.c
> > +endif
> > +
> > default: depend $(LTCOMMAND)
> >
> > include $(BUILDRULES)
> > diff --git a/spaceman/file.c b/spaceman/file.c
> > index 9356066..46b8826 100644
> > --- a/spaceman/file.c
> > +++ b/spaceman/file.c
> > @@ -22,6 +22,7 @@
> > #include "command.h"
> > #include "input.h"
> > #include "init.h"
> > +#include "path.h"
> > #include "space.h"
> >
> > static cmdinfo_t print_cmd;
> > @@ -69,8 +70,10 @@ openfile(
> > char *path,
> > xfs_fsop_geom_t *geom,
> > int flags,
> > - mode_t mode)
> > + mode_t mode,
> > + struct fs_path *fs_path)
> > {
> > + struct fs_path *fsp;
> > int fd;
> >
> > fd = open(path, flags, mode);
> > @@ -95,6 +98,16 @@ openfile(
> > close(fd);
> > return -1;
> > }
> > +
> > + if (fs_path) {
> > + fsp = fs_table_lookup(path, FS_MOUNT_POINT);
> > + if (!fsp) {
> > + fprintf(stderr, _("%s: cannot find mount point."),
> > + path);
> > + return -1;
> > + }
> > + memcpy(fs_path, fsp, sizeof(struct fs_path));
> > + }
> > return fd;
> > }
> >
> > @@ -103,7 +116,8 @@ addfile(
> > char *name,
> > int fd,
> > xfs_fsop_geom_t *geometry,
> > - int flags)
> > + int flags,
> > + struct fs_path *fs_path)
> > {
> > char *filename;
> >
> > @@ -131,6 +145,7 @@ addfile(
> > file->flags = flags;
> > file->name = filename;
> > file->geom = *geometry;
> > + memcpy(&file->fs_path, fs_path, sizeof(file->fs_path));
> > return 0;
> > }
> >
> > diff --git a/spaceman/freesp.c b/spaceman/freesp.c
> > new file mode 100644
> > index 0000000..2290a5e
> > --- /dev/null
> > +++ b/spaceman/freesp.c
> > @@ -0,0 +1,367 @@
> > +/*
> > + * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
> > + * Copyright (c) 2012 Red Hat, Inc.
> > + * Copyright (c) 2017 Oracle.
> > + * All Rights Reserved.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License as
> > + * published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it would be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write the Free Software Foundation,
> > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> > + */
> > +
> > +#include "libxfs.h"
> > +#include <linux/fiemap.h>
> > +#include "command.h"
> > +#include "init.h"
> > +#include "path.h"
> > +#include "space.h"
> > +
> > +typedef struct histent
> > +{
> > + int low;
> > + int high;
> > + long long count;
> > + long long blocks;
> > +} histent_t;
> > +
> > +static int agcount;
> > +static xfs_agnumber_t *aglist;
> > +static int dumpflag;
> > +static int equalsize;
> > +static histent_t *hist;
> > +static int histcount;
> > +static int multsize;
> > +static int seen1;
> > +static int summaryflag;
> > +static bool rtflag;
> > +static long long totblocks;
> > +static long long totexts;
> > +
> > +static cmdinfo_t freesp_cmd;
> > +
> > +static void
> > +addhistent(
> > + int h)
> > +{
> > + hist = realloc(hist, (histcount + 1) * sizeof(*hist));
> > + if (h == 0)
> > + h = 1;
> > + hist[histcount].low = h;
> > + hist[histcount].count = hist[histcount].blocks = 0;
> > + histcount++;
> > + if (h == 1)
> > + seen1 = 1;
> > +}
> > +
> > +static void
> > +addtohist(
> > + xfs_agnumber_t agno,
> > + xfs_agblock_t agbno,
> > + off64_t len)
> > +{
> > + int i;
> > +
> > + if (dumpflag)
> > + printf("%8d %8d %8"PRId64"\n", agno, agbno, len);
> > + totexts++;
> > + totblocks += len;
> > + for (i = 0; i < histcount; i++) {
> > + if (hist[i].high >= len) {
> > + hist[i].count++;
> > + hist[i].blocks += len;
> > + break;
> > + }
> > + }
> > +}
> > +
> > +static int
> > +hcmp(
> > + const void *a,
> > + const void *b)
> > +{
> > + return ((histent_t *)a)->low - ((histent_t *)b)->low;
> > +}
> > +
> > +static void
> > +histinit(
> > + int maxlen)
> > +{
> > + int i;
> > +
> > + if (equalsize) {
> > + for (i = 1; i < maxlen; i += equalsize)
> > + addhistent(i);
> > + } else if (multsize) {
> > + for (i = 1; i < maxlen; i *= multsize)
> > + addhistent(i);
> > + } else {
> > + if (!seen1)
> > + addhistent(1);
> > + qsort(hist, histcount, sizeof(*hist), hcmp);
> > + }
> > + for (i = 0; i < histcount; i++) {
> > + if (i < histcount - 1)
> > + hist[i].high = hist[i + 1].low - 1;
> > + else
> > + hist[i].high = maxlen;
> > + }
> > +}
> > +
> > +static void
> > +printhist(void)
> > +{
> > + int i;
> > +
> > + printf("%7s %7s %7s %7s %6s\n",
> > + _("from"), _("to"), _("extents"), _("blocks"), _("pct"));
> > + for (i = 0; i < histcount; i++) {
> > + if (hist[i].count)
> > + printf("%7d %7d %7lld %7lld %6.2f\n", hist[i].low,
> > + hist[i].high, hist[i].count, hist[i].blocks,
> > + hist[i].blocks * 100.0 / totblocks);
> > + }
> > +}
> > +
> > +static int
> > +inaglist(
> > + xfs_agnumber_t agno)
> > +{
> > + int i;
> > +
> > + if (agcount == 0)
> > + return 1;
> > + for (i = 0; i < agcount; i++)
> > + if (aglist[i] == agno)
> > + return 1;
> > + return 0;
> > +}
> > +
> > +#define NR_EXTENTS 128
> > +
> > +static void
> > +scan_ag(
> > + xfs_agnumber_t agno)
> > +{
> > + struct fsmap_head *fsmap;
> > + struct fsmap *extent;
> > + struct fsmap *l, *h;
> > + struct fsmap *p;
> > + off64_t blocksize = file->geom.blocksize;
> > + off64_t bperag;
> > + off64_t aglen;
> > + xfs_agblock_t agbno;
> > + int ret;
> > + int i;
> > +
> > + bperag = (off64_t)file->geom.agblocks * blocksize;
> > +
> > + fsmap = malloc(fsmap_sizeof(NR_EXTENTS));
> > + if (!fsmap) {
> > + fprintf(stderr, _("%s: fsmap malloc failed.\n"), progname);
> > + exitcode = 1;
> > + return;
> > + }
> > +
> > + memset(fsmap, 0, sizeof(*fsmap));
> > + fsmap->fmh_count = NR_EXTENTS;
> > + l = fsmap->fmh_keys;
> > + h = fsmap->fmh_keys + 1;
> > + if (agno != NULLAGNUMBER) {
> > + l->fmr_physical = agno * bperag;
> > + h->fmr_physical = ((agno + 1) * bperag) - 1;
> > + l->fmr_device = h->fmr_device = file->fs_path.fs_datadev;
> > + } else {
> > + l->fmr_physical = 0;
> > + h->fmr_physical = ULLONG_MAX;
> > + l->fmr_device = h->fmr_device = file->fs_path.fs_rtdev;
> > + }
> > + h->fmr_owner = ULLONG_MAX;
> > + h->fmr_flags = UINT_MAX;
> > + h->fmr_offset = ULLONG_MAX;
> > +
> > + while (true) {
> > + ret = ioctl(file->fd, FS_IOC_GETFSMAP, fsmap);
> > + if (ret < 0) {
> > + fprintf(stderr, _("%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n"),
> > + progname, file->name, strerror(errno));
> > + free(fsmap);
> > + exitcode = 1;
> > + return;
> > + }
> > +
> > + /* No more extents to map, exit */
> > + if (!fsmap->fmh_entries)
> > + break;
> > +
> > + for (i = 0, extent = fsmap->fmh_recs;
> > + i < fsmap->fmh_entries;
> > + i++, extent++) {
> > + if (!(extent->fmr_flags & FMR_OF_SPECIAL_OWNER) ||
> > + extent->fmr_owner != XFS_FMR_OWN_FREE)
> > + continue;
> > + agbno = (extent->fmr_physical - (bperag * agno)) /
> > + blocksize;
> > + aglen = extent->fmr_length / blocksize;
> > +
> > + addtohist(agno, agbno, aglen);
> > + }
> > +
> > + p = &fsmap->fmh_recs[fsmap->fmh_entries - 1];
> > + if (p->fmr_flags & FMR_OF_LAST)
> > + break;
> > + fsmap_advance(fsmap);
> > + }
> > +}
> > +static void
> > +aglistadd(
> > + char *a)
> > +{
> > + aglist = realloc(aglist, (agcount + 1) * sizeof(*aglist));
> > + aglist[agcount] = (xfs_agnumber_t)atoi(a);
> > + agcount++;
> > +}
> > +
> > +static int
> > +init(
> > + int argc,
> > + char **argv)
> > +{
> > + int c;
> > + int speced = 0;
> > +
> > + agcount = dumpflag = equalsize = multsize = optind = 0;
> > + histcount = seen1 = summaryflag = 0;
> > + totblocks = totexts = 0;
> > + aglist = NULL;
> > + hist = NULL;
> > + rtflag = false;
> > + while ((c = getopt(argc, argv, "a:bde:h:m:rs")) != EOF) {
> > + switch (c) {
> > + case 'a':
> > + aglistadd(optarg);
> > + break;
> > + case 'b':
> > + if (speced)
> > + return 0;
> > + multsize = 2;
> > + speced = 1;
> > + break;
> > + case 'd':
> > + dumpflag = 1;
> > + break;
> > + case 'e':
> > + if (speced)
> > + return 0;
> > + equalsize = atoi(optarg);
> > + speced = 1;
> > + break;
> > + case 'h':
> > + if (speced && !histcount)
> > + return 0;
> > + addhistent(atoi(optarg));
> > + speced = 1;
> > + break;
> > + case 'm':
> > + if (speced)
> > + return 0;
> > + multsize = atoi(optarg);
> > + speced = 1;
> > + break;
> > + case 'r':
> > + rtflag = true;
> > + break;
> > + case 's':
> > + summaryflag = 1;
> > + break;
> > + case '?':
> > + return 0;
> > + }
> > + }
> > + if (optind != argc)
> > + return 0;
> > + if (!speced)
> > + multsize = 2;
> > + histinit(file->geom.agblocks);
> > + return 1;
> > +}
> > +
> > +/*
> > + * Report on freespace usage in xfs filesystem.
> > + */
> > +static int
> > +freesp_f(
> > + int argc,
> > + char **argv)
> > +{
> > + xfs_agnumber_t agno;
> > +
> > + if (!init(argc, argv))
> > + return 0;
> > + if (rtflag)
> > + scan_ag(NULLAGNUMBER);
> > + for (agno = 0; !rtflag && agno < file->geom.agcount; agno++) {
> > + if (inaglist(agno))
> > + scan_ag(agno);
> > + }
> > + if (histcount)
> > + printhist();
> > + if (summaryflag) {
> > + printf(_("total free extents %lld\n"), totexts);
> > + printf(_("total free blocks %lld\n"), totblocks);
> > + printf(_("average free extent size %g\n"),
> > + (double)totblocks / (double)totexts);
> > + }
> > + if (aglist)
> > + free(aglist);
> > + if (hist)
> > + free(hist);
> > + return 0;
> > +}
> > +
> > +static void
> > +freesp_help(void)
> > +{
> > + printf(_(
> > +"\n"
> > +"Examine filesystem free space\n"
> > +"\n"
> > +"Options: [-bdsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n"
>
> don't restate options ...
Fixed.
> > +"\n"
> > +" -a agno -- Scan only the given AG agno.\n"
> > +" -b -- binary histogram bin size\n"
> > +" -d -- debug output\n"
> > +" -e bsize -- Use fixed histogram bin size of bsize\n"
> > +" -h hbsz -- Use custom histogram bin size of h1.\n"
> > +" Multiple specifications are allowed.\n"
> > +" -m bmult -- Use histogram bin size multiplier of bmult.\n"
> > +" -r -- Display realtime device free space information.\n"
> > +" -s -- Emit freespace summary information.\n"
> > +"\n"));
> > +
> > +}
> > +
> > +void
> > +freesp_init(void)
> > +{
> > + freesp_cmd.name = "freesp";
> > + freesp_cmd.altname = "fsp";
> > + freesp_cmd.cfunc = freesp_f;
> > + freesp_cmd.argmin = 0;
> > + freesp_cmd.argmax = -1;
> > + freesp_cmd.args = "[-bdsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]";
>
> [-a agno]... right? Multiple allowed?
Yes, and fixed.
--D
> > + freesp_cmd.flags = CMD_FLAG_ONESHOT;
> > + freesp_cmd.oneline = _("Examine filesystem free space");
> > + freesp_cmd.help = freesp_help;
> > +
> > + add_command(&freesp_cmd);
> > +}
> > +
> > diff --git a/spaceman/init.c b/spaceman/init.c
> > index 93a8a1e..f3c93c3 100644
> > --- a/spaceman/init.c
> > +++ b/spaceman/init.c
> > @@ -20,6 +20,7 @@
> > #include "command.h"
> > #include "input.h"
> > #include "init.h"
> > +#include "path.h"
> > #include "space.h"
> >
> > char *progname;
> > @@ -38,6 +39,7 @@ static void
> > init_commands(void)
> > {
> > file_init();
> > + freesp_init();
> > help_init();
> > prealloc_init();
> > quit_init();
> > @@ -71,12 +73,14 @@ init(
> > int c, flags = 0;
> > mode_t mode = 0600;
> > xfs_fsop_geom_t geometry = { 0 };
> > + struct fs_path fsp;
> >
> > progname = basename(argv[0]);
> > setlocale(LC_ALL, "");
> > bindtextdomain(PACKAGE, LOCALEDIR);
> > textdomain(PACKAGE);
> >
> > + fs_table_initialise(0, NULL, 0, NULL);
> > while ((c = getopt(argc, argv, "c:V")) != EOF) {
> > switch (c) {
> > case 'c':
> > @@ -93,11 +97,11 @@ init(
> > if (optind != argc - 1)
> > usage();
> >
> > - if ((c = openfile(argv[optind], &geometry, flags, mode)) < 0)
> > + if ((c = openfile(argv[optind], &geometry, flags, mode, &fsp)) < 0)
> > exit(1);
> > if (!platform_test_xfs_fd(c))
> > printf(_("Not an XFS filesystem!\n"));
> > - if (addfile(argv[optind], c, &geometry, flags) < 0)
> > + if (addfile(argv[optind], c, &geometry, flags, &fsp) < 0)
> > exit(1);
> >
> > init_commands();
> > diff --git a/spaceman/prealloc.c b/spaceman/prealloc.c
> > index 71c0d80..55b85ed 100644
> > --- a/spaceman/prealloc.c
> > +++ b/spaceman/prealloc.c
> > @@ -20,6 +20,7 @@
> > #include "command.h"
> > #include "input.h"
> > #include "init.h"
> > +#include "path.h"
> > #include "space.h"
> >
> > static cmdinfo_t prealloc_cmd;
> > diff --git a/spaceman/space.h b/spaceman/space.h
> > index 0ae3116..bf9a2df 100644
> > --- a/spaceman/space.h
> > +++ b/spaceman/space.h
> > @@ -21,6 +21,7 @@ typedef struct fileio {
> > int flags; /* flags describing file state */
> > char *name; /* file name at time of open */
> > xfs_fsop_geom_t geom; /* XFS filesystem geometry */
> > + struct fs_path fs_path; /* XFS path information */
> > } fileio_t;
> >
> > extern fileio_t *filetable; /* open file table */
> > @@ -28,11 +29,18 @@ extern int filecount; /* number of open files */
> > extern fileio_t *file; /* active file in file table */
> > extern int filelist_f(void);
> >
> > -extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t);
> > -extern int addfile(char *, int , xfs_fsop_geom_t *, int);
> > +extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t,
> > + struct fs_path *);
> > +extern int addfile(char *, int , xfs_fsop_geom_t *, int, struct fs_path *);
> >
> > extern void file_init(void);
> > extern void help_init(void);
> > extern void prealloc_init(void);
> > extern void quit_init(void);
> > extern void trim_init(void);
> > +
> > +#ifdef HAVE_GETFSMAP
> > +extern void freesp_init(void);
> > +#else
> > +# define freesp_init() do { } while (0)
> > +#endif
> > diff --git a/spaceman/trim.c b/spaceman/trim.c
> > index d58f6d1..b5908cc 100644
> > --- a/spaceman/trim.c
> > +++ b/spaceman/trim.c
> > @@ -20,6 +20,7 @@
> > #include <linux/fs.h>
> > #include "command.h"
> > #include "init.h"
> > +#include "path.h"
> > #include "space.h"
> > #include "input.h"
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 08/10] xfs_spaceman: Free space mapping command
2017-06-02 19:52 ` [PATCH 08/10] xfs_spaceman: Free space mapping command Darrick J. Wong
2017-06-14 15:43 ` Eric Sandeen
@ 2017-06-14 16:04 ` Eric Sandeen
2017-06-14 16:57 ` Darrick J. Wong
1 sibling, 1 reply; 29+ messages in thread
From: Eric Sandeen @ 2017-06-14 16:04 UTC (permalink / raw)
To: Darrick J. Wong, sandeen; +Cc: linux-xfs, Dave Chinner
On 6/2/17 2:52 PM, Darrick J. Wong wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> Add freespace mapping tool modelled on the xfs_db freesp command.
> The advantage of this command over xfs_db is that it can be done
> online and is coherent with concurrent modifications to the
> filesystem.
>
> This requires the kernel to support the XFS_IOC_GETFSMAP ioctl to map
> free space indexes.
>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> [darrick: port from FIEMAPFS to GETFSMAP]
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> +static int
> +init(
> + int argc,
> + char **argv)
> +{
> + int c;
> + int speced = 0;
> +
> + agcount = dumpflag = equalsize = multsize = optind = 0;
> + histcount = seen1 = summaryflag = 0;
ew, setting histcount to 0 (already done, right? it's global?)
and checking it here but never setting it is a little confusing.
Maybe the comment below would help.
> + totblocks = totexts = 0;
> + aglist = NULL;
> + hist = NULL;
> + rtflag = false;
> + while ((c = getopt(argc, argv, "a:bde:h:m:rs")) != EOF) {
> + switch (c) {
> + case 'a':
> + aglistadd(optarg);
> + break;
> + case 'b':
> + if (speced)
> + return 0;
> + multsize = 2;
> + speced = 1;
> + break;
> + case 'd':
> + dumpflag = 1;
> + break;
> + case 'e':
> + if (speced)
> + return 0;
> + equalsize = atoi(optarg);
> + speced = 1;
> + break;
> + case 'h':
> + if (speced && !histcount)
> + return 0;
maybe: /* increments histcount */
> + addhistent(atoi(optarg));
> + speced = 1;
> + break;
> + case 'm':
> + if (speced)
> + return 0;
> + multsize = atoi(optarg);
> + speced = 1;
> + break;
> + case 'r':
> + rtflag = true;
> + break;
> + case 's':
> + summaryflag = 1;
> + break;
> + case '?':
> + return 0;
> + }
> + }
> + if (optind != argc)
> + return 0;
> + if (!speced)
> + multsize = 2;
Manpage indicates that -b, -e, and -h are mutually exclusive, but that's
not enforced here (?)
Specifying more than one seems to break the command:
xfs_spaceman> freesp -b
from to extents blocks pct
2 3 1 3 0.00
32768 65536 4 259537 100.00
xfs_spaceman> freesp -e 4096
from to extents blocks pct
1 4096 1 3 0.00
61441 65536 4 259537 100.00
xfs_spaceman> freesp -e 4096 -b
xfs_spaceman>
Oh I see, if more than one is "speced" init returns 0 (silently).
I'd document what speced is for, and I guess print a warning about
the exclusive nature of the 3 arguments in each case if re-spec'd
before returning.
And note the exclusive nature somehow in the help.
(hm, looks like -m is in this exclusive group too?)
in gneneral need to sanitize behavior w/ built in help as well
as manpage...
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 08/10] xfs_spaceman: Free space mapping command
2017-06-14 16:04 ` Eric Sandeen
@ 2017-06-14 16:57 ` Darrick J. Wong
0 siblings, 0 replies; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-14 16:57 UTC (permalink / raw)
To: Eric Sandeen; +Cc: sandeen, linux-xfs, Dave Chinner
On Wed, Jun 14, 2017 at 11:04:11AM -0500, Eric Sandeen wrote:
>
> On 6/2/17 2:52 PM, Darrick J. Wong wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> >
> > Add freespace mapping tool modelled on the xfs_db freesp command.
> > The advantage of this command over xfs_db is that it can be done
> > online and is coherent with concurrent modifications to the
> > filesystem.
> >
> > This requires the kernel to support the XFS_IOC_GETFSMAP ioctl to map
> > free space indexes.
> >
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > [darrick: port from FIEMAPFS to GETFSMAP]
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
>
>
> > +static int
> > +init(
> > + int argc,
> > + char **argv)
> > +{
> > + int c;
> > + int speced = 0;
> > +
> > + agcount = dumpflag = equalsize = multsize = optind = 0;
> > + histcount = seen1 = summaryflag = 0;
>
> ew, setting histcount to 0 (already done, right? it's global?)
> and checking it here but never setting it is a little confusing.
Yes, I'll get rid of the redundant initializers.
> Maybe the comment below would help.
Ok.
> > + totblocks = totexts = 0;
> > + aglist = NULL;
> > + hist = NULL;
> > + rtflag = false;
> > + while ((c = getopt(argc, argv, "a:bde:h:m:rs")) != EOF) {
> > + switch (c) {
> > + case 'a':
> > + aglistadd(optarg);
> > + break;
> > + case 'b':
> > + if (speced)
> > + return 0;
> > + multsize = 2;
> > + speced = 1;
> > + break;
> > + case 'd':
> > + dumpflag = 1;
> > + break;
> > + case 'e':
> > + if (speced)
> > + return 0;
> > + equalsize = atoi(optarg);
> > + speced = 1;
> > + break;
> > + case 'h':
> > + if (speced && !histcount)
> > + return 0;
>
> maybe: /* increments histcount */
Fixed.
> > + addhistent(atoi(optarg));
> > + speced = 1;
> > + break;
> > + case 'm':
> > + if (speced)
> > + return 0;
> > + multsize = atoi(optarg);
> > + speced = 1;
> > + break;
> > + case 'r':
> > + rtflag = true;
> > + break;
> > + case 's':
> > + summaryflag = 1;
> > + break;
> > + case '?':
> > + return 0;
> > + }
> > + }
> > + if (optind != argc)
> > + return 0;
> > + if (!speced)
> > + multsize = 2;
>
> Manpage indicates that -b, -e, and -h are mutually exclusive, but that's
> not enforced here (?)
>
> Specifying more than one seems to break the command:
>
> xfs_spaceman> freesp -b
> from to extents blocks pct
> 2 3 1 3 0.00
> 32768 65536 4 259537 100.00
> xfs_spaceman> freesp -e 4096
> from to extents blocks pct
> 1 4096 1 3 0.00
> 61441 65536 4 259537 100.00
> xfs_spaceman> freesp -e 4096 -b
> xfs_spaceman>
>
> Oh I see, if more than one is "speced" init returns 0 (silently).
>
> I'd document what speced is for, and I guess print a warning about
> the exclusive nature of the 3 arguments in each case if re-spec'd
> before returning.
I made a note of that in the help screen and redirected all the overspec
cases to print the help screen instead of silently returning.
> And note the exclusive nature somehow in the help.
> (hm, looks like -m is in this exclusive group too?)
>
> in gneneral need to sanitize behavior w/ built in help as well
> as manpage...
Ok.
--D
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 09/10] xfs_spaceman: add a man page
2017-06-02 19:51 [PATCH v8 00/10] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
` (7 preceding siblings ...)
2017-06-02 19:52 ` [PATCH 08/10] xfs_spaceman: Free space mapping command Darrick J. Wong
@ 2017-06-02 19:52 ` Darrick J. Wong
2017-06-14 16:06 ` Eric Sandeen
2017-06-02 19:52 ` [PATCH 10/10] xfs_spaceman: add group summary mode Darrick J. Wong
9 siblings, 1 reply; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-02 19:52 UTC (permalink / raw)
To: sandeen, darrick.wong; +Cc: linux-xfs
From: Darrick J. Wong <darrick.wong@oracle.com>
Add a manual page describing xfs_spaceman's behavior.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
man/man8/xfs_spaceman.8 | 102 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 102 insertions(+)
create mode 100644 man/man8/xfs_spaceman.8
diff --git a/man/man8/xfs_spaceman.8 b/man/man8/xfs_spaceman.8
new file mode 100644
index 0000000..c1d19c0
--- /dev/null
+++ b/man/man8/xfs_spaceman.8
@@ -0,0 +1,102 @@
+.TH xfs_spaceman 8
+.SH NAME
+xfs_spaceman \- show free space information about an XFS filesystem
+.SH SYNOPSIS
+.B xfs_spaceman
+[
+.B \-c
+.I cmd
+]
+.I file
+.br
+.B xfs_spaceman \-V
+.SH DESCRIPTION
+.B xfs_spaceman
+reports and controls free space usage in an XFS filesystem.
+.SH OPTIONS
+.TP 1.0i
+.BI \-c " cmd"
+.B xfs_spaceman
+commands may be run interactively (the default) or as arguments on
+the command line. Multiple
+.B \-c
+arguments may be given. The commands are run in the sequence given,
+then the program exits.
+
+.SH COMMANDS
+.TP
+.BI "freesp [ \-sr ] [ \-b | \-e bsize | \-h h1 [ \-m bmult ]] [-a agno]"
+With no arguments,
+.B freesp
+shows a histogram of all free space extents in the filesystem.
+The
+.B -b
+argument establishes that the histogram bins are successive powers of two.
+This is the default.
+The
+.BR -h " and " -m
+options can be used to specify a custom histogram bin size as well as a
+multiplication factor for subsequent bin sizes.
+The
+.BR -e
+option fixes the histogram size to a particular value.
+The
+.BR -a " and " -r
+options constrain the free space information report to a particular AG
+or the realtime device, respectively. The
+.B -a
+option may be specified multiple times.
+A summary of free space information will be printed if the
+.B -s
+option is given.
+.TP
+.BR "help [ " command " ]"
+Display a brief description of one or all commands.
+.TP
+.BI "prealloc [ \-ugp id ] [ \-m minlen ] [ \-s ]"
+Controls speculative preallocation. The
+.BR -u ","
+.BR -g ","
+and
+.B -p
+options will clear all speculative preallocations for a given user,
+group, or project ID, respectively.
+The
+.B -m
+option causes the operation to ignore any file with a size smaller than
+.BR minlen "."
+The
+.B -s
+option will flush all dirty data and metadata to disk.
+.TP
+.B print
+Display a list of all open files.
+.TP
+.B quit
+Exit
+.BR xfs_spaceman .
+.TP
+.BI "trim [ \-f ] [ \-a agno ] [ \-m minlen ] [" " offset length " ]
+Instructs the underlying storage device to release all storage that may
+be backing free space in the filesystem.
+The
+.B -f
+option trims all free space in the entire filesystem.
+The
+.B -a
+option trims only the free space in a given AG.
+The
+.B -m
+option only trims free space extents that are longer than
+.IR minlen "."
+The
+.IR offset " and " length
+arguments trim all free space between
+.I offset
+and
+.IR "offset+length" "."
+The
+.BR -a " and " -f
+options are mutually exclusive with each other as well as with the
+.IR offset " and " length
+arguments.
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 09/10] xfs_spaceman: add a man page
2017-06-02 19:52 ` [PATCH 09/10] xfs_spaceman: add a man page Darrick J. Wong
@ 2017-06-14 16:06 ` Eric Sandeen
2017-06-14 20:49 ` Darrick J. Wong
0 siblings, 1 reply; 29+ messages in thread
From: Eric Sandeen @ 2017-06-14 16:06 UTC (permalink / raw)
To: Darrick J. Wong, sandeen; +Cc: linux-xfs
On 6/2/17 2:52 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
>
> Add a manual page describing xfs_spaceman's behavior.
>
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
> man/man8/xfs_spaceman.8 | 102 +++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 102 insertions(+)
> create mode 100644 man/man8/xfs_spaceman.8
>
>
> diff --git a/man/man8/xfs_spaceman.8 b/man/man8/xfs_spaceman.8
> new file mode 100644
> index 0000000..c1d19c0
> --- /dev/null
> +++ b/man/man8/xfs_spaceman.8
> @@ -0,0 +1,102 @@
> +.TH xfs_spaceman 8
> +.SH NAME
> +xfs_spaceman \- show free space information about an XFS filesystem
> +.SH SYNOPSIS
> +.B xfs_spaceman
> +[
> +.B \-c
> +.I cmd
> +]
> +.I file
> +.br
> +.B xfs_spaceman \-V
> +.SH DESCRIPTION
> +.B xfs_spaceman
> +reports and controls free space usage in an XFS filesystem.
> +.SH OPTIONS
> +.TP 1.0i
> +.BI \-c " cmd"
> +.B xfs_spaceman
> +commands may be run interactively (the default) or as arguments on
> +the command line. Multiple
> +.B \-c
> +arguments may be given. The commands are run in the sequence given,
> +then the program exits.
> +
> +.SH COMMANDS
> +.TP
> +.BI "freesp [ \-sr ] [ \-b | \-e bsize | \-h h1 [ \-m bmult ]] [-a agno]"
Hmm this differs from program help:
freesp [-bdgsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]
are -b, -e, and -h mutually exclusive or not?
xfs_spaceman> freesp -b
from to extents blocks pct
2 3 1 3 0.00
32768 65536 4 259537 100.00
xfs_spaceman> freesp -e 4096
from to extents blocks pct
1 4096 1 3 0.00
61441 65536 4 259537 100.00
xfs_spaceman> freesp -e 4096 -b
xfs_spaceman>
Also, where are -g and -d ?
[-a agno]...
(multiple allowed)
> +With no arguments,
> +.B freesp
> +shows a histogram of all free space extents in the filesystem.
> +The
> +.B -b
> +argument establishes that the histogram bins are successive powers of two.
> +This is the default.
> +The
> +.BR -h " and " -m
> +options can be used to specify a custom histogram bin size as well as a
> +multiplication factor for subsequent bin sizes.
> +The
> +.BR -e
> +option fixes the histogram size to a particular value.
> +The
> +.BR -a " and " -r
> +options constrain the free space information report to a particular AG
> +or the realtime device, respectively. The
> +.B -a
> +option may be specified multiple times.
> +A summary of free space information will be printed if the
> +.B -s
> +option is given.
> +.TP
> +.BR "help [ " command " ]"
> +Display a brief description of one or all commands.
> +.TP
> +.BI "prealloc [ \-ugp id ] [ \-m minlen ] [ \-s ]"
> +Controls speculative preallocation. The
> +.BR -u ","
> +.BR -g ","
> +and
> +.B -p
> +options will clear all speculative preallocations for a given user,
> +group, or project ID, respectively.
> +The
> +.B -m
> +option causes the operation to ignore any file with a size smaller than
> +.BR minlen "."
> +The
> +.B -s
> +option will flush all dirty data and metadata to disk.
> +.TP
> +.B print
> +Display a list of all open files.
> +.TP
> +.B quit
> +Exit
> +.BR xfs_spaceman .
> +.TP
> +.BI "trim [ \-f ] [ \-a agno ] [ \-m minlen ] [" " offset length " ]
Hm, this looks like -f / -a / offset/length are all optional, and not
mutually exclusive.
If this were in a SYNOPSIS section, it'd require 3 synopses I think.
Perhaps here it should be:
trim -f [ -m minlen ] [ offset length ]
trim -a agno [ -m minlen ] [ offset length ]
trim offset length [ -m minlen ]
as 3 separate invocation methods?
> +Instructs the underlying storage device to release all storage that may
> +be backing free space in the filesystem.
> +The
> +.B -f
> +option trims all free space in the entire filesystem.
> +The
> +.B -a
> +option trims only the free space in a given AG.
> +The
> +.B -m
> +option only trims free space extents that are longer than
> +.IR minlen "."
units? (suffixes?)
> +The
> +.IR offset " and " length
> +arguments trim all free space between
> +.I offset
> +and
> +.IR "offset+length" "."
Units?
> +The
> +.BR -a " and " -f
> +options are mutually exclusive with each other as well as with the
> +.IR offset " and " length
> +arguments.
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 09/10] xfs_spaceman: add a man page
2017-06-14 16:06 ` Eric Sandeen
@ 2017-06-14 20:49 ` Darrick J. Wong
0 siblings, 0 replies; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-14 20:49 UTC (permalink / raw)
To: Eric Sandeen; +Cc: sandeen, linux-xfs
On Wed, Jun 14, 2017 at 11:06:44AM -0500, Eric Sandeen wrote:
> On 6/2/17 2:52 PM, Darrick J. Wong wrote:
> > From: Darrick J. Wong <darrick.wong@oracle.com>
> >
> > Add a manual page describing xfs_spaceman's behavior.
> >
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> > man/man8/xfs_spaceman.8 | 102 +++++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 102 insertions(+)
> > create mode 100644 man/man8/xfs_spaceman.8
> >
> >
> > diff --git a/man/man8/xfs_spaceman.8 b/man/man8/xfs_spaceman.8
> > new file mode 100644
> > index 0000000..c1d19c0
> > --- /dev/null
> > +++ b/man/man8/xfs_spaceman.8
> > @@ -0,0 +1,102 @@
> > +.TH xfs_spaceman 8
> > +.SH NAME
> > +xfs_spaceman \- show free space information about an XFS filesystem
> > +.SH SYNOPSIS
> > +.B xfs_spaceman
> > +[
> > +.B \-c
> > +.I cmd
> > +]
> > +.I file
> > +.br
> > +.B xfs_spaceman \-V
> > +.SH DESCRIPTION
> > +.B xfs_spaceman
> > +reports and controls free space usage in an XFS filesystem.
> > +.SH OPTIONS
> > +.TP 1.0i
> > +.BI \-c " cmd"
> > +.B xfs_spaceman
> > +commands may be run interactively (the default) or as arguments on
> > +the command line. Multiple
> > +.B \-c
> > +arguments may be given. The commands are run in the sequence given,
> > +then the program exits.
> > +
> > +.SH COMMANDS
> > +.TP
> > +.BI "freesp [ \-sr ] [ \-b | \-e bsize | \-h h1 [ \-m bmult ]] [-a agno]"
>
> Hmm this differs from program help:
>
> freesp [-bdgsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]
>
> are -b, -e, and -h mutually exclusive or not?
>
> xfs_spaceman> freesp -b
> from to extents blocks pct
> 2 3 1 3 0.00
> 32768 65536 4 259537 100.00
> xfs_spaceman> freesp -e 4096
> from to extents blocks pct
> 1 4096 1 3 0.00
> 61441 65536 4 259537 100.00
> xfs_spaceman> freesp -e 4096 -b
> xfs_spaceman>
>
> Also, where are -g and -d ?
-g is in the next patch.
-d needs to be added.
>
>
> [-a agno]...
>
> (multiple allowed)
Oh heck this manpage is so hard to read I'm going to reflow the whole
section to be easier on the eyes:
freesp [ -drs ] [-a agno] [ -b | -e bsize | -h bsize | -m factor ]
With no arguments, freesp shows a histogram of all free space
extents in the filesystem. The command takes the following
options:
-a agno
Collect free space information from this allocation
group. This option can be specified multiple times to
collect from multiple groups.
-b This argument establishes that the histogram bin sizes
are successive powers of two. This is the default, and
is mutually exclusive with the -e, -h, and -m options.
-d Print debugging information such as the raw free space
extent information.
-e bsize
Set all histogram bin sizes to a specific value. This
option is mutually exclusive with the -b, -h, and -m
options.
-h bsize
Create a histogram bin with a lower bound of this value.
The upper bound of this bin will be one less than the
lower bound of the next highest histogram bin. This
option can be given multiple times to control the exact
bin sizes. This option is mutually exclusive with the
-b, -e, and -m options.
-m factor
Create each histogram bin with a size that is this many
times the size of the prvious bin created. This option
is mutually exclusive with the -b, -e, and -h options.
-r Query the realtime device for free space information.
-s Display a summary of the free space information found.
> > +With no arguments,
> > +.B freesp
> > +shows a histogram of all free space extents in the filesystem.
> > +The
> > +.B -b
> > +argument establishes that the histogram bins are successive powers of two.
> > +This is the default.
> > +The
> > +.BR -h " and " -m
> > +options can be used to specify a custom histogram bin size as well as a
> > +multiplication factor for subsequent bin sizes.
> > +The
> > +.BR -e
> > +option fixes the histogram size to a particular value.
> > +The
> > +.BR -a " and " -r
> > +options constrain the free space information report to a particular AG
> > +or the realtime device, respectively. The
> > +.B -a
> > +option may be specified multiple times.
> > +A summary of free space information will be printed if the
> > +.B -s
> > +option is given.
> > +.TP
> > +.BR "help [ " command " ]"
> > +Display a brief description of one or all commands.
> > +.TP
> > +.BI "prealloc [ \-ugp id ] [ \-m minlen ] [ \-s ]"
> > +Controls speculative preallocation. The
> > +.BR -u ","
> > +.BR -g ","
> > +and
> > +.B -p
> > +options will clear all speculative preallocations for a given user,
> > +group, or project ID, respectively.
> > +The
> > +.B -m
> > +option causes the operation to ignore any file with a size smaller than
> > +.BR minlen "."
> > +The
> > +.B -s
> > +option will flush all dirty data and metadata to disk.
> > +.TP
> > +.B print
> > +Display a list of all open files.
> > +.TP
> > +.B quit
> > +Exit
> > +.BR xfs_spaceman .
> > +.TP
> > +.BI "trim [ \-f ] [ \-a agno ] [ \-m minlen ] [" " offset length " ]
>
> Hm, this looks like -f / -a / offset/length are all optional, and not
> mutually exclusive.
>
> If this were in a SYNOPSIS section, it'd require 3 synopses I think.
>
> Perhaps here it should be:
>
> trim -f [ -m minlen ] [ offset length ]
> trim -a agno [ -m minlen ] [ offset length ]
> trim offset length [ -m minlen ]
>
> as 3 separate invocation methods?
Only problem is that if we add general options in the future we'll have
to add them to all three invocations.
trim ( -a agno | -f | offset length ) [ -m minlen ]
How about that instead?
>
> > +Instructs the underlying storage device to release all storage that may
> > +be backing free space in the filesystem.
> > +The
> > +.B -f
> > +option trims all free space in the entire filesystem.
> > +The
> > +.B -a
> > +option trims only the free space in a given AG.
> > +The
> > +.B -m
> > +option only trims free space extents that are longer than
> > +.IR minlen "."
>
> units? (suffixes?)
I'll add that.
> > +The
> > +.IR offset " and " length
> > +arguments trim all free space between
> > +.I offset
> > +and
> > +.IR "offset+length" "."
>
> Units?
and that.
--D
>
> > +The
> > +.BR -a " and " -f
> > +options are mutually exclusive with each other as well as with the
> > +.IR offset " and " length
> > +arguments.
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 10/10] xfs_spaceman: add group summary mode
2017-06-02 19:51 [PATCH v8 00/10] xfsprogs 4.12: GETFSMAP support Darrick J. Wong
` (8 preceding siblings ...)
2017-06-02 19:52 ` [PATCH 09/10] xfs_spaceman: add a man page Darrick J. Wong
@ 2017-06-02 19:52 ` Darrick J. Wong
2017-06-14 16:23 ` Eric Sandeen
9 siblings, 1 reply; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-02 19:52 UTC (permalink / raw)
To: sandeen, darrick.wong; +Cc: linux-xfs
From: Darrick J. Wong <darrick.wong@oracle.com>
Add a -g switch to show only a per-group summary.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
man/man8/xfs_spaceman.8 | 8 +++++++-
spaceman/freesp.c | 29 +++++++++++++++++++++++++----
2 files changed, 32 insertions(+), 5 deletions(-)
diff --git a/man/man8/xfs_spaceman.8 b/man/man8/xfs_spaceman.8
index c1d19c0..a57a0c3 100644
--- a/man/man8/xfs_spaceman.8
+++ b/man/man8/xfs_spaceman.8
@@ -25,7 +25,7 @@ then the program exits.
.SH COMMANDS
.TP
-.BI "freesp [ \-sr ] [ \-b | \-e bsize | \-h h1 [ \-m bmult ]] [-a agno]"
+.BI "freesp [ \-srg ] [ \-b | \-e bsize | \-h h1 [ \-m bmult ]] [-a agno]"
With no arguments,
.B freesp
shows a histogram of all free space extents in the filesystem.
@@ -49,6 +49,12 @@ option may be specified multiple times.
A summary of free space information will be printed if the
.B -s
option is given.
+The
+.B -g
+option prints a brief per-AG summary of the free space found in that AG.
+If
+.B -r
+is specified it will also report on free space in the realtime device.
.TP
.BR "help [ " command " ]"
Display a brief description of one or all commands.
diff --git a/spaceman/freesp.c b/spaceman/freesp.c
index 2290a5e..351f0ce 100644
--- a/spaceman/freesp.c
+++ b/spaceman/freesp.c
@@ -42,6 +42,7 @@ static int histcount;
static int multsize;
static int seen1;
static int summaryflag;
+static int gflag;
static bool rtflag;
static long long totblocks;
static long long totexts;
@@ -159,6 +160,8 @@ scan_ag(
off64_t bperag;
off64_t aglen;
xfs_agblock_t agbno;
+ unsigned long long freeblks = 0;
+ unsigned long long freeexts = 0;
int ret;
int i;
@@ -211,6 +214,8 @@ scan_ag(
agbno = (extent->fmr_physical - (bperag * agno)) /
blocksize;
aglen = extent->fmr_length / blocksize;
+ freeblks += aglen;
+ freeexts++;
addtohist(agno, agbno, aglen);
}
@@ -220,6 +225,15 @@ scan_ag(
break;
fsmap_advance(fsmap);
}
+
+ if (gflag) {
+ if (agno == NULLAGNUMBER)
+ printf(_(" rtdev %10llu %10llu\n"), freeexts,
+ freeblks);
+ else
+ printf(_("%10u %10llu %10llu\n"), agno, freeexts,
+ freeblks);
+ }
}
static void
aglistadd(
@@ -244,7 +258,7 @@ init(
aglist = NULL;
hist = NULL;
rtflag = false;
- while ((c = getopt(argc, argv, "a:bde:h:m:rs")) != EOF) {
+ while ((c = getopt(argc, argv, "a:bde:gh:m:rs")) != EOF) {
switch (c) {
case 'a':
aglistadd(optarg);
@@ -264,6 +278,10 @@ init(
equalsize = atoi(optarg);
speced = 1;
break;
+ case 'g':
+ histcount = 0;
+ gflag++;
+ break;
case 'h':
if (speced && !histcount)
return 0;
@@ -306,13 +324,15 @@ freesp_f(
if (!init(argc, argv))
return 0;
+ if (gflag)
+ printf(_(" AG extents blocks\n"));
if (rtflag)
scan_ag(NULLAGNUMBER);
for (agno = 0; !rtflag && agno < file->geom.agcount; agno++) {
if (inaglist(agno))
scan_ag(agno);
}
- if (histcount)
+ if (histcount && !gflag)
printhist();
if (summaryflag) {
printf(_("total free extents %lld\n"), totexts);
@@ -334,12 +354,13 @@ freesp_help(void)
"\n"
"Examine filesystem free space\n"
"\n"
-"Options: [-bdsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n"
+"Options: [-bdgsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n"
"\n"
" -a agno -- Scan only the given AG agno.\n"
" -b -- binary histogram bin size\n"
" -d -- debug output\n"
" -e bsize -- Use fixed histogram bin size of bsize\n"
+" -g -- Print only a per-AG summary.\n"
" -h hbsz -- Use custom histogram bin size of h1.\n"
" Multiple specifications are allowed.\n"
" -m bmult -- Use histogram bin size multiplier of bmult.\n"
@@ -357,7 +378,7 @@ freesp_init(void)
freesp_cmd.cfunc = freesp_f;
freesp_cmd.argmin = 0;
freesp_cmd.argmax = -1;
- freesp_cmd.args = "[-bdsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]";
+ freesp_cmd.args = "[-bdgsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]";
freesp_cmd.flags = CMD_FLAG_ONESHOT;
freesp_cmd.oneline = _("Examine filesystem free space");
freesp_cmd.help = freesp_help;
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 10/10] xfs_spaceman: add group summary mode
2017-06-02 19:52 ` [PATCH 10/10] xfs_spaceman: add group summary mode Darrick J. Wong
@ 2017-06-14 16:23 ` Eric Sandeen
2017-06-14 17:22 ` Darrick J. Wong
0 siblings, 1 reply; 29+ messages in thread
From: Eric Sandeen @ 2017-06-14 16:23 UTC (permalink / raw)
To: Darrick J. Wong, sandeen; +Cc: linux-xfs
On 6/2/17 2:52 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
>
> Add a -g switch to show only a per-group summary.
>
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
> man/man8/xfs_spaceman.8 | 8 +++++++-
> spaceman/freesp.c | 29 +++++++++++++++++++++++++----
> 2 files changed, 32 insertions(+), 5 deletions(-)
>
>
> diff --git a/man/man8/xfs_spaceman.8 b/man/man8/xfs_spaceman.8
> index c1d19c0..a57a0c3 100644
> --- a/man/man8/xfs_spaceman.8
> +++ b/man/man8/xfs_spaceman.8
> @@ -25,7 +25,7 @@ then the program exits.
>
> .SH COMMANDS
> .TP
> -.BI "freesp [ \-sr ] [ \-b | \-e bsize | \-h h1 [ \-m bmult ]] [-a agno]"
> +.BI "freesp [ \-srg ] [ \-b | \-e bsize | \-h h1 [ \-m bmult ]] [-a agno]"
> With no arguments,
> .B freesp
> shows a histogram of all free space extents in the filesystem.
> @@ -49,6 +49,12 @@ option may be specified multiple times.
> A summary of free space information will be printed if the
> .B -s
> option is given.
> +The
> +.B -g
> +option prints a brief per-AG summary of the free space found in that AG.
> +If
> +.B -r
> +is specified it will also report on free space in the realtime device.
If you're reworking patches, the -r switch doc should probably go in the manpage
patch, not here, but *shrug*
> .TP
> .BR "help [ " command " ]"
> Display a brief description of one or all commands.
> diff --git a/spaceman/freesp.c b/spaceman/freesp.c
> index 2290a5e..351f0ce 100644
> --- a/spaceman/freesp.c
> +++ b/spaceman/freesp.c
> @@ -42,6 +42,7 @@ static int histcount;
> static int multsize;
> static int seen1;
> static int summaryflag;
> +static int gflag;
> static bool rtflag;
> static long long totblocks;
> static long long totexts;
> @@ -159,6 +160,8 @@ scan_ag(
> off64_t bperag;
> off64_t aglen;
> xfs_agblock_t agbno;
> + unsigned long long freeblks = 0;
> + unsigned long long freeexts = 0;
> int ret;
> int i;
>
> @@ -211,6 +214,8 @@ scan_ag(
> agbno = (extent->fmr_physical - (bperag * agno)) /
> blocksize;
> aglen = extent->fmr_length / blocksize;
> + freeblks += aglen;
> + freeexts++;
>
> addtohist(agno, agbno, aglen);
> }
> @@ -220,6 +225,15 @@ scan_ag(
> break;
> fsmap_advance(fsmap);
> }
> +
> + if (gflag) {
> + if (agno == NULLAGNUMBER)
> + printf(_(" rtdev %10llu %10llu\n"), freeexts,
> + freeblks);
> + else
> + printf(_("%10u %10llu %10llu\n"), agno, freeexts,
> + freeblks);
> + }
ok so -g can be used with -a?
xfs_spaceman> freesp -g
AG extents blocks
0 2 65519
1 1 65527
2 1 62967
3 1 65527
xfs_spaceman> freesp -a 0
AG extents blocks
0 2 65519
xfs_spaceman> freesp -a 0 -g
AG extents blocks
0 2 65519
Ok, so I guess "-g" is the same as "-a" for each AG? Documenting it that
way might help.
Oh, wait, something is wrong here - global vars, danger danger?
xfs_spaceman> freesp
from to extents blocks pct
1 1 1 1 0.00
32768 65536 4 254826 100.00
xfs_spaceman> freesp -g
AG extents blocks
0 1 63479
1 2 62854
2 1 62967
3 1 65527
xfs_spaceman> freesp
AG extents blocks
0 1 63479
1 2 62854
2 1 62967
3 1 65527
*blink*
yeah, I think you need to set gflag = 0 in init().
(and scratch my earlier comment about histcount being init to zero so why
do it in init, now I see why) ;)
> }
> static void
> aglistadd(
> @@ -244,7 +258,7 @@ init(
> aglist = NULL;
> hist = NULL;
> rtflag = false;
> - while ((c = getopt(argc, argv, "a:bde:h:m:rs")) != EOF) {
> + while ((c = getopt(argc, argv, "a:bde:gh:m:rs")) != EOF) {
> switch (c) {
> case 'a':
> aglistadd(optarg);
> @@ -264,6 +278,10 @@ init(
> equalsize = atoi(optarg);
> speced = 1;
> break;
> + case 'g':
> + histcount = 0;
> + gflag++;
> + break;
> case 'h':
> if (speced && !histcount)
> return 0;
> @@ -306,13 +324,15 @@ freesp_f(
>
> if (!init(argc, argv))
> return 0;
> + if (gflag)
> + printf(_(" AG extents blocks\n"));
> if (rtflag)
> scan_ag(NULLAGNUMBER);
> for (agno = 0; !rtflag && agno < file->geom.agcount; agno++) {
> if (inaglist(agno))
> scan_ag(agno);
> }
> - if (histcount)
> + if (histcount && !gflag)
> printhist();
> if (summaryflag) {
> printf(_("total free extents %lld\n"), totexts);
> @@ -334,12 +354,13 @@ freesp_help(void)
> "\n"
> "Examine filesystem free space\n"
> "\n"
> -"Options: [-bdsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n"
> +"Options: [-bdgsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n"
(drop the options re-specification in the long help)
> "\n"
> " -a agno -- Scan only the given AG agno.\n"
> " -b -- binary histogram bin size\n"
> " -d -- debug output\n"
> " -e bsize -- Use fixed histogram bin size of bsize\n"
> +" -g -- Print only a per-AG summary.\n"
> " -h hbsz -- Use custom histogram bin size of h1.\n"
> " Multiple specifications are allowed.\n"
> " -m bmult -- Use histogram bin size multiplier of bmult.\n"
> @@ -357,7 +378,7 @@ freesp_init(void)
> freesp_cmd.cfunc = freesp_f;
> freesp_cmd.argmin = 0;
> freesp_cmd.argmax = -1;
> - freesp_cmd.args = "[-bdsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]";
> + freesp_cmd.args = "[-bdgsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]";
(make clear which ones are mutually exclusive)
> freesp_cmd.flags = CMD_FLAG_ONESHOT;
> freesp_cmd.oneline = _("Examine filesystem free space");
> freesp_cmd.help = freesp_help;
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 10/10] xfs_spaceman: add group summary mode
2017-06-14 16:23 ` Eric Sandeen
@ 2017-06-14 17:22 ` Darrick J. Wong
0 siblings, 0 replies; 29+ messages in thread
From: Darrick J. Wong @ 2017-06-14 17:22 UTC (permalink / raw)
To: Eric Sandeen; +Cc: sandeen, linux-xfs
On Wed, Jun 14, 2017 at 11:23:51AM -0500, Eric Sandeen wrote:
> On 6/2/17 2:52 PM, Darrick J. Wong wrote:
> > From: Darrick J. Wong <darrick.wong@oracle.com>
> >
> > Add a -g switch to show only a per-group summary.
> >
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> > man/man8/xfs_spaceman.8 | 8 +++++++-
> > spaceman/freesp.c | 29 +++++++++++++++++++++++++----
> > 2 files changed, 32 insertions(+), 5 deletions(-)
> >
> >
> > diff --git a/man/man8/xfs_spaceman.8 b/man/man8/xfs_spaceman.8
> > index c1d19c0..a57a0c3 100644
> > --- a/man/man8/xfs_spaceman.8
> > +++ b/man/man8/xfs_spaceman.8
> > @@ -25,7 +25,7 @@ then the program exits.
> >
> > .SH COMMANDS
> > .TP
> > -.BI "freesp [ \-sr ] [ \-b | \-e bsize | \-h h1 [ \-m bmult ]] [-a agno]"
> > +.BI "freesp [ \-srg ] [ \-b | \-e bsize | \-h h1 [ \-m bmult ]] [-a agno]"
> > With no arguments,
> > .B freesp
> > shows a histogram of all free space extents in the filesystem.
> > @@ -49,6 +49,12 @@ option may be specified multiple times.
> > A summary of free space information will be printed if the
> > .B -s
> > option is given.
> > +The
> > +.B -g
> > +option prints a brief per-AG summary of the free space found in that AG.
> > +If
> > +.B -r
> > +is specified it will also report on free space in the realtime device.
>
> If you're reworking patches, the -r switch doc should probably go in the manpage
> patch, not here, but *shrug*
<shrug> I was mostly re
>
> > .TP
> > .BR "help [ " command " ]"
> > Display a brief description of one or all commands.
> > diff --git a/spaceman/freesp.c b/spaceman/freesp.c
> > index 2290a5e..351f0ce 100644
> > --- a/spaceman/freesp.c
> > +++ b/spaceman/freesp.c
> > @@ -42,6 +42,7 @@ static int histcount;
> > static int multsize;
> > static int seen1;
> > static int summaryflag;
> > +static int gflag;
> > static bool rtflag;
> > static long long totblocks;
> > static long long totexts;
> > @@ -159,6 +160,8 @@ scan_ag(
> > off64_t bperag;
> > off64_t aglen;
> > xfs_agblock_t agbno;
> > + unsigned long long freeblks = 0;
> > + unsigned long long freeexts = 0;
> > int ret;
> > int i;
> >
> > @@ -211,6 +214,8 @@ scan_ag(
> > agbno = (extent->fmr_physical - (bperag * agno)) /
> > blocksize;
> > aglen = extent->fmr_length / blocksize;
> > + freeblks += aglen;
> > + freeexts++;
> >
> > addtohist(agno, agbno, aglen);
> > }
> > @@ -220,6 +225,15 @@ scan_ag(
> > break;
> > fsmap_advance(fsmap);
> > }
> > +
> > + if (gflag) {
> > + if (agno == NULLAGNUMBER)
> > + printf(_(" rtdev %10llu %10llu\n"), freeexts,
> > + freeblks);
> > + else
> > + printf(_("%10u %10llu %10llu\n"), agno, freeexts,
> > + freeblks);
> > + }
>
> ok so -g can be used with -a?
>
> xfs_spaceman> freesp -g
> AG extents blocks
> 0 2 65519
> 1 1 65527
> 2 1 62967
> 3 1 65527
> xfs_spaceman> freesp -a 0
> AG extents blocks
> 0 2 65519
> xfs_spaceman> freesp -a 0 -g
> AG extents blocks
> 0 2 65519
>
> Ok, so I guess "-g" is the same as "-a" for each AG? Documenting it that
> way might help.
Well, -g is "tell us about each AG individually" whereas the -a options
together mean "tell us about this specific subset of AGs".
We can make -g and -a mutually exclusive with each other.
> Oh, wait, something is wrong here - global vars, danger danger?
>
> xfs_spaceman> freesp
> from to extents blocks pct
> 1 1 1 1 0.00
> 32768 65536 4 254826 100.00
> xfs_spaceman> freesp -g
> AG extents blocks
> 0 1 63479
> 1 2 62854
> 2 1 62967
> 3 1 65527
> xfs_spaceman> freesp
> AG extents blocks
> 0 1 63479
> 1 2 62854
> 2 1 62967
> 3 1 65527
>
> *blink*
>
> yeah, I think you need to set gflag = 0 in init().
>
> (and scratch my earlier comment about histcount being init to zero so why
> do it in init, now I see why) ;)
Heh. Yeah, I noticed that when I was fiddling with the patches.
> > }
> > static void
> > aglistadd(
> > @@ -244,7 +258,7 @@ init(
> > aglist = NULL;
> > hist = NULL;
> > rtflag = false;
> > - while ((c = getopt(argc, argv, "a:bde:h:m:rs")) != EOF) {
> > + while ((c = getopt(argc, argv, "a:bde:gh:m:rs")) != EOF) {
> > switch (c) {
> > case 'a':
> > aglistadd(optarg);
> > @@ -264,6 +278,10 @@ init(
> > equalsize = atoi(optarg);
> > speced = 1;
> > break;
> > + case 'g':
> > + histcount = 0;
> > + gflag++;
> > + break;
> > case 'h':
> > if (speced && !histcount)
> > return 0;
> > @@ -306,13 +324,15 @@ freesp_f(
> >
> > if (!init(argc, argv))
> > return 0;
> > + if (gflag)
> > + printf(_(" AG extents blocks\n"));
> > if (rtflag)
> > scan_ag(NULLAGNUMBER);
> > for (agno = 0; !rtflag && agno < file->geom.agcount; agno++) {
> > if (inaglist(agno))
> > scan_ag(agno);
> > }
> > - if (histcount)
> > + if (histcount && !gflag)
> > printhist();
> > if (summaryflag) {
> > printf(_("total free extents %lld\n"), totexts);
> > @@ -334,12 +354,13 @@ freesp_help(void)
> > "\n"
> > "Examine filesystem free space\n"
> > "\n"
> > -"Options: [-bdsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n"
> > +"Options: [-bdgsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]\n"
>
> (drop the options re-specification in the long help)
Ok.
> > "\n"
> > " -a agno -- Scan only the given AG agno.\n"
>
> > " -b -- binary histogram bin size\n"
> > " -d -- debug output\n"
> > " -e bsize -- Use fixed histogram bin size of bsize\n"
> > +" -g -- Print only a per-AG summary.\n"
> > " -h hbsz -- Use custom histogram bin size of h1.\n"
> > " Multiple specifications are allowed.\n"
> > " -m bmult -- Use histogram bin size multiplier of bmult.\n"
> > @@ -357,7 +378,7 @@ freesp_init(void)
> > freesp_cmd.cfunc = freesp_f;
> > freesp_cmd.argmin = 0;
> > freesp_cmd.argmax = -1;
> > - freesp_cmd.args = "[-bdsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]";
> > + freesp_cmd.args = "[-bdgsr] [-a agno] [-e bsize] [-h h1]... [-m bmult]";
>
> (make clear which ones are mutually exclusive)
Ok.
--D
>
> > freesp_cmd.flags = CMD_FLAG_ONESHOT;
> > freesp_cmd.oneline = _("Examine filesystem free space");
> > freesp_cmd.help = freesp_help;
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 29+ messages in thread