-
Notifications
You must be signed in to change notification settings - Fork 1.9k
linux/uio: remove "skip" offset for UIO_ITER
#17298
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
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.
It seems to make sense, but I think it is only a part of the confusion. I see zfs_uio_iov_iter_init()
receiving skip
of 0 in zpl_iter_read()
, but iov_offset
in zpl_iter_write()
. Same time aside of this one place I don't see uio_skip
ever used for UIO_ITER
uios. Could we also remove the skip parameter from zfs_uio_iov_iter_init()
?
zfs_uiomove_iter
: ignore the "skip" offsetUIO_ITER
@amotin agreed. I was wary, because I could see it being used in some of the direct IO support code and I wasn't sure. I've not studied it closely, but it does seem like the skip is not used in any interesting way there, as the kernel is asked for pages and the whole point of direct IO is that it's all properly aligned anyway. So, last push removes setting the skip for |
Sigh, this is why my original patch was focused on a specific case - I was here to fix a bug, not rework the whole thing. I'll have a look at next opportunity, maybe not until tomorrow or the weekend. |
@amotin @bwatkinson I've (effectively) reverted the change in |
And the rest of it in the last push, sigh. |
For UIO_ITER, we are just wrapping a kernel iterator. It will take care of its own offsets if necessary. We don't need to do anything, and if we do try to do anything with it (like advancing the iterator by the skip in zfs_uio_advance) we're just confusing the kernel iterator, ending up at the wrong position or worse, off the end of the memory region. Sponsored-by: https://despairlabs.com/sponsor/ Signed-off-by: Rob Norris <robn@despairlabs.com>
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.
Looks good to me now. Thanks.
Heh, and to you :) |
Wow, it looked so simple in the beginning... really good work to all 👍 |
For UIO_ITER, we are just wrapping a kernel iterator. It will take care of its own offsets if necessary. We don't need to do anything, and if we do try to do anything with it (like advancing the iterator by the skip in zfs_uio_advance) we're just confusing the kernel iterator, ending up at the wrong position or worse, off the end of the memory region. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Tony Hutter <hutter2@llnl.gov> Reviewed-by: Alexander Motin <mav@FreeBSD.org> Reviewed-by: Tino Reichardt <milky-zfs@mcmilk.de> Reviewed-by: Brian Atkinson <batkinson@lanl.gov> Signed-off-by: Rob Norris <robn@despairlabs.com> Closes openzfs#17298 (cherry picked from commit 2ee5b51)
For UIO_ITER, we are just wrapping a kernel iterator. It will take care of its own offsets if necessary. We don't need to do anything, and if we do try to do anything with it (like advancing the iterator by the skip in zfs_uio_advance) we're just confusing the kernel iterator, ending up at the wrong position or worse, off the end of the memory region. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Tony Hutter <hutter2@llnl.gov> Reviewed-by: Alexander Motin <mav@FreeBSD.org> Reviewed-by: Tino Reichardt <milky-zfs@mcmilk.de> Reviewed-by: Brian Atkinson <batkinson@lanl.gov> Signed-off-by: Rob Norris <robn@despairlabs.com> Closes openzfs#17298 (cherry picked from commit 2ee5b51)
For UIO_ITER, we are just wrapping a kernel iterator. It will take care of its own offsets if necessary. We don't need to do anything, and if we do try to do anything with it (like advancing the iterator by the skip in zfs_uio_advance) we're just confusing the kernel iterator, ending up at the wrong position or worse, off the end of the memory region. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Tony Hutter <hutter2@llnl.gov> Reviewed-by: Alexander Motin <mav@FreeBSD.org> Reviewed-by: Tino Reichardt <milky-zfs@mcmilk.de> Reviewed-by: Brian Atkinson <batkinson@lanl.gov> Signed-off-by: Rob Norris <robn@despairlabs.com> Closes openzfs#17298 (cherry picked from commit 2ee5b51)
For UIO_ITER, we are just wrapping a kernel iterator. It will take care of its own offsets if necessary. We don't need to do anything, and if we do try to do anything with it (like advancing the iterator by the skip in zfs_uio_advance) we're just confusing the kernel iterator, ending up at the wrong position or worse, off the end of the memory region. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Tony Hutter <hutter2@llnl.gov> Reviewed-by: Alexander Motin <mav@FreeBSD.org> Reviewed-by: Tino Reichardt <milky-zfs@mcmilk.de> Reviewed-by: Brian Atkinson <batkinson@lanl.gov> Signed-off-by: Rob Norris <robn@despairlabs.com> Closes openzfs#17298 (cherry picked from commit 2ee5b51)
For UIO_ITER, we are just wrapping a kernel iterator. It will take care of its own offsets if necessary. We don't need to do anything, and if we do try to do anything with it (like advancing the iterator by the skip in zfs_uio_advance) we're just confusing the kernel iterator, ending up at the wrong position or worse, off the end of the memory region. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Tony Hutter <hutter2@llnl.gov> Reviewed-by: Alexander Motin <mav@FreeBSD.org> Reviewed-by: Tino Reichardt <milky-zfs@mcmilk.de> Reviewed-by: Brian Atkinson <batkinson@lanl.gov> Signed-off-by: Rob Norris <robn@despairlabs.com> Closes #17298 (cherry picked from commit 2ee5b51)
For UIO_ITER, we are just wrapping a kernel iterator. It will take care of its own offsets if necessary. We don't need to do anything, and if we do try to do anything with it (like advancing the iterator by the skip in zfs_uio_advance) we're just confusing the kernel iterator, ending up at the wrong position or worse, off the end of the memory region. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Tony Hutter <hutter2@llnl.gov> Reviewed-by: Alexander Motin <mav@FreeBSD.org> Reviewed-by: Tino Reichardt <milky-zfs@mcmilk.de> Reviewed-by: Brian Atkinson <batkinson@lanl.gov> Signed-off-by: Rob Norris <robn@despairlabs.com> Closes #17298 (cherry picked from commit 2ee5b51)
For UIO_ITER, we are just wrapping a kernel iterator. It will take care of its own offsets if necessary. We don't need to do anything, and if we do try to do anything with it (like advancing the iterator by the skip in zfs_uio_advance) we're just confusing the kernel iterator, ending up at the wrong position or worse, off the end of the memory region. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Tony Hutter <hutter2@llnl.gov> Reviewed-by: Alexander Motin <mav@FreeBSD.org> Reviewed-by: Tino Reichardt <milky-zfs@mcmilk.de> Reviewed-by: Brian Atkinson <batkinson@lanl.gov> Signed-off-by: Rob Norris <robn@despairlabs.com> Closes openzfs#17298
Motivation and Context
torvalds/linux@f2fed44 changes the Linux loop device to (effectively) pass the iterator received from the upper filesystem down the the lower filesystem, where previously it would walk the iterator, create a new single-item iterator over each element, and call into the VFS layer for service.
This change exposed a bug in
UIO_ITER
uios, which wrapiov_iter
: when we advance the uio, if the offset of the data inside theiov_iter
is non-zero (the "skip"), we would try to advance the iterator ourselves. But, this is not our iterator, and we don't have to do that - the iterator internals will sort that out if it needs to.The end result is that if we get an iterator with a first element with a non-zero offset, every time we advance we would skip that many bytes. This either lands somewhere in the middle of the iterator, getting the wrong data, or runs off the end, usually resulting in an
EFAULT
somewhere.In the case of #17277, the iterator passed down from XFS consistently contains segments with non-zero offsets. The additional skipping runs the iterator position off the end of the available data, and results in an
EFAULT
loop inzpl_write_iter()
.Fixes #17277.
Description
The bug proper is fixed by removing the unnecessary advance in
zfs_uiomove_iter()
and just let the underlying iterator sort it out. (note: the first version of this PR did only this).As it turns out, we don't even set the skip for
UIO_ITER
for read, and in the few other places we try to use it (some of the direct IO support code), we don't do anything meaningful with it, so I've removed all traces of skip handling forUIO_ITER
.How Has This Been Tested?
The test case in #17277 is to create a file on a pool, use
losetup
to create a loop device over it, then format the loop device as XFS and try to mount it. Something like:On kernels with the aforementioned change (eg 6.12.25), without this PR, the
mount
call hangs. With this patch, it succeeds.I've done this same test on all release kernels back to 4.19 without the upstream change but with this PR, and that experiment still succeeds.
I do not have a more specific test case.
The
direct
suite appears to pass correctly, but with some tracing shows thatfrom->iov_offset
inzpl_iter_write
was always zero, so if it's possible for it to be anything else in the direct IO cases, I have not tested it.Types of changes
Checklist:
Signed-off-by
.