Index: soft/giet_vm/giet_fat32/fat32.c
===================================================================
--- soft/giet_vm/giet_fat32/fat32.c	(revision 773)
+++ soft/giet_vm/giet_fat32/fat32.c	(revision 783)
@@ -116,4 +116,6 @@
                                                char*             string );
 
+static unsigned int _set_fs_info();
+
 static unsigned int _update_fs_info();
 
@@ -154,8 +156,8 @@
                                       fat_inode_t* parent );
 
-static unsigned int _clusters_release( fat_inode_t* inode );
-
-static unsigned int _cluster_allocate( fat_inode_t*   inode, 
-                                       unsigned int*  cluster );
+static unsigned int _one_cluster_allocate( fat_inode_t*   inode, 
+                                           unsigned int*  cluster );
+
+static unsigned int _all_clusters_release( fat_inode_t* inode );
 
 static void _release_cache_memory( fat_cache_node_t*  root,
@@ -176,5 +178,5 @@
                                   unsigned int    cluster );
 
-static unsigned int _allocate_one_cluster( unsigned int*  cluster );
+static unsigned int _get_free_cluster( unsigned int*  cluster );
 
 static unsigned int _remove_node_from_fs( fat_inode_t* inode );
@@ -224,5 +226,5 @@
             _fat.data_sectors,
             _fat.free_clusters_number,
-            _fat.first_free_cluster,
+            _fat.free_cluster_hint,
             _fat.fat_cache_levels );
 
@@ -563,50 +565,4 @@
 
 
-/////////////////////////////////////
-static unsigned int _update_fs_info()
-{
-    // update buffer if miss
-    if ( _fat.fs_info_lba != _fat.block_buffer_lba )
-    {
-        if ( _fat_ioc_access( 1,                 // descheduling
-                              1,                 // read
-                              _fat.fs_info_lba, 
-                              (unsigned int)_fat.block_buffer, 
-                              1 ) )              // one block
-        {
-            _printf("\n[FAT_ERROR] _update_fs_info(): cannot read block\n");
-            return 1;
-        }
-        _fat.block_buffer_lba = _fat.fs_info_lba;
-    }
-
-    // update FAT buffer
-    unsigned int* ptr;
-    ptr  = (unsigned int*)(_fat.block_buffer + get_offset(FS_FREE_CLUSTERS) );
-    *ptr = _fat.free_clusters_number;
-
-    ptr  = (unsigned int*)(_fat.block_buffer + get_offset(FS_FREE_CLUSTER_HINT) );
-    *ptr = _fat.first_free_cluster;
-   
-    // write bloc to FAT
-    if ( _fat_ioc_access( 1,                // descheduling
-                          0,                // write
-                          _fat.fs_info_lba,
-                          (unsigned int)_fat.block_buffer, 
-                          1 ) )             // one block
-    {
-        _printf("\n[FAT_ERROR] _update_fs_info(): cannot write block\n");
-        return 1;
-    }
-
-#if GIET_DEBUG_FAT
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _update_fs_info(): nb_free = %x / first_free = %x\n",
-        _fat.free_clusters_number , _fat.first_free_cluster );
-#endif
-
-    return 0;
-}  // end _update_fs_info()
-
 
 /////////////////////////////////////////////////////////////////
@@ -739,52 +695,30 @@
 
 ///////////////////////////////////////////////////////////////////
