From mboxrd@z Thu Jan 1 00:00:00 1970 From: Lothar =?UTF-8?B?V2HDn21hbm4=?= Date: Fri, 1 Dec 2017 13:51:44 +0100 Subject: [U-Boot] [PATCH] tools: env: Add support for direct read/write UBI volumes In-Reply-To: <20171115070126.GX21009@vctlabs.com> References: <20171115070126.GX21009@vctlabs.com> Message-ID: <20171201135144.0a3abdb9@karo-electronics.de> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="windows-1252" Content-Transfer-Encoding: quoted-printable To: u-boot@lists.denx.de Hi, On Tue, 14 Nov 2017 23:01:26 -0800 S. Lockwood-Childs 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. >=20 > Add support for direct read/write UBI volumes in order to not use > obsolete gluebi driver. >=20 > Forward-ported from this patch: > http://patchwork.ozlabs.org/patch/619305/ >=20 > Original patch: > Signed-off-by: Marcin Niestroj >=20 > Forward port: > Signed-off-by: S. Lockwood-Childs > --- > tools/env/fw_env.c | 255 ++++++++++++++++++++++++++++++++++++++++++= +++++- > tools/env/fw_env.config | 8 ++ > 2 files changed, 261 insertions(+), 2 deletions(-) >=20 > diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c > index ab06415..867fba5 100644 > --- a/tools/env/fw_env.c > +++ b/tools/env/fw_env.c > @@ -25,6 +25,7 @@ > #include > #include > #include > +#include > =20 > #ifdef MTD_OLD > # include > @@ -34,6 +35,8 @@ > # include > #endif > =20 > +#include > + > #include "fw_env_private.h" > #include "fw_env.h" > =20 > @@ -58,6 +61,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 */ > }; > =20 > static struct envdev_s envdevices[2] =3D > @@ -76,6 +80,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 > =20 > #define CUR_ENVSIZE ENVSIZE(dev_current) > =20 > @@ -122,6 +127,228 @@ static unsigned char obsolete_flag =3D 0; > #define DEFAULT_ENV_INSTANCE_STATIC > #include > =20 > +#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]; > /usr/include/linux/limits.h specifies the constant 'PATH_MAX' which should be used here. > + FILE *file; > + char *name; > + int ret; > + > + strcpy(path, UBI_SYSFS "/"); > + strcat(path, volume_sysfs_name); > + strcat(path, "/name"); > + > + file =3D fopen(path, "r"); > + if (!file) > + return -1; > + > + ret =3D fscanf(file, "%ms", &name); > + fclose(file); > + if (ret <=3D 0 || !name) { > + fprintf(stderr, > + "Failed to read from file %s, ret =3D %d, name =3D %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 =3D opendir(UBI_SYSFS); > + if (!sysfs_ubi) > + return -1; > + > +#ifdef DEBUG > + fprintf(stderr, "Looking for volume name \"%s\"\n", volname); > +#endif > + > + while (1) { > + dirent =3D readdir(sysfs_ubi); > + if (!dirent) > + return -1; > + > + ret =3D sscanf(dirent->d_name, UBI_VOL_NAME_PATT, > + &tmp_devnum, &volnum); > + if (ret =3D=3D 2 && devnum =3D=3D tmp_devnum) { > + if (ubi_check_volume_sysfs_name(dirent->d_name, > + volname) =3D=3D 0) > + return volnum; > + } > + } > + > + return -1; > This can never be reached. > +} > + > +static int ubi_get_devnum_by_devname(const char *devname) > +{ > + int devnum; > + int ret; > + > + ret =3D sscanf(devname + sizeof(UBI_DEV_START) - 1, "%d", &devnum); > + if (ret !=3D 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 =3D ubi_get_devnum_by_devname(devname); > + if (devnum < 0) > + return NULL; > + > + volnum =3D ubi_get_volnum_by_name(devnum, volname); > + if (volnum < 0) > + return NULL; > + > + ret =3D 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 =3D (char *)DEVNAME(dev_id); > + char *pname; > + const char *volname =3D NULL; > + const char *volume_devname; > + > + if (!is_ubi_devname(DEVNAME(dev_id))) > + return; > + > + IS_UBI(dev_id) =3D 1; > + > + for (pname =3D devname; *pname !=3D '\0'; pname++) { > + if (*pname =3D=3D ':') { > + *pname =3D '\0'; > + volname =3D pname + 1; > + break; > + } > + } > + > + if (volname) { > + /* Let's find real volume device name */ > + volume_devname =3D 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) =3D 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 =3D read(fd, buf, count); > + if (ret > 0) { > + count -=3D ret; > + buf +=3D ret; > + > + continue; > + } > + > + if (ret =3D=3D 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. > This sentence no sense. > + * > + * Leave catching this error to CRC check. > + */ > + fprintf(stderr, "Warning: end of data on ubi volume\n"); > + return 0; > + } else if (errno =3D=3D 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 =3D=3D 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 =3D write(fd, buf, count); > + if (ret <=3D 0) { > + if (ret < 0 && errno =3D=3D EINTR) > + continue; > + > + fprintf(stderr, "Cannot write %u bytes to ubi volume\n", > + (unsigned int)count); > '%zu' is an appropriate format string for size_t values. No need for a type cast. > @@ -1347,8 +1587,12 @@ int fw_env_close(struct env_opts *opts) > static int check_device_config(int dev) > { > struct stat st; > + int32_t lnum =3D 0; > This could be defined right before the ioctl, which is the only user of this variable. > int fd, rc =3D 0; > =20 > + /* Fills in IS_UBI(), converts DEVNAME() with ubi volume name */ > + ubi_check_dev(dev); > + > fd =3D open(DEVNAME(dev), O_RDONLY); > if (fd < 0) { > fprintf(stderr, > @@ -1364,7 +1608,14 @@ static int check_device_config(int dev) > goto err; > } > =20 > - if (S_ISCHR(st.st_mode)) { > + if (IS_UBI(dev)) { > + rc =3D ioctl(fd, UBI_IOCEBISMAP, &lnum); > + if (rc < 0) { > + fprintf(stderr, "Cannot get UBI information for %s\n", > + DEVNAME(dev)); > + goto err; > + } > + } else if (S_ISCHR(st.st_mode)) { > struct mtd_info_user mtdinfo; > rc =3D ioctl(fd, MEMGETINFO, &mtdinfo); > if (rc < 0) { Lothar Wa=C3=9Fmann