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
This commit is contained in:
+45
-23
@@ -424,42 +424,50 @@ int WriteToPartition(unsigned char* data, size_t len,
|
|||||||
{
|
{
|
||||||
size_t start = 0;
|
size_t start = 0;
|
||||||
int success = 0;
|
int success = 0;
|
||||||
FILE* f = fopen(partition, "r+b");
|
int fd = open(partition, O_RDWR);
|
||||||
if (f == NULL) {
|
if (fd < 0) {
|
||||||
printf("failed to open %s: %s\n", partition, strerror(errno));
|
printf("failed to open %s: %s\n", partition, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int attempt;
|
int attempt;
|
||||||
|
|
||||||
for (attempt = 0; attempt < 3; ++attempt) {
|
for (attempt = 0; attempt < 10; ++attempt) {
|
||||||
printf("write %s attempt %d start at %d\n", partition, attempt+1, start);
|
off_t next_sync = start + (1<<20);
|
||||||
fseek(f, start, SEEK_SET);
|
printf("raw write %s attempt %d start at %d\n", partition, attempt+1, start);
|
||||||
|
lseek(fd, start, SEEK_SET);
|
||||||
while (start < len) {
|
while (start < len) {
|
||||||
size_t to_write = len - start;
|
size_t to_write = len - start;
|
||||||
if (to_write > (1<<20)) to_write = 1<<20;
|
if (to_write > 4096) to_write = 4096;
|
||||||
|
|
||||||
if (fwrite(data+start, 1, to_write, f) != to_write) {
|
ssize_t written = write(fd, data+start, to_write);
|
||||||
printf("short write writing to %s (%s)\n",
|
if (written < 0) {
|
||||||
partition, strerror(errno));
|
if (errno == EINTR) {
|
||||||
return -1;
|
written = 0;
|
||||||
|
} else {
|
||||||
|
printf("failed write writing to %s (%s)\n",
|
||||||
|
partition, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
start += to_write;
|
start += written;
|
||||||
if (start < len) {
|
if (start >= next_sync) {
|
||||||
usleep(50000); // 50 ms
|
fsync(fd);
|
||||||
|
next_sync = start + (1<<20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fsync(fd);
|
||||||
|
|
||||||
// drop caches so our subsequent verification read
|
// drop caches so our subsequent verification read
|
||||||
// won't just be reading the cache.
|
// won't just be reading the cache.
|
||||||
sync();
|
sync();
|
||||||
FILE* dc = fopen("/proc/sys/vm/drop_caches", "w");
|
int dc = open("/proc/sys/vm/drop_caches", O_WRONLY);
|
||||||
fwrite("3\n", 2, 1, dc);
|
write(dc, "3\n", 2);
|
||||||
fclose(dc);
|
close(dc);
|
||||||
sleep(1);
|
sleep(1);
|
||||||
printf(" caches dropped\n");
|
printf(" caches dropped\n");
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
fseek(f, 0, SEEK_SET);
|
lseek(fd, 0, SEEK_SET);
|
||||||
unsigned char buffer[4096];
|
unsigned char buffer[4096];
|
||||||
start = len;
|
start = len;
|
||||||
size_t p;
|
size_t p;
|
||||||
@@ -467,11 +475,23 @@ int WriteToPartition(unsigned char* data, size_t len,
|
|||||||
size_t to_read = len - p;
|
size_t to_read = len - p;
|
||||||
if (to_read > sizeof(buffer)) to_read = sizeof(buffer);
|
if (to_read > sizeof(buffer)) to_read = sizeof(buffer);
|
||||||
|
|
||||||
if (fread(buffer, 1, to_read, f) != to_read) {
|
size_t so_far = 0;
|
||||||
printf("short verify read %s at %d: %s\n",
|
while (so_far < to_read) {
|
||||||
partition, p, strerror(errno));
|
ssize_t read_count = read(fd, buffer+so_far, to_read-so_far);
|
||||||
start = p;
|
if (read_count < 0) {
|
||||||
break;
|
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)) {
|
if (memcmp(buffer, data+p, to_read)) {
|
||||||
@@ -486,6 +506,8 @@ int WriteToPartition(unsigned char* data, size_t len,
|
|||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sleep(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@@ -493,7 +515,7 @@ int WriteToPartition(unsigned char* data, size_t len,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fclose(f) != 0) {
|
if (close(fd) != 0) {
|
||||||
printf("error closing %s (%s)\n", partition, strerror(errno));
|
printf("error closing %s (%s)\n", partition, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user