-static unsigned int _allocate_one_cluster( unsigned int*  cluster )  
-{
-    unsigned int nb_free = _fat.free_clusters_number;
-    unsigned int free    = _fat.first_free_cluster;
-
+static unsigned int _get_free_cluster( unsigned int*  cluster )  
+{
     // scan FAT to get next free cluster index
-    unsigned int current = free;
-    unsigned int found   = 0;
+    unsigned int current = _fat.free_cluster_hint;
     unsigned int max     = (_fat.data_sectors >> 3);
     unsigned int value;
-    do
-    {
+    while ( current < max )
+    {
+        // get FAT entry indexed by current
+        if ( _get_fat_entry( current , &value ) ) return 1;
+
+        // return if free
+        if ( value == FREE_CLUSTER )
+        {
+            *cluster = current;
+            return 0;
+        }
+
         // increment current
         current++;
-
-        // get FAT entry indexed by current
-        if ( _get_fat_entry( current , &value ) ) return 1;
-
-        // test if free
-        if ( value == FREE_CLUSTER ) found = 1;
-    }
-    while ( (current < max) && (found == 0) );
+    }
         
-    // check found  
-    if ( found == 0 )
-    {
-        _printf("\n[FAT_ERROR] _allocate_one_cluster(): unconsistent FAT state");
-        return 1;
-    }
-
-    // update allocated FAT slot
-    if ( _set_fat_entry( free , END_OF_CHAIN_CLUSTER_MAX ) ) return 1;
-
-    // update FAT descriptor global variables
-    _fat.free_clusters_number = nb_free - 1;
-    _fat.first_free_cluster   = current;
-
-#if GIET_DEBUG_FAT
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _allocate_one_cluster(): allocated cluster = %x / first_free = %x\n",
-        free , current );
-#endif
-
-    // returns free cluster index
-    *cluster = free;
-    return 0;
-
-}  // end _allocate_one_cluster()
+    // return error if not found  
+    return 1;
+
+}  // end _get_free_cluster()
 
 
@@ -896,17 +830,16 @@
 
 
-////////////////////////////////////////////////////////////
-static unsigned int _cluster_allocate( fat_inode_t*   inode,
-                                       unsigned int*  cluster ) 
+////////////////////////////////////////////////////////////////
+static unsigned int _one_cluster_allocate( fat_inode_t*   inode,
+                                           unsigned int*  cluster ) 
 {
     // Check free cluster available
     if ( _fat.free_clusters_number == 0 )
     {
-        _printf("\n[FAT ERROR] in _cluster_allocate(): no more free clusters\n");
+        _printf("\n[FAT ERROR] in _one_cluster_allocate(): no more free clusters\n");
         return 1;
     }
 
-    // compute number of already allocated clusters 
-    // and last allocated cluster index
+    // scan the Fat-Cache to get last allocated cluster index
     unsigned int nb_current_clusters = 0;
     unsigned int current = inode->cluster;
@@ -914,9 +847,12 @@
     unsigned int next    = 0;
     unsigned int new     = 0;
-
     while ( current < END_OF_CHAIN_CLUSTER_MIN )
     {
         // get next cluster
-        if ( _get_fat_entry( current , &next ) )  return 1;
+        if ( _get_fat_entry( current , &next ) )
+        {
+            _printf("\n[FAT ERROR] in _one_cluster_allocate() scanning FAT\n");
+            return 1;
+        }
         
         // increment number of allocated clusters
@@ -929,5 +865,9 @@
 
     // allocate one free cluster from FAT
-    if ( _allocate_one_cluster( &new ) ) return 1;
+    if ( _get_free_cluster( &new ) ) 
+    {
+        _printf("\n[FAT ERROR] in _one_cluster_allocate() : no more free clusters\n");
+        return 1;
+    }
 
     // allocate one 4K buffer to File-Cache
@@ -936,4 +876,15 @@
                           new );
 
+    // update allocated FAT slot
+    if ( _set_fat_entry( new , END_OF_CHAIN_CLUSTER_MAX ) ) 
+    {
+        _printf("\n[FAT ERROR] in _one_cluster_allocate() accessing FAT\n");
+        return 1;
+    }
+
+    // update FAT descriptor global variables
+    _fat.free_clusters_number--;
+    _fat.free_cluster_hint = new;
+
     if ( nb_current_clusters == 0 )  // first cluster : inode and directory entry
     {
@@ -946,5 +897,9 @@
     else                             // update previous last cluster in FAT
     {
-        if ( _set_fat_entry( last , new ) ) return 1;
+        if ( _set_fat_entry( last , new ) ) 
+        {
+            _printf("\n[FAT ERROR] in _one_cluster_allocate() accessing FAT\n");
+            return 1;
+        }
     }
 
@@ -952,12 +907,20 @@
     if ( _update_device_from_cache( _fat.fat_cache_levels,
                                     _fat.fat_cache_root,
-                                    "FAT" ) )              return 1;
+                                    "FAT" ) ) 
+    {
+        _printf("\n[FAT ERROR] in _one_cluster_allocate() updating FAT on device\n");
+        return 1;
+    }
 
     // update FS-INFO sector on device
-    if ( _update_fs_info() )  return 1;
-
-#if GIET_DEBUG_FAT
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _cluster_allocate(): for <%s>\n"
+    if ( _update_fs_info() )
+    {
+        _printf("\n[FAT ERROR] in _one_cluster_allocate() updating FS-INFO sector on device\n");
+        return 1;
+    }
+
+#if GIET_DEBUG_FAT
+if ( _get_proctime() > GIET_DEBUG_FAT )
+_printf("\n[DEBUG FAT] _one_cluster_allocate(): for <%s>\n"
         " nb_clusters = %d / last_cluster = %x / new_cluster = %x\n",
         inode->name , nb_current_clusters , last , new );
