This is the mail archive of the
ecos-discuss@sources.redhat.com
mailing list for the eCos project.
JFFS2 Garbage Collection Error?
- From: Scott Wilkinson <scott at alliantnetworks dot com>
- To: ecos-discuss at sources dot redhat dot com
- Date: 08 Jul 2003 15:33:43 -0700
- Subject: [ECOS] JFFS2 Garbage Collection Error?
- Organization:
Hi All,
I have been running JFFS2 tests on both the Linux Synthetic Target (with
synthetic flash driver) and on a PPC embedded system. I have a simple
test which loops forever doing the following:
for (N=0;;N++)
{
a) Create File(N), fill with known pattern
if (N>0)
{
b) Open File(N-1), verify known pattern
c) Delete File(N-1)
}
}
What I see is that on both the synthetic and real target the exact same
behavior happens. Everything works fine until the first time that
jffs2_garbage_collect_dnode() gets called. A few more calls down the
stack and I take and exception caused by rb_remove_color dereferencing a
null pointer.
Has anyone seen anything like this? If you are successfully using
JFFS2, have you ever seen jffs2_garbage_collect_dnode() get called?
I have attached the test code I'm using. For the synthetic target I
have the flash configured to be 8 sectors of 65536 bytes each. In this
case it fails when N = 2797.
I am not really sure where to start looking. I have actually merged the
latest jffs2 code from www.intradead.org and it runs(!) but didn't fix
the problem :(.
Thanks,
Scott
#include <stdio.h>
#include <stdlib.h>
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/io_fileio.h>
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/kernel/kapi.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
#include <cyg/io/flash.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#include <cyg/fileio/fileio.h>
#include <cyg/infra/testcase.h>
#include <cyg/infra/diag.h> // HAL polled output
#include <pkgconf/fs_jffs2.h> // Address of JFFS2
#define SHOW_RESULT( _fn, _res ) \
diag_printf("<FAIL>: " #_fn "() returned %d %s\n", \
_res, _res<0?strerror(errno):"");
//==========================================================================
#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
static char stack[STACK_SIZE];
static cyg_thread thread_data;
static cyg_handle_t thread_handle;
#define IOSIZE 100
/* 0 to disable, otherwise max ticks for random sleeps. */
int gSLEEP = 0;
static bool DirList(const char *name, int statp, int numexpected)
{
int err;
DIR *dirp;
int num=0;
diag_printf("<INFO>: reading directory %s\n",name);
dirp = opendir( name );
if( dirp == NULL )
{
SHOW_RESULT( opendir, -1 );
return false;
}
for(;;)
{
struct dirent *entry = readdir( dirp );
if( entry == NULL )
{
break;
}
num++;
diag_printf("<INFO>: entry %14s",entry->d_name);
if( statp )
{
char fullname[PATH_MAX];
struct stat sbuf;
if( name[0] )
{
strcpy(fullname, name );
if( !(name[0] == '/' && name[1] == 0 ) )
{
strcat(fullname, "/" );
}
}
else
{
fullname[0] = 0;
}
strcat(fullname, entry->d_name );
err = stat( fullname, &sbuf );
if( err < 0 )
{
if( errno == ENOSYS )
{
diag_printf(" <no status available>");
}
else
{
SHOW_RESULT( stat, err );
}
}
else
{
diag_printf(" [mode %08x ino %08x nlink %d size %d]",
sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size);
}
}
diag_printf("\n");
}
err = closedir( dirp );
if( err < 0 ) SHOW_RESULT( stat, err );
if (numexpected >= 0 && num != numexpected)
{
CYG_TEST_FAIL("Wrong number of dir entries\n");
}
return true;
}
static bool GetLastFile(const char *dirName, int *lastNumber)
{
int number = 0;
int numberMax = 0;
int err;
DIR *dirp;
dirp = opendir(dirName);
if( dirp == NULL )
{
diag_printf("failed\nunable to open directory\n");
return false;
}
for(;;)
{
struct dirent *entry = readdir( dirp );
if( entry == NULL )
{
break;
}
if (strcmp(entry->d_name, ".") == 0)
{
continue;
}
if (strcmp(entry->d_name, "..") == 0)
{
continue;
}
sscanf(entry->d_name,"myfile%d", &number);
if (number > numberMax)
{
numberMax = number;
}
}
*lastNumber = numberMax;
err = closedir( dirp );
if( err < 0 )
{
diag_printf("failed\n unable to open directory\n");
return false;
}
return true;
}
static bool FileCreate(char *name, int size )
{
char buf[IOSIZE];
int fd;
ssize_t wrote;
int i;
int err;
diag_printf("Creating file %s of size %d\n", name, size);
err = access( name, F_OK );
if( err < 0 && errno != EACCES )
{
SHOW_RESULT( access, err );
}
for( i = 0; i < IOSIZE; i++ )
{
buf[i] = i%256;
}
fd = open( name, O_WRONLY|O_CREAT );
if( fd < 0 ) SHOW_RESULT( open, fd );
// Sleep a bit here.
if (gSLEEP)
{
cyg_thread_delay(rand() % gSLEEP);
}
while( size > 0 )
{
ssize_t len = size;
if ( len > IOSIZE ) len = IOSIZE;
wrote = write( fd, buf, len );
if( wrote != len ) SHOW_RESULT( write, wrote );
if (gSLEEP)
{
cyg_thread_delay(rand() % gSLEEP);
}
size -= wrote;
}
if(gSLEEP)
{
cyg_thread_delay(rand() % gSLEEP);
}
err = close( fd );
if( err < 0 )
{
SHOW_RESULT( close, err );
return false;
}
return true;
}
static bool FileCheck( char *name )
{
char buf[IOSIZE];
int fd;
ssize_t done;
int i;
int err;
off_t pos = 0;
diag_printf("Checking file %s\n",name);
err = access( name, F_OK );
if( err != 0 )
{
SHOW_RESULT( access, err );
return false;
}
fd = open( name, O_RDONLY );
if( fd < 0 )
{
SHOW_RESULT( open, fd );
return false;
}
if (gSLEEP)
{
cyg_thread_delay(rand() % gSLEEP);
}
for(;;)
{
done = read( fd, buf, IOSIZE );
if (gSLEEP)
{
cyg_thread_delay(rand() % gSLEEP);
}
if( done < 0 )
{
SHOW_RESULT( read, done );
return false;
}
if( done == 0 ) break;
for( i = 0; i < done; i++ )
{
if( buf[i] != i%256 )
{
diag_printf("buf[%d+%d](%02x) != %02x\n",pos,i,buf[i],i%256);
CYG_TEST_FAIL("Data read not equal to data written\n");
return false;
}
}
pos += done;
}
err = close( fd );
if( err < 0 )
{
SHOW_RESULT( close, err );
return false;
}
return true;
}
void main_test(cyg_addrword_t)
{
const char *WARN_PRE = "JffRobustTest: ";
const char *JFFS_DIR = "/jffs2fs";
int lastFile = 0;
char fileName[100];
int i = 0;
int fileSize = 0;
if (mount(CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_1, "/jffs2fs", "jffs2" ) < 0)
{
diag_printf("failed\n%s unable to mount jffs\n", WARN_PRE);
return;
}
if(chdir( JFFS_DIR) < 0)
{
diag_printf("failed\n%s can't chdir\n", WARN_PRE);
return;
}
DirList(JFFS_DIR, true, -1);
if(!GetLastFile(JFFS_DIR, &lastFile))
{
diag_printf("failed\n%s getting last file failed\n", WARN_PRE);
return;
}
/*
We've retrieved the last file number. So now keep creating
the next file.
*/
for(i=lastFile+1;;++i)
{
cyg_thread_delay(2);
sprintf(fileName, "myfile%d", i);
fileSize = rand() % 2000;
if(!FileCreate(fileName, fileSize))
{
diag_printf("failed\n%s unable to create file\n", WARN_PRE);
return;
}
if (gSLEEP)
{
cyg_thread_delay(rand() % gSLEEP);
}
if ((i-1) != 0)
{
sprintf(fileName, "myfile%d", (i-1));
if(!FileCheck(fileName))
{
diag_printf("failed\n%s unable to create file\n", WARN_PRE);
return;
}
diag_printf("Deleting file %s\n", fileName);
int err = 0;
if ((err = unlink(fileName)) < 0)
{
SHOW_RESULT( unlink, err );
diag_printf("failed\n%s unable to unlink file\n", WARN_PRE);
return;
}
}
}
return;
}
extern "C" void cyg_start(void)
{
diag_printf("Creating Main Test Thread and starting Scheduler...\n");
// Create a main thread, so we can run the scheduler and have time 'pass'
cyg_thread_create(10, // Priority - just a number
main_test, // entry
0, // entry parameter
"Main Test", // Name
&stack[0], // Stack
STACK_SIZE, // Size
&thread_handle, // Handle
&thread_data // Thread data structure
);
cyg_thread_resume(thread_handle); // Start it
cyg_scheduler_start();
}
--
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss