diff options
author | Raghavendra Bhat <raghavendra@redhat.com> | 2018-11-06 15:27:31 -0500 |
---|---|---|
committer | Amar Tumballi <amarts@redhat.com> | 2018-12-12 15:56:55 +0000 |
commit | 7dadea15c58eb92e5f5727190bf9446dd6fe7a3c (patch) | |
tree | 4ced04de0219407604f30b1663b586f16b54dd06 /tests/basic/gfapi | |
parent | 5c723ade196600030ee84621384cceb10fff64d8 (diff) |
copy_file_range support in GlusterFS
* libglusterfs changes to add new fop
* Fuse changes:
- Changes in fuse bridge xlator to receive and send responses
* posix changes to perform the op on the backend filesystem
* protocol and rpc changes for sending and receiving the fop
* gfapi changes for performing the fop
* tools: glfs-copy-file-range tool for testing copy_file_range fop
- Although, copy_file_range support has been added to the upstream
fuse kernel module, no release has been made yet of a kernel
which contains the support. It is expected to come in the
upcoming release of linux-4.20
So, as of now, executing copy_file_range fop on a fused based
filesystem results in fuse kernel module sending read on the
source fd and write on the destination fd.
Therefore a small gfapi based tool has been written to be able
test the copy_file_range fop. This tool is similar (in functionality)
to the example program given in copy_file_range man page.
So, running regular copy_file_range on a fuse mount point and
running gfapi based glfs-copy-file-range tool gives some idea about
how fast, the copy_file_range (or reflink) can be.
On the local machine this was the result obtained.
mount -t glusterfs workstation:new /mnt/glusterfs
[root@workstation ~]# cd /mnt/glusterfs/
[root@workstation glusterfs]# ls
file
[root@workstation glusterfs]# cd
[root@workstation ~]# time /tmp/a.out /mnt/glusterfs/file /mnt/glusterfs/new
real 0m6.495s
user 0m0.000s
sys 0m1.439s
[root@workstation ~]# time glfs-copy-file-range $(hostname) new /tmp/glfs.log /file /rrr
OPEN_SRC: opening /file is success
OPEN_DST: opening /rrr is success
FSTAT_SRC: fstat on /rrr is success
copy_file_range successful
real 0m0.309s
user 0m0.039s
sys 0m0.017s
This tool needs following arguments
1) hostname
2) volume name
3) log file path
4) source file path (relative to the gluster volume root)
5) destination file path (relative to the gluster volume root)
"glfs-copy-file-range <hostname> <volume> <log file path> <source> <destination>"
- Added a testcase as well to run glfs-copy-file-range tool
* io-stats changes to capture the fop for profiling
* NOTE:
- Added conditional check to see whether the copy_file_range syscall
is available or not. If not, then return ENOSYS.
- Added conditional check for kernel minor version in fuse_kernel.h
and fuse-bridge while referring to copy_file_range. And the kernel
minor version is kept as it is. i.e. 24. Increment it in future
when there is a kernel release which contains the support for
copy_file_range fop in fuse kernel module.
* The document which contains a writeup on this enhancement can be found at
https://docs.google.com/document/d/1BSILbXr_knynNwxSyyu503JoTz5QFM_4suNIh2WwrSc/edit
Change-Id: I280069c814dd21ce6ec3be00a884fc24ab692367
updates: #536
Signed-off-by: Raghavendra Bhat <raghavendra@redhat.com>
Diffstat (limited to 'tests/basic/gfapi')
-rw-r--r-- | tests/basic/gfapi/gfapi-copy-file-range.t | 80 | ||||
-rw-r--r-- | tests/basic/gfapi/glfs-copy-file-range.c | 177 |
2 files changed, 257 insertions, 0 deletions
diff --git a/tests/basic/gfapi/gfapi-copy-file-range.t b/tests/basic/gfapi/gfapi-copy-file-range.t new file mode 100644 index 00000000000..c24c1433edf --- /dev/null +++ b/tests/basic/gfapi/gfapi-copy-file-range.t @@ -0,0 +1,80 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +# for now, a xfs filesystem with reflink support is created. +# In future, better to make changes in MKFS_LOOP so that, +# once can create a xfs filesystem with reflink enabled in +# generic and simple way, instead of doing below steps each +# time. +TEST truncate -s 2G $B0/xfs_image +mkfs.xfs 2>&1 | grep reflink +if [ $? -eq 0 ]; then + mkfs.xfs -f -i size=512 -m reflink=1 $B0/xfs_image; +else + mkfs.xfs -f -i size=512 $B0/xfs_image; +fi + +TEST mkdir $B0/bricks +TEST mount -t xfs -o loop $B0/xfs_image $B0/bricks + +# Just a single brick volume. More test cases need to be +# added in future for distribute, replicate, +# distributed replicate and distributed replicated sharded +# volumes. +TEST $CLI volume create $V0 $H0:$B0/bricks/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 + +TEST dd if=/dev/urandom of=$M0/file bs=1M count=555; + +# check for the existence of the created file +TEST stat $M0/file; + +# grab the size of the file +SRC_SIZE=$(stat -c %s $M0/file); + +logdir=`gluster --print-logdir` + +# TODO: +# For now, do not call copy-file-range utility. This is because, +# the regression machines are centos-7 based which does not have +# copy_file_range API available. So, instead of this testcase +# causing regression failures, for now, this is just a dummy test +# case. Uncomment the below tests (until volume stop) when there +# is support for copy_file_range in the regression machines. +# + +TEST build_tester $(dirname $0)/glfs-copy-file-range.c -lgfapi + +TEST ./$(dirname $0)/glfs-copy-file-range $H0 $V0 $logdir/gfapi-copy-file-range.log /file /new + +# check whether the destination file is created or not +TEST stat $M0/new + +# check the size of the destination file +DST_SIZE=$(stat -c %s $M0/new); + +# The sizes of the source and destination should be same. +# Atleast it ensures that, copy_file_range API is working +# as expected. Whether the actual cloning happened via reflink +# or a read/write happened is different matter. +TEST [ $SRC_SIZE == $DST_SIZE ]; + +cleanup_tester $(dirname $0)/glfs-copy-file-range + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +UMOUNT_LOOP $B0/bricks; + +cleanup; diff --git a/tests/basic/gfapi/glfs-copy-file-range.c b/tests/basic/gfapi/glfs-copy-file-range.c new file mode 100644 index 00000000000..756c38d21ec --- /dev/null +++ b/tests/basic/gfapi/glfs-copy-file-range.c @@ -0,0 +1,177 @@ +/* + Copyright (c) 2018 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> +#include <string.h> +#include <time.h> +#include <libgen.h> + +static void +cleanup(glfs_t *fs) +{ + if (!fs) + return; +#if 0 + /* glfs fini path is still racy and crashing the program. Since + * this program any way has to die, we are not going to call fini + * in the released versions. i.e. final builds. For all + * internal testing lets enable this so that glfs_fini code + * path becomes stable. */ + glfs_fini (fs); +#endif +} + +int +main(int argc, char **argv) +{ + glfs_t *fs = NULL; + int ret = -1; + char *volname = NULL; + char *logfilepath = NULL; + char *path_src = NULL; + char *path_dst = NULL; + glfs_fd_t *glfd_in = NULL; + glfs_fd_t *glfd_out = NULL; + char *volfile_server = NULL; + + struct stat stbuf = { + 0, + }; + struct stat prestat_dst = { + 0, + }; + struct stat poststat_dst = { + 0, + }; + size_t len; + + if (argc < 6) { + printf("%s <volume> <log file path> <source> <destination>", argv[0]); + ret = -1; + goto out; + } + + volfile_server = argv[1]; + volname = argv[2]; + logfilepath = argv[3]; + path_src = argv[4]; + path_dst = argv[5]; + + if (path_src[0] != '/') { + fprintf(stderr, "source path %s is not absolute", path_src); + errno = EINVAL; + goto out; + } + + if (path_dst[0] != '/') { + fprintf(stderr, "destination path %s is not absolute", path_dst); + errno = EINVAL; + goto out; + } + + fs = glfs_new(volname); + if (!fs) { + ret = -errno; + fprintf(stderr, "Not able to initialize volume '%s'", volname); + goto out; + } + + ret = glfs_set_volfile_server(fs, "tcp", volfile_server, 24007); + if (ret < 0) { + ret = -errno; + fprintf(stderr, + "Failed to set the volfile server, " + "%s", + strerror(errno)); + goto out; + } + + ret = glfs_set_logging(fs, logfilepath, 7); + if (ret < 0) { + ret = -errno; + fprintf(stderr, + "Failed to set the log file path, " + "%s", + strerror(errno)); + goto out; + } + + ret = glfs_init(fs); + if (ret < 0) { + ret = -errno; + if (errno == ENOENT) { + fprintf(stderr, "Volume %s does not exist", volname); + } else { + fprintf(stderr, + "%s: Not able to fetch " + "volfile from glusterd", + volname); + } + goto out; + } + + glfd_in = glfs_open(fs, path_src, O_RDONLY | O_NONBLOCK); + if (!glfd_in) { + ret = -errno; + goto out; + } else { + printf("OPEN_SRC: opening %s is success\n", path_src); + } + + glfd_out = glfs_creat(fs, path_dst, O_RDWR, 0644); + if (!glfd_out) { + fprintf(stderr, + "FAILED_DST_OPEN: failed to " + "open (create) %s (%s)\n", + path_dst, strerror(errno)); + ret = -errno; + goto out; + } else { + printf("OPEN_DST: opening %s is success\n", path_dst); + } + + ret = glfs_fstat(glfd_in, &stbuf); + if (ret < 0) { + ret = -errno; + goto out; + } else { + printf("FSTAT_SRC: fstat on %s is success\n", path_dst); + } + + len = stbuf.st_size; + + do { + ret = glfs_copy_file_range(glfd_in, NULL, glfd_out, NULL, len, 0, + &stbuf, &prestat_dst, &poststat_dst); + if (ret == -1) { + fprintf(stderr, "copy_file_range failed with %s\n", + strerror(errno)); + ret = -errno; + break; + } else { + printf("copy_file_range successful\n"); + len -= ret; + } + } while (len > 0); + +out: + if (glfd_in) + glfs_close(glfd_in); + if (glfd_out) + glfs_close(glfd_out); + + cleanup(fs); + + return ret; +} |