[Skiboot] [PATCH 4/7] libflash/file: Add a file access backend to for the blocklevel interface.
Cyril Bur
cyrilbur at gmail.com
Tue Jun 16 17:32:23 AEST 2015
On Fri, 12 Jun 2015 12:39:01 +1000
Alistair Popple <alistair at popple.id.au> wrote:
> Cyril,
>
> Comments below.
>
> Regards,
>
> Alistair
>
> On Fri, 5 Jun 2015 14:11:28 Cyril Bur wrote:
>
> <snip>
>
> > +
> > +static int file_write(struct blocklevel_device *bl, uint32_t dst,
> > const void *src,
> > + uint32_t len)
> > +{
> > + struct file_data *file_data = container_of(bl, struct
> > file_data, bl);
> > + int count = 0;
> > + int rc;
> > +
> > + rc = lseek(file_data->fd, dst, SEEK_SET);
> > + /* errno should remain set */
> > + if (rc == -1)
> > + return FLASH_ERR_PARM_ERROR;
> > +
> > + while (count < len) {
> > + rc = write(file_data->fd, src, len);
> > + /* errno should remain set */
> > + if (rc == -1)
> > + return FLASH_ERR_VERIFY_FAILURE;
> > + count += rc;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int file_erase(struct blocklevel_device *bl, uint32_t dst,
> > uint32_t len)
>
> Probably worth a comment here on what it actually means to "erase" a
> file.
>
yeah added.
> > +{
> > + unsigned long long int d = ULLONG_MAX;
> > + int i = 0;
> > + int rc = 0;
> > +
> > + while (len - i > 0) {
> > + rc = file_write(bl, dst + i, &d, len - i >
> > sizeof(d) ? sizeof(d) : len - i);
> > + if (rc)
> > + return rc;
> > + i += sizeof(d);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int mtd_erase(struct blocklevel_device *bl, uint32_t dst,
> > uint32_t len) +{
> > + struct file_data *file_data = container_of(bl, struct
> > file_data, bl);
> > + struct erase_info_user erase_info = {
> > + .start = dst,
> > + .length = len
> > + };
> > +
> > + return ioctl(file_data->fd, MEMERASE, &erase_info) == -1 ?
> > -1 : 0; +}
> > +
> > +static int get_info_name(struct file_data *file_data, char **name)
> > +{
> > + char *path, *lpath;
> > + int len;
> > + struct stat st;
> > +
> > + path = strdup("/proc/self/fd/");
> > + if (!path)
> > + return FLASH_ERR_MALLOC_FAILED;
> > +
> > + /* strlen() + 1 to count the \0 */
> > + len = snprintf(path, strlen(path) + 1, "%s%d", path,
> > file_data->fd);
> > + while (len > 0 && len > strlen(path)) {
> > + len++; /* count the /0 */
> > + path = realloc(path, len);
> > + if (!path)
> > + return FLASH_ERR_MALLOC_FAILED;
> > + len = snprintf(path, len, "%s%d", path,
> > file_data->fd);
> > + }
>
> What am I missing here? As this won't be used in skiboot couldn't you
> just do asprintf(path, len, "/proc/self/fd/%d", path, file_data->fd)?
>
Well if I'd thought of that ;), yeah looks much nicer, also I could
have not leaked path... but you say anything so it didn't happen :).
> > +
> > + if (len <= 0) {
> > + free(path);
> > + return FLASH_ERR_VERIFY_FAILURE;
> > + }
> > +
> > + if (lstat(path, &st)) {
> > + free(path);
> > + return FLASH_ERR_PARM_ERROR;
> > + }
> > +
> > + lpath = malloc(st.st_size + 1);
> > + if (!lpath) {
> > + free(path);
> > + return FLASH_ERR_MALLOC_FAILED;
> > + }
> > +
> > + len = readlink(path, lpath, st.st_size +1);
> > + if (len == -1) {
> > + free(path);
> > + free(lpath);
> > + return FLASH_ERR_PARM_ERROR;
> > + }
> > + lpath[len] = '\0';
> > +
> > + *name = lpath;
> > +
> > + return 0;
> > +}
> > +
> > +
> > +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;
> > +
> > + if (total_size)
> > + *total_size = mtd_info.size;
> > +
> > + if (erase_granule)
> > + *erase_granule = mtd_info.erasesize;
> > +
> > + if (name) {
> > + rc = get_info_name(file_data, &(file_data->name));
> > + if (rc)
> > + return rc;
> > + *name = file_data->name;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +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;
> > + int rc;
> > +
> > + if (fstat(file_data->fd, &st))
> > + return FLASH_ERR_PARM_ERROR;
> > +
> > + if (total_size)
> > + *total_size = st.st_size;
> > +
> > + if (erase_granule)
> > + *erase_granule = 1;
> > +
> > + if (name) {
> > + rc = get_info_name(file_data, &(file_data->name));
> > + if (rc)
> > + return rc;
> > + *name = file_data->name;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +int file_init(int fd, struct blocklevel_device **bl)
> > +{
> > + struct file_data *file_data;
> > + struct stat sbuf;
> > +
> > + if (!bl)
> > + return FLASH_ERR_PARM_ERROR;
> > +
> > + *bl = NULL;
> > +
> > + file_data = malloc(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.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;
> > + /*
> > + * Unfortunately not all file descriptors are created
> > equal...
> > + * Here we check to see if the file descriptor is to an
> > MTD device, in
> > + * which case we have to erase and get the size of it
> > differently.
> > + */
> > + if (fstat(file_data->fd, &sbuf) == -1)
> > + goto out;
> > +
> > + /* Won't be able to handle other than MTD devices for now
> > */
> > + if (S_ISCHR(sbuf.st_mode)) {
> > + file_data->bl.erase = &mtd_erase;
> > + file_data->bl.get_info = &mtd_get_info;
> > + file_data->bl.flags = WRITE_NEED_ERASE;
> > + mtd_get_info(&file_data->bl, NULL, NULL,
> > &(file_data->bl.erase_mask));
> > + file_data->bl.erase_mask--;
> > + } else if (!S_ISREG(sbuf.st_mode)) {
> > + /* If not a char device or a regular file
> > something went wrong */
> > + goto out;
> > + }
> > +
> > + *bl = &(file_data->bl);
> > + return 0;
> > +out:
> > + free(file_data);
> > + return FLASH_ERR_PARM_ERROR;
> > +}
> > +
> > +int file_init_path(const char *path, int *r_fd, struct
> > blocklevel_device **bl) +{
> > + int fd, rc;
> > +
> > + if (!path || !bl)
> > + return FLASH_ERR_PARM_ERROR;
> > +
> > + fd = open(path, O_RDWR);
> > + if (fd == -1)
> > + return FLASH_ERR_PARM_ERROR;
> > +
> > + rc = file_init(fd, bl);
> > + if (rc)
> > + close(fd);
> > +
> > + if (r_fd)
> > + *r_fd = fd;
> > +
> > + return rc;
> > +}
> > +
> > +void file_exit(struct blocklevel_device *bl)
> > +{
> > + struct file_data *file_data;
> > + if (bl)
> > + file_data = container_of(bl, struct file_data, bl);
> > + free(file_data->name);
> > + free(file_data);
> > +}
> > +
> > +void file_exit_close(struct blocklevel_device *bl)
> > +{
> > + struct file_data *file_data;
> > + if (bl) {
> > + file_data = container_of(bl, struct file_data, bl);
> > + close(file_data->fd);
> > + file_exit(bl);
> > + }
> > +}
> > diff --git a/libflash/file.h b/libflash/file.h
> > new file mode 100644
> > index 0000000..1ad9129
> > --- /dev/null
> > +++ b/libflash/file.h
> > @@ -0,0 +1,43 @@
> > +/* Copyright 2013-2015 IBM Corp.
> > + *
> > + * Licensed under the Apache License, Version 2.0 (the "License");
> > + * you may not use this file except in compliance with the License.
> > + * You may obtain a copy of the License at
> > + *
> > + * http://www.apache.org/licenses/LICENSE-2.0
> > + *
> > + * Unless required by applicable law or agreed to in writing,
> > software
> > + * distributed under the License is distributed on an "AS IS"
> > BASIS,
> > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> > + * implied.
> > + * See the License for the specific language governing permissions
> > and
> > + * limitations under the License.
> > + */
> > +
> > +#ifndef __LIBFLASH_FILE_H
> > +#define __LIBFLASH_FILE_H
> > +
> > +/*
> > + * Blockevel functions created leave errno set on errors, as these
> > calls
> > + * often boil down to standard read() and write() calls,
> > inspecting errno
> > + * may prove useful
> > + */
> > +
> > +int file_init(int fd, struct blocklevel_device **bl);
> > +void file_exit(struct blocklevel_device *bl);
> > +
> > +/*
> > + * file_init_path() is a convenience wrapper which will open the
> > path and call
> > + * file_init(). The call to open happens with O_RDWR and no
> > additional flags
> > + * 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); +
> > +/*
> > + * file_exit_close is a convenience wrapper which will close the
> > open
> > + * file descriptor and call file_exit().
> > + */
> > +void file_exit_close(struct blocklevel_device *bl);
> > +
> > +#endif /* __LIBFLASH_FILE_H */
> >
>
> _______________________________________________
> Skiboot mailing list
> Skiboot at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/skiboot
More information about the Skiboot
mailing list