fs/splice: don't report a partialResult error if there is no data loss

PiperOrigin-RevId: 288642552
This commit is contained in:
Andrei Vagin
2020-01-07 23:54:14 -08:00
committed by gVisor bot
parent e77ad57423
commit a53ac7307a
3 changed files with 40 additions and 0 deletions
+7
View File
@@ -555,6 +555,10 @@ type lockedWriter struct {
//
// This applies only to Write, not WriteAt.
Offset int64
// Err contains the first error encountered while copying. This is
// useful to determine whether Writer or Reader failed during io.Copy.
Err error
}
// Write implements io.Writer.Write.
@@ -590,5 +594,8 @@ func (w *lockedWriter) WriteAt(buf []byte, offset int64) (int, error) {
break
}
}
if w.Err == nil {
w.Err = err
}
return written, err
}
+5
View File
@@ -167,6 +167,11 @@ func Splice(ctx context.Context, dst *File, src *File, opts SpliceOpts) (int64,
if !srcPipe && !opts.SrcOffset {
atomic.StoreInt64(&src.offset, src.offset+n)
}
// Don't report any errors if we have some progress without data loss.
if w.Err == nil {
err = nil
}
}
// Drop locks.
+28
View File
@@ -1591,6 +1591,34 @@ TEST(Inotify, EpollNoDeadlock) {
}
}
TEST(Inotify, SpliceEvent) {
int pipes[2];
ASSERT_THAT(pipe2(pipes, O_NONBLOCK), SyscallSucceeds());
const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
const FileDescriptor fd =
ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
const TempPath file1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
root.path(), "some content", TempPath::kDefaultFileMode));
const FileDescriptor file1_fd =
ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_RDONLY));
const int watcher = ASSERT_NO_ERRNO_AND_VALUE(
InotifyAddWatch(fd.get(), file1.path(), IN_ALL_EVENTS));
char buf;
EXPECT_THAT(read(file1_fd.get(), &buf, 1), SyscallSucceeds());
EXPECT_THAT(splice(fd.get(), nullptr, pipes[1], nullptr,
sizeof(struct inotify_event) + 1, SPLICE_F_NONBLOCK),
SyscallSucceedsWithValue(sizeof(struct inotify_event)));
const FileDescriptor read_fd(pipes[0]);
const std::vector<Event> events =
ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(read_fd.get()));
ASSERT_THAT(events, Are({Event(IN_ACCESS, watcher)}));
}
} // namespace
} // namespace testing
} // namespace gvisor