aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--external/common/arch_flash.h3
-rw-r--r--external/common/arch_flash_arm.c4
-rw-r--r--external/common/arch_flash_powerpc.c8
-rw-r--r--external/common/arch_flash_x86.c4
-rw-r--r--external/gard/gard.c2
-rw-r--r--external/pflash/pflash.c2
-rw-r--r--libflash/blocklevel.c70
-rw-r--r--libflash/blocklevel.h4
-rw-r--r--libflash/file.c94
-rw-r--r--libflash/file.h4
-rw-r--r--libflash/libflash.c4
11 files changed, 162 insertions, 37 deletions
diff --git a/external/common/arch_flash.h b/external/common/arch_flash.h
index 60c4de8..918ffa9 100644
--- a/external/common/arch_flash.h
+++ b/external/common/arch_flash.h
@@ -20,7 +20,8 @@
#include <getopt.h>
#include <libflash/blocklevel.h>
-int arch_flash_init(struct blocklevel_device **bl, const char *file);
+int arch_flash_init(struct blocklevel_device **bl, const char *file,
+ bool keep_alive);
void arch_flash_close(struct blocklevel_device *bl, const char *file);
diff --git a/external/common/arch_flash_arm.c b/external/common/arch_flash_arm.c
index 13d2946..f65bddc 100644
--- a/external/common/arch_flash_arm.c
+++ b/external/common/arch_flash_arm.c
@@ -263,7 +263,7 @@ int arch_flash_set_wrprotect(struct blocklevel_device *bl, int set)
return set_wrprotect(set);
}
-int arch_flash_init(struct blocklevel_device **r_bl, const char *file)
+int arch_flash_init(struct blocklevel_device **r_bl, const char *file, bool keep_alive)
{
struct blocklevel_device *new_bl;
@@ -272,7 +272,7 @@ int arch_flash_init(struct blocklevel_device **r_bl, const char *file)
return -1;
if (file) {
- file_init_path(file, NULL, &new_bl);
+ file_init_path(file, NULL, keep_alive, &new_bl);
} else {
new_bl = flash_setup(arch_data.bmc);
}
diff --git a/external/common/arch_flash_powerpc.c b/external/common/arch_flash_powerpc.c
index 93eacee..19dfec8 100644
--- a/external/common/arch_flash_powerpc.c
+++ b/external/common/arch_flash_powerpc.c
@@ -188,7 +188,7 @@ static int get_dev_mtd(const char *fdt_flash_path, char **mtd_path)
return done ? rc : -1;
}
-static struct blocklevel_device *arch_init_blocklevel(const char *file)
+static struct blocklevel_device *arch_init_blocklevel(const char *file, bool keep_alive)
{
int rc;
struct blocklevel_device *new_bl = NULL;
@@ -200,7 +200,7 @@ static struct blocklevel_device *arch_init_blocklevel(const char *file)
return NULL;
}
- file_init_path(file ? file : real_file, NULL, &new_bl);
+ file_init_path(file ? file : real_file, NULL, keep_alive, &new_bl);
free(real_file);
return new_bl;
}
@@ -211,11 +211,11 @@ int arch_flash_set_wrprotect(struct blocklevel_device *bl, int set)
return 0;
}
-int arch_flash_init(struct blocklevel_device **r_bl, const char *file)
+int arch_flash_init(struct blocklevel_device **r_bl, const char *file, bool keep_alive)
{
struct blocklevel_device *new_bl;
- new_bl = arch_init_blocklevel(file);
+ new_bl = arch_init_blocklevel(file, keep_alive);
if (!new_bl)
return -1;
diff --git a/external/common/arch_flash_x86.c b/external/common/arch_flash_x86.c
index 29c0229..3be05df 100644
--- a/external/common/arch_flash_x86.c
+++ b/external/common/arch_flash_x86.c
@@ -28,7 +28,7 @@
#include "arch_flash.h"
-int arch_flash_init(struct blocklevel_device **r_bl, const char *file)
+int arch_flash_init(struct blocklevel_device **r_bl, const char *file, bool keep_alive)
{
struct blocklevel_device *new_bl;
@@ -38,7 +38,7 @@ int arch_flash_init(struct blocklevel_device **r_bl, const char *file)
return -1;
}
- file_init_path(file, NULL, &new_bl);
+ file_init_path(file, NULL, keep_alive, &new_bl);
if (!new_bl)
return -1;
diff --git a/external/gard/gard.c b/external/gard/gard.c
index 53f31d9..2163707 100644
--- a/external/gard/gard.c
+++ b/external/gard/gard.c
@@ -637,7 +637,7 @@ int main(int argc, char **argv)
argv += optind;
action = argv[0];
- if (arch_flash_init(&(ctx->bl), filename)) {
+ if (arch_flash_init(&(ctx->bl), filename, true)) {
/* Can fail for a few ways, most likely couldn't open MTD device */
fprintf(stderr, "Can't open %s\n", filename ? filename : "MTD Device. Are you root?");
rc = EXIT_FAILURE;
diff --git a/external/pflash/pflash.c b/external/pflash/pflash.c
index 8231708..c1d4949 100644
--- a/external/pflash/pflash.c
+++ b/external/pflash/pflash.c
@@ -722,7 +722,7 @@ int main(int argc, char *argv[])
}
}
- if (arch_flash_init(&bl, NULL))
+ if (arch_flash_init(&bl, NULL, true))
exit(1);
on_exit(exiting, NULL);
diff --git a/libflash/blocklevel.c b/libflash/blocklevel.c
index 83823c5..9591194 100644
--- a/libflash/blocklevel.c
+++ b/libflash/blocklevel.c
@@ -58,6 +58,25 @@ static int ecc_protected(struct blocklevel_device *bl, uint32_t pos, uint32_t le
return 0;
}
+static int reacquire(struct blocklevel_device *bl)
+{
+ if (!bl->keep_alive && bl->reacquire)
+ return bl->reacquire(bl);
+ return 0;
+}
+
+static int release(struct blocklevel_device *bl)
+{
+ int rc = 0;
+ if (!bl->keep_alive && bl->release) {
+ /* This is the error return path a lot, preserve errno */
+ int err = errno;
+ rc = bl->release(bl);
+ errno = err;
+ }
+ return rc;
+}
+
int blocklevel_read(struct blocklevel_device *bl, uint32_t pos, void *buf, uint32_t len)
{
int rc;
@@ -69,14 +88,21 @@ int blocklevel_read(struct blocklevel_device *bl, uint32_t pos, void *buf, uint3
return FLASH_ERR_PARM_ERROR;
}
+ rc = reacquire(bl);
+ if (rc)
+ return rc;
+
if (!ecc_protected(bl, pos, len)) {
- return bl->read(bl, pos, buf, len);
+ rc = bl->read(bl, pos, buf, len);
+ release(bl);
+ return rc;
}
buffer = malloc(ecc_len);
if (!buffer) {
errno = ENOMEM;
- return FLASH_ERR_MALLOC_FAILED;
+ rc = FLASH_ERR_MALLOC_FAILED;
+ goto out;
}
rc = bl->read(bl, pos, buffer, ecc_len);
@@ -89,6 +115,7 @@ int blocklevel_read(struct blocklevel_device *bl, uint32_t pos, void *buf, uint3
}
out:
+ release(bl);
free(buffer);
return rc;
}
@@ -104,14 +131,21 @@ int blocklevel_write(struct blocklevel_device *bl, uint32_t pos, const void *buf
return FLASH_ERR_PARM_ERROR;
}
+ rc = reacquire(bl);
+ if (rc)
+ return rc;
+
if (!ecc_protected(bl, pos, len)) {
- return bl->write(bl, pos, buf, len);
+ rc = bl->write(bl, pos, buf, len);
+ release(bl);
+ return rc;
}
buffer = malloc(ecc_len);
if (!buffer) {
errno = ENOMEM;
- return FLASH_ERR_MALLOC_FAILED;
+ rc = FLASH_ERR_MALLOC_FAILED;
+ goto out;
}
if (memcpy_to_ecc(buffer, buf, len)) {
@@ -119,14 +153,18 @@ int blocklevel_write(struct blocklevel_device *bl, uint32_t pos, const void *buf
rc = FLASH_ERR_ECC_INVALID;
goto out;
}
+
rc = bl->write(bl, pos, buffer, ecc_len);
+
out:
+ release(bl);
free(buffer);
return rc;
}
int blocklevel_erase(struct blocklevel_device *bl, uint32_t pos, uint32_t len)
{
+ int rc;
if (!bl || !bl->erase) {
errno = EINVAL;
return FLASH_ERR_PARM_ERROR;
@@ -139,7 +177,15 @@ int blocklevel_erase(struct blocklevel_device *bl, uint32_t pos, uint32_t len)
return FLASH_ERR_ERASE_BOUNDARY;
}
- return bl->erase(bl, pos, len);
+ rc = reacquire(bl);
+ if (rc)
+ return rc;
+
+ rc = bl->erase(bl, pos, len);
+
+ release(bl);
+
+ return rc;
}
int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint32_t *total_size,
@@ -152,6 +198,10 @@ int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint32_
return FLASH_ERR_PARM_ERROR;
}
+ rc = reacquire(bl);
+ if (rc)
+ return rc;
+
rc = bl->get_info(bl, name, total_size, erase_granule);
/* Check the validity of what we are being told */
@@ -159,6 +209,8 @@ int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint32_
fprintf(stderr, "blocklevel_get_info: WARNING: erase_granule (0x%08x) and erase_mask"
" (0x%08x) don't match\n", *erase_granule, bl->erase_mask + 1);
+ release(bl);
+
return rc;
}
@@ -231,9 +283,13 @@ int blocklevel_smart_write(struct blocklevel_device *bl, uint32_t pos, const voi
if (!erase_buf) {
errno = ENOMEM;
rc = FLASH_ERR_MALLOC_FAILED;
- goto out;
+ goto out_free;
}
+ rc = reacquire(bl);
+ if (rc)
+ goto out_free;
+
while (len > 0) {
uint32_t erase_block = pos & ~(erase_size - 1);
uint32_t block_offset = pos & (erase_size - 1);
@@ -264,6 +320,8 @@ int blocklevel_smart_write(struct blocklevel_device *bl, uint32_t pos, const voi
}
out:
+ release(bl);
+out_free:
free(write_buf_start);
free(erase_buf);
return rc;
diff --git a/libflash/blocklevel.h b/libflash/blocklevel.h
index e9a1978..9f4285e 100644
--- a/libflash/blocklevel.h
+++ b/libflash/blocklevel.h
@@ -17,6 +17,7 @@
#define __LIBFLASH_BLOCKLEVEL_H
#include <stdint.h>
+#include <stdbool.h>
struct bl_prot_range {
uint32_t start;
@@ -39,6 +40,8 @@ enum blocklevel_flags {
*/
struct blocklevel_device {
void *priv;
+ int (*reacquire)(struct blocklevel_device *bl);
+ int (*release)(struct blocklevel_device *bl);
int (*read)(struct blocklevel_device *bl, uint32_t pos, void *buf, uint32_t len);
int (*write)(struct blocklevel_device *bl, uint32_t pos, const void *buf, uint32_t len);
int (*erase)(struct blocklevel_device *bl, uint32_t pos, uint32_t len);
@@ -49,6 +52,7 @@ struct blocklevel_device {
* Keep the erase mask so that blocklevel_erase() can do sanity checking
*/
uint32_t erase_mask;
+ bool keep_alive;
enum blocklevel_flags flags;
struct blocklevel_range ecc_prot;
diff --git a/libflash/file.c b/libflash/file.c
index 0dbe610..72e2da9 100644
--- a/libflash/file.c
+++ b/libflash/file.c
@@ -14,11 +14,10 @@
* limitations under the License.
*/
#define _GNU_SOURCE
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -36,14 +35,35 @@
struct file_data {
int fd;
char *name;
+ char *path;
struct blocklevel_device bl;
};
+static int file_release(struct blocklevel_device *bl)
+{
+ struct file_data *file_data = container_of(bl, struct file_data, bl);
+ close(file_data->fd);
+ file_data->fd = -1;
+ return 0;
+}
+
+static int file_reacquire(struct blocklevel_device *bl)
+{
+ struct file_data *file_data = container_of(bl, struct file_data, bl);
+ int fd;
+
+ fd = open(file_data->path, O_RDWR);
+ if (fd == -1)
+ return FLASH_ERR_PARM_ERROR;
+ file_data->fd = fd;
+ return 0;
+}
+
static int file_read(struct blocklevel_device *bl, uint32_t pos, void *buf, uint32_t len)
{
struct file_data *file_data = container_of(bl, struct file_data, bl);
- int count = 0;
- int rc;
+ int rc, count = 0;
+
rc = lseek(file_data->fd, pos, SEEK_SET);
/* errno should remain set */
if (rc != pos)
@@ -54,6 +74,7 @@ static int file_read(struct blocklevel_device *bl, uint32_t pos, void *buf, uint
/* errno should remain set */
if (rc == -1)
return FLASH_ERR_BAD_READ;
+
count += rc;
}
@@ -64,12 +85,11 @@ static int file_write(struct blocklevel_device *bl, uint32_t dst, const void *sr
uint32_t len)
{
struct file_data *file_data = container_of(bl, struct file_data, bl);
- int count = 0;
- int rc;
+ int rc, count = 0;
rc = lseek(file_data->fd, dst, SEEK_SET);
/* errno should remain set */
- if (rc == -1)
+ if (rc != dst)
return FLASH_ERR_PARM_ERROR;
while (count < len) {
@@ -77,6 +97,7 @@ static int file_write(struct blocklevel_device *bl, uint32_t dst, const void *sr
/* errno should remain set */
if (rc == -1)
return FLASH_ERR_VERIFY_FAILURE;
+
count += rc;
}
@@ -94,7 +115,7 @@ static int file_erase(struct blocklevel_device *bl, uint32_t dst, uint32_t len)
{
unsigned long long int d = ULLONG_MAX;
int i = 0;
- int rc = 0;
+ int rc;
while (len - i > 0) {
rc = file_write(bl, dst + i, &d, len - i > sizeof(d) ? sizeof(d) : len - i);
@@ -114,7 +135,10 @@ static int mtd_erase(struct blocklevel_device *bl, uint32_t dst, uint32_t len)
.length = len
};
- return ioctl(file_data->fd, MEMERASE, &erase_info) == -1 ? -1 : 0;
+ if (ioctl(file_data->fd, MEMERASE, &erase_info) == -1)
+ return FLASH_ERR_PARM_ERROR;
+
+ return 0;
}
static int get_info_name(struct file_data *file_data, char **name)
@@ -152,15 +176,16 @@ static int get_info_name(struct file_data *file_data, char **name)
}
-static int mtd_get_info(struct blocklevel_device *bl, const char **name, uint32_t *total_size,
- uint32_t *erase_granule)
+static int mtd_get_info(struct blocklevel_device *bl, const char **name,
+ uint32_t *total_size, uint32_t *erase_granule)
{
struct file_data *file_data = container_of(bl, struct file_data, bl);
struct mtd_info_user mtd_info;
int rc;
- if (ioctl(file_data->fd, MEMGETINFO, &mtd_info) == -1)
- return FLASH_ERR_BAD_READ;
+ rc = ioctl(file_data->fd, MEMGETINFO, &mtd_info);
+ if (rc == -1)
+ return FLASH_ERR_BAD_READ;
if (total_size)
*total_size = mtd_info.size;
@@ -178,8 +203,8 @@ static int mtd_get_info(struct blocklevel_device *bl, const char **name, uint32_
return 0;
}
-static int file_get_info(struct blocklevel_device *bl, const char **name, uint32_t *total_size,
- uint32_t *erase_granule)
+static int file_get_info(struct blocklevel_device *bl, const char **name,
+ uint32_t *total_size, uint32_t *erase_granule)
{
struct file_data *file_data = container_of(bl, struct file_data, bl);
struct stat st;
@@ -214,17 +239,26 @@ int file_init(int fd, struct blocklevel_device **bl)
*bl = NULL;
- file_data = malloc(sizeof(struct file_data));
+ file_data = calloc(1, sizeof(struct file_data));
if (!file_data)
return FLASH_ERR_MALLOC_FAILED;
- memset(file_data, 0, sizeof(*file_data));
file_data->fd = fd;
+ file_data->bl.reacquire = &file_reacquire;
+ file_data->bl.release = &file_release;
file_data->bl.read = &file_read;
file_data->bl.write = &file_write;
file_data->bl.erase = &file_erase;
file_data->bl.get_info = &file_get_info;
file_data->bl.erase_mask = 0;
+
+ /*
+ * If the blocklevel_device is only inited with file_init() then keep
+ * alive is assumed, as fd will change otherwise and this may break
+ * callers assumptions.
+ */
+ file_data->bl.keep_alive = 1;
+
/*
* Unfortunately not all file descriptors are created equal...
* Here we check to see if the file descriptor is to an MTD device, in
@@ -252,9 +286,12 @@ out:
return FLASH_ERR_PARM_ERROR;
}
-int file_init_path(const char *path, int *r_fd, struct blocklevel_device **bl)
+int file_init_path(const char *path, int *r_fd, bool keep_alive,
+ struct blocklevel_device **bl)
{
int fd, rc;
+ char *path_ptr = NULL;
+ struct file_data *file_data;
if (!path || !bl)
return FLASH_ERR_PARM_ERROR;
@@ -263,14 +300,32 @@ int file_init_path(const char *path, int *r_fd, struct blocklevel_device **bl)
if (fd == -1)
return FLASH_ERR_PARM_ERROR;
+ /*
+ * strdup() first so don't have to deal with malloc failure after
+ * file_init()
+ */
+ path_ptr = strdup(path);
+ if (!path_ptr) {
+ rc = FLASH_ERR_MALLOC_FAILED;
+ goto out;
+ }
+
rc = file_init(fd, bl);
if (rc)
- close(fd);
+ goto out;
+
+ file_data = container_of(*bl, struct file_data, bl);
+ file_data->bl.keep_alive = keep_alive;
+ file_data->path = path_ptr;
if (r_fd)
*r_fd = fd;
return rc;
+out:
+ free(path_ptr);
+ close(fd);
+ return rc;
}
void file_exit(struct blocklevel_device *bl)
@@ -280,6 +335,7 @@ void file_exit(struct blocklevel_device *bl)
free(bl->ecc_prot.prot);
file_data = container_of(bl, struct file_data, bl);
free(file_data->name);
+ free(file_data->path);
free(file_data);
}
}
diff --git a/libflash/file.h b/libflash/file.h
index a9a89fe..c8e58a6 100644
--- a/libflash/file.h
+++ b/libflash/file.h
@@ -17,6 +17,8 @@
#ifndef __LIBFLASH_FILE_H
#define __LIBFLASH_FILE_H
+#include <stdbool.h>
+
#include "blocklevel.h"
/*
@@ -34,7 +36,7 @@ void file_exit(struct blocklevel_device *bl);
* Because file_exit() doesn't close the file descriptor, file_init_path()
* makes it available.
*/
-int file_init_path(const char *path, int *fd, struct blocklevel_device **bl);
+int file_init_path(const char *path, int *fd, bool keep_alive, struct blocklevel_device **bl);
/*
* file_exit_close is a convenience wrapper which will close the open
diff --git a/libflash/libflash.c b/libflash/libflash.c
index 69e809e..50dc54d 100644
--- a/libflash/libflash.c
+++ b/libflash/libflash.c
@@ -835,6 +835,10 @@ bail:
return rc;
}
+ /* The flash backend doesn't support reiniting it */
+ c->bl.keep_alive = true;
+ c->bl.reacquire = NULL;
+ c->bl.release = NULL;
c->bl.read = &flash_read;
c->bl.write = &flash_smart_write;
c->bl.erase = &flash_erase;