From: Eric Biggers <ebiggers@kernel.org>
To: linux-f2fs-devel@lists.sourceforge.net, Jaegeuk Kim <jaegeuk@kernel.org>
Subject: [f2fs-dev] [PATCH 2/2] f2fs_io: add copy command
Date: Fri, 4 Oct 2019 15:43:17 -0700 [thread overview]
Message-ID: <20191004224317.153566-3-ebiggers@kernel.org> (raw)
In-Reply-To: <20191004224317.153566-1-ebiggers@kernel.org>
From: Eric Biggers <ebiggers@google.com>
Add a copy command to f2fs_io, to allow testing direct I/O writes where
the source page is from a different file (mmap) or an internal kernel
page (sendfile). It could be useful for other tests in the future too.
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
tools/f2fs_io/f2fs_io.c | 108 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 108 insertions(+)
diff --git a/tools/f2fs_io/f2fs_io.c b/tools/f2fs_io/f2fs_io.c
index f5493ff..0d90835 100644
--- a/tools/f2fs_io/f2fs_io.c
+++ b/tools/f2fs_io/f2fs_io.c
@@ -21,7 +21,9 @@
#include <errno.h>
#include <fcntl.h>
+#include <getopt.h>
#include <inttypes.h>
+#include <limits.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
@@ -29,6 +31,8 @@
#include <stdlib.h>
#include <string.h>
#include <string.h>
+#include <sys/mman.h>
+#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <termios.h>
@@ -105,6 +109,27 @@ static int xopen(const char *pathname, int flags, mode_t mode)
return fd;
}
+static ssize_t xread(int fd, void *buf, size_t count)
+{
+ ssize_t ret = read(fd, buf, count);
+
+ if (ret < 0)
+ die_errno("read failed");
+ return ret;
+}
+
+static void full_write(int fd, const void *buf, size_t count)
+{
+ while (count) {
+ ssize_t ret = write(fd, buf, count);
+
+ if (ret < 0)
+ die_errno("write failed");
+ buf = (char *)buf + ret;
+ count -= ret;
+ }
+}
+
#define getflags_desc "getflags ioctl"
#define getflags_help \
"f2fs_io getflags [file]\n\n" \
@@ -563,6 +588,88 @@ static void do_defrag_file(int argc, char **argv, const struct cmd_desc *cmd)
exit(0);
}
+#define copy_desc "copy a file"
+#define copy_help \
+"f2fs_io copy [-d] [-m] [-s] src_path dst_path\n\n" \
+" src_path : path to source file\n" \
+" dst_path : path to destination file\n" \
+" -d : use direct I/O\n" \
+" -m : mmap the source file\n" \
+" -s : use sendfile\n" \
+
+static void do_copy(int argc, char **argv, const struct cmd_desc *cmd)
+{
+ int c;
+ int src_fd;
+ int dst_fd;
+ int open_flags = 0;
+ bool mmap_source_file = false;
+ bool use_sendfile = false;
+ ssize_t ret;
+
+ while ((c = getopt(argc, argv, "dms")) != -1) {
+ switch (c) {
+ case 'd':
+ open_flags |= O_DIRECT;
+ break;
+ case 'm':
+ mmap_source_file = true;
+ break;
+ case 's':
+ use_sendfile = true;
+ break;
+ default:
+ fputs(cmd->cmd_help, stderr);
+ exit(2);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc != 2) {
+ fputs("Wrong number of arguments\n\n", stderr);
+ fputs(cmd->cmd_help, stderr);
+ exit(2);
+ }
+ if (mmap_source_file && use_sendfile)
+ die("-m and -s are mutually exclusive");
+
+ src_fd = xopen(argv[0], O_RDONLY | open_flags, 0);
+ dst_fd = xopen(argv[1], O_WRONLY | O_CREAT | O_TRUNC | open_flags, 0644);
+
+ if (mmap_source_file) {
+ struct stat stbuf;
+ void *src_addr;
+
+ if (fstat(src_fd, &stbuf) != 0)
+ die_errno("fstat of source file failed");
+
+ if ((size_t)stbuf.st_size != stbuf.st_size)
+ die("Source file is too large");
+
+ src_addr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_SHARED,
+ src_fd, 0);
+ if (src_addr == MAP_FAILED)
+ die("mmap of source file failed");
+
+ full_write(dst_fd, src_addr, stbuf.st_size);
+
+ munmap(src_addr, stbuf.st_size);
+ } else if (use_sendfile) {
+ while ((ret = sendfile(dst_fd, src_fd, NULL, INT_MAX)) > 0)
+ ;
+ if (ret < 0)
+ die_errno("sendfile failed");
+ } else {
+ char *buf = aligned_xalloc(4096, 4096);
+
+ while ((ret = xread(src_fd, buf, 4096)) > 0)
+ full_write(dst_fd, buf, ret);
+ free(buf);
+ }
+ close(src_fd);
+ close(dst_fd);
+}
+
#define CMD_HIDDEN 0x0001
#define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 }
@@ -581,6 +688,7 @@ const struct cmd_desc cmd_list[] = {
CMD(fiemap),
CMD(gc_urgent),
CMD(defrag_file),
+ CMD(copy),
{ NULL, NULL, NULL, NULL, 0 }
};
--
2.23.0.581.g78d2f28ef7-goog
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
prev parent reply other threads:[~2019-10-04 22:45 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-10-04 22:43 [f2fs-dev] [PATCH 0/2] f2fs-tools: add 'copy' command to f2fs_io Eric Biggers
2019-10-04 22:43 ` [f2fs-dev] [PATCH 1/2] f2fs_io: add helper functions for handling errors Eric Biggers
2019-10-15 7:03 ` Chao Yu
2019-10-04 22:43 ` Eric Biggers [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=20191004224317.153566-3-ebiggers@kernel.org \
--to=ebiggers@kernel.org \
--cc=jaegeuk@kernel.org \
--cc=linux-f2fs-devel@lists.sourceforge.net \
/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).