Re: [U-Boot] [PATCH 09/17] fs: fat: support write with non-zero offset

2018-07-23 Thread AKASHI Takahiro
On Fri, Jul 20, 2018 at 07:46:49PM +0200, Heinrich Schuchardt wrote:
> On 07/20/2018 04:57 AM, AKASHI Takahiro wrote:
> > In this patch, all the necessary code for allowing for a file offset
> > at write is implemented. What plays a major roll here is get_set_cluster(),
> > which, in contrast to its counterpart, set_cluster(), only operates on
> > already-allocated clusters, overwriting with data.
> > 
> > So, with a file offset specified, set_contents() seeks and writes data
> > with set_get_cluster() until the end of a file, and, once it reaches
> > there, continues writing with set_cluster() for the rest.
> > 
> > Please note that a file will be trimmed as a result of write operation if
> > write ends before reaching file's end. This is an intended behavior
> > in order to maitain compatibility with the current interface.
> 
> This does not match the EFI spec.

First, please understand my standpoint that I mentioned in a reply
to your comment on my cover letter.

> > 
> > Signed-off-by: AKASHI Takahiro 
> 
> When testing I observed that I could not write at an offset larger than
> the file size. This does not match the EFI spec:

So this is an intended behavior.

> EFI_FILE_PROTOCOL.SetPosition():
> seeking past the end of the file is allowed (a subsequent write would
> grow the file).

Surely, this is a discussion point.
Any comment from other folks?

-Takahiro AKASHI

