HTTP upload fails due to FAT error -16

Hello,
I’m experiencing a strange issue in my firmware running web server on a RCM3700.
When I try to upload a file, on CGI_START the sspec_open() function returns -16 so the CGI is skipped.
According to errno.lib -16 should be EBUSY but I’m using the FAT blocking mode. How is this possible?

Here my code snippet:

#define FAT_BLOCK
#use “fat.lib”
#use “http.lib”

SSPEC_RESOURCETABLE_START
SSPEC_RESOURCE_P_CGI(“/upload.cgi”, http_uploadCGI, “File Upload”,
ADMIN_GROUP, 0x0000, SERVER_HTTP, SERVER_AUTH_BASIC)
SSPEC_RESOURCETABLE_END

_debug int http_uploadCGI(HttpState *state) {
int rc, len, newlen;

if (http_getState(state) == 0) {
http_setState(state, 1);
http_setCond(state, COND_FILEHANDLE, -1);
}

rc = 0;
switch (http_getAction(state)) {
case CGI_START:
if (http_getField(state)[0] != ‘/’) {
log_print(“CGI upload skipping %s”, http_getAction(state), http_getField(state));
return http_skipCGI(state);
}
http_setCond(state, COND_FILEHANDLE, sspec_open(http_getField(state), http_getContext(state), O_WRITE|O_CREATE|O_TRUNC, 0));
if (http_getCond(state, COND_FILEHANDLE) < 0) {
log_print(“CGI upload action %d error %d”, http_getAction(state), http_getCond(state, COND_FILEHANDLE));
return http_skipCGI(state);
}
state->main_timeout = set_timeout(HTTP_TIMEOUT);
break;
case CGI_DATA:
len = sspec_write(http_getCond(state, COND_FILEHANDLE), http_getData(state), http_getDataLength(state));
if (len < 0) {
log_print(“CGI upload action %d error %d”, http_getAction(state), len);
http_genStatus(state, http_getData(state), HTTP_MAXBUFFER, 503, NULL, 0, NULL, NULL);
rc = CGI_SEND_DONE;
} else if (len < http_getDataLength(state)) {
http_setCond(state, COND_FILELENGTH, len);
rc = CGI_MORE;
}
break;
case CGI_CONTINUE:
len = http_getCond(state, COND_FILELENGTH);
newlen = sspec_write(http_getCond(state, COND_FILEHANDLE), http_getData(state) + len, http_getDataLength(state) - len);
if (newlen < 0) {
log_print(“CGI upload action %d error %d”, http_getAction(state), len);
http_genStatus(state, http_getData(state), HTTP_MAXBUFFER, 503, NULL, 0, NULL, NULL);
rc = CGI_SEND_DONE;
} else {
len += newlen;
if (len < http_getDataLength(state)) {
http_setCond(state, COND_FILELENGTH, len);
rc = CGI_MORE;
}
}
break;
case CGI_END:
if (strcmpi(FAT_FILE_DEVICES, http_getFileName(state)) == 0) {
cgi_upload_devices(state);
} else if (strcmpi(FAT_FILE_PASSKEYS, http_getFileName(state)) == 0) {
cgi_upload_passkeys(state);
} else if (strcmpi(FAT_FILE_IOLOGIC, http_getFileName(state)) == 0) {
cgi_upload_iologic(state);
} else if (strcmpi(FAT_FILE_SMTP, http_getFileName(state)) == 0) {
cgi_upload_smtp(state);
}
sspec_close(http_getCond(state, COND_FILEHANDLE));
http_setCond(state, COND_FILEHANDLE, -1);
break;
case CGI_EOF:
if (http_getCond(state, COND_REDIRECT) > 0) {
cgi_redirectto(state, “/index.htm”);
} else {
http_genStatus(state, http_getData(state), HTTP_MAXBUFFER, 200, NULL, 0, NULL, NULL);
rc = CGI_SEND_DONE;
}
break;
case CGI_ABORT:
if (http_getCond(state, COND_FILEHANDLE) >= 0) {
sspec_close(http_getCond(state, COND_FILEHANDLE));
}
break;
}

return rc;
}

Can you reproduce this in the debugger? If you define FAT_DEBUG in your program and single-step through the sspec_open() call, where does it throw the -EBUSY?

