Message ID | 1462539510-18306-2-git-send-email-m.niestroj@grinn-global.com |
---|---|
State | Changes Requested |
Delegated to: | Heiko Schocher |
Headers | show |
On 06.05.2016 14:58, Marcin Niestroj wrote: > Up to now we were able to read/write environment data from/to UBI > volumes only indirectly by gluebi driver. This driver creates NAND MTD > on top of UBI volumes, which is quite a workaroung for this use case. > > Add support for direct read/write UBI volumes in order to not use > obsolete gluebi driver. > > Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com> > --- > tools/env/fw_env.c | 249 +++++++++++++++++++++++++++++++++++++++++++++++- > tools/env/fw_env.config | 8 ++ > 2 files changed, 256 insertions(+), 1 deletion(-) > > diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c > index b4b542a..0e977e3 100644 > --- a/tools/env/fw_env.c > +++ b/tools/env/fw_env.c > @@ -24,6 +24,7 @@ > #include <sys/ioctl.h> > #include <sys/stat.h> > #include <unistd.h> > +#include <dirent.h> > > #ifdef MTD_OLD > # include <stdint.h> > @@ -33,6 +34,8 @@ > # include <mtd/mtd-user.h> > #endif > > +#include <mtd/ubi-user.h> > + > #include "fw_env.h" > > struct common_args common_args; > @@ -54,6 +57,7 @@ struct envdev_s { > ulong erase_size; /* device erase size */ > ulong env_sectors; /* number of environment sectors */ > uint8_t mtd_type; /* type of the MTD device */ > + int is_ubi; /* set if we use UBI volume */ > }; > > static struct envdev_s envdevices[2] = > @@ -72,6 +76,7 @@ static int dev_current; > #define DEVESIZE(i) envdevices[(i)].erase_size > #define ENVSECTORS(i) envdevices[(i)].env_sectors > #define DEVTYPE(i) envdevices[(i)].mtd_type > +#define IS_UBI(i) envdevices[(i)].is_ubi > > #define CUR_ENVSIZE ENVSIZE(dev_current) > > @@ -117,6 +122,229 @@ static unsigned char obsolete_flag = 0; > #define DEFAULT_ENV_INSTANCE_STATIC > #include <env_default.h> > > +#define UBI_DEV_START "/dev/ubi" > +#define UBI_SYSFS "/sys/class/ubi" > +#define UBI_VOL_NAME_PATT "ubi%d_%d" > + > +static int is_ubi_devname(const char *devname) > +{ > + return !strncmp(devname, UBI_DEV_START, sizeof(UBI_DEV_START) - 1); > +} > + > +static int ubi_check_volume_sysfs_name(const char *volume_sysfs_name, > + const char *volname) > +{ > + char path[256]; > + FILE *file; > + char *name; > + int ret; > + > + strcpy(path, UBI_SYSFS "/"); > + strcat(path, volume_sysfs_name); > + strcat(path, "/name"); > + > + file = fopen(path, "r"); > + if (!file) > + return -1; > + > + ret = fscanf(file, "%ms", &name); > + fclose(file); > + if (ret <= 0 || !name) { > + fprintf(stderr, > + "Failed to read from file %s, ret = %d, name = %s\n", > + path, ret, name); > + return -1; > + } > + > + if (!strcmp(name, volname)) { > + free(name); > + return 0; > + } > + free(name); > + > + return -1; > +} > + > +static int ubi_get_volnum_by_name(int devnum, const char *volname) > +{ > + DIR *sysfs_ubi; > + struct dirent *dirent; > + int ret; > + int tmp_devnum; > + int volnum; > + > + sysfs_ubi = opendir(UBI_SYSFS); > + if (!sysfs_ubi) > + return -1; > + > +#ifdef DEBUG > + fprintf(stderr, "Looking for volume name \"%s\"\n", volname); > +#endif > + > + while (1) { > + dirent = readdir(sysfs_ubi); > + if (!dirent) > + return -1; > + > + ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT, > + &tmp_devnum, &volnum); > + if (ret == 2 && devnum == tmp_devnum) { > + if (ubi_check_volume_sysfs_name(dirent->d_name, > + volname) == 0) > + return volnum; > + } > + } > + > + return -1; > +} > + > +static int ubi_get_devnum_by_devname(const char *devname) > +{ > + int devnum; > + int ret; > + > + ret = sscanf(devname + sizeof(UBI_DEV_START) - 1, "%d", &devnum); > + if (ret != 1) > + return -1; > + > + return devnum; > +} > + > +static const char *ubi_get_volume_devname(const char *devname, > + const char *volname) > +{ > + char *volume_devname; > + int volnum; > + int devnum; > + int ret; > + > + devnum = ubi_get_devnum_by_devname(devname); > + if (devnum < 0) > + return NULL; > + > + volnum = ubi_get_volnum_by_name(devnum, volname); > + if (volnum < 0) > + return NULL; > + > + ret = asprintf(&volume_devname, "%s_%d", devname, volnum); > + if (ret < 0) > + return NULL; > + > +#ifdef DEBUG > + fprintf(stderr, "Found ubi volume \"%s:%s\" -> %s\n", > + devname, volname, volume_devname); > +#endif > + > + return volume_devname; > +} > + > +static void ubi_check_dev(unsigned int dev_id) > +{ > + char *devname = (char *) DEVNAME(dev_id); > + char *pname; > + const char *volname = NULL; > + const char *volume_devname; > + > + if (!is_ubi_devname(DEVNAME(dev_id))) > + return; > + > + IS_UBI(dev_id) = 1; > + > + for (pname = devname; *pname != '\0'; pname++) { > + if (*pname == ':') { > + *pname = '\0'; > + volname = pname + 1; > + break; > + } > + } > + > + if (volname) { > + /* Let's find real volume device name */ > + volume_devname = ubi_get_volume_devname(devname, > + volname); > + if (!volume_devname) { > + fprintf(stderr, "Didn't found ubi volume \"%s\"\n", > + volname); > + return; > + } > + > + free(devname); > + DEVNAME(dev_id) = volume_devname; > + } > +} > + > +static int ubi_update_start(int fd, int64_t bytes) > +{ > + if (ioctl(fd, UBI_IOCVOLUP, &bytes)) > + return -1; > + return 0; > +} > + > +static int ubi_read(int fd, void *buf, size_t count) > +{ > + ssize_t ret; > + > + while (count > 0) { > + ret = read(fd, buf, count); > + if (ret > 0) { > + count -= ret; > + buf += ret; > + > + continue; > + } > + > + if (ret == 0) { > + /* > + * Happens in case of too short volume data size. If we > + * return error status we will fail it will be treated > + * as UBI device error. > + * > + * Leave catching this error to CRC check. > + */ > + fprintf(stderr, "Warning: end of data on ubi volume\n"); > + return 0; > + } else if (errno == EBADF) { > + /* > + * Happens in case of corrupted volume. The same as > + * above, we cannot return error now, as we will still > + * be able to successfully write environment later. > + */ > + fprintf(stderr, "Warning: corrupted volume?\n"); > + return 0; > + } else if (errno == EINTR) { > + continue; > + } > + > + fprintf(stderr, "Cannot read %u bytes from ubi volume, %s\n", > + (unsigned int) count, strerror(errno)); > + return -1; > + } > + > + return 0; > +} > + > +static int ubi_write(int fd, const void *buf, size_t count) > +{ > + ssize_t ret; > + > + while (count > 0) { > + ret = write(fd, buf, count); > + if (ret <= 0) { > + if (ret < 0 && errno == EINTR) > + continue; > + > + fprintf(stderr, "Cannot write %u bytes to ubi volume\n", > + (unsigned int) count); > + return -1; > + } > + > + count -= ret; > + buf += ret; > + } > + > + return 0; > +} > + > static int flash_io (int mode); > static char *envmatch (char * s1, char * s2); > static int parse_config (void); > @@ -997,6 +1225,12 @@ static int flash_write (int fd_current, int fd_target, int dev_target) > DEVOFFSET (dev_target), DEVNAME (dev_target)); > #endif > > + if (IS_UBI(dev_target)) { > + if (ubi_update_start(fd_target, CUR_ENVSIZE) < 0) > + return 0; > + return ubi_write(fd_target, environment.image, CUR_ENVSIZE); > + } > + > rc = flash_write_buf(dev_target, fd_target, environment.image, > CUR_ENVSIZE, DEVOFFSET(dev_target), > DEVTYPE(dev_target)); > @@ -1024,6 +1258,12 @@ static int flash_read (int fd) > struct stat st; > int rc; > > + if (IS_UBI(dev_current)) { > + DEVTYPE(dev_current) = MTD_ABSENT; > + > + return ubi_read(fd, environment.image, CUR_ENVSIZE); > + } > + > rc = fstat(fd, &st); > if (rc < 0) { > fprintf(stderr, "Cannot stat the file %s\n", > @@ -1236,7 +1476,8 @@ int fw_env_open(void) > DEVTYPE(!dev_current) == MTD_UBIVOLUME) { > environment.flag_scheme = FLAG_INCREMENTAL; > } else if (DEVTYPE(dev_current) == MTD_ABSENT && > - DEVTYPE(!dev_current) == MTD_ABSENT) { > + DEVTYPE(!dev_current) == MTD_ABSENT && > + IS_UBI(dev_current) == IS_UBI(!dev_current)) { > environment.flag_scheme = FLAG_INCREMENTAL; > } else { > fprintf (stderr, "Incompatible flash types!\n"); > @@ -1369,6 +1610,12 @@ static int parse_config () > HaveRedundEnv = 1; > #endif > #endif > + > + /* Fills in IS_UBI(), converts DEVNAME() with ubi volume name */ > + ubi_check_dev(0); > + if (HaveRedundEnv) > + ubi_check_dev(1); > + > if (stat (DEVNAME (0), &st)) { > fprintf (stderr, > "Cannot access MTD device %s: %s\n", > diff --git a/tools/env/fw_env.config b/tools/env/fw_env.config > index 6f216f9..db5498a 100644 > --- a/tools/env/fw_env.config > +++ b/tools/env/fw_env.config > @@ -23,3 +23,11 @@ > > # VFAT example > #/boot/uboot.env 0x0000 0x4000 > + > +# UBI volume > +#/dev/ubi0_0 0x0 0x20000 > +#/dev/ubi0_1 0x0 0x20000 > + > +# UBI volume by name > +#/dev/ubi0:env 0x0 0x20000 > +#/dev/ubi0:env-redund 0x0 0x20000 >
Hello Marcin, Sorry for the long delay Am 06.05.2016 um 14:58 schrieb Marcin Niestroj: > Up to now we were able to read/write environment data from/to UBI > volumes only indirectly by gluebi driver. This driver creates NAND MTD > on top of UBI volumes, which is quite a workaroung for this use case. > > Add support for direct read/write UBI volumes in order to not use > obsolete gluebi driver. > > Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com> > --- > tools/env/fw_env.c | 249 +++++++++++++++++++++++++++++++++++++++++++++++- > tools/env/fw_env.config | 8 ++ > 2 files changed, 256 insertions(+), 1 deletion(-) I tried to apply your patch, but this fails, and I was unsure, if I could fix it correct... can you please send a new rebased version? Thanks! bye, Heiko > > diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c > index b4b542a..0e977e3 100644 > --- a/tools/env/fw_env.c > +++ b/tools/env/fw_env.c > @@ -24,6 +24,7 @@ > #include <sys/ioctl.h> > #include <sys/stat.h> > #include <unistd.h> > +#include <dirent.h> > > #ifdef MTD_OLD > # include <stdint.h> > @@ -33,6 +34,8 @@ > # include <mtd/mtd-user.h> > #endif > > +#include <mtd/ubi-user.h> > + > #include "fw_env.h" > > struct common_args common_args; > @@ -54,6 +57,7 @@ struct envdev_s { > ulong erase_size; /* device erase size */ > ulong env_sectors; /* number of environment sectors */ > uint8_t mtd_type; /* type of the MTD device */ > + int is_ubi; /* set if we use UBI volume */ > }; > > static struct envdev_s envdevices[2] = > @@ -72,6 +76,7 @@ static int dev_current; > #define DEVESIZE(i) envdevices[(i)].erase_size > #define ENVSECTORS(i) envdevices[(i)].env_sectors > #define DEVTYPE(i) envdevices[(i)].mtd_type > +#define IS_UBI(i) envdevices[(i)].is_ubi > > #define CUR_ENVSIZE ENVSIZE(dev_current) > > @@ -117,6 +122,229 @@ static unsigned char obsolete_flag = 0; > #define DEFAULT_ENV_INSTANCE_STATIC > #include <env_default.h> > > +#define UBI_DEV_START "/dev/ubi" > +#define UBI_SYSFS "/sys/class/ubi" > +#define UBI_VOL_NAME_PATT "ubi%d_%d" > + > +static int is_ubi_devname(const char *devname) > +{ > + return !strncmp(devname, UBI_DEV_START, sizeof(UBI_DEV_START) - 1); > +} > + > +static int ubi_check_volume_sysfs_name(const char *volume_sysfs_name, > + const char *volname) > +{ > + char path[256]; > + FILE *file; > + char *name; > + int ret; > + > + strcpy(path, UBI_SYSFS "/"); > + strcat(path, volume_sysfs_name); > + strcat(path, "/name"); > + > + file = fopen(path, "r"); > + if (!file) > + return -1; > + > + ret = fscanf(file, "%ms", &name); > + fclose(file); > + if (ret <= 0 || !name) { > + fprintf(stderr, > + "Failed to read from file %s, ret = %d, name = %s\n", > + path, ret, name); > + return -1; > + } > + > + if (!strcmp(name, volname)) { > + free(name); > + return 0; > + } > + free(name); > + > + return -1; > +} > + > +static int ubi_get_volnum_by_name(int devnum, const char *volname) > +{ > + DIR *sysfs_ubi; > + struct dirent *dirent; > + int ret; > + int tmp_devnum; > + int volnum; > + > + sysfs_ubi = opendir(UBI_SYSFS); > + if (!sysfs_ubi) > + return -1; > + > +#ifdef DEBUG > + fprintf(stderr, "Looking for volume name \"%s\"\n", volname); > +#endif > + > + while (1) { > + dirent = readdir(sysfs_ubi); > + if (!dirent) > + return -1; > + > + ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT, > + &tmp_devnum, &volnum); > + if (ret == 2 && devnum == tmp_devnum) { > + if (ubi_check_volume_sysfs_name(dirent->d_name, > + volname) == 0) > + return volnum; > + } > + } > + > + return -1; > +} > + > +static int ubi_get_devnum_by_devname(const char *devname) > +{ > + int devnum; > + int ret; > + > + ret = sscanf(devname + sizeof(UBI_DEV_START) - 1, "%d", &devnum); > + if (ret != 1) > + return -1; > + > + return devnum; > +} > + > +static const char *ubi_get_volume_devname(const char *devname, > + const char *volname) > +{ > + char *volume_devname; > + int volnum; > + int devnum; > + int ret; > + > + devnum = ubi_get_devnum_by_devname(devname); > + if (devnum < 0) > + return NULL; > + > + volnum = ubi_get_volnum_by_name(devnum, volname); > + if (volnum < 0) > + return NULL; > + > + ret = asprintf(&volume_devname, "%s_%d", devname, volnum); > + if (ret < 0) > + return NULL; > + > +#ifdef DEBUG > + fprintf(stderr, "Found ubi volume \"%s:%s\" -> %s\n", > + devname, volname, volume_devname); > +#endif > + > + return volume_devname; > +} > + > +static void ubi_check_dev(unsigned int dev_id) > +{ > + char *devname = (char *) DEVNAME(dev_id); > + char *pname; > + const char *volname = NULL; > + const char *volume_devname; > + > + if (!is_ubi_devname(DEVNAME(dev_id))) > + return; > + > + IS_UBI(dev_id) = 1; > + > + for (pname = devname; *pname != '\0'; pname++) { > + if (*pname == ':') { > + *pname = '\0'; > + volname = pname + 1; > + break; > + } > + } > + > + if (volname) { > + /* Let's find real volume device name */ > + volume_devname = ubi_get_volume_devname(devname, > + volname); > + if (!volume_devname) { > + fprintf(stderr, "Didn't found ubi volume \"%s\"\n", > + volname); > + return; > + } > + > + free(devname); > + DEVNAME(dev_id) = volume_devname; > + } > +} > + > +static int ubi_update_start(int fd, int64_t bytes) > +{ > + if (ioctl(fd, UBI_IOCVOLUP, &bytes)) > + return -1; > + return 0; > +} > + > +static int ubi_read(int fd, void *buf, size_t count) > +{ > + ssize_t ret; > + > + while (count > 0) { > + ret = read(fd, buf, count); > + if (ret > 0) { > + count -= ret; > + buf += ret; > + > + continue; > + } > + > + if (ret == 0) { > + /* > + * Happens in case of too short volume data size. If we > + * return error status we will fail it will be treated > + * as UBI device error. > + * > + * Leave catching this error to CRC check. > + */ > + fprintf(stderr, "Warning: end of data on ubi volume\n"); > + return 0; > + } else if (errno == EBADF) { > + /* > + * Happens in case of corrupted volume. The same as > + * above, we cannot return error now, as we will still > + * be able to successfully write environment later. > + */ > + fprintf(stderr, "Warning: corrupted volume?\n"); > + return 0; > + } else if (errno == EINTR) { > + continue; > + } > + > + fprintf(stderr, "Cannot read %u bytes from ubi volume, %s\n", > + (unsigned int) count, strerror(errno)); > + return -1; > + } > + > + return 0; > +} > + > +static int ubi_write(int fd, const void *buf, size_t count) > +{ > + ssize_t ret; > + > + while (count > 0) { > + ret = write(fd, buf, count); > + if (ret <= 0) { > + if (ret < 0 && errno == EINTR) > + continue; > + > + fprintf(stderr, "Cannot write %u bytes to ubi volume\n", > + (unsigned int) count); > + return -1; > + } > + > + count -= ret; > + buf += ret; > + } > + > + return 0; > +} > + > static int flash_io (int mode); > static char *envmatch (char * s1, char * s2); > static int parse_config (void); > @@ -997,6 +1225,12 @@ static int flash_write (int fd_current, int fd_target, int dev_target) > DEVOFFSET (dev_target), DEVNAME (dev_target)); > #endif > > + if (IS_UBI(dev_target)) { > + if (ubi_update_start(fd_target, CUR_ENVSIZE) < 0) > + return 0; > + return ubi_write(fd_target, environment.image, CUR_ENVSIZE); > + } > + > rc = flash_write_buf(dev_target, fd_target, environment.image, > CUR_ENVSIZE, DEVOFFSET(dev_target), > DEVTYPE(dev_target)); > @@ -1024,6 +1258,12 @@ static int flash_read (int fd) > struct stat st; > int rc; > > + if (IS_UBI(dev_current)) { > + DEVTYPE(dev_current) = MTD_ABSENT; > + > + return ubi_read(fd, environment.image, CUR_ENVSIZE); > + } > + > rc = fstat(fd, &st); > if (rc < 0) { > fprintf(stderr, "Cannot stat the file %s\n", > @@ -1236,7 +1476,8 @@ int fw_env_open(void) > DEVTYPE(!dev_current) == MTD_UBIVOLUME) { > environment.flag_scheme = FLAG_INCREMENTAL; > } else if (DEVTYPE(dev_current) == MTD_ABSENT && > - DEVTYPE(!dev_current) == MTD_ABSENT) { > + DEVTYPE(!dev_current) == MTD_ABSENT && > + IS_UBI(dev_current) == IS_UBI(!dev_current)) { > environment.flag_scheme = FLAG_INCREMENTAL; > } else { > fprintf (stderr, "Incompatible flash types!\n"); > @@ -1369,6 +1610,12 @@ static int parse_config () > HaveRedundEnv = 1; > #endif > #endif > + > + /* Fills in IS_UBI(), converts DEVNAME() with ubi volume name */ > + ubi_check_dev(0); > + if (HaveRedundEnv) > + ubi_check_dev(1); > + > if (stat (DEVNAME (0), &st)) { > fprintf (stderr, > "Cannot access MTD device %s: %s\n", > diff --git a/tools/env/fw_env.config b/tools/env/fw_env.config > index 6f216f9..db5498a 100644 > --- a/tools/env/fw_env.config > +++ b/tools/env/fw_env.config > @@ -23,3 +23,11 @@ > > # VFAT example > #/boot/uboot.env 0x0000 0x4000 > + > +# UBI volume > +#/dev/ubi0_0 0x0 0x20000 > +#/dev/ubi0_1 0x0 0x20000 > + > +# UBI volume by name > +#/dev/ubi0:env 0x0 0x20000 > +#/dev/ubi0:env-redund 0x0 0x20000 >
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c index b4b542a..0e977e3 100644 --- a/tools/env/fw_env.c +++ b/tools/env/fw_env.c @@ -24,6 +24,7 @@ #include <sys/ioctl.h> #include <sys/stat.h> #include <unistd.h> +#include <dirent.h> #ifdef MTD_OLD # include <stdint.h> @@ -33,6 +34,8 @@ # include <mtd/mtd-user.h> #endif +#include <mtd/ubi-user.h> + #include "fw_env.h" struct common_args common_args; @@ -54,6 +57,7 @@ struct envdev_s { ulong erase_size; /* device erase size */ ulong env_sectors; /* number of environment sectors */ uint8_t mtd_type; /* type of the MTD device */ + int is_ubi; /* set if we use UBI volume */ }; static struct envdev_s envdevices[2] = @@ -72,6 +76,7 @@ static int dev_current; #define DEVESIZE(i) envdevices[(i)].erase_size #define ENVSECTORS(i) envdevices[(i)].env_sectors #define DEVTYPE(i) envdevices[(i)].mtd_type +#define IS_UBI(i) envdevices[(i)].is_ubi #define CUR_ENVSIZE ENVSIZE(dev_current) @@ -117,6 +122,229 @@ static unsigned char obsolete_flag = 0; #define DEFAULT_ENV_INSTANCE_STATIC #include <env_default.h> +#define UBI_DEV_START "/dev/ubi" +#define UBI_SYSFS "/sys/class/ubi" +#define UBI_VOL_NAME_PATT "ubi%d_%d" + +static int is_ubi_devname(const char *devname) +{ + return !strncmp(devname, UBI_DEV_START, sizeof(UBI_DEV_START) - 1); +} + +static int ubi_check_volume_sysfs_name(const char *volume_sysfs_name, + const char *volname) +{ + char path[256]; + FILE *file; + char *name; + int ret; + + strcpy(path, UBI_SYSFS "/"); + strcat(path, volume_sysfs_name); + strcat(path, "/name"); + + file = fopen(path, "r"); + if (!file) + return -1; + + ret = fscanf(file, "%ms", &name); + fclose(file); + if (ret <= 0 || !name) { + fprintf(stderr, + "Failed to read from file %s, ret = %d, name = %s\n", + path, ret, name); + return -1; + } + + if (!strcmp(name, volname)) { + free(name); + return 0; + } + free(name); + + return -1; +} + +static int ubi_get_volnum_by_name(int devnum, const char *volname) +{ + DIR *sysfs_ubi; + struct dirent *dirent; + int ret; + int tmp_devnum; + int volnum; + + sysfs_ubi = opendir(UBI_SYSFS); + if (!sysfs_ubi) + return -1; + +#ifdef DEBUG + fprintf(stderr, "Looking for volume name \"%s\"\n", volname); +#endif + + while (1) { + dirent = readdir(sysfs_ubi); + if (!dirent) + return -1; + + ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT, + &tmp_devnum, &volnum); + if (ret == 2 && devnum == tmp_devnum) { + if (ubi_check_volume_sysfs_name(dirent->d_name, + volname) == 0) + return volnum; + } + } + + return -1; +} + +static int ubi_get_devnum_by_devname(const char *devname) +{ + int devnum; + int ret; + + ret = sscanf(devname + sizeof(UBI_DEV_START) - 1, "%d", &devnum); + if (ret != 1) + return -1; + + return devnum; +} + +static const char *ubi_get_volume_devname(const char *devname, + const char *volname) +{ + char *volume_devname; + int volnum; + int devnum; + int ret; + + devnum = ubi_get_devnum_by_devname(devname); + if (devnum < 0) + return NULL; + + volnum = ubi_get_volnum_by_name(devnum, volname); + if (volnum < 0) + return NULL; + + ret = asprintf(&volume_devname, "%s_%d", devname, volnum); + if (ret < 0) + return NULL; + +#ifdef DEBUG + fprintf(stderr, "Found ubi volume \"%s:%s\" -> %s\n", + devname, volname, volume_devname); +#endif + + return volume_devname; +} + +static void ubi_check_dev(unsigned int dev_id) +{ + char *devname = (char *) DEVNAME(dev_id); + char *pname; + const char *volname = NULL; + const char *volume_devname; + + if (!is_ubi_devname(DEVNAME(dev_id))) + return; + + IS_UBI(dev_id) = 1; + + for (pname = devname; *pname != '\0'; pname++) { + if (*pname == ':') { + *pname = '\0'; + volname = pname + 1; + break; + } + } + + if (volname) { + /* Let's find real volume device name */ + volume_devname = ubi_get_volume_devname(devname, + volname); + if (!volume_devname) { + fprintf(stderr, "Didn't found ubi volume \"%s\"\n", + volname); + return; + } + + free(devname); + DEVNAME(dev_id) = volume_devname; + } +} + +static int ubi_update_start(int fd, int64_t bytes) +{ + if (ioctl(fd, UBI_IOCVOLUP, &bytes)) + return -1; + return 0; +} + +static int ubi_read(int fd, void *buf, size_t count) +{ + ssize_t ret; + + while (count > 0) { + ret = read(fd, buf, count); + if (ret > 0) { + count -= ret; + buf += ret; + + continue; + } + + if (ret == 0) { + /* + * Happens in case of too short volume data size. If we + * return error status we will fail it will be treated + * as UBI device error. + * + * Leave catching this error to CRC check. + */ + fprintf(stderr, "Warning: end of data on ubi volume\n"); + return 0; + } else if (errno == EBADF) { + /* + * Happens in case of corrupted volume. The same as + * above, we cannot return error now, as we will still + * be able to successfully write environment later. + */ + fprintf(stderr, "Warning: corrupted volume?\n"); + return 0; + } else if (errno == EINTR) { + continue; + } + + fprintf(stderr, "Cannot read %u bytes from ubi volume, %s\n", + (unsigned int) count, strerror(errno)); + return -1; + } + + return 0; +} + +static int ubi_write(int fd, const void *buf, size_t count) +{ + ssize_t ret; + + while (count > 0) { + ret = write(fd, buf, count); + if (ret <= 0) { + if (ret < 0 && errno == EINTR) + continue; + + fprintf(stderr, "Cannot write %u bytes to ubi volume\n", + (unsigned int) count); + return -1; + } + + count -= ret; + buf += ret; + } + + return 0; +} + static int flash_io (int mode); static char *envmatch (char * s1, char * s2); static int parse_config (void); @@ -997,6 +1225,12 @@ static int flash_write (int fd_current, int fd_target, int dev_target) DEVOFFSET (dev_target), DEVNAME (dev_target)); #endif + if (IS_UBI(dev_target)) { + if (ubi_update_start(fd_target, CUR_ENVSIZE) < 0) + return 0; + return ubi_write(fd_target, environment.image, CUR_ENVSIZE); + } + rc = flash_write_buf(dev_target, fd_target, environment.image, CUR_ENVSIZE, DEVOFFSET(dev_target), DEVTYPE(dev_target)); @@ -1024,6 +1258,12 @@ static int flash_read (int fd) struct stat st; int rc; + if (IS_UBI(dev_current)) { + DEVTYPE(dev_current) = MTD_ABSENT; + + return ubi_read(fd, environment.image, CUR_ENVSIZE); + } + rc = fstat(fd, &st); if (rc < 0) { fprintf(stderr, "Cannot stat the file %s\n", @@ -1236,7 +1476,8 @@ int fw_env_open(void) DEVTYPE(!dev_current) == MTD_UBIVOLUME) { environment.flag_scheme = FLAG_INCREMENTAL; } else if (DEVTYPE(dev_current) == MTD_ABSENT && - DEVTYPE(!dev_current) == MTD_ABSENT) { + DEVTYPE(!dev_current) == MTD_ABSENT && + IS_UBI(dev_current) == IS_UBI(!dev_current)) { environment.flag_scheme = FLAG_INCREMENTAL; } else { fprintf (stderr, "Incompatible flash types!\n"); @@ -1369,6 +1610,12 @@ static int parse_config () HaveRedundEnv = 1; #endif #endif + + /* Fills in IS_UBI(), converts DEVNAME() with ubi volume name */ + ubi_check_dev(0); + if (HaveRedundEnv) + ubi_check_dev(1); + if (stat (DEVNAME (0), &st)) { fprintf (stderr, "Cannot access MTD device %s: %s\n", diff --git a/tools/env/fw_env.config b/tools/env/fw_env.config index 6f216f9..db5498a 100644 --- a/tools/env/fw_env.config +++ b/tools/env/fw_env.config @@ -23,3 +23,11 @@ # VFAT example #/boot/uboot.env 0x0000 0x4000 + +# UBI volume +#/dev/ubi0_0 0x0 0x20000 +#/dev/ubi0_1 0x0 0x20000 + +# UBI volume by name +#/dev/ubi0:env 0x0 0x20000 +#/dev/ubi0:env-redund 0x0 0x20000
Up to now we were able to read/write environment data from/to UBI volumes only indirectly by gluebi driver. This driver creates NAND MTD on top of UBI volumes, which is quite a workaroung for this use case. Add support for direct read/write UBI volumes in order to not use obsolete gluebi driver. Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com> --- tools/env/fw_env.c | 249 +++++++++++++++++++++++++++++++++++++++++++++++- tools/env/fw_env.config | 8 ++ 2 files changed, 256 insertions(+), 1 deletion(-)