-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactored lzc_send_resume_redacted with a thread. #11992
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hate that this is necessary to fix the problem, but I wouldn't object to it landing as long as it received appropriate performance testing first.
Do we know that this is necessary? Would it be possible to submit a patch upstream to handle the "convoluted semantics" associated with FSes that export both write() and write_iter() options? What about the semantics are convoluted, and how hard would it be to fix it? Obviously this is a task that you may not want to take on yourself, but I think it's worth considering if that's a better route to fixing our issue than a ZFS-specific patch.
I considered writing a patch to fix that instead, since my understanding is that it'd be a pretty simple patch, but quickly concluded that it would just end in tears once they found out why I was submitting it. edit: I was misunderstanding - tl;dr it is a very simple patch, but satisfying everyone's concerns would be quite difficult. (Included for anyone who's trying to understand the context) Longer: The original version of the patch dropped the "write" version of the function, but according to the v2 patch's description, that part was removed as it caused a performance regression in writing to /dev/null, and here we are. So if anyone wanted to write a patch, they'd probably have to do one of:
|
lib/libzfs_core/libzfs_core.c
Outdated
{ | ||
sendargs_t *args = (sendargs_t *)voidargs; | ||
sigset_t sigs; | ||
int buflen = 131072; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make this less out-of-thin-air, you might want to steal some logic from libzfs_set_pipe_max()
and (a) bump the pipe and (b) transfer in pipe-sized chunks.
Doesn't help on other platforms (according to a forum, FreeBSD pipes under no memory pressure start at 16k and grow up to 64k, or start at 4k and don't grow, or all pipes are shrunk down to 4k if possible, which is a great time), but.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I yanked the logic from libzfs into a new function in libzfs_core so it could be the same code called from both locations.
I find it pretty ugly to do, tbh, but we'll see if anyone else agrees with me...the alternative was duplicating the logic either inline or in a separate function in libzfs_core anyway, so this seemed least bad.
Well that's inconvenient. It seems like it might be infeasible to reproduce the exact same error code returns in all cases. I'm currently diving into the failure of the pyzfs/pyzfs_unittest test, and there are some times where the ioctl got EINTR and the thread got EPIPE, and the test expects EPIPE, and other times where the same thing happens, and the test expects EINTR. (test_send_to_broken_pipe and _2, respectively). Is it a dealbreaker if I can't make this reproduce the exact error codes in all cases? (And if not, is there any standard guidance for how to decide what the "correct" behavior should be, or just dealer's choice? ex. I special-cased not returning EBADF if the thread hit it because it fixed some of the other test cases, but that breaks some of the pyzfs_unittest cases. Short of that case, though, it's still always going to be erroring when errors are expected and not when not, it just might be a different error code.) |
Or I could be bad at error log reading comprehension and it could be straightforward to fix, that works too. |
Okay, the pyzfs/pyzfs_unittest failure on the FBSD test bots (test_send_bad_fd), I don't see a way to fix at the moment, because it's expecting a return of EBADF, while the send ioctl is returning 0 and the send thread is returning EPIPE, so even if I wanted to special case it, I'd break other cases that are expecting EPIPE. (I'm seeing another test failure in pyzfs/pyzfs_unittest just on FBSD, in test_snaprange_space_same_snap, but since that's also happening on vanilla git too I'm going to write it off as an oddity of my setup and look at it later if I get bored.) Assuming I'm not completely misreading things and there really isn't an obvious solution, what's the right thing to do here? Changing that one test to permit EPIPE seems like the least painful solution, but is there a reason not to decide to allow that? Absent anyone's objections or discovering new ZTS failures locally, I think the next commit I push is going to include a change to pyzfs_unittest to do just that. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's really unfortunate this is needed, but I think it's something we could live with as long as it doesn't have a significant impact on performance.
Regarding the test failures:
edit to add: I finally reproduced that specific failure of fault/auto_spare_multiple on Ubuntu 18.04 + vanilla git master, so I'm not going to be concerned about it failing going forward unless someone else disagrees. The current zloop crash also happens on the same pool files with vanilla git master, and the relevant pool files seem to have originated with a ztest run. Since AFAICT ztest doesn't involve send/recv, I'm reasonably confident its existence is unrelated to these changes, but I welcome someone more knowledgable telling me I'm completely wrong. |
include/libzfs_core.h
Outdated
@@ -137,6 +137,20 @@ 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this doesn't need to have this linkage and visibility, does it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I absolutely agree - I stuck it in there quickly back in the initial commit, as none of the other functions in libzfs_core had prototypes inlined in libzfs_core.c, and have been hoping someone would suggest a better place for both the function definition and prototype ever since.
Absent anyone having proposed brighter ideas, I'll just migrate it to being at the top of libzfs_core.c. If you have a better suggestion for where to put it than that, I'm all ears.
include/libzfs_core.h
Outdated
@@ -137,6 +137,20 @@ 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 __linux__ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this definitely shouldn't pollute the global namespace
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems reasonable. As above, I'll just land it in the top of libzfs_core.c - and if that seems unreasonable, the only other place I can see it going is inside the function using it.
lib/libzfs_core/libzfs_core.c
Outdated
@@ -96,6 +97,18 @@ static int g_fd = -1; | |||
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER; | |||
static int g_refcount; | |||
|
|||
void* __do_send_output(void* voidargs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this still has external linkage and you declaring this name yields UB (starts with two underscores); is there any reason you can't (drop the declaration and) mark it static?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely no reason I'm aware of. So I've done it and pushed.
Thanks!
lib/libzfs_core/libzfs_core.c
Outdated
@@ -645,6 +658,90 @@ lzc_send_resume(const char *snapname, const char *from, int fd, | |||
resumeoff, NULL)); | |||
} | |||
|
|||
int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this can and will overflow
nabijaczleweli@tarta:~/uwu$ cat max.c
#include <stdio.h>
int
lzc_get_pipe_max()
{
unsigned long max_psize = 65536;
#ifdef __linux__
FILE *procf = fopen("/proc/sys/fs/pipe-max-size", "re");
if (procf != NULL) {
if (fscanf(procf, "%lu", &max_psize) <= 0) {
// safe default
max_psize = 65536;
}
fclose(procf);
}
#endif
return (max_psize);
}
int main() {
int ret = lzc_get_pipe_max();
printf("%d\n", ret);
}
nabijaczleweli@tarta:~/uwu$ cc max.c -omax
nabijaczleweli@tarta:~/uwu$ echo 2147483649 | sudo tee /proc/sys/fs/pipe-max-size
2147483649
nabijaczleweli@tarta:~/uwu$ ./max
-2147483648
why not just return an unsigned long (or whichever type makes sense for this)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very good point; I overlooked that it was using unsigned longs when I factored out the logic. Corrected.
fcntl(infd, F_SETPIPE_SZ, | ||
max_psize); | ||
#endif | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's awkward to split the lzc_get_pipe_max
and lzc_set_pipe_max
functionality across libraries. I don't see any reason we couldn't move the libzfs_set_pipe_max()
call from zfs_receive()
in to the recv_impll()
function in libzfs_core
. Then this code could remain private, just in libzfs_core instead of libzfs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There; was that change (35bc51c) something like what you had in mind?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, that's what I had in mind. Let just make sure to remove libzfs_set_pipe_max
from libzfs_impl.h
and make sure the replacement lzc_*_pipe_max
functions are static
. We should be able to keep those functions private.
|
||
#ifndef F_GETPIPE_SZ | ||
#define F_GETPIPE_SZ (F_GETLEASE + 7) | ||
#endif /* F_GETPIPE_SZ */ | ||
|
||
void | ||
libzfs_set_pipe_max(int infd) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason to keep this unused file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope. I thought I had git rm'd it along with the Makefile update.
@@ -39,12 +39,6 @@ | |||
#define ZFS_KMOD "openzfs" | |||
#endif | |||
|
|||
void | |||
libzfs_set_pipe_max(int infd) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should should probably remove the declaration from libzfs_impl.h
if you're removing all definitions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea. Done.
void | ||
lzc_set_pipe_max(int infd) | ||
{ | ||
#ifdef __linux__ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
something like the "FreeBSD automatically resizes" comment from the libzfs impl would be good here as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, a comment along the lines of "FreeBSD grows automatically to 64k" on the unsigned long max_psize = 65536;
line above would kill both wrens in one twist maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, done.
The original |
FILE *procf = fopen("/proc/sys/fs/pipe-max-size", "re"); | ||
|
||
if (procf != NULL) { | ||
if (fscanf(procf, "%lu", &max_psize) <= 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're parsing exactly one field here, so any failure means that it remains unchanged. You can drop the if entirely and just do (void) fscanf();
, especially since you're setting it back to the initialised value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems reasonable. Sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat, either I did it incorrectly, or no I can't, as I've not seen that much red in the CI in a while.
I knew --enable-debug
turned on -Werror
, but I'm surprised I didn't see the warning that's getting promoted to an error without it. Oh well, simple enough...
edit: Oh, I see from the CI that this builds fine on Debian 10. So it's not just me being blind, it really didn't report it. Exciting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, yeah, in that case it'll probably need a dummy variable (and some convincing, potentially?), or to just be reverted to the conditional
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the way I put it back worked on Centos Stream 8 and Debian 10, so hopefully it doesn't get rejected by Ubuntu 18.04 or something.
Okay, fortunately I went through to rebase all my PRs; I completely forgot about some of these outstanding comments. |
033f8fd
to
1c2c11e
Compare
Okay, I'm no longer confused about what's going on with the failing pyzfs test case. You would not think that handing an invalid fd could give back EBADF sometimes and EPIPE others, right? Well, the precise way the test case functions is:
For those of you unversed in Python - the key point is that the tempfile (and, consequently, its fd which is copied to bad_fd) goes poof when the with statement ends - e.g. So let's say the now-closed file got fd 5. We call But what if you, say, did So if we did I'm going to add a quick check at the head of the function after the |
After the changes documented in openzfs#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>
Okay, so I know of two possible things that need to be resolved:
I can figure out the former, though I'll basically just be stealing examples from ZTS to test it; for the latter, does anyone have any examples of what they'd like to see? I can run |
By introducing lzc_send_wrapper() and routing all ZFS_IOC_SEND* users through it, we fix a Linux 5.10-introduced bug (see comment) This is all /transparent/ to the users API, ABI, and usage-wise, and disabled on FreeBSD and if the output is already a pipe, and transparently nestable (i.e. zfs_send_one() is wrapped, but so is lzc_send_redacted() it calls to ‒ this wouldn't be strictly necessary if ZFS_IOC_SEND_PROGRESS wasn't strictly denominational w.r.t. the descriptor the send is happening on) Supersedes openzfs#11992 Closes openzfs#11445 Co-authored-by: Rich Ercolani <rincebrain@gmail.com> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
By introducing lzc_send_wrapper() and routing all ZFS_IOC_SEND* users through it, we fix a Linux 5.10-introduced bug (see comment) This is all /transparent/ to the users API, ABI, and usage-wise, and disabled on FreeBSD and if the output is already a pipe, and transparently nestable (i.e. zfs_send_one() is wrapped, but so is lzc_send_redacted() it calls to ‒ this wouldn't be strictly necessary if ZFS_IOC_SEND_PROGRESS wasn't strictly denominational w.r.t. the descriptor the send is happening on) Supersedes openzfs#11992 Closes openzfs#11445 Co-authored-by: Rich Ercolani <rincebrain@gmail.com> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
By introducing lzc_send_wrapper() and routing all ZFS_IOC_SEND* users through it, we fix a Linux 5.10-introduced bug (see comment) This is all /transparent/ to the users API, ABI, and usage-wise, and disabled on FreeBSD and if the output is already a pipe, and transparently nestable (i.e. zfs_send_one() is wrapped, but so is lzc_send_redacted() it calls to ‒ this wouldn't be strictly necessary if ZFS_IOC_SEND_PROGRESS wasn't strictly denominational w.r.t. the descriptor the send is happening on) Supersedes openzfs#11992 Closes openzfs#11445 Co-authored-by: Rich Ercolani <rincebrain@gmail.com> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
By introducing lzc_send_wrapper() and routing all ZFS_IOC_SEND* users through it, we fix a Linux 5.10-introduced bug (see comment) This is all /transparent/ to the users API, ABI, and usage-wise, and disabled on FreeBSD and if the output is already a pipe, and transparently nestable (i.e. zfs_send_one() is wrapped, but so is lzc_send_redacted() it calls to ‒ this wouldn't be strictly necessary if ZFS_IOC_SEND_PROGRESS wasn't strictly denominational w.r.t. the descriptor the send is happening on) Supersedes openzfs#11992 Closes openzfs#11445 Co-authored-by: Rich Ercolani <rincebrain@gmail.com> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
By introducing lzc_send_wrapper() and routing all ZFS_IOC_SEND* users through it, we fix a Linux 5.10-introduced bug (see comment) This is all /transparent/ to the users API, ABI, and usage-wise, and disabled on FreeBSD and if the output is already a pipe, and transparently nestable (i.e. zfs_send_one() is wrapped, but so is lzc_send_redacted() it calls to ‒ this wouldn't be strictly necessary if ZFS_IOC_SEND_PROGRESS wasn't strictly denominational w.r.t. the descriptor the send is happening on) Supersedes openzfs#11992 Closes openzfs#11445 Co-authored-by: Rich Ercolani <rincebrain@gmail.com> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
By introducing lzc_send_wrapper() and routing all ZFS_IOC_SEND* users through it, we fix a Linux 5.10-introduced bug (see comment) This is all /transparent/ to the users API, ABI, and usage-wise, and disabled on FreeBSD and if the output is already a pipe, and transparently nestable (i.e. zfs_send_one() is wrapped, but so is lzc_send_redacted() it calls to ‒ this wouldn't be strictly necessary if ZFS_IOC_SEND_PROGRESS wasn't strictly denominational w.r.t. the descriptor the send is happening on) Supersedes openzfs#11992 Closes openzfs#11445 Co-authored-by: Rich Ercolani <rincebrain@gmail.com> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
By introducing lzc_send_wrapper() and routing all ZFS_IOC_SEND* users through it, we fix a Linux 5.10-introduced bug (see comment) This is all /transparent/ to the users API, ABI, and usage-wise, and disabled on FreeBSD and if the output is already a pipe, and transparently nestable (i.e. zfs_send_one() is wrapped, but so is lzc_send_redacted() it calls to ‒ this wouldn't be strictly necessary if ZFS_IOC_SEND_PROGRESS wasn't strictly denominational w.r.t. the descriptor the send is happening on) Supersedes openzfs#11992 Closes openzfs#11445 Co-authored-by: Rich Ercolani <rincebrain@gmail.com> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
By introducing lzc_send_wrapper() and routing all ZFS_IOC_SEND* users through it, we fix a Linux 5.10-introduced bug (see comment) This is all /transparent/ to the users API, ABI, and usage-wise, and disabled on FreeBSD and if the output is already a pipe, and transparently nestable (i.e. zfs_send_one() is wrapped, but so is lzc_send_redacted() it calls to ‒ this wouldn't be strictly necessary if ZFS_IOC_SEND_PROGRESS wasn't strictly denominational w.r.t. the descriptor the send is happening on) Supersedes openzfs#11992 Closes openzfs#11445 Co-authored-by: Rich Ercolani <rincebrain@gmail.com> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
By introducing lzc_send_wrapper() and routing all ZFS_IOC_SEND* users through it, we fix a Linux 5.10-introduced bug (see comment) This is all /transparent/ to the users API, ABI, and usage-wise, and disabled on FreeBSD and if the output is already a pipe, and transparently nestable (i.e. zfs_send_one() is wrapped, but so is lzc_send_redacted() it calls to ‒ this wouldn't be strictly necessary if ZFS_IOC_SEND_PROGRESS wasn't strictly denominational w.r.t. the descriptor the send is happening on) Supersedes openzfs#11992 Closes openzfs#11445 Co-authored-by: Rich Ercolani <rincebrain@gmail.com> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
By introducing lzc_send_wrapper() and routing all ZFS_IOC_SEND* users through it, we fix a Linux 5.10-introduced bug (see comment) This is all /transparent/ to the users API, ABI, and usage-wise, and disabled on FreeBSD and if the output is already a pipe, and transparently nestable (i.e. zfs_send_one() is wrapped, but so is lzc_send_redacted() it calls to ‒ this wouldn't be strictly necessary if ZFS_IOC_SEND_PROGRESS wasn't strictly denominational w.r.t. the descriptor the send is happening on) Supersedes openzfs#11992 Closes openzfs#11445 Co-authored-by: Rich Ercolani <rincebrain@gmail.com> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
By introducing lzc_send_wrapper() and routing all ZFS_IOC_SEND* users through it, we fix a Linux 5.10-introduced bug (see comment) This is all /transparent/ to the users API, ABI, and usage-wise, and disabled on FreeBSD and if the output is already a pipe, and transparently nestable (i.e. zfs_send_one() is wrapped, but so is lzc_send_redacted() it calls to ‒ this wouldn't be strictly necessary if ZFS_IOC_SEND_PROGRESS wasn't strictly denominational w.r.t. the descriptor the send is happening on) Supersedes openzfs#11992 Closes openzfs#11445 Co-authored-by: Rich Ercolani <rincebrain@gmail.com> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
By introducing lzc_send_wrapper() and routing all ZFS_IOC_SEND* users through it, we fix a Linux 5.10-introduced bug (see comment) This is all /transparent/ to the users API, ABI, and usage-wise, and disabled on FreeBSD and if the output is already a pipe, and transparently nestable (i.e. zfs_send_one() is wrapped, but so is lzc_send_redacted() it calls to ‒ this wouldn't be strictly necessary if ZFS_IOC_SEND_PROGRESS wasn't strictly denominational w.r.t. the descriptor the send is happening on) Supersedes openzfs#11992 Closes openzfs#11445 Co-authored-by: Rich Ercolani <rincebrain@gmail.com> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
By introducing lzc_send_wrapper() and routing all ZFS_IOC_SEND* users through it, we fix a Linux 5.10-introduced bug (see comment) This is all /transparent/ to the users API, ABI, and usage-wise, and disabled on FreeBSD and if the output is already a pipe, and transparently nestable (i.e. zfs_send_one() is wrapped, but so is lzc_send_redacted() it calls to ‒ this wouldn't be strictly necessary if ZFS_IOC_SEND_PROGRESS wasn't strictly denominational w.r.t. the descriptor the send is happening on) Supersedes openzfs#11992 Closes openzfs#11445 Co-authored-by: Rich Ercolani <rincebrain@gmail.com> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
By introducing lzc_send_wrapper() and routing all ZFS_IOC_SEND* users through it, we fix a Linux 5.10-introduced bug (see comment) This is all /transparent/ to the users API, ABI, and usage-wise, and disabled on FreeBSD and if the output is already a pipe, and transparently nestable (i.e. zfs_send_one() is wrapped, but so is lzc_send_redacted() it calls to ‒ this wouldn't be strictly necessary if ZFS_IOC_SEND_PROGRESS wasn't strictly denominational w.r.t. the descriptor the send is happening on) Supersedes openzfs#11992 Closes openzfs#11445 Co-authored-by: Rich Ercolani <rincebrain@gmail.com> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
By introducing lzc_send_wrapper() and routing all ZFS_IOC_SEND* users through it, we fix a Linux 5.10-introduced bug (see comment) This is all /transparent/ to the users API, ABI, and usage-wise, and disabled on FreeBSD and if the output is already a pipe, and transparently nestable (i.e. zfs_send_one() is wrapped, but so is lzc_send_redacted() it calls to ‒ this wouldn't be strictly necessary if ZFS_IOC_SEND_PROGRESS wasn't strictly denominational w.r.t. the descriptor the send is happening on) Supersedes openzfs#11992 Closes openzfs#11445 Co-authored-by: Rich Ercolani <rincebrain@gmail.com> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
Closing. A version of this was merged as #13133. |
(Creating this PR to get feedback on whether people think this approach is remotely reasonable, or I should abandon it.)
(The FreeBSD test failures don't seem to have anything to do with this change, they just failed to install a package before ever touching this code.)
Motivation and Context
After the changes documented in #11445, writing to certain files
errored out with an opaque error message.
Description
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.
As said above, this is mostly to get feedback on whether something like this would remotely be accepted or I should throw it out.
Known caveats include
Definitely doesn't work on FreeBSD at the moment due to usingWorks now.splice()
; going to correct that next.__do_send_output
thanright above the call.libzfs_core.hlzc_send_space_resume_redacted
the same way yet.How Has This Been Tested?
Tested on Debian buster and bullseye, with both tiny snapshots and letting a send of a 12T snapshot run to at least 600G.
Types of changes
Checklist:
Signed-off-by
.