linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sidong Yang <realwakka@gmail.com>
To: linux-btrfs <linux-btrfs@vger.kernel.org>,
	David Sterba <dsterba@suse.cz>,
	Qu Wenruo <quwenruo.btrfs@gmx.com>
Cc: Sidong Yang <realwakka@gmail.com>
Subject: [PATCH v5 2/2] btrfs-progs: cmds: Add subcommand that dumps file extents
Date: Sun, 22 Aug 2021 15:01:40 +0000	[thread overview]
Message-ID: <20210822150140.44152-3-realwakka@gmail.com> (raw)
In-Reply-To: <20210822150140.44152-1-realwakka@gmail.com>

This patch adds an subcommand in inspect-internal. It dumps file extents of
the file that user provided. It helps to show the internal information
about file extents comprise the file. It supports json format by using
formatted printing. An example is below.

{
  "__header": {
    "version": "1"
  },
  "file-extents": [
    {
      "start": "0",
      "disk_bytenr": "21651456",
      "disk_num_bytes": "4096",
      "offset": "0",
      "len": "65536",
      "compression": "zstd",
      "type": "regular"
    },
    {
      "start": "65536",
      "len": "131072",
      "compression": "none",
      "type": "hole"
    }
  ]
}

Signed-off-by: Sidong Yang <realwakka@gmail.com>
---
 Makefile                         |   2 +-
 cmds/commands.h                  |   2 +-
 cmds/inspect-dump-file-extents.c | 161 +++++++++++++++++++++++++++++++
 cmds/inspect.c                   |   1 +
 4 files changed, 164 insertions(+), 2 deletions(-)
 create mode 100644 cmds/inspect-dump-file-extents.c

diff --git a/Makefile b/Makefile
index a1cc457b..911e16de 100644
--- a/Makefile
+++ b/Makefile
@@ -156,7 +156,7 @@ cmds_objects = cmds/subvolume.o cmds/filesystem.o cmds/device.o cmds/scrub.o \
 	       cmds/restore.o cmds/rescue.o cmds/rescue-chunk-recover.o \
 	       cmds/rescue-super-recover.o \
 	       cmds/property.o cmds/filesystem-usage.o cmds/inspect-dump-tree.o \
-	       cmds/inspect-dump-super.o cmds/inspect-tree-stats.o cmds/filesystem-du.o \
+	       cmds/inspect-dump-super.o cmds/inspect-tree-stats.o cmds/inspect-dump-file-extents.o cmds/filesystem-du.o \
 	       mkfs/common.o check/mode-common.o check/mode-lowmem.o
 libbtrfs_objects = common/send-stream.o common/send-utils.o kernel-lib/rbtree.o btrfs-list.o \
 		   kernel-lib/radix-tree.o common/extent-cache.o kernel-shared/extent_io.o \
diff --git a/cmds/commands.h b/cmds/commands.h
index 8fa85d6c..55de248e 100644
--- a/cmds/commands.h
+++ b/cmds/commands.h
@@ -154,5 +154,5 @@ DECLARE_COMMAND(select_super);
 DECLARE_COMMAND(dump_super);
 DECLARE_COMMAND(debug_tree);
 DECLARE_COMMAND(rescue);
-
+DECLARE_COMMAND(inspect_dump_file_extents);
 #endif
