diff options
author | Daichi Hirono <hirono@google.com> | 2017-03-29 13:02:30 +0900 |
---|---|---|
committer | Daichi Hirono <hirono@google.com> | 2017-03-31 01:50:50 +0000 |
commit | 6f6210dd5c0aae99d67fd945e270a0948e6c4f42 (patch) | |
tree | 936618a2efc279f7fc2244ca847cba08ddd65798 /libappfuse/FuseBuffer.cc | |
parent | 281531bdcbfc99128d54fc5220488a5a6612079b (diff) | |
download | core-6f6210dd5c0aae99d67fd945e270a0948e6c4f42.tar.gz core-6f6210dd5c0aae99d67fd945e270a0948e6c4f42.tar.bz2 core-6f6210dd5c0aae99d67fd945e270a0948e6c4f42.zip |
Retry write operation when getting ENOBUFS.
Previously libappfuse set SO_SNDBUF to the maximum message size. However
it does not prevent ENOBUF and it made AppFusePerfTest#testReadWriteFile
flaky.
The CL let FuseBuffer retry write operation when getting ENOBUFS.
Bug: 34903085
Test: libappfuse
Change-Id: I1602474d852e1599f6e69103bcf6f18277a5644b
Diffstat (limited to 'libappfuse/FuseBuffer.cc')
-rw-r--r-- | libappfuse/FuseBuffer.cc | 51 |
1 files changed, 30 insertions, 21 deletions
diff --git a/libappfuse/FuseBuffer.cc b/libappfuse/FuseBuffer.cc index 5bc549743..b42a04954 100644 --- a/libappfuse/FuseBuffer.cc +++ b/libappfuse/FuseBuffer.cc @@ -34,6 +34,8 @@ namespace android { namespace fuse { namespace { +constexpr useconds_t kRetrySleepForWriting = 1000; // 1 ms + template <typename T> bool CheckHeaderLength(const FuseMessage<T>* self, const char* name, size_t max_size) { const auto& header = static_cast<const T*>(self)->header; @@ -91,28 +93,35 @@ ResultOrAgain WriteInternal(const FuseMessage<T>* self, int fd, int sockflag, co const char* const buf = reinterpret_cast<const char*>(self); const auto& header = static_cast<const T*>(self)->header; - int result; - if (sockflag) { - CHECK(data == nullptr); - result = TEMP_FAILURE_RETRY(send(fd, buf, header.len, sockflag)); - } else if (data) { - const struct iovec vec[] = {{const_cast<char*>(buf), sizeof(header)}, - {const_cast<void*>(data), header.len - sizeof(header)}}; - result = TEMP_FAILURE_RETRY(writev(fd, vec, arraysize(vec))); - } else { - result = TEMP_FAILURE_RETRY(write(fd, buf, header.len)); - } - - if (result == -1) { - if (errno == EAGAIN) { - return ResultOrAgain::kAgain; + while (true) { + int result; + if (sockflag) { + CHECK(data == nullptr); + result = TEMP_FAILURE_RETRY(send(fd, buf, header.len, sockflag)); + } else if (data) { + const struct iovec vec[] = {{const_cast<char*>(buf), sizeof(header)}, + {const_cast<void*>(data), header.len - sizeof(header)}}; + result = TEMP_FAILURE_RETRY(writev(fd, vec, arraysize(vec))); + } else { + result = TEMP_FAILURE_RETRY(write(fd, buf, header.len)); } - PLOG(ERROR) << "Failed to write a FUSE message"; - return ResultOrAgain::kFailure; + if (result == -1) { + switch (errno) { + case ENOBUFS: + // When returning ENOBUFS, epoll still reports the FD is writable. Just usleep + // and retry again. + usleep(kRetrySleepForWriting); + continue; + case EAGAIN: + return ResultOrAgain::kAgain; + default: + PLOG(ERROR) << "Failed to write a FUSE message"; + return ResultOrAgain::kFailure; + } + } + CHECK(static_cast<uint32_t>(result) == header.len); + return ResultOrAgain::kSuccess; } - - CHECK(static_cast<uint32_t>(result) == header.len); - return ResultOrAgain::kSuccess; } } @@ -161,7 +170,7 @@ bool FuseMessage<T>::Write(int fd) const { template <typename T> bool FuseMessage<T>::WriteWithBody(int fd, size_t max_size, const void* data) const { CHECK(data != nullptr); - return WriteInternal<T>(this, fd, 0, data, max_size) == ResultOrAgain::kSuccess; + return WriteInternal(this, fd, 0, data, max_size) == ResultOrAgain::kSuccess; } template <typename T> |