Merge "adbd: limit the sizes of aio writes." am: 50cb647e7d
am: c423d790b7
Change-Id: Ic71e98f05911f9b0a3e3142774addbc21c588ea0
This commit is contained in:
commit
57ba09aea9
1 changed files with 35 additions and 14 deletions
|
|
@ -29,6 +29,7 @@
|
||||||
#include <linux/usb/functionfs.h>
|
#include <linux/usb/functionfs.h>
|
||||||
#include <sys/eventfd.h>
|
#include <sys/eventfd.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
@ -60,6 +61,7 @@ static constexpr size_t kUsbReadQueueDepth = 16;
|
||||||
static constexpr size_t kUsbReadSize = 16384;
|
static constexpr size_t kUsbReadSize = 16384;
|
||||||
|
|
||||||
static constexpr size_t kUsbWriteQueueDepth = 16;
|
static constexpr size_t kUsbWriteQueueDepth = 16;
|
||||||
|
static constexpr size_t kUsbWriteSize = 16 * PAGE_SIZE;
|
||||||
|
|
||||||
static const char* to_string(enum usb_functionfs_event_type type) {
|
static const char* to_string(enum usb_functionfs_event_type type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
@ -115,7 +117,7 @@ struct TransferId {
|
||||||
struct IoBlock {
|
struct IoBlock {
|
||||||
bool pending;
|
bool pending;
|
||||||
struct iocb control;
|
struct iocb control;
|
||||||
Block payload;
|
std::shared_ptr<Block> payload;
|
||||||
|
|
||||||
TransferId id() const { return TransferId::from_value(control.aio_data); }
|
TransferId id() const { return TransferId::from_value(control.aio_data); }
|
||||||
};
|
};
|
||||||
|
|
@ -207,8 +209,20 @@ struct UsbFfsConnection : public Connection {
|
||||||
std::lock_guard<std::mutex> lock(write_mutex_);
|
std::lock_guard<std::mutex> lock(write_mutex_);
|
||||||
write_requests_.push_back(CreateWriteBlock(std::move(header), next_write_id_++));
|
write_requests_.push_back(CreateWriteBlock(std::move(header), next_write_id_++));
|
||||||
if (!packet->payload.empty()) {
|
if (!packet->payload.empty()) {
|
||||||
write_requests_.push_back(
|
// The kernel attempts to allocate a contiguous block of memory for each write,
|
||||||
CreateWriteBlock(std::move(packet->payload), next_write_id_++));
|
// which can fail if the write is large and the kernel heap is fragmented.
|
||||||
|
// Split large writes into smaller chunks to avoid this.
|
||||||
|
std::shared_ptr<Block> payload = std::make_shared<Block>(std::move(packet->payload));
|
||||||
|
size_t offset = 0;
|
||||||
|
size_t len = payload->size();
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
size_t write_size = std::min(kUsbWriteSize, len);
|
||||||
|
write_requests_.push_back(
|
||||||
|
CreateWriteBlock(payload, offset, write_size, next_write_id_++));
|
||||||
|
len -= write_size;
|
||||||
|
offset += write_size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
SubmitWrites();
|
SubmitWrites();
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -367,10 +381,10 @@ struct UsbFfsConnection : public Connection {
|
||||||
|
|
||||||
void PrepareReadBlock(IoBlock* block, uint64_t id) {
|
void PrepareReadBlock(IoBlock* block, uint64_t id) {
|
||||||
block->pending = false;
|
block->pending = false;
|
||||||
block->payload.resize(kUsbReadSize);
|
block->payload = std::make_shared<Block>(kUsbReadSize);
|
||||||
block->control.aio_data = static_cast<uint64_t>(TransferId::read(id));
|
block->control.aio_data = static_cast<uint64_t>(TransferId::read(id));
|
||||||
block->control.aio_buf = reinterpret_cast<uintptr_t>(block->payload.data());
|
block->control.aio_buf = reinterpret_cast<uintptr_t>(block->payload->data());
|
||||||
block->control.aio_nbytes = block->payload.size();
|
block->control.aio_nbytes = block->payload->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
IoBlock CreateReadBlock(uint64_t id) {
|
IoBlock CreateReadBlock(uint64_t id) {
|
||||||
|
|
@ -421,7 +435,7 @@ struct UsbFfsConnection : public Connection {
|
||||||
uint64_t read_idx = id.id % kUsbReadQueueDepth;
|
uint64_t read_idx = id.id % kUsbReadQueueDepth;
|
||||||
IoBlock* block = &read_requests_[read_idx];
|
IoBlock* block = &read_requests_[read_idx];
|
||||||
block->pending = false;
|
block->pending = false;
|
||||||
block->payload.resize(size);
|
block->payload->resize(size);
|
||||||
|
|
||||||
// Notification for completed reads can be received out of order.
|
// Notification for completed reads can be received out of order.
|
||||||
if (block->id().id != needed_read_id_) {
|
if (block->id().id != needed_read_id_) {
|
||||||
|
|
@ -442,16 +456,16 @@ struct UsbFfsConnection : public Connection {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessRead(IoBlock* block) {
|
void ProcessRead(IoBlock* block) {
|
||||||
if (!block->payload.empty()) {
|
if (!block->payload->empty()) {
|
||||||
if (!incoming_header_.has_value()) {
|
if (!incoming_header_.has_value()) {
|
||||||
CHECK_EQ(sizeof(amessage), block->payload.size());
|
CHECK_EQ(sizeof(amessage), block->payload->size());
|
||||||
amessage msg;
|
amessage msg;
|
||||||
memcpy(&msg, block->payload.data(), sizeof(amessage));
|
memcpy(&msg, block->payload->data(), sizeof(amessage));
|
||||||
LOG(DEBUG) << "USB read:" << dump_header(&msg);
|
LOG(DEBUG) << "USB read:" << dump_header(&msg);
|
||||||
incoming_header_ = msg;
|
incoming_header_ = msg;
|
||||||
} else {
|
} else {
|
||||||
size_t bytes_left = incoming_header_->data_length - incoming_payload_.size();
|
size_t bytes_left = incoming_header_->data_length - incoming_payload_.size();
|
||||||
Block payload = std::move(block->payload);
|
Block payload = std::move(*block->payload);
|
||||||
CHECK_LE(payload.size(), bytes_left);
|
CHECK_LE(payload.size(), bytes_left);
|
||||||
incoming_payload_.append(std::make_unique<Block>(std::move(payload)));
|
incoming_payload_.append(std::make_unique<Block>(std::move(payload)));
|
||||||
}
|
}
|
||||||
|
|
@ -506,7 +520,8 @@ struct UsbFfsConnection : public Connection {
|
||||||
SubmitWrites();
|
SubmitWrites();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<IoBlock> CreateWriteBlock(Block payload, uint64_t id) {
|
std::unique_ptr<IoBlock> CreateWriteBlock(std::shared_ptr<Block> payload, size_t offset,
|
||||||
|
size_t len, uint64_t id) {
|
||||||
auto block = std::make_unique<IoBlock>();
|
auto block = std::make_unique<IoBlock>();
|
||||||
block->payload = std::move(payload);
|
block->payload = std::move(payload);
|
||||||
block->control.aio_data = static_cast<uint64_t>(TransferId::write(id));
|
block->control.aio_data = static_cast<uint64_t>(TransferId::write(id));
|
||||||
|
|
@ -514,14 +529,20 @@ struct UsbFfsConnection : public Connection {
|
||||||
block->control.aio_lio_opcode = IOCB_CMD_PWRITE;
|
block->control.aio_lio_opcode = IOCB_CMD_PWRITE;
|
||||||
block->control.aio_reqprio = 0;
|
block->control.aio_reqprio = 0;
|
||||||
block->control.aio_fildes = write_fd_.get();
|
block->control.aio_fildes = write_fd_.get();
|
||||||
block->control.aio_buf = reinterpret_cast<uintptr_t>(block->payload.data());
|
block->control.aio_buf = reinterpret_cast<uintptr_t>(block->payload->data() + offset);
|
||||||
block->control.aio_nbytes = block->payload.size();
|
block->control.aio_nbytes = len;
|
||||||
block->control.aio_offset = 0;
|
block->control.aio_offset = 0;
|
||||||
block->control.aio_flags = IOCB_FLAG_RESFD;
|
block->control.aio_flags = IOCB_FLAG_RESFD;
|
||||||
block->control.aio_resfd = worker_event_fd_.get();
|
block->control.aio_resfd = worker_event_fd_.get();
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IoBlock> CreateWriteBlock(Block payload, uint64_t id) {
|
||||||
|
std::shared_ptr<Block> block = std::make_shared<Block>(std::move(payload));
|
||||||
|
size_t len = block->size();
|
||||||
|
return CreateWriteBlock(std::move(block), 0, len, id);
|
||||||
|
}
|
||||||
|
|
||||||
void SubmitWrites() REQUIRES(write_mutex_) {
|
void SubmitWrites() REQUIRES(write_mutex_) {
|
||||||
if (writes_submitted_ == kUsbWriteQueueDepth) {
|
if (writes_submitted_ == kUsbWriteQueueDepth) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue