diff mbox series

Update fails when ubifs is compressed - fixed and patch attached

Message ID 96e98b7d-ee04-4581-a55c-a4a99dd3c8af@googlegroups.com
State Rejected
Headers show
Series Update fails when ubifs is compressed - fixed and patch attached | expand

Commit Message

mattmatician@outlook.com May 10, 2018, 4:34 p.m. UTC
I found when trying to use an ubifs.gz file and adding compressed = true; to the sw-description resulted in a failure to perform the swupdate.

I found this was a problem with the following lines in
 - handlers/ubivol_handler.c

------------

err = ubi_update_start(libubi, fdout, bytes);
if (err) {
	ERROR("cannot start volume \"%s\" update", node);
	return -1;
}

---------

The ubi_update_start command 'enables' writing to the number of bytes specified by the variable bytes.

However, the variable 'bytes' contains the size of the compressed ubifs.gz file, and not the size of the decompressed ubifs file, as required.

By obtaining the decompressed filesize from the gzipped file using this logic:

https://stackoverflow.com/questions/9715046/find-the-size-of-the-file-inside-a-gzip-file/9727599#9727599

I have created a patch that solves this issue, but note (as described in the link above) this limits the original ubifs file size to 4 GiB.

Patch is below:
#########################################

Comments

Stefano Babic May 10, 2018, 7:52 p.m. UTC | #1
Hi Matt,

On 10/05/2018 18:34, mattmatician@outlook.com wrote:
> I found when trying to use an ubifs.gz file and adding compressed = true; to the sw-description resulted in a failure to perform the swupdate.
> 

This is a known issue, already raised by seeting encrypted = true, see
commit 72c2a0c5eeac382916bb26b274d64b28bd1d6be0. However, there is not
an easy solution because the MTD library requires to know the size of
the volume before starting.

> I found this was a problem with the following lines in
>  - handlers/ubivol_handler.c
> 
> ------------
> 
> err = ubi_update_start(libubi, fdout, bytes);
> if (err) {
> 	ERROR("cannot start volume \"%s\" update", node);
> 	return -1;
> }
> 

Yes. ub_update_start() requires the toral numbér of bytes before
starting to write.

> ---------
> 
> The ubi_update_start command 'enables' writing to the number of bytes specified by the variable bytes.
> 
> However, the variable 'bytes' contains the size of the compressed ubifs.gz file, and not the size of the decompressed ubifs file, as required.
> 

True.

> By obtaining the decompressed filesize from the gzipped file using this logic:
> 
> https://stackoverflow.com/questions/9715046/find-the-size-of-the-file-inside-a-gzip-file/9727599#9727599
> 
> I have created a patch that solves this issue, but note (as described in the link above) this limits the original ubifs file size to 4 GiB.
> 
> Patch is below:
> #########################################
> 
> diff --git a/handlers/ubivol_handler.c b/handlers/ubivol_handler.c
> index 0c6fcbf..6a88487 100644
> --- a/handlers/ubivol_handler.c
> +++ b/handlers/ubivol_handler.c
> @@ -42,6 +42,7 @@ static int update_volume(libubi_t libubi, struct img_type *img,
>  	char node[64];
>  	int err;
>  	char sbuf[128];
> +	uint32_t decompressed_bytes;
>  
>  	bytes = img->size;
>  	if (img->is_encrypted) {
> @@ -91,7 +92,17 @@ static int update_volume(libubi_t libubi, struct img_type *img,
>  		ERROR("cannot open UBI volume \"%s\"", node);
>  		return -1;
>  	}
> -	err = ubi_update_start(libubi, fdout, bytes);
> +
> +	if (img->compressed) {
> +		lseek(img->fdin, img->size-4, SEEK_CUR);
> +		read(img->fdin, &decompressed_bytes, 4);
> +		lseek(img->fdin, -img->size, SEEK_CUR);

NAK. You forget that SWUpdate works in most cases with streams, not with
files. You cannot seek in a stream - this works just in case of a local
file. Try to update from network with install-directly activated, this
does not work.

> +	}
> +	else {
> +		decompressed_bytes = bytes;
> +	}
> +
> +	err = ubi_update_start(libubi, fdout, decompressed_bytes);
>  	if (err) {
>  		ERROR("cannot start volume \"%s\" update", node);
>  		return -1;
> 

Best regards,
Stefano Babic
mattmatician@outlook.com May 10, 2018, 8:16 p.m. UTC | #2
On Thursday, 10 May 2018 17:34:43 UTC+1, mattma...@outlook.com  wrote:
> I found when trying to use an ubifs.gz file and adding compressed = true; to the sw-description resulted in a failure to perform the swupdate.
> 
> I found this was a problem with the following lines in
>  - handlers/ubivol_handler.c
> 
> ------------
> 
> err = ubi_update_start(libubi, fdout, bytes);
> if (err) {
> 	ERROR("cannot start volume \"%s\" update", node);
> 	return -1;
> }
> 
> ---------
> 
> The ubi_update_start command 'enables' writing to the number of bytes specified by the variable bytes.
> 
> However, the variable 'bytes' contains the size of the compressed ubifs.gz file, and not the size of the decompressed ubifs file, as required.
> 
> By obtaining the decompressed filesize from the gzipped file using this logic:
> 
> https://stackoverflow.com/questions/9715046/find-the-size-of-the-file-inside-a-gzip-file/9727599#9727599
> 
> I have created a patch that solves this issue, but note (as described in the link above) this limits the original ubifs file size to 4 GiB.
> 
> Patch is below:
> #########################################
> 
> diff --git a/handlers/ubivol_handler.c b/handlers/ubivol_handler.c
> index 0c6fcbf..6a88487 100644
> --- a/handlers/ubivol_handler.c
> +++ b/handlers/ubivol_handler.c
> @@ -42,6 +42,7 @@ static int update_volume(libubi_t libubi, struct img_type *img,
>  	char node[64];
>  	int err;
>  	char sbuf[128];
> +	uint32_t decompressed_bytes;
>  
>  	bytes = img->size;
>  	if (img->is_encrypted) {
> @@ -91,7 +92,17 @@ static int update_volume(libubi_t libubi, struct img_type *img,
>  		ERROR("cannot open UBI volume \"%s\"", node);
>  		return -1;
>  	}
> -	err = ubi_update_start(libubi, fdout, bytes);
> +
> +	if (img->compressed) {
> +		lseek(img->fdin, img->size-4, SEEK_CUR);
> +		read(img->fdin, &decompressed_bytes, 4);
> +		lseek(img->fdin, -img->size, SEEK_CUR);
> +	}
> +	else {
> +		decompressed_bytes = bytes;
> +	}
> +
> +	err = ubi_update_start(libubi, fdout, decompressed_bytes);
>  	if (err) {
>  		ERROR("cannot start volume \"%s\" update", node);
>  		return -1;

Ah okay, silly me.

Originally, I had passed the decompressed size to the handler with the "data" attribute. This would work with stream installed-directly aswell, no...?

How about adding a new attribute to the ubivol type in sw_description. A new 'decompressed_size' field could become mandatory if compressed is true...?
Stefano Babic May 10, 2018, 8:39 p.m. UTC | #3
Hi Matt,

On 10/05/2018 22:16, mattmatician@outlook.com wrote:
> On Thursday, 10 May 2018 17:34:43 UTC+1, mattma...@outlook.com  wrote:
>> I found when trying to use an ubifs.gz file and adding compressed = true; to the sw-description resulted in a failure to perform the swupdate.
>>
>> I found this was a problem with the following lines in
>>  - handlers/ubivol_handler.c
>>
>> ------------
>>
>> err = ubi_update_start(libubi, fdout, bytes);
>> if (err) {
>> 	ERROR("cannot start volume \"%s\" update", node);
>> 	return -1;
>> }
>>
>> ---------
>>
>> The ubi_update_start command 'enables' writing to the number of bytes specified by the variable bytes.
>>
>> However, the variable 'bytes' contains the size of the compressed ubifs.gz file, and not the size of the decompressed ubifs file, as required.
>>
>> By obtaining the decompressed filesize from the gzipped file using this logic:
>>
>> https://stackoverflow.com/questions/9715046/find-the-size-of-the-file-inside-a-gzip-file/9727599#9727599
>>
>> I have created a patch that solves this issue, but note (as described in the link above) this limits the original ubifs file size to 4 GiB.
>>
>> Patch is below:
>> #########################################
>>
>> diff --git a/handlers/ubivol_handler.c b/handlers/ubivol_handler.c
>> index 0c6fcbf..6a88487 100644
>> --- a/handlers/ubivol_handler.c
>> +++ b/handlers/ubivol_handler.c
>> @@ -42,6 +42,7 @@ static int update_volume(libubi_t libubi, struct img_type *img,
>>  	char node[64];
>>  	int err;
>>  	char sbuf[128];
>> +	uint32_t decompressed_bytes;
>>  
>>  	bytes = img->size;
>>  	if (img->is_encrypted) {
>> @@ -91,7 +92,17 @@ static int update_volume(libubi_t libubi, struct img_type *img,
>>  		ERROR("cannot open UBI volume \"%s\"", node);
>>  		return -1;
>>  	}
>> -	err = ubi_update_start(libubi, fdout, bytes);
>> +
>> +	if (img->compressed) {
>> +		lseek(img->fdin, img->size-4, SEEK_CUR);
>> +		read(img->fdin, &decompressed_bytes, 4);
>> +		lseek(img->fdin, -img->size, SEEK_CUR);
>> +	}
>> +	else {
>> +		decompressed_bytes = bytes;
>> +	}
>> +
>> +	err = ubi_update_start(libubi, fdout, decompressed_bytes);
>>  	if (err) {
>>  		ERROR("cannot start volume \"%s\" update", node);
>>  		return -1;
> 
> Ah okay, silly me.
> 
> Originally, I had passed the decompressed size to the handler with the "data" attribute. This would work with stream installed-directly aswell, no...?

Yes, this works.

> 
> How about adding a new attribute to the ubivol type in sw_description. A new 'decompressed_size' field could become mandatory if compressed is true...? 

We have now "properties" for such cases - see as reference the
swuforwarder handler.

Anyway, I am ask myself why the UBI volume should be compressed when UBI
runs the decompression on-the-fly. IMHO it is much more efficient to not
compress the volume, but deliver a already compressed UBIFS and the
target decompress it on demand. Feature is in mainline kernel since a
very long time.

Best regards,
Stefano Babic
mattbeaumontgts@gmail.com May 11, 2018, 8:45 a.m. UTC | #4
On Thursday, May 10, 2018 at 9:40:00 PM UTC+1, Stefano Babic wrote:
> Hi Matt,
> 
> On 10/05/2018 22:16, matt wrote:
> > On Thursday, 10 May 2018 17:34:43 UTC+1, mattma...@outlook.com  wrote:
> >> I found when trying to use an ubifs.gz file and adding compressed = true; to the sw-description resulted in a failure to perform the swupdate.
> >>
> >> I found this was a problem with the following lines in
> >>  - handlers/ubivol_handler.c
> >>
> >> ------------
> >>
> >> err = ubi_update_start(libubi, fdout, bytes);
> >> if (err) {
> >> 	ERROR("cannot start volume \"%s\" update", node);
> >> 	return -1;
> >> }
> >>
> >> ---------
> >>
> >> The ubi_update_start command 'enables' writing to the number of bytes specified by the variable bytes.
> >>
> >> However, the variable 'bytes' contains the size of the compressed ubifs.gz file, and not the size of the decompressed ubifs file, as required.
> >>
> >> By obtaining the decompressed filesize from the gzipped file using this logic:
> >>
> >> https://stackoverflow.com/questions/9715046/find-the-size-of-the-file-inside-a-gzip-file/9727599#9727599
> >>
> >> I have created a patch that solves this issue, but note (as described in the link above) this limits the original ubifs file size to 4 GiB.
> >>
> >> Patch is below:
> >> #########################################
> >>
> >> diff --git a/handlers/ubivol_handler.c b/handlers/ubivol_handler.c
> >> index 0c6fcbf..6a88487 100644
> >> --- a/handlers/ubivol_handler.c
> >> +++ b/handlers/ubivol_handler.c
> >> @@ -42,6 +42,7 @@ static int update_volume(libubi_t libubi, struct img_type *img,
> >>  	char node[64];
> >>  	int err;
> >>  	char sbuf[128];
> >> +	uint32_t decompressed_bytes;
> >>  
> >>  	bytes = img->size;
> >>  	if (img->is_encrypted) {
> >> @@ -91,7 +92,17 @@ static int update_volume(libubi_t libubi, struct img_type *img,
> >>  		ERROR("cannot open UBI volume \"%s\"", node);
> >>  		return -1;
> >>  	}
> >> -	err = ubi_update_start(libubi, fdout, bytes);
> >> +
> >> +	if (img->compressed) {
> >> +		lseek(img->fdin, img->size-4, SEEK_CUR);
> >> +		read(img->fdin, &decompressed_bytes, 4);
> >> +		lseek(img->fdin, -img->size, SEEK_CUR);
> >> +	}
> >> +	else {
> >> +		decompressed_bytes = bytes;
> >> +	}
> >> +
> >> +	err = ubi_update_start(libubi, fdout, decompressed_bytes);
> >>  	if (err) {
> >>  		ERROR("cannot start volume \"%s\" update", node);
> >>  		return -1;
> > 
> > Ah okay, silly me.
> > 
> > Originally, I had passed the decompressed size to the handler with the "data" attribute. This would work with stream installed-directly aswell, no...?
> 
> Yes, this works.
> 
> > 
> > How about adding a new attribute to the ubivol type in sw_description. A new 'decompressed_size' field could become mandatory if compressed is true...? 
> 
> We have now "properties" for such cases - see as reference the
> swuforwarder handler.
> 
> Anyway, I am ask myself why the UBI volume should be compressed when UBI
> runs the decompression on-the-fly. IMHO it is much more efficient to not
> compress the volume, but deliver a already compressed UBIFS and the
> target decompress it on demand. Feature is in mainline kernel since a
> very long time.
> 
> Best regards,
> Stefano Babic
> 
> 
> -- 
> =====================================================================
> DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic@denx.de
> =====================================================================

Hi Stefano,

Thanks, I will explore the "properties".

And yes, I have seen you suggest using runtime compression in the ubifs in previous compression questions.

Firstly, my target hardware may have low bandwidth but will have high storage. I don't want to inhibit my performance at runtime to decrease the swu size.

Secondly, I generated differentl compressed ubifs to gather the following sizes:

Uncompressed ubifs: 73MB -> Gzipped 27MB
Zlibbed ubifs: 39MB

Notably, the Zlibbed ubifs is 39MB vs the Uncompressed, and then gzipped 27MB.

Increasing my ubifs my ~50% is not ideal, and has the added problem of slowing my read/write times.

Regards,

Matt
Stefano Babic May 11, 2018, 9:39 a.m. UTC | #5
Hi Matt,

On 11/05/2018 10:45, mattbeaumontgts@gmail.com wrote:
> On Thursday, May 10, 2018 at 9:40:00 PM UTC+1, Stefano Babic wrote:
>> Hi Matt,
>>
>> On 10/05/2018 22:16, matt wrote:
>>> On Thursday, 10 May 2018 17:34:43 UTC+1, mattma...@outlook.com  wrote:
>>>> I found when trying to use an ubifs.gz file and adding compressed = true; to the sw-description resulted in a failure to perform the swupdate.
>>>>
>>>> I found this was a problem with the following lines in
>>>>  - handlers/ubivol_handler.c
>>>>
>>>> ------------
>>>>
>>>> err = ubi_update_start(libubi, fdout, bytes);
>>>> if (err) {
>>>> 	ERROR("cannot start volume \"%s\" update", node);
>>>> 	return -1;
>>>> }
>>>>
>>>> ---------
>>>>
>>>> The ubi_update_start command 'enables' writing to the number of bytes specified by the variable bytes.
>>>>
>>>> However, the variable 'bytes' contains the size of the compressed ubifs.gz file, and not the size of the decompressed ubifs file, as required.
>>>>
>>>> By obtaining the decompressed filesize from the gzipped file using this logic:
>>>>
>>>> https://stackoverflow.com/questions/9715046/find-the-size-of-the-file-inside-a-gzip-file/9727599#9727599
>>>>
>>>> I have created a patch that solves this issue, but note (as described in the link above) this limits the original ubifs file size to 4 GiB.
>>>>
>>>> Patch is below:
>>>> #########################################
>>>>
>>>> diff --git a/handlers/ubivol_handler.c b/handlers/ubivol_handler.c
>>>> index 0c6fcbf..6a88487 100644
>>>> --- a/handlers/ubivol_handler.c
>>>> +++ b/handlers/ubivol_handler.c
>>>> @@ -42,6 +42,7 @@ static int update_volume(libubi_t libubi, struct img_type *img,
>>>>  	char node[64];
>>>>  	int err;
>>>>  	char sbuf[128];
>>>> +	uint32_t decompressed_bytes;
>>>>  
>>>>  	bytes = img->size;
>>>>  	if (img->is_encrypted) {
>>>> @@ -91,7 +92,17 @@ static int update_volume(libubi_t libubi, struct img_type *img,
>>>>  		ERROR("cannot open UBI volume \"%s\"", node);
>>>>  		return -1;
>>>>  	}
>>>> -	err = ubi_update_start(libubi, fdout, bytes);
>>>> +
>>>> +	if (img->compressed) {
>>>> +		lseek(img->fdin, img->size-4, SEEK_CUR);
>>>> +		read(img->fdin, &decompressed_bytes, 4);
>>>> +		lseek(img->fdin, -img->size, SEEK_CUR);
>>>> +	}
>>>> +	else {
>>>> +		decompressed_bytes = bytes;
>>>> +	}
>>>> +
>>>> +	err = ubi_update_start(libubi, fdout, decompressed_bytes);
>>>>  	if (err) {
>>>>  		ERROR("cannot start volume \"%s\" update", node);
>>>>  		return -1;
>>>
>>> Ah okay, silly me.
>>>
>>> Originally, I had passed the decompressed size to the handler with the "data" attribute. This would work with stream installed-directly aswell, no...?
>>
>> Yes, this works.
>>
>>>
>>> How about adding a new attribute to the ubivol type in sw_description. A new 'decompressed_size' field could become mandatory if compressed is true...? 
>>
>> We have now "properties" for such cases - see as reference the
>> swuforwarder handler.
>>
>> Anyway, I am ask myself why the UBI volume should be compressed when UBI
>> runs the decompression on-the-fly. IMHO it is much more efficient to not
>> compress the volume, but deliver a already compressed UBIFS and the
>> target decompress it on demand. Feature is in mainline kernel since a
>> very long time.
>>
>> Best regards,
>> Stefano Babic
>>
>>
>> -- 
>> =====================================================================
>> DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
>> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
>> Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic@denx.de
>> =====================================================================
> 
> Hi Stefano,
> 
> Thanks, I will explore the "properties".
> 
> And yes, I have seen you suggest using runtime compression in the ubifs in previous compression questions.
> 
> Firstly, my target hardware may have low bandwidth but will have high storage. I don't want to inhibit my performance at runtime to decrease the swu size.

ok

> 
> Secondly, I generated differentl compressed ubifs to gather the following sizes:
> 
> Uncompressed ubifs: 73MB -> Gzipped 27MB
> Zlibbed ubifs: 39MB
> 
> Notably, the Zlibbed ubifs is 39MB vs the Uncompressed, and then gzipped 27MB.

By the way, UBI supports LZO, too, and the compression rate is higher as
with zlib.

> 
> Increasing my ubifs my ~50% is not ideal, and has the added problem of slowing my read/write times.

Ok - regarding the decompression problem, we are building a work-around,
but IMHO the correct solution should be done in kernel. Currently,
drivers/mtd/ubi/upd.c checks for the receivd bytes to set automatically
the update marker, see:

362         ubi_assert(vol->upd_received <= vol->upd_bytes);
 363         if (vol->upd_received == vol->upd_bytes) {
 364                 err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
 365                 if (err)
 366                         return err;
 367                 /* The update is finished, clear the update marker */
 368                 err = clear_update_marker(ubi, vol, vol->upd_bytes);


However, this forbids streaming if we do not know, as for compressed
images, the whole size of the volume. I guess this question could be
post to MTD ML, asking if the en-of-file can be determined in a
different was, for example with an (rather new) ioctl.

Best regards,
Stefano Babic
mattbeaumontgts@gmail.com May 11, 2018, 9:55 a.m. UTC | #6
Hi Stefano,

Thanks for your time Stefano, I'm new to this.

I've written some code to take the decompressed size from the properties dict, I've added the field to sw-description respectively.

However, I suspect I will take your advise and use runtime-compression only.

Also, does the following link not suggest that Zlib compresses better then Lzo?
http://www.linux-mtd.infradead.org/misc.html

###############################

diff --git a/handlers/ubivol_handler.c b/handlers/ubivol_handler.c
index 0c6fcbf..d906f1f 100644
--- a/handlers/ubivol_handler.c
+++ b/handlers/ubivol_handler.c
@@ -37,7 +37,7 @@ static struct ubi_part *search_volume(const char *str, struct ubilist *list)
 static int update_volume(libubi_t libubi, struct img_type *img,
 	struct ubi_vol_info *vol)
 {
-	long long bytes;
+	long long bytes, decompressed_bytes;
 	int fdout;
 	char node[64];
 	int err;
@@ -91,7 +91,19 @@ static int update_volume(libubi_t libubi, struct img_type *img,
 		ERROR("cannot open UBI volume \"%s\"", node);
 		return -1;
 	}
-	err = ubi_update_start(libubi, fdout, bytes);
+
+	if (img->compressed) {
+		decompressed_bytes = strtoll(dict_get_value(&img->properties, "decompressed_size"), NULL, 10);
+		if (!decompressed_bytes) {
+			ERROR("UBIFS to be decompressed, but decompressed_size not found");
+			return -EINVAL;
+		}
+	}
+	else {
+		decompressed_bytes = bytes;
+	}
+
+	err = ubi_update_start(libubi, fdout, decompressed_bytes);
 	if (err) {
 		ERROR("cannot start volume \"%s\" update", node);
 		return -1;

######################################

Thanks,

Matt


On Friday, May 11, 2018 at 10:39:38 AM UTC+1, Stefano Babic wrote:
> Hi Matt,
> 
> On 11/05/2018 10:45, mattbeaumontgts@gmail.com wrote:
> > On Thursday, May 10, 2018 at 9:40:00 PM UTC+1, Stefano Babic wrote:
> >> Hi Matt,
> >>
> >> On 10/05/2018 22:16, matt wrote:
> >>> On Thursday, 10 May 2018 17:34:43 UTC+1, mattma...@outlook.com  wrote:
> >>>> I found when trying to use an ubifs.gz file and adding compressed = true; to the sw-description resulted in a failure to perform the swupdate.
> >>>>
> >>>> I found this was a problem with the following lines in
> >>>>  - handlers/ubivol_handler.c
> >>>>
> >>>> ------------
> >>>>
> >>>> err = ubi_update_start(libubi, fdout, bytes);
> >>>> if (err) {
> >>>> 	ERROR("cannot start volume \"%s\" update", node);
> >>>> 	return -1;
> >>>> }
> >>>>
> >>>> ---------
> >>>>
> >>>> The ubi_update_start command 'enables' writing to the number of bytes specified by the variable bytes.
> >>>>
> >>>> However, the variable 'bytes' contains the size of the compressed ubifs.gz file, and not the size of the decompressed ubifs file, as required.
> >>>>
> >>>> By obtaining the decompressed filesize from the gzipped file using this logic:
> >>>>
> >>>> https://stackoverflow.com/questions/9715046/find-the-size-of-the-file-inside-a-gzip-file/9727599#9727599
> >>>>
> >>>> I have created a patch that solves this issue, but note (as described in the link above) this limits the original ubifs file size to 4 GiB.
> >>>>
> >>>> Patch is below:
> >>>> #########################################
> >>>>
> >>>> diff --git a/handlers/ubivol_handler.c b/handlers/ubivol_handler.c
> >>>> index 0c6fcbf..6a88487 100644
> >>>> --- a/handlers/ubivol_handler.c
> >>>> +++ b/handlers/ubivol_handler.c
> >>>> @@ -42,6 +42,7 @@ static int update_volume(libubi_t libubi, struct img_type *img,
> >>>>  	char node[64];
> >>>>  	int err;
> >>>>  	char sbuf[128];
> >>>> +	uint32_t decompressed_bytes;
> >>>>  
> >>>>  	bytes = img->size;
> >>>>  	if (img->is_encrypted) {
> >>>> @@ -91,7 +92,17 @@ static int update_volume(libubi_t libubi, struct img_type *img,
> >>>>  		ERROR("cannot open UBI volume \"%s\"", node);
> >>>>  		return -1;
> >>>>  	}
> >>>> -	err = ubi_update_start(libubi, fdout, bytes);
> >>>> +
> >>>> +	if (img->compressed) {
> >>>> +		lseek(img->fdin, img->size-4, SEEK_CUR);
> >>>> +		read(img->fdin, &decompressed_bytes, 4);
> >>>> +		lseek(img->fdin, -img->size, SEEK_CUR);
> >>>> +	}
> >>>> +	else {
> >>>> +		decompressed_bytes = bytes;
> >>>> +	}
> >>>> +
> >>>> +	err = ubi_update_start(libubi, fdout, decompressed_bytes);
> >>>>  	if (err) {
> >>>>  		ERROR("cannot start volume \"%s\" update", node);
> >>>>  		return -1;
> >>>
> >>> Ah okay, silly me.
> >>>
> >>> Originally, I had passed the decompressed size to the handler with the "data" attribute. This would work with stream installed-directly aswell, no...?
> >>
> >> Yes, this works.
> >>
> >>>
> >>> How about adding a new attribute to the ubivol type in sw_description. A new 'decompressed_size' field could become mandatory if compressed is true...? 
> >>
> >> We have now "properties" for such cases - see as reference the
> >> swuforwarder handler.
> >>
> >> Anyway, I am ask myself why the UBI volume should be compressed when UBI
> >> runs the decompression on-the-fly. IMHO it is much more efficient to not
> >> compress the volume, but deliver a already compressed UBIFS and the
> >> target decompress it on demand. Feature is in mainline kernel since a
> >> very long time.
> >>
> >> Best regards,
> >> Stefano Babic
> >>
> >>
> >> -- 
> >> =====================================================================
> >> DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
> >> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> >> Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic@denx.de
> >> =====================================================================
> > 
> > Hi Stefano,
> > 
> > Thanks, I will explore the "properties".
> > 
> > And yes, I have seen you suggest using runtime compression in the ubifs in previous compression questions.
> > 
> > Firstly, my target hardware may have low bandwidth but will have high storage. I don't want to inhibit my performance at runtime to decrease the swu size.
> 
> ok
> 
> > 
> > Secondly, I generated differentl compressed ubifs to gather the following sizes:
> > 
> > Uncompressed ubifs: 73MB -> Gzipped 27MB
> > Zlibbed ubifs: 39MB
> > 
> > Notably, the Zlibbed ubifs is 39MB vs the Uncompressed, and then gzipped 27MB.
> 
> By the way, UBI supports LZO, too, and the compression rate is higher as
> with zlib.
> 
> > 
> > Increasing my ubifs my ~50% is not ideal, and has the added problem of slowing my read/write times.
> 
> Ok - regarding the decompression problem, we are building a work-around,
> but IMHO the correct solution should be done in kernel. Currently,
> drivers/mtd/ubi/upd.c checks for the receivd bytes to set automatically
> the update marker, see:
> 
> 362         ubi_assert(vol->upd_received <= vol->upd_bytes);
>  363         if (vol->upd_received == vol->upd_bytes) {
>  364                 err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
>  365                 if (err)
>  366                         return err;
>  367                 /* The update is finished, clear the update marker */
>  368                 err = clear_update_marker(ubi, vol, vol->upd_bytes);
> 
> 
> However, this forbids streaming if we do not know, as for compressed
> images, the whole size of the volume. I guess this question could be
> post to MTD ML, asking if the en-of-file can be determined in a
> different was, for example with an (rather new) ioctl.
> 
> Best regards,
> Stefano Babic
> 
> 
> -- 
> =====================================================================
> DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic@denx.de
> =====================================================================
Stefano Babic May 11, 2018, 10 a.m. UTC | #7
Hi Matt,

On 11/05/2018 11:55, mattbeaumontgts@gmail.com wrote:
> Hi Stefano,
> 
> Thanks for your time Stefano, I'm new to this.
> 
> I've written some code to take the decompressed size from the properties dict, I've added the field to sw-description respectively.
> 
> However, I suspect I will take your advise and use runtime-compression only.
> 
> Also, does the following link not suggest that Zlib compresses better then Lzo?
> http://www.linux-mtd.infradead.org/misc.html
> 

My fault, yes. LZO is faster, but zlib has better compression.

> ###############################
> 
> diff --git a/handlers/ubivol_handler.c b/handlers/ubivol_handler.c
> index 0c6fcbf..d906f1f 100644
> --- a/handlers/ubivol_handler.c
> +++ b/handlers/ubivol_handler.c
> @@ -37,7 +37,7 @@ static struct ubi_part *search_volume(const char *str, struct ubilist *list)
>  static int update_volume(libubi_t libubi, struct img_type *img,
>  	struct ubi_vol_info *vol)
>  {
> -	long long bytes;
> +	long long bytes, decompressed_bytes;
>  	int fdout;
>  	char node[64];
>  	int err;
> @@ -91,7 +91,19 @@ static int update_volume(libubi_t libubi, struct img_type *img,
>  		ERROR("cannot open UBI volume \"%s\"", node);
>  		return -1;
>  	}
> -	err = ubi_update_start(libubi, fdout, bytes);
> +
> +	if (img->compressed) {
> +		decompressed_bytes = strtoll(dict_get_value(&img->properties, "decompressed_size"), NULL, 10);
> +		if (!decompressed_bytes) {
> +			ERROR("UBIFS to be decompressed, but decompressed_size not found");
> +			return -EINVAL;
> +		}
> +	}
> +	else {
> +		decompressed_bytes = bytes;
> +	}
> +
> +	err = ubi_update_start(libubi, fdout, decompressed_bytes);
>  	if (err) {
>  		ERROR("cannot start volume \"%s\" update", node);
>  		return -1;
> 
> ######################################
> 
> Thanks,
> 


Best regards,
Stefano Babic
diff mbox series

Patch

diff --git a/handlers/ubivol_handler.c b/handlers/ubivol_handler.c
index 0c6fcbf..6a88487 100644
--- a/handlers/ubivol_handler.c
+++ b/handlers/ubivol_handler.c
@@ -42,6 +42,7 @@  static int update_volume(libubi_t libubi, struct img_type *img,
 	char node[64];
 	int err;
 	char sbuf[128];
+	uint32_t decompressed_bytes;
 
 	bytes = img->size;
 	if (img->is_encrypted) {
@@ -91,7 +92,17 @@  static int update_volume(libubi_t libubi, struct img_type *img,
 		ERROR("cannot open UBI volume \"%s\"", node);
 		return -1;
 	}
-	err = ubi_update_start(libubi, fdout, bytes);
+
+	if (img->compressed) {
+		lseek(img->fdin, img->size-4, SEEK_CUR);
+		read(img->fdin, &decompressed_bytes, 4);
+		lseek(img->fdin, -img->size, SEEK_CUR);
+	}
+	else {
+		decompressed_bytes = bytes;
+	}
+
+	err = ubi_update_start(libubi, fdout, decompressed_bytes);
 	if (err) {
 		ERROR("cannot start volume \"%s\" update", node);
 		return -1;