diff options
author | Doug Zongker <dougz@android.com> | 2013-07-09 10:34:46 -0700 |
---|---|---|
committer | Doug Zongker <dougz@android.com> | 2013-07-09 10:42:15 -0700 |
commit | c870a99c4aeb9e232ee68951e666b5fa670d1680 (patch) | |
tree | fa17347278bb2b3c013d5834491ce639bb6b1c1a /applypatch | |
parent | 044a0b4d49a11edfa13471ce20914b0514eb7e0e (diff) | |
download | bootable_recovery-c870a99c4aeb9e232ee68951e666b5fa670d1680.zip bootable_recovery-c870a99c4aeb9e232ee68951e666b5fa670d1680.tar.gz bootable_recovery-c870a99c4aeb9e232ee68951e666b5fa670d1680.tar.bz2 |
recovery: write partitions more conservatively
Write and verify partitions using write(2) and read(2) rather than the
stdio functions. Read and write in 4kb blocks. When writing, fsync()
every 1MB.
Bug: 9602014
Change-Id: Ie98ce38e857786fc0f4ebf36bb5ffc93b41bc96f
Diffstat (limited to 'applypatch')
-rw-r--r-- | applypatch/applypatch.c | 70 |
1 files changed, 46 insertions, 24 deletions
diff --git a/applypatch/applypatch.c b/applypatch/applypatch.c index 2f134df..3f67c32 100644 --- a/applypatch/applypatch.c +++ b/applypatch/applypatch.c @@ -424,42 +424,50 @@ int WriteToPartition(unsigned char* data, size_t len, { size_t start = 0; int success = 0; - FILE* f = fopen(partition, "r+b"); - if (f == NULL) { + int fd = open(partition, O_RDWR); + if (fd < 0) { printf("failed to open %s: %s\n", partition, strerror(errno)); return -1; } int attempt; - for (attempt = 0; attempt < 3; ++attempt) { - printf("write %s attempt %d start at %d\n", partition, attempt+1, start); - fseek(f, start, SEEK_SET); + for (attempt = 0; attempt < 10; ++attempt) { + off_t next_sync = start + (1<<20); + printf("raw write %s attempt %d start at %d\n", partition, attempt+1, start); + lseek(fd, start, SEEK_SET); while (start < len) { size_t to_write = len - start; - if (to_write > (1<<20)) to_write = 1<<20; - - if (fwrite(data+start, 1, to_write, f) != to_write) { - printf("short write writing to %s (%s)\n", - partition, strerror(errno)); - return -1; + if (to_write > 4096) to_write = 4096; + + ssize_t written = write(fd, data+start, to_write); + if (written < 0) { + if (errno == EINTR) { + written = 0; + } else { + printf("failed write writing to %s (%s)\n", + partition, strerror(errno)); + return -1; + } } - start += to_write; - if (start < len) { - usleep(50000); // 50 ms + start += written; + if (start >= next_sync) { + fsync(fd); + next_sync = start + (1<<20); } } + fsync(fd); // drop caches so our subsequent verification read // won't just be reading the cache. sync(); - FILE* dc = fopen("/proc/sys/vm/drop_caches", "w"); - fwrite("3\n", 2, 1, dc); - fclose(dc); + int dc = open("/proc/sys/vm/drop_caches", O_WRONLY); + write(dc, "3\n", 2); + close(dc); sleep(1); printf(" caches dropped\n"); // verify - fseek(f, 0, SEEK_SET); + lseek(fd, 0, SEEK_SET); unsigned char buffer[4096]; start = len; size_t p; @@ -467,11 +475,23 @@ int WriteToPartition(unsigned char* data, size_t len, size_t to_read = len - p; if (to_read > sizeof(buffer)) to_read = sizeof(buffer); - if (fread(buffer, 1, to_read, f) != to_read) { - printf("short verify read %s at %d: %s\n", - partition, p, strerror(errno)); - start = p; - break; + size_t so_far = 0; + while (so_far < to_read) { + ssize_t read_count = read(fd, buffer+so_far, to_read-so_far); + if (read_count < 0) { + if (errno == EINTR) { + read_count = 0; + } else { + printf("verify read error %s at %d: %s\n", + partition, p, strerror(errno)); + return -1; + } + } + if (read_count < to_read) { + printf("short verify read %s at %d: %d %d %s\n", + partition, p, read_count, to_read, strerror(errno)); + } + so_far += read_count; } if (memcmp(buffer, data+p, to_read)) { @@ -486,6 +506,8 @@ int WriteToPartition(unsigned char* data, size_t len, success = true; break; } + + sleep(2); } if (!success) { @@ -493,7 +515,7 @@ int WriteToPartition(unsigned char* data, size_t len, return -1; } - if (fclose(f) != 0) { + if (close(fd) != 0) { printf("error closing %s (%s)\n", partition, strerror(errno)); return -1; } |