diff mbox

[v3,2/4] btrfs-progs: introduce new send-dump object

Message ID 20161101080147.13163-3-quwenruo@cn.fujitsu.com (mailing list archive)
State Superseded
Headers show

Commit Message

Qu Wenruo Nov. 1, 2016, 8:01 a.m. UTC
Introduce send-dump.[ch] which implements a new btrfs_send_ops to
exam and output all operations inside a send stream.

It has a better output format than the old and no longer compilable
send-test tool, but still tries to be script friendly.

Provides the basis for later "inspect-internal dump-send" command.

Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Signed-off-by: David Sterba <dsterba@suse.com>
---
 Makefile.in |   2 +-
 send-dump.c | 299 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 send-dump.h |  29 ++++++
 3 files changed, 329 insertions(+), 1 deletion(-)
 create mode 100644 send-dump.c
 create mode 100644 send-dump.h

Comments

David Sterba Nov. 1, 2016, 10:22 a.m. UTC | #1
On Tue, Nov 01, 2016 at 04:01:44PM +0800, Qu Wenruo wrote:
> +/*
> + * Underlying PRINT_DUMP, the only difference is how we handle
> + * the full path.
> + */
> +static int __print_dump(int subvol, void *user, const char *path,
> +			const char *title, const char *fmt, ...)

printf-like the __attribute__ ((format (printf, ...)))

