diff options
-rw-r--r-- | external/common/arch_flash.h | 3 | ||||
-rw-r--r-- | external/common/arch_flash_arm.c | 4 | ||||
-rw-r--r-- | external/common/arch_flash_powerpc.c | 8 | ||||
-rw-r--r-- | external/common/arch_flash_x86.c | 4 | ||||
-rw-r--r-- | external/gard/gard.c | 2 | ||||
-rw-r--r-- | external/pflash/pflash.c | 2 | ||||
-rw-r--r-- | libflash/blocklevel.c | 70 | ||||
-rw-r--r-- | libflash/blocklevel.h | 4 | ||||
-rw-r--r-- | libflash/file.c | 94 | ||||
-rw-r--r-- | libflash/file.h | 4 | ||||
-rw-r--r-- | libflash/libflash.c | 4 |
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; |