libupgrade: Ensure main/backup partition in sync
For r/w variables, hnvram maintains a main and a backup partition which
should be identical under normal circumstances. For read operations, it
looks at the main partition first and only reads the backup partition if
it fails to read the main partition. Inconsistencies go unnoticed. For
write operations, it would only write to the flash if the value being
written is different from the value that is already stored on the flash.
With this approach, we might end up in a situation where the main and
the backup partitions contain different values for the same variable,
but still, a write operation would not fix the problem.
Example: Let's say the main and backup partitions contain VAR=abc and
VAR=xyz, respectively. Previously, the command "hnvram -w VAR=abc" would
not write VAR=abc to the backup partition because a read operation
yields VAR=abc which is why it decides that no write operation is
necessary.
Let's move the logic that skips unnecessary writes a few levels down
where it checks the main and backup partitions separately.
Change-Id: I6c120b9cb537da2097681a619a568a1ca917509f
diff --git a/libupgrade/hmx_upgrade_flash.c b/libupgrade/hmx_upgrade_flash.c
index 7a22a01..ce9268c 100644
--- a/libupgrade/hmx_upgrade_flash.c
+++ b/libupgrade/hmx_upgrade_flash.c
@@ -115,14 +115,22 @@
unsigned int size )
{
int ret;
+ void *buf;
if (libupgrade_verbose) printf("[%s] offset %08lx, size %d, data = %02x\n",
__FUNCTION__, offset, size, data[0] );
+ buf = malloc(size);
+ if(!buf) {
+ perror("malloc");
+ return -1;
+ }
+
if ( fd_nvram < 0 ) {
fd_nvram = open(TARGET_NVRAM_MTD, (O_RDWR | O_SYNC) );
if( fd_nvram < 0 ) {
perror(TARGET_NVRAM_MTD);
+ free(buf);
return -1;
}
}
@@ -130,14 +138,32 @@
ret = lseek(fd_nvram, offset, SEEK_SET);
if(ret < 0) {
perror("lseek");
+ free(buf);
return -1;
}
- ret = write(fd_nvram, data, size);
+ /* Only write to flash if data is different from what is already there. */
+ ret = read(fd_nvram, buf, size);
if(ret < 0) {
- perror("write");
+ perror("read");
+ free(buf);
return -1;
}
+ if (ret!=size || memcmp(data, buf, size)) {
+ ret = lseek(fd_nvram, offset, SEEK_SET);
+ if(ret < 0) {
+ perror("lseek");
+ free(buf);
+ return -1;
+ }
+
+ ret = write(fd_nvram, data, size);
+ if(ret < 0) {
+ perror("write");
+ free(buf);
+ return -1;
+ }
+ }
/* Writes to /dev/mtdblockX are cached indefinitely until the last file
* descriptor is closed. Flush this cache after writing. The user depends on
@@ -146,9 +172,11 @@
ret = ioctl(fd_nvram, BLKFLSBUF, 0);
if(ret < 0) {
perror("ioctl(hnvram, BLKFLSBUF, 0)");
+ free(buf);
return -1;
}
+ free(buf);
return 0;
}
diff --git a/libupgrade/hmx_upgrade_nvram.c b/libupgrade/hmx_upgrade_nvram.c
index c3434d6..77563b8 100644
--- a/libupgrade/hmx_upgrade_nvram.c
+++ b/libupgrade/hmx_upgrade_nvram.c
@@ -856,33 +856,12 @@
unsigned char szFileName[MAX_NVRAM_FILENAME_LENGTH];
HMX_NVRAM_PARTITION_E partition;
unsigned int defaultSize;
- unsigned char *pBuf;
unsigned int systemId;
- unsigned int pLen = 0;
if (data == NULL || field == NVRAM_FIELD_DUMMY) {
return DRV_ERR_INVALID_PARAMETER;
}
- pBuf = malloc(nDataSize);
- if (pBuf == NULL) {
- return DRV_ERR_OUTOFMEMORY;
- }
-
- unsigned int fieldLen = 0;
- // Need to use fieldLen for actual field length because pLen is always
- // <= nDataSize. If input data size is shorter this may falsely skip hnvram
- // writing.
- if (HMX_NVRAM_GetLength(field, &fieldLen) == DRV_OK &&
- HMX_NVRAM_GetFieldAndSize(field, offset, pBuf, nDataSize, &pLen)
- == DRV_OK) {
- if (memcmp(pBuf, data, nDataSize) == 0 && fieldLen == nDataSize) {
- free(pBuf);
- return DRV_OK;
- }
- }
- free(pBuf);
-
errCode = drv_NVRAM_GetFieldInfo(field, &partition, szFileName, &defaultSize);
if (errCode != DRV_OK) {
DEBUG_ERR("[HMX_NVRAM_SetField] error(%08X) : HMX_NVRAM_GetFieldInfo, "