diff --git a/cmds/inspect-dump-file-extents.c b/cmds/inspect-dump-file-extents.c
new file mode 100644
index 00000000..5f5469a3
--- /dev/null
+++ b/cmds/inspect-dump-file-extents.c
@@ -0,0 +1,161 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will 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 to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#include <sys/ioctl.h>
+
+#include "common/utils.h"
+#include "common/format-output.h"
+#include "cmds/commands.h"
+#include "kernel-shared/print-tree.h"
+
+static const char * const cmd_inspect_dump_file_extents_usage[] = {
+	"btrfs inspect-internal dump-extent path",
+	"Dump file extent in a textual form",
+	NULL
+};
+
+static const struct rowspec dump_file_extents_rowspec[] = {
+	{ .key = "device", .fmt = "%s", .out_text = "device", .out_json = "device" },
+	{ .key = "type", .fmt = "%s", .out_text = "type", .out_json = "type" },
+	{ .key = "start", .fmt = "%u", .out_text = "start", .out_json = "start" },
+	{ .key = "len", .fmt = "%u", .out_text = "len", .out_json = "len" },
+	{ .key = "disk_bytenr", .fmt = "%u", .out_text = "disk_bytenr", .out_json = "disk_bytenr" },
+	{ .key = "disk_num_bytes", .fmt = "%u", .out_text = "disk_num_bytes", .out_json = "disk_num_bytes" },
+	{ .key = "offset", .fmt = "%u", .out_text = "offset", .out_json = "offset" },
+	{ .key = "compression", .fmt = "%s", .out_text = "compression", .out_json = "compression" },
+	ROWSPEC_END
+};
+
+static int cmd_inspect_dump_file_extents(const struct cmd_struct *cmd,
+										 int argc, char **argv)
+{
+	int fd;
+	struct stat statbuf;
+	struct btrfs_ioctl_ino_lookup_args lookup;
+	struct btrfs_ioctl_search_args args;
+	struct btrfs_ioctl_search_key *sk = &args.key;
+	struct btrfs_file_extent_item *extent_item;
+	struct btrfs_ioctl_search_header *header;
+	u64 start, buf_off;
+	int ret, i;
+
+	struct format_ctx fctx;
+
+	fd = open(argv[optind], O_RDONLY);
+	if (fd < 0) {
+		error("cannot open %s: %m", argv[optind]);
+		ret = 1;
+		goto out;
+	}
+
+	if (fstat(fd, &statbuf) < 0) {
+		error("failed to fstat %s: %m", argv[optind]);
+		ret = 1;
+		goto out;
+	}
+
+	lookup.treeid = 0;
+	lookup.objectid = BTRFS_FIRST_FREE_OBJECTID;
+
+	if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &lookup) < 0) {
+		error("failed to lookup inode %s: %m", argv[optind]);
+		ret = 1;
+		goto out;
+	}
+
+	sk->tree_id = lookup.treeid;
+	sk->min_objectid = statbuf.st_ino;
+	sk->max_objectid = statbuf.st_ino;
+	sk->min_offset = 0;
+	sk->max_offset = UINT64_MAX;
+	sk->min_transid = 0;
+	sk->max_transid = UINT64_MAX;
+	sk->min_type = sk->max_type = BTRFS_EXTENT_DATA_KEY;
+	sk->nr_items = UINT32_MAX;
+
+again:
+	if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args)) {
+		error("failed to search tree ioctl %s: %m", argv[optind]);
+		ret = 1;
+		goto out;
+	}
+
+	buf_off = 0;
+	fmt_start(&fctx, dump_file_extents_rowspec, 24, 0);
+	fmt_print_start_group(&fctx, "file-extents", JSON_TYPE_ARRAY);
+	for(i=0; i<sk->nr_items; ++i) {
+		header = (struct btrfs_ioctl_search_header *)(args.buf + buf_off);
+
+		if (btrfs_search_header_type(header) == BTRFS_EXTENT_DATA_KEY) {
+			u64 len, disk_bytenr, disk_num_bytes, offset;
+			const char *type_str;
+			char compress_str[BTRFS_COMPRESS_STR_LEN];
+
+			extent_item = (struct btrfs_file_extent_item *)(header + 1);
+			fmt_print_start_group(&fctx, NULL, JSON_TYPE_MAP);
+
+			start = btrfs_search_header_offset(header);
+			fmt_print(&fctx, "start", start);
+			type_str = btrfs_file_extent_type_to_str(extent_item->type);
+			btrfs_compress_type_to_str(extent_item->compression, compress_str);
+
+			switch (extent_item->type) {
+			case BTRFS_FILE_EXTENT_INLINE:
+				len = le64_to_cpu(extent_item->ram_bytes);
+				break;
+			case BTRFS_FILE_EXTENT_REG:
+			case BTRFS_FILE_EXTENT_PREALLOC:
+				len = le64_to_cpu(extent_item->num_bytes);
+				disk_bytenr = le64_to_cpu(extent_item->disk_bytenr);
+				if (disk_bytenr) {
+					disk_num_bytes = le64_to_cpu(extent_item->disk_num_bytes);
+					offset = le64_to_cpu(extent_item->offset);
+					fmt_print(&fctx, "disk_bytenr", disk_bytenr);
+					fmt_print(&fctx, "disk_num_bytes", disk_num_bytes);
+					fmt_print(&fctx, "offset", offset);
+
+				} else {
+					type_str = "hole";
+				}
+				break;
+			}
+
+			fmt_print(&fctx, "len", len);
+			fmt_print(&fctx, "compression", compress_str);
+			fmt_print(&fctx, "type", type_str);
+			fmt_print_end_group(&fctx, NULL);
+		}
+		buf_off += sizeof(*header) + btrfs_search_header_len(header);
+	}
+	fmt_print_end_group(&fctx, "file-extents");
+	fmt_end(&fctx);
+
+	if (sk->nr_items > 512) {
+		sk->nr_items = UINT32_MAX;
+		sk->min_offset = start + 1;
+		goto again;
+	}
+	ret = 0;
+out:
+	close(fd);
+	return ret;
+}
+
+DEFINE_COMMAND_WITH_FLAGS(inspect_dump_file_extents, "dump-file-extents", CMD_FORMAT_JSON);
diff --git a/cmds/inspect.c b/cmds/inspect.c
index 2ef5f4b6..dfb0e27b 100644
--- a/cmds/inspect.c
+++ b/cmds/inspect.c
@@ -696,6 +696,7 @@ static const struct cmd_group inspect_cmd_group = {
 		&cmd_struct_inspect_dump_tree,
 		&cmd_struct_inspect_dump_super,
 		&cmd_struct_inspect_tree_stats,
+		&cmd_struct_inspect_dump_file_extents,
 		NULL
 	}
 };
-- 
2.25.1


      parent reply	other threads:[~2021-08-22 15:02 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-22 15:01 [RFC PATCH v5 0/2] Add subcommand that dumps file extents Sidong Yang
2021-08-22 15:01 ` [PATCH v5 1/2] btrfs-progs: export util functions about file extent items Sidong Yang
2021-08-22 15:01 ` Sidong Yang [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210822150140.44152-3-realwakka@gmail.com \
    --to=realwakka@gmail.com \
    --cc=dsterba@suse.cz \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=quwenruo.btrfs@gmx.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).