> Best regards
> 
> Heinrich
> 
> 
> > ---
> >  fs/fat/fat_write.c | 287 ++---
> >  1 file changed, 272 insertions(+), 15 deletions(-)
> > 
> > diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c
> > index 3a9c53e253..cc45a33876 100644
> > --- a/fs/fat/fat_write.c
> > +++ b/fs/fat/fat_write.c
> > @@ -450,6 +450,120 @@ set_cluster(fsdata *mydata, __u32 clustnum, __u8 
> > *buffer,
> > return 0;
> >  }
> >  
> > +static __u8 tmpbuf_cluster[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN);
> > +
> > +/*
> > + * Read and modify data on existing and consecutive cluster blocks
> > + */
> > +static int
> > +get_set_cluster(fsdata *mydata, __u32 clustnum, loff_t pos, __u8 *buffer,
> > +   loff_t size, loff_t *gotsize)
> > +{
> > +   unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
> > +   __u32 startsect;
> > +   loff_t wsize;
> > +   int clustcount, i, ret;
> > +
> > +   *gotsize = 0;
> > +   if (!size)
> > +   return 0;
> > +
> > +   assert(pos < bytesperclust);
> > +   startsect = clust_to_sect(mydata, clustnum);
> > +
> > +   debug("clustnum: %d, startsect: %d, pos: %lld\n", clustnum, startsect,
> > +   pos);
> > +
> > +   /* partial write at beginning */
> > +   if (pos) {
> > +   wsize = min(bytesperclust - pos, size);
> > +   ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
> > +   if (ret != mydata->clust_size) {
> > +   debug("Error reading data (got %d)\n", ret);
> > +   return -1;
> > +   }
> > +
> > +   memcpy(tmpbuf_cluster + pos, buffer, wsize);
> > +   ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
> > +   if (ret != mydata->clust_size) {
> > +   debug("Error writing data (got %d)\n", ret);
> > +   return -1;
> > +   }
> > +
> > +   size -= wsize;
> > +   buffer += wsize;
> > +   *gotsize += wsize;
> > +
> > +   startsect += mydata->clust_size;
> > +
> > +   if (!size)
> > +   return 0;
> > +   }
> > +
> > +   /* full-cluster write */
> > +   if (size >= bytesperclust) {
> > +   clustcount = lldiv(size, bytesperclust);
> > +
> > +   if (!((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1))) {
> > +   wsize = clustcount * bytesperclust;
> > +   ret = disk_write(startsect,
> > +   clustcount * mydata->clust_size,
> > +   buffer);
> > +   if (ret != clustcount * mydata->clust_size) {
> > +   debug("Error writing data (got %d)\n", ret);
> > +   return -1;
> > +   }
> > +
> > +   size -= wsize;
> > +   buffer += wsize;
> > +   *gotsize += wsize;
> > +
> > +   startsect += clustcount * mydata->clust_size;
> > +   } else {
> > +   for (i = 0; i < clustcount; i++) {
> > +   memcpy(tmpbuf_cluster, buffer, bytesperclust);
> > +   ret = disk_write(startsect, mydata->clust_size,
> > +   tmpbuf_cluster);
> > +   if (ret != mydata->clust_size) {
> > +   debug("Error writing data (got %d)\n",
> > +   

Re: [U-Boot] [PATCH 09/17] fs: fat: support write with non-zero offset

2018-07-20 Thread Heinrich Schuchardt
On 07/20/2018 04:57 AM, AKASHI Takahiro wrote:
> In this patch, all the necessary code for allowing for a file offset
> at write is implemented. What plays a major roll here is get_set_cluster(),
> which, in contrast to its counterpart, set_cluster(), only operates on
> already-allocated clusters, overwriting with data.
> 
> So, with a file offset specified, set_contents() seeks and writes data
> with set_get_cluster() until the end of a file, and, once it reaches
> there, continues writing with set_cluster() for the rest.
> 
> Please note that a file will be trimmed as a result of write operation if
> write ends before reaching file's end. This is an intended behavior
> in order to maitain compatibility with the current interface.

This does not match the EFI spec.

> 
> Signed-off-by: AKASHI Takahiro 

When testing I observed that I could not write at an offset larger than
the file size. This does not match the EFI spec:

EFI_FILE_PROTOCOL.SetPosition():
seeking past the end of the file is allowed (a subsequent write would
grow the file).

Best regards

Heinrich


> ---
>  fs/fat/fat_write.c | 287 ++---
>  1 file changed, 272 insertions(+), 15 deletions(-)
> 
> diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c
> index 3a9c53e253..cc45a33876 100644
> --- a/fs/fat/fat_write.c
> +++ b/fs/fat/fat_write.c
> @@ -450,6 +450,120 @@ set_cluster(fsdata *mydata, __u32 clustnum, __u8 
> *buffer,
>   return 0;
>  }
>  
> +static __u8 tmpbuf_cluster[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN);
> +
> +/*
> + * Read and modify data on existing and consecutive cluster blocks
> + */
> +static int
> +get_set_cluster(fsdata *mydata, __u32 clustnum, loff_t pos, __u8 *buffer,
> + loff_t size, loff_t *gotsize)
> +{
> + unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
> + __u32 startsect;
> + loff_t wsize;
> + int clustcount, i, ret;
> +
> + *gotsize = 0;
> + if (!size)
> + return 0;
> +
> + assert(pos < bytesperclust);
> + startsect = clust_to_sect(mydata, clustnum);
> +
> + debug("clustnum: %d, startsect: %d, pos: %lld\n", clustnum, startsect,
> + pos);
> +
> + /* partial write at beginning */
> + if (pos) {
> + wsize = min(bytesperclust - pos, size);
> + ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
> + if (ret != mydata->clust_size) {
> + debug("Error reading data (got %d)\n", ret);
> + return -1;
> + }
> +
> + memcpy(tmpbuf_cluster + pos, buffer, wsize);
> + ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
> + if (ret != mydata->clust_size) {
> + debug("Error writing data (got %d)\n", ret);
> + return -1;
> + }
> +
> + size -= wsize;
> + buffer += wsize;
> + *gotsize += wsize;
> +
> + startsect += mydata->clust_size;
> +
> + if (!size)
> + return 0;
> + }
> +
> + /* full-cluster write */
> + if (size >= bytesperclust) {
> + clustcount = lldiv(size, bytesperclust);
> +
> + if (!((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1))) {
> + wsize = clustcount * bytesperclust;
> + ret = disk_write(startsect,
> + clustcount * mydata->clust_size,
> + buffer);
> + if (ret != clustcount * mydata->clust_size) {
> + debug("Error writing data (got %d)\n", ret);
> + return -1;
> + }
> +
> + size -= wsize;
> + buffer += wsize;
> + *gotsize += wsize;
> +
> + startsect += clustcount * mydata->clust_size;
> + } else {
> + for (i = 0; i < clustcount; i++) {
> + memcpy(tmpbuf_cluster, buffer, bytesperclust);
> + ret = disk_write(startsect, mydata->clust_size,
> + tmpbuf_cluster);
> + if (ret != mydata->clust_size) {
> + debug("Error writing data (got %d)\n",
> + ret);
> + return -1;
> + }
> +
> + size -= bytesperclust;
> + buffer += bytesperclust;
> + *gotsize += bytesperclust;
> +
> + startsect += mydata->clust_size;
> + }
> + }
> + }
> +
> + /* partial 

[U-Boot] [PATCH 09/17] fs: fat: support write with non-zero offset

2018-07-19 Thread AKASHI Takahiro
In this patch, all the necessary code for allowing for a file offset
at write is implemented. What plays a major roll here is get_set_cluster(),
which, in contrast to its counterpart, set_cluster(), only operates on
already-allocated clusters, overwriting with data.

So, with a file offset specified, set_contents() seeks and writes data
with set_get_cluster() until the end of a file, and, once it reaches
there, continues writing with set_cluster() for the rest.

Please note that a file will be trimmed as a result of write operation if
write ends before reaching file's end. This is an intended behavior
in order to maitain compatibility with the current interface.

Signed-off-by: AKASHI Takahiro 
---
 fs/fat/fat_write.c | 287 ++---
 1 file changed, 272 insertions(+), 15 deletions(-)

diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c
index 3a9c53e253..cc45a33876 100644
--- a/fs/fat/fat_write.c
+++ b/fs/fat/fat_write.c
@@ -450,6 +450,120 @@ set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer,
return 0;
 }
 
+static __u8 tmpbuf_cluster[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN);
+
+/*
+ * Read and modify data on existing and consecutive cluster blocks
+ */
+static int
+get_set_cluster(fsdata *mydata, __u32 clustnum, loff_t pos, __u8 *buffer,
+   loff_t size, loff_t *gotsize)
+{
+   unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
+   __u32 startsect;
+   loff_t wsize;
+   int clustcount, i, ret;
+
+   *gotsize = 0;
+   if (!size)
+   return 0;
+
+   assert(pos < bytesperclust);
+   startsect = clust_to_sect(mydata, clustnum);
+
+   debug("clustnum: %d, startsect: %d, pos: %lld\n", clustnum, startsect,
+   pos);
+
+   /* partial write at beginning */
+   if (pos) {
+   wsize = min(bytesperclust - pos, size);
+   ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
+   if (ret != mydata->clust_size) {
+   debug("Error reading data (got %d)\n", ret);
+   return -1;
+   }
+
+   memcpy(tmpbuf_cluster + pos, buffer, wsize);
+   ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
+   if (ret != mydata->clust_size) {
+   debug("Error writing data (got %d)\n", ret);
+   return -1;
+   }
+
+   size -= wsize;
+   buffer += wsize;
+   *gotsize += wsize;
+
+   startsect += mydata->clust_size;
+
+   if (!size)
+   return 0;
+   }
+
+   /* full-cluster write */
+   if (size >= bytesperclust) {
+   clustcount = lldiv(size, bytesperclust);
+
+   if (!((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1))) {
+   wsize = clustcount * bytesperclust;
+   ret = disk_write(startsect,
+   clustcount * mydata->clust_size,
+   buffer);
+   if (ret != clustcount * mydata->clust_size) {
+   debug("Error writing data (got %d)\n", ret);
+   return -1;
+   }
+
+   size -= wsize;
+   buffer += wsize;
+   *gotsize += wsize;
+
+   startsect += clustcount * mydata->clust_size;
+   } else {
+   for (i = 0; i < clustcount; i++) {
+   memcpy(tmpbuf_cluster, buffer, bytesperclust);
+   ret = disk_write(startsect, mydata->clust_size,
+   tmpbuf_cluster);
+   if (ret != mydata->clust_size) {
+   debug("Error writing data (got %d)\n",
+   ret);
+   return -1;
+   }
+
+   size -= bytesperclust;
+   buffer += bytesperclust;
+   *gotsize += bytesperclust;
+
+   startsect += mydata->clust_size;
+   }
+   }
+   }
+
+   /* partial write at end */
+   if (size) {
+   wsize = size;
+   ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
+   if (ret != mydata->clust_size) {
+   debug("Error reading data (got %d)\n", ret);
+   return -1;
+   }
+   memcpy(tmpbuf_cluster, buffer, wsize);
+   ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);