@@ -966,48 +929,79 @@
     // returns allocated cluster index 
     *cluster = new;
-
     return 0;
-}  // end _cluster_allocate()
-
-
-
-///////////////////////////////////////////////////////////
-static unsigned int _clusters_release( fat_inode_t* inode )
-{
-    // scan the FAT
-    unsigned int current = inode->cluster;
-    unsigned int next;
-    do
-    { 
-        // get next_cluster index
-        if ( _get_fat_entry( current , &next ) )  return 1;
-
-        // release current_cluster
-        if ( _set_fat_entry( current , FREE_CLUSTER ) )   return 1;
-
-        // update first_free_cluster and free_clusters_number in FAT descriptor
-        _fat.free_clusters_number = _fat.free_clusters_number + 1;
-        if ( _fat.first_free_cluster > current ) _fat.first_free_cluster = current;
-
-        // update loop variable
-        current = next;
-    }
-    while ( next < END_OF_CHAIN_CLUSTER_MIN );
-
-    // update the FAT on block device
+
+}  // end _one_cluster_allocate()
+
+////////////////////////////////////////////////////////////
+static unsigned int _cluster_release( unsigned int cluster )
+{
+    if ( cluster >= END_OF_CHAIN_CLUSTER_MIN )  // terminal case : nothing to do
+    {
+        return 0;        
+    }
+    else                 // non terminal case : recursive call, then release cluster
+    {
+        // get next cluster
+        unsigned int next;
+        if ( _get_fat_entry( cluster , &next ) ) 
+        {
+            _printf("\n[FAT ERROR] in _cluster_release() accessing Fat-Cache"
+                    " for cluster %x\n", cluster );
+            return 1;
+        }
+
+        // call _cluster_release() on next
+        if ( _cluster_release( next ) ) return 1;
+        
+        // release current cluster
+        if ( _set_fat_entry( cluster , FREE_CLUSTER ) )
+        {
+            _printf("\n[FAT ERROR] in _cluster_release() updating Fat-Cache"
+                    " for cluster %x\n", cluster );
+            return 1;
+        }
+
+        // update free_cluster _hint and free_clusters_number in FAT descriptor
+        _fat.free_clusters_number++;
+        if ( cluster < _fat.free_cluster_hint ) _fat.free_cluster_hint = cluster;
+
+        return 0;
+    }
+}  // end _cluster_release()
+
+///////////////////////////////////////////////////////////////
+static unsigned int _all_clusters_release( fat_inode_t* inode )
+{
+    // release recursively all clusters in FAT chaining,
+    // starting from last cluster in chain, ending by first. 
+    if ( _cluster_release( inode->cluster ) )
+    {
+        _printf("\n[FAT ERROR] in _all_clusters_release() releasing clusters\n");
+        return 1;
+    }
+
+    // update FAT on device
     if ( _update_device_from_cache( _fat.fat_cache_levels,
                                     _fat.fat_cache_root,
-                                    "FAT" ) )                return 1;
+                                    "FAT" ) )
+    {
+        _printf("\n[FAT ERROR] in _all_clusters_release() updating FAT on device\n");
+        return 1;
+    }
 
     // update FS-INFO sector on device
-    if ( _update_fs_info() )  return 1;
-
-#if GIET_DEBUG_FAT
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _clusters_release(): for file <%s>\n", inode->name );
+    if ( _update_fs_info() )
+    {
+        _printf("\n[FAT ERROR] in _all_clusters_release() updating FS_INFO sector on device\n");
+        return 1;
+    }
+
+#if GIET_DEBUG_FAT
+if ( _get_proctime() > GIET_DEBUG_FAT )
+_printf("\n[DEBUG FAT] _all_clusters_release() done for file <%s>\n", inode->name );
 #endif
 
     return 0;
-}  // end _clusters_release()
+}  // end _all_clusters_release()
 
 
@@ -1931,5 +1925,5 @@
 
     // release clusters allocated to file/dir in DATA region
-    if ( _clusters_release( inode ) ) return 1;
+    if ( _all_clusters_release( inode ) ) return 1;
 
     // release File-Cache