(side note: wrap your code in “code” and “/code” tags using square brackets to have it formatted in monospace and preserve spacing)

Hi Tom, it fails here:


_fat_debug int fat_Delete( fat_part *part, int type, char *name ) {
   ..
   ..
   if (part-&gt;opstate == FAT_IDLE)
   {
      if (rc = fatrj_transtart(part-&gt;wtc_prt)) {
         if (rc == -ETRANSOPEN)
            // Somebody got in with (probably) file create.  Let it complete.
            return -EBUSY;
         return rc;
   ..
}

sspec_open implements as delete/create operation but it fails when it tries to delete the file if already exists.

I’ve noted also that this not always occurs every time from a compilation to another. At first I thought it was due a corrupted flash chips or some bad RCM modules, but I found out that this could be due a compilation problem. I’m sure I’ve installed all library patches in my Dynamic C 9.62 environment.

I guess the “code” tag doesn’t work in comments.

There’s a chance that this is an issue with the FAT cache or journal. If it’s returning -EBUSY from that path, it’s because there’s already a transaction open in the rollback journal.

How do you mount the file system at the start of your program? Are you checking the return codes to ensure that the mount completes correctly/completely before continuing? Maybe there’s an incomplete transaction based on when you reset your program.

At the start of my program I check for an input state (dip switch) in case I want to reset to factory defaults, then I (re)mount every partitions fat_AutoMount(). I verify the result of the function.

At the end of my program (in case of a cold reboot due to a remote command) I unmount every partitions.

Here my code:


_debug void sysInit(void) {
   // initialization routine
   // ..
   // ..
   if (mboard.dpsw &amp; SW2) {
      printf("resetting %s
", "FAT");
      rc = fat_AutoMount(FDDF_UNCOND_DEV_FORMAT | FDDF_MOUNT_DEV_0 | FDDF_UNCOND_PART_FORMAT | FDDF_MOUNT_PART_0);
      if (rc &amp;&amp; rc != -EBADPART &amp;&amp; rc != -EUNFORMAT) {
         printf("FAT %s device error %d
", "format", rc);
	      exit(1);
      }
      // .. creating default files
      fat_CreateFile(PARTITION_A, "file1.dat", 0, NULL);
      fat_CreateFile(PARTITION_A, "file2.dat", 0, NULL);
      // ..
   }

   // mounting all FAT devices
   rc = fat_AutoMount(FDDF_MOUNT_DEV_ALL | FDDF_MOUNT_PART_ALL);
   if (rc) {
      printf("FAT %s device error %d
", "mount", rc);
      exit(1);
   }

   // continuing with other initializations
}

_debug void sysHalt(void) {
   // this routine is called after exited from main loop
   // and before MCU restart

   for (i = 0; i &lt; num_fat_devices * FAT_MAX_PARTITIONS; ++i) {
      if (fat_part_mounted[i]) {
         fat_UnmountDevice(fat_part_mounted[i]-&gt;dev);
      }
   }

   // ..
   // ..
}


Do you always get the -EBUSY on sspec_open()? Does it happen with both SW2 open and closed? If setting up defaults, does fat_CreateFile() return success? Do you get -EBUSY on both a cold boot (initial power on) and warm boot (software reset)? Do you have a backup battery with good voltage attached to Vbatt to preserve the FAT cache between power cycles?

I’m curious about the behavior of the second fat_AutoMount() in the case of restoring defaults. Should you skip that automount (since you’ve already mounted), or does your “restore defaults” unmount when it’s done?

I noticed this strange behaviour happens some times when I upload my firmware for the very first time on a new brand module via the RFU application. It doesn’t matter the SW2 status and if cold or warm boot. In these cases I have to reflash the firmware or try to format again the FAT flash with “format.c” program. But this is not systematically.
When I’ve started to investigate the issue in debug mode I’ve noticed this issue happens or not from a compilation to another.
The battery attached to Vbatt (in series with a 1k2 resistor) is a CR2450 and is always new.

My “restore defaults” routine, if executed at start, doesn’t unmount the FAT partition, so the 2nd fat_Automount() is always executed since “this function may be called multiple times…” according to the documentation.