Call ioctl before each write on retry
If the update is a retry, ioctl(BLKDISCARD) the destination blocks before writing to these blocks. Bug: 28990135 Change-Id: I1e703808e68ebb1292cd66afd76be8fd6946ee59
This commit is contained in:
parent
50f6417317
commit
7ce287d432
4 changed files with 76 additions and 14 deletions
|
@ -49,6 +49,8 @@ typedef struct {
|
||||||
// in addition to the error code.
|
// in addition to the error code.
|
||||||
CauseCode cause_code = kNoCause;
|
CauseCode cause_code = kNoCause;
|
||||||
|
|
||||||
|
bool is_retry = false;
|
||||||
|
|
||||||
} State;
|
} State;
|
||||||
|
|
||||||
#define VAL_STRING 1 // data will be NULL-terminated; size doesn't count null
|
#define VAL_STRING 1 // data will be NULL-terminated; size doesn't count null
|
||||||
|
|
19
install.cpp
19
install.cpp
|
@ -56,7 +56,7 @@ static const float DEFAULT_IMAGE_PROGRESS_FRACTION = 0.1;
|
||||||
// If the package contains an update binary, extract it and run it.
|
// If the package contains an update binary, extract it and run it.
|
||||||
static int
|
static int
|
||||||
try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache,
|
try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache,
|
||||||
std::vector<std::string>& log_buffer)
|
std::vector<std::string>& log_buffer, int retry_count)
|
||||||
{
|
{
|
||||||
const ZipEntry* binary_entry =
|
const ZipEntry* binary_entry =
|
||||||
mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
|
mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
|
||||||
|
@ -130,15 +130,19 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache,
|
||||||
//
|
//
|
||||||
// - the name of the package zip file.
|
// - the name of the package zip file.
|
||||||
//
|
//
|
||||||
|
// - an optional argument "retry" if this update is a retry of a failed
|
||||||
|
// update attempt.
|
||||||
|
//
|
||||||
|
|
||||||
const char** args = (const char**)malloc(sizeof(char*) * 5);
|
const char** args = (const char**)malloc(sizeof(char*) * 6);
|
||||||
args[0] = binary;
|
args[0] = binary;
|
||||||
args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk
|
args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk
|
||||||
char* temp = (char*)malloc(10);
|
char* temp = (char*)malloc(10);
|
||||||
sprintf(temp, "%d", pipefd[1]);
|
sprintf(temp, "%d", pipefd[1]);
|
||||||
args[2] = temp;
|
args[2] = temp;
|
||||||
args[3] = (char*)path;
|
args[3] = (char*)path;
|
||||||
args[4] = NULL;
|
args[4] = retry_count > 0 ? "retry" : NULL;
|
||||||
|
args[5] = NULL;
|
||||||
|
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
|
@ -215,7 +219,7 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache,
|
||||||
|
|
||||||
static int
|
static int
|
||||||
really_install_package(const char *path, bool* wipe_cache, bool needs_mount,
|
really_install_package(const char *path, bool* wipe_cache, bool needs_mount,
|
||||||
std::vector<std::string>& log_buffer)
|
std::vector<std::string>& log_buffer, int retry_count)
|
||||||
{
|
{
|
||||||
ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
|
ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
|
||||||
ui->Print("Finding update package...\n");
|
ui->Print("Finding update package...\n");
|
||||||
|
@ -276,8 +280,11 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount,
|
||||||
|
|
||||||
// Verify and install the contents of the package.
|
// Verify and install the contents of the package.
|
||||||
ui->Print("Installing update...\n");
|
ui->Print("Installing update...\n");
|
||||||
|
if (retry_count > 0) {
|
||||||
|
ui->Print("Retry attempt: %d\n", retry_count);
|
||||||
|
}
|
||||||
ui->SetEnableReboot(false);
|
ui->SetEnableReboot(false);
|
||||||
int result = try_update_binary(path, &zip, wipe_cache, log_buffer);
|
int result = try_update_binary(path, &zip, wipe_cache, log_buffer, retry_count);
|
||||||
ui->SetEnableReboot(true);
|
ui->SetEnableReboot(true);
|
||||||
ui->Print("\n");
|
ui->Print("\n");
|
||||||
|
|
||||||
|
@ -306,7 +313,7 @@ install_package(const char* path, bool* wipe_cache, const char* install_file,
|
||||||
LOGE("failed to set up expected mounts for install; aborting\n");
|
LOGE("failed to set up expected mounts for install; aborting\n");
|
||||||
result = INSTALL_ERROR;
|
result = INSTALL_ERROR;
|
||||||
} else {
|
} else {
|
||||||
result = really_install_package(path, wipe_cache, needs_mount, log_buffer);
|
result = really_install_package(path, wipe_cache, needs_mount, log_buffer, retry_count);
|
||||||
}
|
}
|
||||||
if (install_log != nullptr) {
|
if (install_log != nullptr) {
|
||||||
fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log);
|
fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log);
|
||||||
|
|
|
@ -70,6 +70,7 @@ struct RangeSet {
|
||||||
};
|
};
|
||||||
|
|
||||||
static CauseCode failure_type = kNoCause;
|
static CauseCode failure_type = kNoCause;
|
||||||
|
static bool is_retry = false;
|
||||||
static std::map<std::string, RangeSet> stash_map;
|
static std::map<std::string, RangeSet> stash_map;
|
||||||
|
|
||||||
static void parse_range(const std::string& range_text, RangeSet& rs) {
|
static void parse_range(const std::string& range_text, RangeSet& rs) {
|
||||||
|
@ -179,6 +180,21 @@ static int write_all(int fd, const std::vector<uint8_t>& buffer, size_t size) {
|
||||||
return write_all(fd, buffer.data(), size);
|
return write_all(fd, buffer.data(), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool discard_blocks(int fd, off64_t offset, uint64_t size) {
|
||||||
|
// Don't discard blocks unless the update is a retry run.
|
||||||
|
if (!is_retry) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t args[2] = {static_cast<uint64_t>(offset), size};
|
||||||
|
int status = ioctl(fd, BLKDISCARD, &args);
|
||||||
|
if (status == -1) {
|
||||||
|
fprintf(stderr, "BLKDISCARD ioctl failed: %s\n", strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool check_lseek(int fd, off64_t offset, int whence) {
|
static bool check_lseek(int fd, off64_t offset, int whence) {
|
||||||
off64_t rc = TEMP_FAILURE_RETRY(lseek64(fd, offset, whence));
|
off64_t rc = TEMP_FAILURE_RETRY(lseek64(fd, offset, whence));
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
|
@ -238,10 +254,15 @@ static ssize_t RangeSinkWrite(const uint8_t* data, ssize_t size, void* token) {
|
||||||
rss->p_remain = (rss->tgt.pos[rss->p_block * 2 + 1] -
|
rss->p_remain = (rss->tgt.pos[rss->p_block * 2 + 1] -
|
||||||
rss->tgt.pos[rss->p_block * 2]) * BLOCKSIZE;
|
rss->tgt.pos[rss->p_block * 2]) * BLOCKSIZE;
|
||||||
|
|
||||||
if (!check_lseek(rss->fd, (off64_t)rss->tgt.pos[rss->p_block*2] * BLOCKSIZE,
|
off64_t offset = static_cast<off64_t>(rss->tgt.pos[rss->p_block*2]) * BLOCKSIZE;
|
||||||
SEEK_SET)) {
|
if (!discard_blocks(rss->fd, offset, rss->p_remain)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!check_lseek(rss->fd, offset, SEEK_SET)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// we can't write any more; return how many bytes have
|
// we can't write any more; return how many bytes have
|
||||||
// been written so far.
|
// been written so far.
|
||||||
|
@ -347,11 +368,15 @@ static int WriteBlocks(const RangeSet& tgt, const std::vector<uint8_t>& buffer,
|
||||||
|
|
||||||
size_t p = 0;
|
size_t p = 0;
|
||||||
for (size_t i = 0; i < tgt.count; ++i) {
|
for (size_t i = 0; i < tgt.count; ++i) {
|
||||||
if (!check_lseek(fd, (off64_t) tgt.pos[i * 2] * BLOCKSIZE, SEEK_SET)) {
|
off64_t offset = static_cast<off64_t>(tgt.pos[i * 2]) * BLOCKSIZE;
|
||||||
|
size_t size = (tgt.pos[i * 2 + 1] - tgt.pos[i * 2]) * BLOCKSIZE;
|
||||||
|
if (!discard_blocks(fd, offset, size)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size = (tgt.pos[i * 2 + 1] - tgt.pos[i * 2]) * BLOCKSIZE;
|
if (!check_lseek(fd, offset, SEEK_SET)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (write_all(fd, data + p, size) == -1) {
|
if (write_all(fd, data + p, size) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1104,7 +1129,13 @@ static int PerformCommandZero(CommandParameters& params) {
|
||||||
|
|
||||||
if (params.canwrite) {
|
if (params.canwrite) {
|
||||||
for (size_t i = 0; i < tgt.count; ++i) {
|
for (size_t i = 0; i < tgt.count; ++i) {
|
||||||
if (!check_lseek(params.fd, (off64_t) tgt.pos[i * 2] * BLOCKSIZE, SEEK_SET)) {
|
off64_t offset = static_cast<off64_t>(tgt.pos[i * 2]) * BLOCKSIZE;
|
||||||
|
size_t size = (tgt.pos[i * 2 + 1] - tgt.pos[i * 2]) * BLOCKSIZE;
|
||||||
|
if (!discard_blocks(params.fd, offset, size)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!check_lseek(params.fd, offset, SEEK_SET)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1143,7 +1174,12 @@ static int PerformCommandNew(CommandParameters& params) {
|
||||||
rss.p_block = 0;
|
rss.p_block = 0;
|
||||||
rss.p_remain = (tgt.pos[1] - tgt.pos[0]) * BLOCKSIZE;
|
rss.p_remain = (tgt.pos[1] - tgt.pos[0]) * BLOCKSIZE;
|
||||||
|
|
||||||
if (!check_lseek(params.fd, (off64_t) tgt.pos[0] * BLOCKSIZE, SEEK_SET)) {
|
off64_t offset = static_cast<off64_t>(tgt.pos[0]) * BLOCKSIZE;
|
||||||
|
if (!discard_blocks(params.fd, offset, tgt.size * BLOCKSIZE)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!check_lseek(params.fd, offset, SEEK_SET)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1221,7 +1257,12 @@ static int PerformCommandDiff(CommandParameters& params) {
|
||||||
rss.p_block = 0;
|
rss.p_block = 0;
|
||||||
rss.p_remain = (tgt.pos[1] - tgt.pos[0]) * BLOCKSIZE;
|
rss.p_remain = (tgt.pos[1] - tgt.pos[0]) * BLOCKSIZE;
|
||||||
|
|
||||||
if (!check_lseek(params.fd, (off64_t) tgt.pos[0] * BLOCKSIZE, SEEK_SET)) {
|
off64_t offset = static_cast<off64_t>(tgt.pos[0]) * BLOCKSIZE;
|
||||||
|
if (!discard_blocks(params.fd, offset, rss.p_remain)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!check_lseek(params.fd, offset, SEEK_SET)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1340,6 +1381,10 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
|
||||||
params.canwrite = !dryrun;
|
params.canwrite = !dryrun;
|
||||||
|
|
||||||
fprintf(stderr, "performing %s\n", dryrun ? "verification" : "update");
|
fprintf(stderr, "performing %s\n", dryrun ? "verification" : "update");
|
||||||
|
if (state->is_retry) {
|
||||||
|
is_retry = true;
|
||||||
|
fprintf(stderr, "This update is a retry.\n");
|
||||||
|
}
|
||||||
|
|
||||||
Value* blockdev_filename = nullptr;
|
Value* blockdev_filename = nullptr;
|
||||||
Value* transfer_list_value = nullptr;
|
Value* transfer_list_value = nullptr;
|
||||||
|
|
|
@ -48,7 +48,7 @@ int main(int argc, char** argv) {
|
||||||
setbuf(stdout, NULL);
|
setbuf(stdout, NULL);
|
||||||
setbuf(stderr, NULL);
|
setbuf(stderr, NULL);
|
||||||
|
|
||||||
if (argc != 4) {
|
if (argc != 4 && argc != 5) {
|
||||||
printf("unexpected number of arguments (%d)\n", argc);
|
printf("unexpected number of arguments (%d)\n", argc);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -142,6 +142,14 @@ int main(int argc, char** argv) {
|
||||||
state.script = script;
|
state.script = script;
|
||||||
state.errmsg = NULL;
|
state.errmsg = NULL;
|
||||||
|
|
||||||
|
if (argc == 5) {
|
||||||
|
if (strcmp(argv[4], "retry") == 0) {
|
||||||
|
state.is_retry = true;
|
||||||
|
} else {
|
||||||
|
printf("unexpected argument: %s", argv[4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
char* result = Evaluate(&state, root);
|
char* result = Evaluate(&state, root);
|
||||||
|
|
||||||
if (have_eio_error) {
|
if (have_eio_error) {
|
||||||
|
|
Loading…
Reference in a new issue