storaged: align buffer address and size for direct_io

O_DIRECT requires buffer address and size to be aligned

Bug: 63629306

Change-Id: I268abb1c0ba32af4fd2e92210192c47a1f173238
This commit is contained in:
Jin Qian 2017-12-12 18:38:25 -08:00
parent 9c6587ad1f
commit 4c23c4576b
3 changed files with 86 additions and 71 deletions

View file

@ -36,6 +36,9 @@ friend class test_case_name##_##test_name##_Test
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define IS_ALIGNED(x, align) (!((x) & ((align) - 1)))
#define ROUND_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1))
#define SECTOR_SIZE ( 512 )
#define SEC_TO_MSEC ( 1000 )
#define MSEC_TO_USEC ( 1000 )
@ -83,12 +86,12 @@ class storaged_t : public android::hardware::health::V2_0::IHealthInfoCallback,
time_t mStarttime;
sp<android::hardware::health::V2_0::IHealth> health;
unique_ptr<storage_info_t> storage_info;
static const uint32_t crc_init;
static const uint32_t current_version;
unordered_map<userid_t, bool> proto_loaded;
void load_proto(userid_t user_id);
void prepare_proto(userid_t user_id, StoragedProto* proto);
char* prepare_proto(userid_t user_id, StoragedProto* proto);
void flush_proto(userid_t user_id, StoragedProto* proto);
void flush_proto_user_system(StoragedProto* proto);
void flush_proto_data(userid_t user_id, const char* data, ssize_t size);
string proto_path(userid_t user_id) {
return string("/data/misc_ce/") + to_string(user_id) +
"/storaged/storaged.proto";

View file

@ -54,11 +54,13 @@ namespace {
*/
constexpr int USER_SYSTEM = 0;
constexpr uint32_t benchmark_unit_size = 16 * 1024; // 16KB
constexpr ssize_t benchmark_unit_size = 16 * 1024; // 16KB
constexpr ssize_t min_benchmark_size = 128 * 1024; // 128KB
} // namespace
const uint32_t storaged_t::crc_init = 0x5108A4ED; /* STORAGED */
const uint32_t storaged_t::current_version = 4;
using android::hardware::health::V1_0::BatteryStatus;
using android::hardware::health::V1_0::toString;
@ -186,14 +188,11 @@ void storaged_t::load_proto(userid_t user_id) {
StoragedProto proto;
proto.ParseFromString(ss.str());
uint32_t crc = proto.crc();
proto.set_crc(crc_init);
string proto_str = proto.SerializeAsString();
uint32_t computed_crc = crc32(crc_init,
reinterpret_cast<const Bytef*>(proto_str.c_str()),
proto_str.size());
if (crc != computed_crc) {
const UidIOUsage& uid_io_usage = proto.uid_io_usage();
uint32_t computed_crc = crc32(current_version,
reinterpret_cast<const Bytef*>(uid_io_usage.SerializeAsString().c_str()),
uid_io_usage.ByteSize());
if (proto.crc() != computed_crc) {
LOG_TO(SYSTEM, WARNING) << "CRC mismatch in " << proto_file;
return;
}
@ -205,88 +204,101 @@ void storaged_t::load_proto(userid_t user_id) {
}
}
void storaged_t:: prepare_proto(userid_t user_id, StoragedProto* proto) {
proto->set_version(3);
proto->set_crc(crc_init);
char* storaged_t:: prepare_proto(userid_t user_id, StoragedProto* proto) {
proto->set_version(current_version);
const UidIOUsage& uid_io_usage = proto->uid_io_usage();
proto->set_crc(crc32(current_version,
reinterpret_cast<const Bytef*>(uid_io_usage.SerializeAsString().c_str()),
uid_io_usage.ByteSize()));
uint32_t pagesize = sysconf(_SC_PAGESIZE);
if (user_id == USER_SYSTEM) {
while (proto->ByteSize() < 128 * 1024) {
proto->add_padding(0xFEEDBABE);
proto->set_padding("", 1);
vector<char> padding;
ssize_t size = ROUND_UP(MAX(min_benchmark_size, proto->ByteSize()),
pagesize);
padding = vector<char>(size - proto->ByteSize(), 0xFD);
proto->set_padding(padding.data(), padding.size());
while (!IS_ALIGNED(proto->ByteSize(), pagesize)) {
padding.push_back(0xFD);
proto->set_padding(padding.data(), padding.size());
}
}
string proto_str = proto->SerializeAsString();
proto->set_crc(crc32(crc_init,
reinterpret_cast<const Bytef*>(proto_str.c_str()),
proto_str.size()));
char* data = nullptr;
if (posix_memalign(reinterpret_cast<void**>(&data),
pagesize, proto->ByteSize())) {
PLOG_TO(SYSTEM, ERROR) << "Faied to alloc aligned buffer (size: "
<< proto->ByteSize() << ")";
return data;
}
proto->SerializeToArray(data, proto->ByteSize());
return data;
}
void storaged_t::flush_proto_user_system(StoragedProto* proto) {
string proto_str = proto->SerializeAsString();
const char* data = proto_str.data();
uint32_t size = proto_str.size();
ssize_t ret;
time_point<steady_clock> start, end;
string proto_file = proto_path(USER_SYSTEM);
void storaged_t::flush_proto_data(userid_t user_id,
const char* data, ssize_t size) {
string proto_file = proto_path(user_id);
string tmp_file = proto_file + "_tmp";
unique_fd fd(TEMP_FAILURE_RETRY(open(tmp_file.c_str(),
O_DIRECT | O_SYNC | O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC,
S_IRUSR | S_IWUSR)));
O_SYNC | O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC |
(user_id == USER_SYSTEM ? O_DIRECT : 0),
S_IRUSR | S_IWUSR)));
if (fd == -1) {
PLOG_TO(SYSTEM, ERROR) << "Faied to open tmp file: " << tmp_file;
return;
}
uint32_t benchmark_size = 0;
uint64_t benchmark_time_ns = 0;
while (size > 0) {
start = steady_clock::now();
ret = write(fd, data, MIN(benchmark_unit_size, size));
if (ret <= 0) {
if (user_id == USER_SYSTEM) {
time_point<steady_clock> start, end;
uint32_t benchmark_size = 0;
uint64_t benchmark_time_ns = 0;
ssize_t ret;
bool first_write = true;
while (size > 0) {
start = steady_clock::now();
ret = write(fd, data, MIN(benchmark_unit_size, size));
if (ret <= 0) {
PLOG_TO(SYSTEM, ERROR) << "Faied to write tmp file: " << tmp_file;
return;
}
end = steady_clock::now();
/*
* compute bandwidth after the first write and if write returns
* exactly unit size.
*/
if (!first_write && ret == benchmark_unit_size) {
benchmark_size += benchmark_unit_size;
benchmark_time_ns += duration_cast<nanoseconds>(end - start).count();
}
size -= ret;
data += ret;
first_write = false;
}
if (benchmark_size) {
int perf = benchmark_size * 1000000LLU / benchmark_time_ns;
storage_info->update_perf_history(perf, system_clock::now());
}
} else {
if (!WriteFully(fd, data, size)) {
PLOG_TO(SYSTEM, ERROR) << "Faied to write tmp file: " << tmp_file;
return;
}
end = steady_clock::now();
/*
* compute bandwidth after the first write and if write returns
* exactly unit size.
*/
if (size != proto_str.size() && ret == benchmark_unit_size) {
benchmark_size += benchmark_unit_size;
benchmark_time_ns += duration_cast<nanoseconds>(end - start).count();
}
size -= ret;
data += ret;
}
if (benchmark_size) {
int perf = benchmark_size * 1000000LLU / benchmark_time_ns;
storage_info->update_perf_history(perf, system_clock::now());
}
fd.reset(-1);
/* Atomically replace existing proto file to reduce chance of data loss. */
rename(tmp_file.c_str(), proto_file.c_str());
}
void storaged_t::flush_proto(userid_t user_id, StoragedProto* proto) {
prepare_proto(user_id, proto);
unique_ptr<char> proto_data(prepare_proto(user_id, proto));
if (proto_data == nullptr) return;
if (user_id == USER_SYSTEM) {
flush_proto_user_system(proto);
return;
}
string proto_file = proto_path(user_id);
string tmp_file = proto_file + "_tmp";
if (!WriteStringToFile(proto->SerializeAsString(), tmp_file,
S_IRUSR | S_IWUSR)) {
return;
}
/* Atomically replace existing proto file to reduce chance of data loss. */
rename(tmp_file.c_str(), proto_file.c_str());
flush_proto_data(user_id, proto_data.get(), proto->ByteSize());
}
void storaged_t::flush_protos(unordered_map<int, StoragedProto>* protos) {

View file

@ -56,5 +56,5 @@ message StoragedProto {
optional uint32 version = 2;
optional UidIOUsage uid_io_usage = 3;
optional IOPerfHistory perf_history = 4;
repeated uint32 padding = 5;
optional bytes padding = 5;
}