Index: fs/jffs2/current/ChangeLog =================================================================== RCS file: /cvs/ecos/ecos/packages/fs/jffs2/current/ChangeLog,v retrieving revision 1.42 diff -u -r1.42 ChangeLog --- fs/jffs2/current/ChangeLog 13 Dec 2004 20:33:43 -0000 1.42 +++ fs/jffs2/current/ChangeLog 19 Jan 2005 20:30:42 -0000 @@ -1,3 +1,9 @@ +2004-11-14 Per Hedblom + + * src/os-ecos.h: Added gc tread support + * src/fs-ecos.c: Removed some includes + * cdl/jffs2.cdl: Added gc thread support + 2004-12-13 John Dallaway * tests/fileio1.c: Rename to jffs2_1.c. eCos test names should be Index: fs/jffs2/current/cdl/jffs2.cdl =================================================================== RCS file: /cvs/ecos/ecos/packages/fs/jffs2/current/cdl/jffs2.cdl,v retrieving revision 1.20 diff -u -r1.20 jffs2.cdl --- fs/jffs2/current/cdl/jffs2.cdl 13 Dec 2004 20:33:44 -0000 1.20 +++ fs/jffs2/current/cdl/jffs2.cdl 19 Jan 2005 20:30:43 -0000 @@ -77,16 +77,47 @@ # This could be overridden by an alternative direct I/O method. compile flashio.c - cdl_option CYGOPT_FS_JFFS2_GCTHREAD { + cdl_component CYGOPT_FS_JFFS2_GCTHREAD { display "Support garbage-collection background thread" flavor bool + default_value 0 compile gcthread.c -# Leave this off till it's been implemented. And don't implement it till -# icache locking has been made thread-safe. - requires CYGPKG_KERNEL && 0 + requires CYGPKG_KERNEL description " Enable background garbage collection thread, for making - free space ahead of time." + free space ahead of time. Leave this off till it's been + implemented. And don't implement it till icache locking has + been made thread-safe. + " + + + cdl_option CYGNUM_JFFS2_GC_THREAD_PRIORITY { + display "jffs2 gc thread priority" + flavor data + default_value { CYGNUM_KERNEL_SCHED_PRIORITIES-2 } + legal_values 0 to CYGNUM_KERNEL_SCHED_PRIORITIES + description "The jffs2 system contains one garbage collect thread." + } + + cdl_option CYGNUM_JFFS2_GC_THREAD_STACK_SIZE { + display "jffs2 gc stackstack size" + flavor data + legal_values 2048 to 0x7fffffff + default_value 8192 + description " + This option sets the size of the stack used + for jffs2 garbage collect thread" + } + + cdl_option CYGNUM_JFFS2_GS_THREAD_TICKS { + display "ticks between each garbage collect" + flavor data + default_value 100 + description " + This option sets how many clock ticks there will be between + each garbage collect operation triggered by the background + thread" + } } cdl_option CYGOPT_FS_JFFS2_WRITE { @@ -229,9 +260,10 @@ display "JFFS2 FS tests" flavor data no_define - calculated { "tests/jffs2_1 tests/jffs2_2" } + calculated { "tests/jffs2_1 tests/jffs2_2 tests/jffs2_3" } description " - This option specifies the set of tests for the JFFS2 FS package." + This option specifies the set of tests for the JFFS2 + FS package." } } Index: fs/jffs2/current/src/fs-ecos.c =================================================================== RCS file: /cvs/ecos/ecos/packages/fs/jffs2/current/src/fs-ecos.c,v retrieving revision 1.33 diff -u -r1.33 fs-ecos.c --- fs/jffs2/current/src/fs-ecos.c 11 Dec 2004 12:22:36 -0000 1.33 +++ fs/jffs2/current/src/fs-ecos.c 19 Jan 2005 20:30:45 -0000 @@ -12,20 +12,13 @@ * */ -#include -#include #include -#include -#include -#include +#include "nodelist.h" #include #include -#include "nodelist.h" #include "compr.h" - #include #include -#include #include #if (__GNUC__ == 3) && (__GNUC_MINOR__ == 2) && defined (__ARM_ARCH_4__) @@ -1721,7 +1714,6 @@ break; } } - return inode; } @@ -1737,7 +1729,6 @@ break; } } - return inode; } @@ -1797,8 +1788,8 @@ BUG(); if (i->i_count) - return; - + return; + if (!i->i_nlink) { struct _inode *parent; Index: fs/jffs2/current/src/gcthread.c =================================================================== RCS file: /cvs/ecos/ecos/packages/fs/jffs2/current/src/gcthread.c,v retrieving revision 1.1 diff -u -r1.1 gcthread.c --- fs/jffs2/current/src/gcthread.c 11 Dec 2003 23:38:21 -0000 1.1 +++ fs/jffs2/current/src/gcthread.c 19 Jan 2005 20:30:45 -0000 @@ -7,46 +7,118 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: gcthread.c,v 1.1 2003/11/26 15:55:35 dwmw2 Exp $ + * $Id: gcthread.c,v 1.1 2003/12/01 17:02:31 affe Exp $ * */ - #include -#include -#include #include "nodelist.h" +#include +#define GC_THREAD_FLAG_TRIG 1 +#define GC_THREAD_FLAG_STOP 2 +#define GC_THREAD_FLAG_HAS_EXIT 4 -static void jffs2_garbage_collect_thread(struct jffs2_sb_info *c); +static cyg_thread_entry_t jffs2_garbage_collect_thread; void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c) { - /* Wake up the thread */ - (void)&jffs2_garbage_collect_thread; + struct super_block *sb=OFNI_BS_2SFFJ(c); + + /* Wake up the thread */ + D1(printk("jffs2_garbage_collect_trigger\n")); + + cyg_flag_setbits(&sb->s_gc_thread_flags,GC_THREAD_FLAG_TRIG); } -void jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) + +void +jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) { - /* Start the thread. Doesn't matter if it fails -- it's only an optimisation anyway */ + struct super_block *sb=OFNI_BS_2SFFJ(c); + + CYG_ASSERTC(c); + CYG_ASSERTC(!sb->s_gc_thread_handle); + + cyg_flag_init(&sb->s_gc_thread_flags); + cyg_mutex_init(&sb->s_lock); + + D1(printk("jffs2_start_garbage_collect_thread\n")); + /* Start the thread. Doesn't matter if it fails -- it's only an + * optimisation anyway */ + cyg_thread_create(CYGNUM_JFFS2_GC_THREAD_PRIORITY, + jffs2_garbage_collect_thread, + (cyg_addrword_t)c,"jffs2 gc thread", + (void*)sb->s_gc_thread_stack, + sizeof(sb->s_gc_thread_stack), + &sb->s_gc_thread_handle, + &sb->s_gc_thread); + + cyg_thread_resume(sb->s_gc_thread_handle); } -void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c) +void +jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c) { - /* Stop the thread and wait for it if necessary */ + struct super_block *sb=OFNI_BS_2SFFJ(c); + + CYG_ASSERTC(sb->s_gc_thread_handle); + + D1(printk("jffs2_stop_garbage_collect_thread\n")); + /* Stop the thread and wait for it if necessary */ + + cyg_flag_setbits(&sb->s_gc_thread_flags,GC_THREAD_FLAG_STOP); + + D1(printk("jffs2_stop_garbage_collect_thread wait\n")); + + cyg_flag_wait(&sb->s_gc_thread_flags, + GC_THREAD_FLAG_HAS_EXIT, + CYG_FLAG_WAITMODE_OR| CYG_FLAG_WAITMODE_CLR); + + // Kill and free the resources ... this is safe due to the flag + // from the thread. + cyg_thread_kill(sb->s_gc_thread_handle); + cyg_thread_delete(sb->s_gc_thread_handle); + + cyg_mutex_destroy(&sb->s_lock); + cyg_flag_destroy(&sb->s_gc_thread_flags); } -static void jffs2_garbage_collect_thread(struct jffs2_sb_info *c) +static void +jffs2_garbage_collect_thread(cyg_addrword_t data) { -#define this_thread_should_die() 0 - while(!this_thread_should_die()) { - while(!jffs2_thread_should_wake(c)) { - /* Sleep.... */ - continue; - } - if (jffs2_garbage_collect_pass(c) == -ENOSPC) { - printf("No space for garbage collection. Aborting JFFS2 GC thread\n"); - break; - } - } + struct jffs2_sb_info *c=(struct jffs2_sb_info *)data; + struct super_block *sb=OFNI_BS_2SFFJ(c); + cyg_flag_value_t flag; + cyg_mtab_entry *mte; + + D1(printk("jffs2_garbage_collect_thread START\n")); + + while(1) { + flag=cyg_flag_timed_wait(&sb->s_gc_thread_flags, + GC_THREAD_FLAG_TRIG|GC_THREAD_FLAG_STOP, + CYG_FLAG_WAITMODE_OR| CYG_FLAG_WAITMODE_CLR, + cyg_current_time()+ + CYGNUM_JFFS2_GS_THREAD_TICKS); + + if (flag & GC_THREAD_FLAG_STOP) + break; + + D1(printk("jffs2: GC THREAD GC BEGIN\n")); + + mte=cyg_fs_root_lookup((cyg_dir *) sb->s_root); + CYG_ASSERT(mte, "Bad mount point"); + cyg_fs_lock(mte, mte->fs->syncmode); + + if (jffs2_garbage_collect_pass(c) == -ENOSPC) { + printf("No space for garbage collection. " + "Aborting JFFS2 GC thread\n"); + break; + } + cyg_fs_unlock(mte, mte->fs->syncmode); + D1(printk("jffs2: GC THREAD GC END\n")); + } + + D1(printk("jffs2_garbage_collect_thread EXIT\n")); + cyg_flag_setbits(&sb->s_gc_thread_flags,GC_THREAD_FLAG_HAS_EXIT); } Index: fs/jffs2/current/src/os-ecos.h =================================================================== RCS file: /cvs/ecos/ecos/packages/fs/jffs2/current/src/os-ecos.h,v retrieving revision 1.10 diff -u -r1.10 os-ecos.h --- fs/jffs2/current/src/os-ecos.h 12 Nov 2004 16:50:34 -0000 1.10 +++ fs/jffs2/current/src/os-ecos.h 19 Jan 2005 20:30:46 -0000 @@ -127,6 +127,19 @@ struct _inode * s_root; unsigned long s_mount_count; cyg_io_handle_t s_dev; + +#ifdef CYGOPT_FS_JFFS2_GCTHREAD + cyg_mutex_t s_lock; // Lock the inode cache + cyg_flag_t s_gc_thread_flags; // Communication with the gcthread + cyg_handle_t s_gc_thread_handle; + cyg_thread s_gc_thread; +#if (CYGNUM_JFFS2_GC_THREAD_STACK_SIZE >= CYGNUM_HAL_STACK_SIZE_MINIMUM) + char s_gc_thread_stack[CYGNUM_JFFS2_GC_THREAD_STACK_SIZE]; +#else + char s_gc_thread_stack[CYGNUM_HAL_STACK_SIZE_MINIMUM]; +#endif + cyg_mtab_entry *mte; +#endif }; #define sleep_on_spinunlock(wq, sl) spin_unlock(sl) Index: fs/jffs2/current/tests/jffs2_1.c =================================================================== RCS file: /cvs/ecos/ecos/packages/fs/jffs2/current/tests/jffs2_1.c,v retrieving revision 1.1 diff -u -r1.1 jffs2_1.c --- fs/jffs2/current/tests/jffs2_1.c 13 Dec 2004 20:33:44 -0000 1.1 +++ fs/jffs2/current/tests/jffs2_1.c 19 Jan 2005 20:30:46 -0000 @@ -654,11 +654,15 @@ err = chdir( "/" ); if( err < 0 ) SHOW_RESULT( chdir, err ); checkcwd( "/" ); +#ifdef CYGOPT_FS_JFFS2_GCTHREAD + diag_printf(": Letting garbage collect thread run\n"); + cyg_thread_delay(2*100); +#endif diag_printf(": umount /jffs2\n"); err = umount( "/jffs2" ); if( err < 0 ) SHOW_RESULT( umount, err ); - + diag_printf(": umount /\n"); err = umount( "/" ); if( err < 0 ) SHOW_RESULT( umount, err ); Index: fs/jffs2/current/tests/jffs2_2.c =================================================================== RCS file: /cvs/ecos/ecos/packages/fs/jffs2/current/tests/jffs2_2.c,v retrieving revision 1.1 diff -u -r1.1 jffs2_2.c --- fs/jffs2/current/tests/jffs2_2.c 13 Dec 2004 20:33:44 -0000 1.1 +++ fs/jffs2/current/tests/jffs2_2.c 19 Jan 2005 20:30:46 -0000 @@ -45,7 +45,7 @@ // Contributors: asl // Date: 2004-03-29 // Purpose: Test fseek on a filesystem -// Description: This test uses the ramfs to check out the fseek +// Description: This test uses the jffs2 to check out the fseek // operation on a filesystem. // // Index: fs/jffs2/current/tests/jffs2_3.c =================================================================== RCS file: fs/jffs2/current/tests/jffs2_3.c diff -N fs/jffs2/current/tests/jffs2_3.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ fs/jffs2/current/tests/jffs2_3.c 19 Jan 2005 20:30:48 -0000 @@ -0,0 +1,180 @@ +//========================================================================== +// +// jffs2_3.c +// +// Test garbage collect on a filesystem +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2005 Andrew Lunn +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): asl +// Contributors: asl +// Date: 2005-01-16 +// Purpose: Test garbage collect on a filesystem +// Description: This test creates and deletes files in order +// to test the garbage collection code. +// +//####DESCRIPTIONEND#### +// +//========================================================================== +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include // HAL polled output + +//========================================================================== + +#define ITERATIONS 1000000 +#define NELEM(_x_) (sizeof(_x_)/sizeof(*(_x_))) + +#define SHOW_RESULT( _fn, _res ) \ +diag_printf("FAIL: " #_fn "() returned %d %s\n", _res, \ + _res<0?strerror(errno):""); + +//========================================================================== +// file creation, deletion and testing functions + +static void create_file(int i) +{ + cyg_int32 buffer[1020]; + char name[16]; + cyg_uint32 j; + int fd, err; + + sprintf(name,"test%07d",i); + + fd = creat(name, S_IRWXU); + if (fd == -1) SHOW_RESULT( creat, fd ); + + for (j=1; j < NELEM(buffer); j++) { + buffer[j] = rand(); + } + + buffer[0] = 0; + buffer[0] = cyg_posix_crc32((char *)buffer, sizeof(buffer)); + + err = write(fd, buffer, sizeof(buffer)); + if (err == -1) SHOW_RESULT( write, err ); + + err = close(fd); + if (err == -1) SHOW_RESULT( close, err ); +} + +static void delete_file(int i) +{ + char name[16]; + int err; + + sprintf(name,"test%07d",i); + + err = unlink(name); + if (err == -1) SHOW_RESULT( unlink, err ); +} + +static void check_file(int i) +{ + char name[16]; + int err, fd; + cyg_int32 buffer[1020]; + cyg_uint32 crc; + + sprintf(name,"test%07d",i); + + fd = open(name, O_RDONLY); + if (fd == -1) SHOW_RESULT( open, fd ); + + err = read(fd, buffer, sizeof(buffer)); + if (err == -1) SHOW_RESULT( read, fd ); + + crc = buffer[0]; + buffer[0] = 0; + + if (crc != cyg_posix_crc32((char *)buffer, sizeof(buffer))) { + CYG_TEST_FAIL("File corrupt"); + } + + err = close(fd); + if (err == -1) SHOW_RESULT( read, fd ); +} + + +//========================================================================== +// main + +int main( int argc, char **argv ) +{ + int err, iteration; + cyg_tick_count_t ticks; + struct mallinfo minfo +; + CYG_TEST_INIT(); + + // -------------------------------------------------------------- + + CYG_TEST_INFO("mount /"); + err = mount( CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_1, "/", "jffs2" ); + if( err < 0 ) SHOW_RESULT( mount, err ); + + chdir ("/"); + + iteration=0; + create_file(iteration); + while (iteration < ITERATIONS) { + if (!(iteration % 1000)) { + minfo = mallinfo(); + diag_printf(" Iteration %07d fordblks = %7d\n", + iteration, minfo.fordblks); + } + iteration++; + create_file(iteration); + check_file(iteration-1); + delete_file(iteration-1); + check_file(iteration); + } + + CYG_TEST_INFO("umount /"); + err = umount( "/" ); + if( err < 0 ) SHOW_RESULT( umount, err ); + + CYG_TEST_PASS_FINISH("jffs2_3"); +}