@@ -2166,10 +2160,4 @@
 unsigned int _set_fs_info()
 {
-
-#if GIET_DEBUG_FAT
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _set_fs_info(): enters at cycle %d\n", _get_proctime() );
-#endif
-
     // load FS_INFO sector into FAT buffer
     if ( _fat_ioc_access( 0,                                // no descheduling 
@@ -2182,17 +2170,8 @@
         return 1;
     }
-
     _fat.block_buffer_lba = _fat.fs_info_lba;
 
-#if GIET_DEBUG_FAT
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _set_fs_info(): FS-INFO sector loaded\n");
-#endif
-
     // get general info from FAT descriptor
-    unsigned int  fat_blocks   = _fat.fat_sectors;
     unsigned int  data_blocks  = _fat.data_sectors;
-    unsigned int  lba          = _fat.fat_lba; 
-    unsigned int* buf          = (unsigned int*)_fat.block_buffer;
 
     // initialise <free_clusters_number> from FS-INFO sector
@@ -2208,5 +2187,5 @@
     _fat.free_clusters_number  = free_clusters;
 
-    // scan FAT on device from FS-FREE_CLUSTER_HINT to initialise <first_free_cluster> 
+    // initialise <free_cluster_hint> from FS_INFO sector 
     unsigned int free_cluster_hint = _read_entry( FS_FREE_CLUSTER_HINT, _fat.block_buffer, 1);     
     if ( free_cluster_hint > (data_blocks>>3) )
@@ -2218,60 +2197,66 @@
     }
 
-    unsigned int block_id    = free_cluster_hint>>7;
-    unsigned int first_entry = free_cluster_hint & 0x7F;
-    unsigned int  search     = 1;
-    unsigned int  first_free = 0;
-
-    // loop on the FAT blocks from free_cluster_hint 
-    // until free cluster found or end of FAT region
-    while ( search && (block_id < fat_blocks) )
-    {
-        // read one FAT block from device
-        if ( _fat_ioc_access( 0,                   // no_irq
-                              1,                   // to_mem,
-                              lba + block_id,      // lba
-                              (unsigned int)buf,   // FAT local buffer
-                              1 ) )                // one block
-        {
-            _printf("\n[FAT_ERROR] _set_fs_info() : cannot read FAT block %d\n", block_id);
+    _fat.free_cluster_hint  = free_cluster_hint;
+
+#if GIET_DEBUG_FAT
+if ( _get_proctime() > GIET_DEBUG_FAT )
+_printf("\n[DEBUG FAT] _set_fs_info() : free_clusters = %x / free_cluster_hint = %x\n",
+        free_clusters , free_cluster_hint );
+#endif
+
+    return 0;
+    
+}  // end _set_fs_info()
+
+
+
+
+/////////////////////////////////////
+static unsigned int _update_fs_info()
+{
+    // load buffer if miss
+    if ( _fat.fs_info_lba != _fat.block_buffer_lba )
+    {
+        if ( _fat_ioc_access( 1,                 // descheduling
+                              1,                 // read
+                              _fat.fs_info_lba, 
+                              (unsigned int)_fat.block_buffer, 
+                              1 ) )              // one block
+        {
+            _printf("\n[FAT_ERROR] _update_fs_info(): cannot read block\n");
             return 1;
         }
-
-        _fat.block_buffer_lba = lba + block_id;
-
-        // scan the entries in block from first_entry to 128
-        unsigned int entry;
-        for ( entry = first_entry ; entry < 128 ; entry++ )
-        {
-            if ( buf[entry] == FREE_CLUSTER )
-            {
-                first_free = (block_id<<7) + entry;
-                search = 0;
-                break;
-            }
-        }  // end loop on entries
-
-        block_id++;
-        first_entry = 0;
-    }  // end loop on blocks
-
-    if ( search )               // no free cluster  
-    {
-        _printf("\n[FAT_ERROR] _set_fs_info() : No free cluster found in FAT\n");
+        _fat.block_buffer_lba = _fat.fs_info_lba;
+    }
+
+    // update buffer
+    unsigned int* ptr;
+
+    ptr  = (unsigned int*)(_fat.block_buffer + get_offset(FS_FREE_CLUSTERS) );
+    *ptr = _fat.free_clusters_number;
+
+    ptr  = (unsigned int*)(_fat.block_buffer + get_offset(FS_FREE_CLUSTER_HINT) );
+    *ptr = _fat.free_cluster_hint;
+   
+    // write bloc to FAT
+    if ( _fat_ioc_access( 1,                // descheduling
+                          0,                // write
+                          _fat.fs_info_lba,
+                          (unsigned int)_fat.block_buffer, 
+                          1 ) )             // one block
+    {
+        _printf("\n[FAT_ERROR] _update_fs_info(): cannot write block\n");
         return 1;
     }
-    else          // update fat descriptor
-    {
-        _fat.first_free_cluster = first_free;
-
-#if GIET_DEBUG_FAT
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _set_fs_info() completes : free_clusters = %x / first_free = %x\n",
-        free_clusters , first_free );
-#endif
-
-        return 0;
-    }
-}  // end _set_fs_info()
+
+#if GIET_DEBUG_FAT
+if ( _get_proctime() > GIET_DEBUG_FAT )
+_printf("\n[DEBUG FAT] _update_fs_info() : free_clusters = %x / free_cluster_hint = %x\n",
+        _fat.free_clusters_number , _fat.free_cluster_hint );
+#endif
+
+    return 0;
+}  // end _update_fs_info()
+
 
 
@@ -2658,5 +2643,5 @@
 
         // release clusters allocated to file/dir in DATA region
