Skip to content

Commit

Permalink
A big blob of preliminary experimenting in BRT support on Linux
Browse files Browse the repository at this point in the history
Signed-off-by: Rich Ercolani <rincebrain@gmail.com>
  • Loading branch information
rincebrain committed Mar 11, 2023
1 parent b15ab50 commit fd21c46
Show file tree
Hide file tree
Showing 10 changed files with 467 additions and 1 deletion.
1 change: 1 addition & 0 deletions cmd/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ include $(srcdir)/%D%/zinject/Makefile.am
include $(srcdir)/%D%/zpool/Makefile.am
include $(srcdir)/%D%/zpool_influxdb/Makefile.am
include $(srcdir)/%D%/zstream/Makefile.am
include $(srcdir)/%D%/clonefile/Makefile.am


if BUILD_LINUX
Expand Down
15 changes: 15 additions & 0 deletions cmd/clonefile/Makefile.am
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
clonefile_CPPFLAGS = $(AM_CPPFLAGS) -Wno-error
clonefile_CFLAGS = $(AM_CFLAGS) -Wno-error

sbin_PROGRAMS += clonefile

clonefile_SOURCES = %D%/clonefile.c

clonefile_LDADD = \
libzpool.la \
libzfs_core.la \
libnvpair.la


#zdb_LDADD

236 changes: 236 additions & 0 deletions cmd/clonefile/clonefile.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2022 Pawel Jakub Dawidek <pawel@dawidek.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#include <sys/types.h>
#include <sys/ioctl.h>
#ifdef __FreeBSD__
#include <sys/module.h>
#endif
#include <libnvpair.h>

#include <sys/stat.h>
#include <sys/syscall.h>

#include <sys/fs/zfs.h>
#include <libzfs_core.h>

#include <err.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#if defined(__FreeBSD__)
static int sys_fclonefile;

static void
register_syscall(void)
{
struct module_stat stat;
int modid;

stat.version = sizeof(stat);
if ((modid = modfind("sys/fclonefile")) == -1)
err(1, "modfind");
if (modstat(modid, &stat) != 0)
err(1, "modstat");
sys_fclonefile = stat.data.intval;
}

static ssize_t
fclonefile(int srcfd, int dstfd)
{

return (__syscall(sys_fclonefile, (int64_t)srcfd, (int64_t)dstfd));
}
//#elsif defined(__linux__)
#else
#if 0
typedef struct fclonefile_args {
uint64_t srcfd;
uint64_t dstfd;
loff_t src_off;
loff_t dst_off;
ssize_t len;
} fclonefile_args_t;
#endif

static ssize_t fclonefile(int srcfd, int dstfd, ssize_t srcsz) {
return copy_file_range(srcfd, NULL, dstfd, NULL, srcsz, 0);

}

#if 0
static ssize_t
fclonefile(char* srcpath, char* dstpath) {
#if 0
fclonefile_args_t args;
args.srcfd = srcfd;
args.dstfd = dstfd;
args.src_off = 0;
args.dst_off = 0;
args.len = 0;
#endif
(void) libzfs_core_init();
int err = 0;
// fnvlist_add_int32(innvl, "srcfd", srcfd);
// fnvlist_add_int32(innvl, "dstfd", dstfd);
err = lzc_clonefile(srcpath,dstpath,0,0,0);
if (err == 0) {
printf("we did it!\n");
return(0);
}
libzfs_core_fini();
return(err);
}
#endif
#endif
static void
usage(const char *progname)
{

errx(1, "usage: %s [-f] <srcfile> <dstfile>", progname);
}

