summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaichi Hirono2017-03-28 23:02:30 -0500
committerDaichi Hirono2017-03-30 20:50:50 -0500
commit6f6210dd5c0aae99d67fd945e270a0948e6c4f42 (patch)
tree936618a2efc279f7fc2244ca847cba08ddd65798 /libappfuse/FuseBuffer.cc
parent281531bdcbfc99128d54fc5220488a5a6612079b (diff)
downloadplatform-system-core-6f6210dd5c0aae99d67fd945e270a0948e6c4f42.tar.gz
platform-system-core-6f6210dd5c0aae99d67fd945e270a0948e6c4f42.tar.xz
platform-system-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.cc51
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 {
34namespace fuse { 34namespace fuse {
35namespace { 35namespace {
36 36
37constexpr useconds_t kRetrySleepForWriting = 1000; // 1 ms
38
37template <typename T> 39template <typename T>
38bool CheckHeaderLength(const FuseMessage<T>* self, const char* name, size_t max_size) { 40bool CheckHeaderLength(const FuseMessage<T>* self, const char* name, size_t max_size) {
39 const auto& header = static_cast<const T*>(self)->header; 41 const auto& header = static_cast<const T*>(self)->header;
@@ -91,28 +93,35 @@ ResultOrAgain WriteInternal(const FuseMessage<T>* self, int fd, int sockflag, co
91 const char* const buf = reinterpret_cast<const char*>(self); 93 const char* const buf = reinterpret_cast<const char*>(self);
92 const auto& header = static_cast<const T*>(self)->header; 94 const auto& header = static_cast<const T*>(self)->header;
93 95
94 int result; 96 while (true) {
95 if (sockflag) { 97 int result;
96 CHECK(data == nullptr); 98 if (sockflag) {
97 result = TEMP_FAILURE_RETRY(send(fd, buf, header.len, sockflag)); 99 CHECK(data == nullptr);
98 } else if (data) { 100 result = TEMP_FAILURE_RETRY(send(fd, buf, header.len, sockflag));
99 const struct iovec vec[] = {{const_cast<char*>(buf), sizeof(header)}, 101 } else if (data) {
100 {const_cast<void*>(data), header.len - sizeof(header)}}; 102 const struct iovec vec[] = {{const_cast<char*>(buf), sizeof(header)},
101 result = TEMP_FAILURE_RETRY(writev(fd, vec, arraysize(vec))); 103 {const_cast<void*>(data), header.len - sizeof(header)}};
102 } else { 104 result = TEMP_FAILURE_RETRY(writev(fd, vec, arraysize(vec)));
103 result = TEMP_FAILURE_RETRY(write(fd, buf, header.len)); 105 } else {
104 } 106 result = TEMP_FAILURE_RETRY(write(fd, buf, header.len));
105
106 if (result == -1) {
107 if (errno == EAGAIN) {
108 return ResultOrAgain::kAgain;
109 } 107 }
110 PLOG(ERROR) << "Failed to write a FUSE message"; 108 if (result == -1) {
111 return ResultOrAgain::kFailure; 109 switch (errno) {
110 case ENOBUFS:
111 // When returning ENOBUFS, epoll still reports the FD is writable. Just usleep
112 // and retry again.
113 usleep(kRetrySleepForWriting);
114 continue;
115 case EAGAIN:
116 return ResultOrAgain::kAgain;
117 default:
118 PLOG(ERROR) << "Failed to write a FUSE message";
119 return ResultOrAgain::kFailure;
120 }
121 }
122 CHECK(static_cast<uint32_t>(result) == header.len);
123 return ResultOrAgain::kSuccess;
112 } 124 }
113
114 CHECK(static_cast<uint32_t>(result) == header.len);
115 return ResultOrAgain::kSuccess;
116} 125}
117} 126}
118 127
@@ -161,7 +170,7 @@ bool FuseMessage<T>::Write(int fd) const {
161template <typename T> 170template <typename T>
162bool FuseMessage<T>::WriteWithBody(int fd, size_t max_size, const void* data) const { 171bool FuseMessage<T>::WriteWithBody(int fd, size_t max_size, const void* data) const {
163 CHECK(data != nullptr); 172 CHECK(data != nullptr);
164 return WriteInternal<T>(this, fd, 0, data, max_size) == ResultOrAgain::kSuccess; 173 return WriteInternal(this, fd, 0, data, max_size) == ResultOrAgain::kSuccess;
165} 174}
166 175
167template <typename T> 176template <typename T>