Skip to content

Commit

Permalink
Refactored lzc_send_resume_redacted with a thread.
Browse files Browse the repository at this point in the history
After the changes documented in #11445, writing to certain files
errored out with an opaque error message. Unfortunately, the path
of least resistance to fixing this seemed to be sticking a pipe
into the path of zfs send, along with a thread to copy data to
stdout.

Signed-off-by: Rich Ercolani <rincebrain@gmail.com>
  • Loading branch information
rincebrain committed May 3, 2021
1 parent c903a75 commit 27139e1
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 1 deletion.
3 changes: 3 additions & 0 deletions include/libzfs_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ int lzc_wait_fs(const char *, zfs_wait_activity_t, boolean_t *);

int lzc_set_bootenv(const char *, const nvlist_t *);
int lzc_get_bootenv(const char *, nvlist_t **);

void* __do_send_output(void* voidargs);

#ifdef __cplusplus
}
#endif
Expand Down
77 changes: 76 additions & 1 deletion lib/libzfs_core/libzfs_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
* Copyright 2017 RackTop Systems.
* Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
* Copyright (c) 2019, 2020 by Christian Schwarz. All rights reserved.
* Copyright (c) 2021 Rich Ercolani.
*/

/*
Expand Down Expand Up @@ -645,6 +646,58 @@ lzc_send_resume(const char *snapname, const char *from, int fd,
resumeoff, NULL));
}

struct sendargs {
int ioctlfd;
int inputfd;
int outputfd;
};
typedef struct sendargs sendargs_t;

void *
__do_send_output(void *voidargs)
{
sendargs_t *args = (sendargs_t *)voidargs;
sigset_t sigs;
int buflen = 131072;

// see the comment above the close() calls for why
// we can't just die from SIGPIPE
sigemptyset(&sigs);
sigaddset(&sigs, SIGPIPE);
pthread_sigmask(SIG_BLOCK, &sigs, NULL);

#ifndef __linux__
void* buf = calloc(1,buflen);
#endif

int err = 0;
while (err >= 0) {
#ifdef __linux__
err = splice(args->inputfd, 0, args->outputfd, 0, buflen,
SPLICE_F_MORE);
#else
err = read(args->inputfd, buf, buflen);
if (err <= 0) {
break;
}
err = write(args->outputfd, buf, err);
#endif
if (err <= 0) {
break;
}
}
if (err < 0) {
// If we just call exit here, the other thread often blocks
// indefinitely on the ioctl completing, which won't happen
// because we stopped consuming the data. So we close the pipe
// here, and the other thread exits in a timely fashion.
close(args->ioctlfd);
close(args->inputfd);
exit(1);
}
return ((void *)(uint64_t)err);
}

/*
* snapname: The name of the "tosnap", or the snapshot whose contents we are
* sending.
Expand All @@ -664,9 +717,18 @@ lzc_send_resume_redacted(const char *snapname, const char *from, int fd,
{
nvlist_t *args;
int err;
int pipefd[2];
pthread_t mythread;
pthread_attr_t myattr;
sendargs_t sendargs;
uintptr_t dumbstatus;


err = pipe(pipefd);
err = pthread_attr_init(&myattr);

args = fnvlist_alloc();
fnvlist_add_int32(args, "fd", fd);
fnvlist_add_int32(args, "fd", pipefd[1]);
if (from != NULL)
fnvlist_add_string(args, "fromsnap", from);
if (flags & LZC_SEND_FLAG_LARGE_BLOCK)
Expand All @@ -686,7 +748,20 @@ lzc_send_resume_redacted(const char *snapname, const char *from, int fd,
if (redactbook != NULL)
fnvlist_add_string(args, "redactbook", redactbook);

sendargs.inputfd = pipefd[0];
sendargs.outputfd = fd;
sendargs.ioctlfd = pipefd[1];

pthread_create(&mythread, &myattr, __do_send_output, (void *)&sendargs);

err = lzc_ioctl(ZFS_IOC_SEND_NEW, snapname, args, NULL);

close(pipefd[1]);

pthread_join(mythread, (void *)&dumbstatus);

pthread_attr_destroy(&myattr);

nvlist_free(args);
return (err);
}
Expand Down

0 comments on commit 27139e1

Please sign in to comment.