int
main(int argc, char *argv[])
{
struct stat sb,db;
const char *progname, *srcfile, *dstfile;
int srcfd, dstfd, flags;
ssize_t done = 0;
bool force;

progname = argv[0];

if (argc == 4 && strcmp(argv[1], "-f") == 0) {
force = true;
argv++;
argc--;
} else {
force = false;
}
if (argc != 3) {
usage(progname);
}

srcfile = argv[1];
dstfile = argv[2];

#if defined(__FreeBSD__)
register_syscall();

srcfd = open(srcfile, O_RDONLY);
if (srcfd < 0) {
err(1, "open(%s) failed", srcfile);
}

flags = O_WRONLY | O_CREAT;
if (force) {
flags |= O_TRUNC;
} else {
flags |= O_EXCL;
}
dstfd = open(dstfile, flags, 0644);
if (dstfd < 0) {
err(1, "open(%s) failed", dstfile);
}

done = fclonefile(srcfd, dstfd);
//#elsif defined(__linux__)
#else
#if 0
// libzfs_core_init();
char *canonsrcpath = calloc(1024,1);
char *canondstpath = calloc(1024,1);
char *basename = calloc(PATH_MAX, 1);
getcwd(basename, PATH_MAX);
if (srcfile[0] != '/') {
strcat(canonsrcpath,basename);
strcat(canonsrcpath,"/");
}
if (dstfile[0] != '/') {
strcat(canondstpath,basename);
strcat(canondstpath,"/");
}
strcat(canonsrcpath,srcfile);
strcat(canondstpath,dstfile);
srcfd = open(canonsrcpath, O_RDONLY);
fprintf(stderr, "Bees?\n");
done = fclonefile(canonsrcpath,canondstpath);
dstfd = open(canonsrcpath, O_RDONLY);
#endif
srcfd = open(srcfile, O_RDONLY);
if (srcfd < 0) {
err(1, "open(%s) failed", srcfile);
}

flags = O_WRONLY | O_CREAT;
if (force) {
flags |= O_TRUNC;
} else {
flags |= O_EXCL;
}
dstfd = open(dstfile, flags, 0644);
if (dstfd < 0) {
err(1, "open(%s) failed", dstfile);
}

if (fstat(srcfd, &sb) < 0) {
err(1, "fstat(%s) failed", srcfile);
}
fprintf(stderr, "Keys?\n");
done = fclonefile(srcfd, dstfd, sb.st_size);

#endif
fprintf(stderr, "Fleas?\n");
if (done < 0) {
err(1, "fclonefile() failed");
} else {
printf("We think we did the thing, with %llu (%lld) bytes\n", done, done);
}

if (fstat(srcfd, &sb) < 0) {
err(1, "fstat(%s) failed", srcfile);
}
if (fstat(dstfd, &db) < 0) {
err(1, "fstat(%s) failed", srcfile);
}
if (sb.st_size > (size_t)done) {
warnx("file %s not fully cloned (%zd out of %zu)",
srcfile, done, sb.st_size);
} else if (sb.st_size < (size_t)done) {
warnx("file %s appears to shrunk after cloning (%zd > %zu)",
srcfile, done, sb.st_size);
}

exit(0);
}
1 change: 1 addition & 0 deletions include/libzfs_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ _LIBZFS_CORE_H int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **);
_LIBZFS_CORE_H int lzc_create(const char *, enum lzc_dataset_type, nvlist_t *,
uint8_t *, uint_t);
_LIBZFS_CORE_H int lzc_clone(const char *, const char *, nvlist_t *);
_LIBZFS_CORE_H int lzc_clonefile(const char* srcpath, const char* dstpath, uint64_t src_off, uint64_t dst_off, uint64_t len);
_LIBZFS_CORE_H int lzc_promote(const char *, char *, int);
_LIBZFS_CORE_H int lzc_destroy_snaps(nvlist_t *, boolean_t, nvlist_t **);
_LIBZFS_CORE_H int lzc_bookmark(nvlist_t *, nvlist_t **);
Expand Down
7 changes: 7 additions & 0 deletions include/os/linux/zfs/sys/zpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ zpl_chmod_acl(struct inode *ip)
return (0);
}
#endif /* CONFIG_FS_POSIX_ACL */
extern ssize_t zpl_copy_range(struct file * srcf, loff_t off_in, struct file * dstf,
loff_t off_out, size_t len, unsigned int flags);

extern loff_t
zpl_remap_range(struct file *file_in, loff_t pos_in,
struct file *file_out, loff_t pos_out, loff_t len,
unsigned int remap_flags);

extern xattr_handler_t *zpl_xattr_handlers[];

Expand Down
1 change: 1 addition & 0 deletions include/sys/fs/zfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1453,6 +1453,7 @@ typedef enum zfs_ioc {
ZFS_IOC_WAIT_FS, /* 0x5a54 */
ZFS_IOC_VDEV_GET_PROPS, /* 0x5a55 */
ZFS_IOC_VDEV_SET_PROPS, /* 0x5a56 */
ZFS_IOC_FCLONEFILE, /* 0x5a57 */

/*
* Per-platform (Optional) - 8/128 numbers reserved.
Expand Down
19 changes: 19 additions & 0 deletions lib/libzfs_core/libzfs_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
if (ioc == fail_ioc_cmd)
return (fail_ioc_err);
#endif
// fprintf(stderr, "We made it at least to point 1.\n");

if (name != NULL)
(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
Expand All @@ -211,6 +212,7 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
goto out;
}
}
// fprintf(stderr, "We made it at least to point 2.\n");

while (lzc_ioctl_fd(g_fd, ioc, &zc) != 0) {
/*
Expand All @@ -220,6 +222,7 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
* Channel programs that exit with ENOMEM ran over the
* lua memory sandbox; they should not be retried.
*/
// fprintf(stderr, "We made it at least to point 3.\n");
if (errno == ENOMEM && resultp != NULL &&
ioc != ZFS_IOC_CHANNEL_PROGRAM) {
free((void *)(uintptr_t)zc.zc_nvlist_dst);
Expand All @@ -241,12 +244,28 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
}

out:
// fprintf(stderr, "We made it at least to point 4. %d\n", error);
if (packed != NULL)
fnvlist_pack_free(packed, size);
free((void *)(uintptr_t)zc.zc_nvlist_dst);
return (error);
}

int
lzc_clonefile(const char* srcpath, const char* dstpath, uint64_t src_off, uint64_t dst_off, uint64_t len) {
int error = 0;
nvlist_t *innvl = fnvlist_alloc();
nvlist_t *outnvl = NULL;
fnvlist_add_string(innvl, "src", srcpath);
fnvlist_add_string(innvl, "dst", dstpath);
fnvlist_add_uint64(innvl, "src_off", src_off);
fnvlist_add_uint64(innvl, "dst_off", dst_off);
fnvlist_add_uint64(innvl, "len", len);
error = lzc_ioctl(ZFS_IOC_FCLONEFILE, NULL, innvl, &outnvl);
nvlist_free(innvl);
return (error);
}

int
lzc_create(const char *fsname, enum lzc_dataset_type type, nvlist_t *props,
uint8_t *wkeydata, uint_t wkeylen)
Expand Down
Loading

0 comments on commit fd21c46

Please sign in to comment.