This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

JFFS2 Garbage Collection Error?


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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]