
Hi Everyone,
As far as I noticed, set_cluster can be called quite often with a size being zero. That can indeed be with a file that has a size being an exact multiple (including 0) of the clustersize, but also for files that are smaller than the size of one cluster. In that case, the 1st call to set_cluster has a size being zero:
fatwrite mmc 0:1 42000000 test3 200
writing test3 set_cluster; clustnum: 1487, startsect: 6104, size 0 set_cluster; clustnum: 1487, startsect: 6104, size 512 set_cluster; clustnum: -6, startsect: 132, size 2048 512 bytes written
This was solved by adding the "if(size)" in set_cluster (otherwise the above test would fail). However: this does not solve all the problems. If I tried to write a file of 16 bytes, I still got an error. Looking closer at set_cluster, the 1st call to disk_write( ) has a size being "size / mydata->sect_size". This would mean that for any file (or file remainder) smaller than the sector size (typicaly 512 bytes), the fatwrite would fail.
So to my opinion, the actual cause of the problem is in the function "disk_write( )", that can't be called with a size being zero. That could be solved by adding tests before calling set_cluster and/or before calling disk_write from set_cluster, but the safest (and simplest) would be to add this piece of code to disk_write:
if(nr_blocks == 0) { return 0; }
With this change I have been able to write various file sizes so far without problems (512 bytes, 2048, 2049, 16, 0).
Another option would be to solve this in the cur_dev->block_write function, being mmc_bwrite( ) for the mmc device. Since his has a do { } while, it will always call mmc_write_blocks() even if blkcnt equals zero. Maybe even the mmc_write_blocks would be the best place to fix this...
I will do some further testing here. Meanwhile, please let me know if this change would make sense to you, and what would be the best place to put it. Probably the lowest level function, if you would ask me. Also I would like to know if it would not cause any oher problems according to your knowledge.
Regards,
Ruud
-----Oorspronkelijk bericht----- Van: Benoît Thébaudeau [mailto:benoit.thebaudeau@advansee.com] Verzonden: vrijdag 12 april 2013 23:18 Aan: Tom Rini CC: Ruud Commandeur; u-boot@lists.denx.de; Mats K?rrman Onderwerp: Re: [U-Boot] fatwrite problem
Hi Tom,
On Friday, April 12, 2013 10:42:34 PM, Tom Rini wrote:
On Fri, Apr 12, 2013 at 09:39:19PM +0200, Beno??t Th??baudeau wrote:
Hi Tom, Ruud, Mats,
On Friday, April 12, 2013 5:12:31 PM, Tom Rini wrote:
On Fri, Apr 12, 2013 at 05:06:35PM +0200, Ruud Commandeur wrote:
Hi Mats,
Thanks a lot, this seems to solve my problem. Nothing more actualy than adding a "if(size)" around the code block of set_sector( ). I could have thought of that myself, but was not sure if anything else should be done in this case...
Since your change sounds slightly different, can you confirm that it also solves the problem and if so post it as patch with Signed-off-by and so forth? Thanks!
Regards,
Ruud
-----Oorspronkelijk bericht----- Van: Mats K?rrman [mailto:Mats.Karrman@tritech.se] Verzonden: vrijdag 12 april 2013 16:11 Aan: Ruud Commandeur CC: u-boot@lists.denx.de Onderwerp: RE: fatwrite problem
Hi Ruud,
Ruud Commandeur wrote:
Once the size of the set_cluster call equals 0, the mmc command is incomplete and times out. In the earlier reported problem, a patch is mentioned, but not available for dowload here. Also in the latest versions of the git repository I could not find a patch for this problem. Can anyone tell me if there is a fix for this problem?
I asked Damien Huang (back then) and got the following reply (I think there was some character encoding problem so his mail never was accepted by the list). I have not further analyzed the contents, anyway it wasn't the solution to my problem. BR // Mats
Damien Huang wrote: As requested from Mats, I am resending this email. The patch is given below:
diff -cr ./u-boot-original/u-boot/fs/fat/fat_write.c ./u-boot-test/u-boot/fs/fat/fat_write.c *** ./u-boot-original/u-boot/fs/fat/fat_write.c 2013-02-07 14:47:33.314732999 +1100 --- ./u-boot-test/u-boot/fs/fat/fat_write.c 2013-02-28 15:36:24.551861920 +1100
*** 562,596 **** { int idx = 0; __u32 startsect; ! ! if (clustnum > 0) ! startsect = mydata->data_begin + ! clustnum * mydata->clust_size; ! else ! startsect = mydata->rootdir_sect; ! ! debug("clustnum: %d, startsect: %d\n", clustnum, startsect); ! ! if (disk_write(startsect, size / mydata->sect_size, buffer) < 0) { ! debug("Error writing data\n"); ! return -1; ! } ! ! if (size % mydata->sect_size) { ! __u8 tmpbuf[mydata->sect_size]; ! ! idx = size / mydata->sect_size; ! buffer += idx * mydata->sect_size; ! memcpy(tmpbuf, buffer, size % mydata->sect_size); ! ! if (disk_write(startsect + idx, 1, tmpbuf) < 0) { ! debug("Error writing data\n"); ! return -1; ! } ! ! return 0; ! } ! return 0; }
--- 562,595 ---- { int idx = 0; __u32 startsect; ! if(size) //if there are data to be set ! { ! if (clustnum > 0) ! startsect = mydata->data_begin + ! clustnum * mydata->clust_size; ! else ! startsect = mydata->rootdir_sect; ! ! debug("clustnum: %d, startsect: %d\n", clustnum, startsect); ! ! if (disk_write(startsect, size / mydata->sect_size, buffer) < 0) { ! debug("Error writing data\n"); ! return -1; ! } ! ! if (size % mydata->sect_size) { ! __u8 tmpbuf[mydata->sect_size]; ! ! idx = size / mydata->sect_size; ! buffer += idx * mydata->sect_size; ! memcpy(tmpbuf, buffer, size % mydata->sect_size); ! ! if (disk_write(startsect + idx, 1, tmpbuf) < 0) { ! debug("Error writing data\n"); ! return -1; ! } ! } ! }//end if data to be set return 0; }
diff -cr ./u-boot-original/u-boot/include/configs/am335x_evm.h ./u-boot-test/u-boot/include/configs/am335x_evm.h *** ./u-boot-original/u-boot/include/configs/am335x_evm.h 2013-02-07 14:47:35.754702325 +1100 --- ./u-boot-test/u-boot/include/configs/am335x_evm.h 2013-03-01 12:25:23.942104474 +1100
*** 143,148 **** --- 143,149 ---- #define CONFIG_CMD_MMC #define CONFIG_DOS_PARTITION #define CONFIG_FS_FAT
- #define CONFIG_FAT_WRITE #define CONFIG_FS_EXT4 #define CONFIG_CMD_FAT #define CONFIG_CMD_EXT2
Benoit, what do you think? Thanks!
This is fine as a workaround, but it does not fix the root cause of the issue: set_clusster() should not have been called with size set to 0 in the first place. This is hiding some cluster mishandling. It may mean that a cluster is wasted at EoF in some cases, which is unexpected and may trigger abnormal behaviors on systems reading back those files.
What kind of action triggered this issue for you:
- writing an empty file?
- writing a file with a size equal to an integer multiple of the cluster
size?
- something else?
This can be caused only be lines 713, 724 or 739. Looking closer at the code, only line 713 triggers this issue, so an 'if' could be added here rather than in set_cluster().
The code for writing an empty file is broken: It should set both the start cluster and the size to 0 in the corresponding directory entry, but it actually allocates a single cluster (see find_empty_cluster() called from do_fat_write()).
So 2 fixes are required here:
- 'if' either in set_cluster(), or on line 713 to discard empty sizes, or
make the underlying MMC driver return without doing anything if size is 0, the latter being perhaps the most robust solution if it does not cause other issues for this driver,
I prefer updating set_cluster since he sees this in one MMC driver and I in another (meaning we would have to go whack all of them, or start poking drivers/mmc/mmc.c). I can confirm that size != 0 in that test fixes the problem here.
OK.
- empty file creation.
I took a stab at this and ended up killing my test FAT partition, which is not a big deal, but can you take a stab at this please? Thanks!
OK, but I can't guarantee when.
Best regards, Benoît