-        if ( _clusters_release( child ) )
+        if ( _all_clusters_release( child ) )
         {
             _spin_lock_release( &_fat.fat_lock );
@@ -3117,5 +3102,5 @@
             for ( cid = 0 ; cid < (new_clusters - old_clusters) ; cid++ )
             {
-                if ( _cluster_allocate( inode , &index ) )
+                if ( _one_cluster_allocate( inode , &index ) )
                 {
                     _spin_lock_release( &_fat.fat_lock );
@@ -3809,20 +3794,8 @@
         _get_last_name( pathname , name );
 
-        // allocate one cluster from FAT for the new directory
-        unsigned int cluster;
-        if ( _allocate_one_cluster( &cluster ) )
-        {
-            _spin_lock_release( &_fat.fat_lock );
-            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
-
-            _printf("\n[FAT ERROR] _fat_mkdir(): no free cluster"
-                    " for directory <%s>\n" , pathname );
-            return GIET_FAT32_NO_FREE_SPACE;
-        }
-
         // allocate a new inode and an empty Cache-File 
         child = _allocate_one_inode( name,
                                      1,           // it's a directory
-                                     cluster,  
+                                     0xFFFFFFFF,  // cluster index not defined yet
                                      0,           // size = 0 for a directory
                                      0,           // count
@@ -3833,4 +3806,19 @@
         _add_inode_in_tree( child , parent );
  
+        // allocate cluster from FAT
+        unsigned int cluster;
+        if ( _one_cluster_allocate( inode , &cluster ) )
+        {
+            _spin_lock_release( &_fat.fat_lock );
+            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
+
+            _printf("\n[FAT ERROR] _fat_mkdir(): no free cluster"
+                    " for directory <%s>\n" , pathname );
+            return GIET_FAT32_NO_FREE_SPACE;
+        }
+
+        // update cluster index in inode
+        child->cluster = cluster;
+
         // allocate and initialise one 4 Kbytes buffer and associated descriptor
         _allocate_one_buffer( child,
@@ -4283,5 +4271,5 @@
             unsigned int        cid;
             unsigned int        lba;
-            unsigned int        cluster_allocated;
+            unsigned int        one_cluster_allocated;
 
             // File-Cache miss handling:
@@ -4302,9 +4290,9 @@
         (unsigned int)inode->cache->children[cluster_id] );
 #endif
-                // compute cluster_allocated condition, depending on file / dir type
-                if ( is_dir )  cluster_allocated = ( cluster_id < is_dir );
-                else           cluster_allocated = ( (cluster_id<<12) < size );
-
-                if ( cluster_allocated )  // cluster already allocated => allocate buffer
+                // compute one_cluster_allocated condition, depending on file / dir type
+                if ( is_dir )  one_cluster_allocated = ( cluster_id < is_dir );
+                else           one_cluster_allocated = ( (cluster_id<<12) < size );
+
+                if ( one_cluster_allocated )  // cluster already allocated => allocate buffer
                 {
                     // scan the FAT to find the cluster index for cluster_id
@@ -4363,5 +4351,5 @@
                         {
                             // allocate one cluster on device
-                            if ( _cluster_allocate( inode , &current ) )
+                            if ( _one_cluster_allocate( inode , &current ) )
                             {
                                 _printf("\n[FAT ERROR] in _get_file_cache_buffer() : "