> +{
> +	struct btrfs_dump_send_args *r = user;
> +	char real_title[TITLE_WIDTH + 1] = { 0 };
> +	char full_path[PATH_MAX] = {0};
> +	char *out_path;
> +	va_list args;
> +	int ret;
> +
> +	if (subvol) {
> +		PATH_CAT_OR_RET(title, r->full_subvol_path, r->root_path, path, ret);
> +		out_path = r->full_subvol_path;
> +	} else {
> +		PATH_CAT_OR_RET(title, full_path, r->full_subvol_path, path, ret);
> +		out_path = full_path;
> +	}
> +	string_escape_inplace(out_path, " \n\t\\");
> +
> +	/* Append ':' to title */
> +	strncpy(real_title, title, TITLE_WIDTH - 1);
> +	strncat(real_title, ":", TITLE_WIDTH);

I'd rather avoid such string operations, ':', just print everything.

> +
> +	/* Unified header, */
> +	printf("%-*s%-*s", TITLE_WIDTH, real_title, PATH_WIDTH, out_path);

PATH_WIDTH is used only here, please hardcode it into the format string.

The rest of the patch looks good. I think I've seen some artifacts in
the output, but we can tune this later.

> +	ret = strftime(dest, max_size, "%Y-%m-%d %H:%M:%S", tm);

We should use the RFC 3339 format, as it's standardized and also is a
string without whitespace.
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Qu Wenruo Nov. 2, 2016, 12:37 a.m. UTC | #2
At 11/01/2016 06:22 PM, David Sterba wrote:
> On Tue, Nov 01, 2016 at 04:01:44PM +0800, Qu Wenruo wrote:
>> +/*
>> + * Underlying PRINT_DUMP, the only difference is how we handle
>> + * the full path.
>> + */
>> +static int __print_dump(int subvol, void *user, const char *path,
>> +			const char *title, const char *fmt, ...)
>
> printf-like the __attribute__ ((format (printf, ...)))
>
>> +{
>> +	struct btrfs_dump_send_args *r = user;
>> +	char real_title[TITLE_WIDTH + 1] = { 0 };
>> +	char full_path[PATH_MAX] = {0};
>> +	char *out_path;
>> +	va_list args;
>> +	int ret;
>> +
>> +	if (subvol) {
>> +		PATH_CAT_OR_RET(title, r->full_subvol_path, r->root_path, path, ret);
>> +		out_path = r->full_subvol_path;
>> +	} else {
>> +		PATH_CAT_OR_RET(title, full_path, r->full_subvol_path, path, ret);
>> +		out_path = full_path;
>> +	}
>> +	string_escape_inplace(out_path, " \n\t\\");
>> +
>> +	/* Append ':' to title */
>> +	strncpy(real_title, title, TITLE_WIDTH - 1);
>> +	strncat(real_title, ":", TITLE_WIDTH);
>
> I'd rather avoid such string operations, ':', just print everything.

I'm completely OK to remove the ':'.

>
>> +
>> +	/* Unified header, */
>> +	printf("%-*s%-*s", TITLE_WIDTH, real_title, PATH_WIDTH, out_path);
>
> PATH_WIDTH is used only here, please hardcode it into the format string.
>
> The rest of the patch looks good. I think I've seen some artifacts in
> the output, but we can tune this later.

Would you like to share the artifacts so I can handle them in next update?

>
>> +	ret = strftime(dest, max_size, "%Y-%m-%d %H:%M:%S", tm);
>
> We should use the RFC 3339 format, as it's standardized and also is a
> string without whitespace.

Will use RFC 3339 in next version.

Thanks,
Qu


--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Sterba Nov. 2, 2016, 10:52 a.m. UTC | #3
On Wed, Nov 02, 2016 at 08:37:20AM +0800, Qu Wenruo wrote:
> > PATH_WIDTH is used only here, please hardcode it into the format string.
> >
> > The rest of the patch looks good. I think I've seen some artifacts in
> > the output, but we can tune this later.
> 
> Would you like to share the artifacts so I can handle them in next update?

From the output of misc test 016:

snapshot: [...] parent_transid= 14
                               ^ extra space

set_xattr:      ./snap_creation/xattr_file      name=user.test, len=1
                                                              ^ comma

also set xattr does not print the attribute data.
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Qu Wenruo Nov. 3, 2016, 12:21 a.m. UTC | #4
At 11/02/2016 06:52 PM, David Sterba wrote:
> On Wed, Nov 02, 2016 at 08:37:20AM +0800, Qu Wenruo wrote:
>>> PATH_WIDTH is used only here, please hardcode it into the format string.
>>>
>>> The rest of the patch looks good. I think I've seen some artifacts in
>>> the output, but we can tune this later.
>>
>> Would you like to share the artifacts so I can handle them in next update?
>
> From the output of misc test 016:
>
> snapshot: [...] parent_transid= 14
>                                ^ extra space
>
> set_xattr:      ./snap_creation/xattr_file      name=user.test, len=1
>                                                               ^ comma
>
> also set xattr does not print the attribute data.

Thanks, I'll fix them.

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

Patch

diff --git a/Makefile.in b/Makefile.in
index b53cf2c..c535c19 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -93,7 +93,7 @@  objects = ctree.o disk-io.o kernel-lib/radix-tree.o extent-tree.o print-tree.o \
 	  extent-cache.o extent_io.o volumes.o utils.o repair.o \
 	  qgroup.o raid56.o free-space-cache.o kernel-lib/list_sort.o props.o \
 	  ulist.o qgroup-verify.o backref.o string-table.o task-utils.o \
-	  inode.o file.o find-root.o free-space-tree.o help.o
+	  inode.o file.o find-root.o free-space-tree.o help.o send-dump.o
 cmds_objects = cmds-subvolume.o cmds-filesystem.o cmds-device.o cmds-scrub.o \
 	       cmds-inspect.o cmds-balance.o cmds-send.o cmds-receive.o \
 	       cmds-quota.o cmds-qgroup.o cmds-replace.o cmds-check.o \
diff --git a/send-dump.c b/send-dump.c
new file mode 100644
index 0000000..b4d8a19
--- /dev/null
+++ b/send-dump.c
@@ -0,0 +1,299 @@ 
+/*
+ * Copyright (C) 2016 Fujitsu.  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 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.
+ */
+
+#include <unistd.h>
+#include <stdint.h>
+#include <dirent.h>
+#include <pthread.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <libgen.h>
+#include <mntent.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <time.h>
+#include <asm/types.h>
+#include <uuid/uuid.h>
+#include "utils.h"
+#include "commands.h"
+#include "send-utils.h"
+#include "send-stream.h"
+#include "send-dump.h"
+
+#define PATH_CAT_OR_RET(function_name, outpath, path1, path2, ret)	\
+({									\
+	ret = path_cat_out(outpath, path1, path2);			\
+	if (ret < 0) {							\
+		error("%s: path invalid: %s\n", function_name, path2);	\
+		return ret;						\
+	}								\
+})
+
+#define TITLE_WIDTH	16
+#define PATH_WIDTH	32
+
+/*
+ * Underlying PRINT_DUMP, the only difference is how we handle
+ * the full path.
+ */
+static int __print_dump(int subvol, void *user, const char *path,
+			const char *title, const char *fmt, ...)
+{
+	struct btrfs_dump_send_args *r = user;
+	char real_title[TITLE_WIDTH + 1] = { 0 };
+	char full_path[PATH_MAX] = {0};
+	char *out_path;
+	va_list args;
+	int ret;
+
+	if (subvol) {
+		PATH_CAT_OR_RET(title, r->full_subvol_path, r->root_path, path, ret);
+		out_path = r->full_subvol_path;
+	} else {
+		PATH_CAT_OR_RET(title, full_path, r->full_subvol_path, path, ret);
+		out_path = full_path;
+	}
+	string_escape_inplace(out_path, " \n\t\\");
+
+	/* Append ':' to title */
+	strncpy(real_title, title, TITLE_WIDTH - 1);
+	strncat(real_title, ":", TITLE_WIDTH);
+
+	/* Unified header, */
+	printf("%-*s%-*s", TITLE_WIDTH, real_title, PATH_WIDTH, out_path);
+	va_start(args, fmt);
+	/* Operation specified ones */
+	vprintf(fmt, args);
+	va_end(args);
+	printf("\n");
+	return 0;
+}
+
+/* For subvolume/snapshot operation only */
+#define PRINT_DUMP_SUBVOL(user, path, title, fmt, ...) \
+	__print_dump(1, user, path, title, fmt, ##__VA_ARGS__)
+
+/* For other operations */
+#define PRINT_DUMP(user, path, title, fmt, ...) \
+	__print_dump(0, user, path, title, fmt, ##__VA_ARGS__)
+
+static int print_subvol(const char *path, const u8 *uuid, u64 ctransid,
+			void *user)
+{
+	char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
+
+	uuid_unparse(uuid, uuid_str);
+
+	return PRINT_DUMP_SUBVOL(user, path, "subvol", "uuid=%s transid=%llu",
+				 uuid_str, ctransid);
+}
+
+static int print_snapshot(const char *path, const u8 *uuid, u64 ctransid,
+			  const u8 *parent_uuid, u64 parent_ctransid,
+			  void *user)
+{
+	char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
+	char parent_uuid_str[BTRFS_UUID_UNPARSED_SIZE];
+	int ret;
+
+	uuid_unparse(uuid, uuid_str);
+	uuid_unparse(parent_uuid, parent_uuid_str);
+
+	ret = PRINT_DUMP_SUBVOL(user, path, "snapshot",
+		"uuid=%s transid=%llu parent_uuid=%s parent_transid= %llu",
+				uuid_str, ctransid, parent_uuid_str,
+				parent_ctransid);
+	return ret;
+}
+
+static int print_mkfile(const char *path, void *user)
+{
+	return PRINT_DUMP(user, path, "mkfile", "");
+}
+
+static int print_mkdir(const char *path, void *user)
+{
+	return PRINT_DUMP(user, path, "mkdir", "");
+}
+
+static int print_mknod(const char *path, u64 mode, u64 dev, void *user)
+{
+	return PRINT_DUMP(user, path, "mknod", "mode=%llo dev=0x%llx", mode,
+			  dev);
+}
+
+static int print_mkfifo(const char *path, void *user)
+{
+	return PRINT_DUMP(user, path, "mkfifo", "");
+}
+
+static int print_mksock(const char *path, void *user)
+{
+	return PRINT_DUMP(user, path, "mksock", "");
+}
+
+static int print_symlink(const char *path, const char *lnk, void *user)
+{
+	return PRINT_DUMP(user, path, "symlink", "dest=%s", lnk);
+}
+
+static int print_rename(const char *from, const char *to, void *user)
+{
+	struct btrfs_dump_send_args *r = user;
+	char full_to[PATH_MAX];
+	int ret;
+
+	PATH_CAT_OR_RET("rename", full_to, r->full_subvol_path, to, ret);
+	return PRINT_DUMP(user, from, "rename", "dest=%s", full_to);
+}
+
+static int print_link(const char *path, const char *lnk, void *user)
+{
+	return PRINT_DUMP(user, path, "link", "dest=%s", lnk);
+}
+
+static int print_unlink(const char *path, void *user)
+{
+	return PRINT_DUMP(user, path, "unlink", "");
+}
+
+static int print_rmdir(const char *path, void *user)
+{
+	return PRINT_DUMP(user, path, "rmdir", "");
+}
+
+static int print_write(const char *path, const void *data, u64 offset,
+		       u64 len, void *user)
+{
+	return PRINT_DUMP(user, path, "write", "offset=%llu len=%llu",
+			  offset, len);
+}
+
+static int print_clone(const char *path, u64 offset, u64 len,
+		       const u8 *clone_uuid, u64 clone_ctransid,
+		       const char *clone_path, u64 clone_offset,
+		       void *user)
+{
+	struct btrfs_dump_send_args *r = user;
+	char full_path[PATH_MAX];
+	int ret;
+
+	PATH_CAT_OR_RET("clone", full_path, r->full_subvol_path, clone_path,
+			ret);
+	return PRINT_DUMP(user, path, "clone",
+			  "offset=%llu len=%llu from=%s clone_offset=%llu",
+			  offset, len, full_path, clone_offset);
+}
+
+static int print_set_xattr(const char *path, const char *name,
+			   const void *data, int len, void *user)
+{
+	return PRINT_DUMP(user, path, "set_xattr", "name=%s, len=%d",
+			  name, len);
+}
+
+static int print_remove_xattr(const char *path, const char *name, void *user)
+{
+
+	return PRINT_DUMP(user, path, "remove_xattr", "name=%s", name);
+}
+
+static int print_truncate(const char *path, u64 size, void *user)
+{
+	return PRINT_DUMP(user, path, "truncate", "size=%llu", size);
+}
+
+static int print_chmod(const char *path, u64 mode, void *user)
+{
+	return PRINT_DUMP(user, path, "chmod", "mode=%llo", mode);
+}
+
+static int print_chown(const char *path, u64 uid, u64 gid, void *user)
+{
+	return PRINT_DUMP(user, path, "chown", "gid=%llu uid=%llu", gid, uid);
+}
+
+static int sprint_timespec(struct timespec *ts, char *restrict dest, int max_size)
+{
+	struct tm *tm;
+	int ret;
+
+	tm = localtime(&ts->tv_sec);
+	if (!tm) {
+		error("failed to convert time %lld.%.9ld to local time",
+		      (long long)ts->tv_sec, ts->tv_nsec);
+		return -EINVAL;
+	}
+	ret = strftime(dest, max_size, "%Y-%m-%d %H:%M:%S", tm);
+	if (ret == 0) {
+		error(
+		"time %lld.%ld is too long to convert into readable string",
+		      (long long)ts->tv_sec, ts->tv_nsec);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+#define TIME_STRING_MAX	64
+static int print_utimes(const char *path, struct timespec *at,
+			struct timespec *mt, struct timespec *ct,
+			void *user)
+{
+	char at_str[TIME_STRING_MAX];
+	char mt_str[TIME_STRING_MAX];
+	char ct_str[TIME_STRING_MAX];
+
+	if (sprint_timespec(at, at_str, TIME_STRING_MAX - 1) < 0 ||
+	    sprint_timespec(mt, mt_str, TIME_STRING_MAX - 1) < 0 ||
+	    sprint_timespec(ct, ct_str, TIME_STRING_MAX - 1) < 0)
+		return -EINVAL;
+	return PRINT_DUMP(user, path, "utimes", "atime=%s mtime=%s ctime=%s",
+			  at_str, mt_str, ct_str);
+}
+
+static int print_update_extent(const char *path, u64 offset, u64 len,
+			       void *user)
+{
+	return PRINT_DUMP(user, path, "update_extent", "offset=%llu len=%llu",
+			  offset, len);
+}
+
+struct btrfs_send_ops btrfs_print_send_ops = {
+	.subvol = print_subvol,
+	.snapshot = print_snapshot,
+	.mkfile = print_mkfile,
+	.mkdir = print_mkdir,
+	.mknod = print_mknod,
+	.mkfifo = print_mkfifo,
+	.mksock = print_mksock,
+	.symlink = print_symlink,
+	.rename = print_rename,
+	.link = print_link,
+	.unlink = print_unlink,
+	.rmdir = print_rmdir,
+	.write = print_write,
+	.clone = print_clone,
+	.set_xattr = print_set_xattr,
+	.remove_xattr = print_remove_xattr,
+	.truncate = print_truncate,
+	.chmod = print_chmod,
+	.chown = print_chown,
+	.utimes = print_utimes,
+	.update_extent = print_update_extent
+};
diff --git a/send-dump.h b/send-dump.h
new file mode 100644
index 0000000..06a6108
--- /dev/null
+++ b/send-dump.h
@@ -0,0 +1,29 @@ 
+/*
+ * Copyright (C) 2016 Fujitsu.  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 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.
+ */
+
+#ifndef __BTRFS_SEND_DUMP_H__
+#define __BTRFS_SEND_DUMP_H__
+
+#include <linux/limits.h>
+
+struct btrfs_dump_send_args {
+	char full_subvol_path[PATH_MAX];
+	char root_path[PATH_MAX];
+};
+
+extern struct btrfs_send_ops btrfs_print_send_ops;
+
+#endif