Index: trunk/kernel/fs/vfs.c
===================================================================
--- trunk/kernel/fs/vfs.c	(revision 598)
+++ trunk/kernel/fs/vfs.c	(revision 602)
@@ -57,6 +57,6 @@
 extern char *             lock_type_str[];            // allocated in kernel_init.c
   
-//////////////////////////////////////////////////////////////////////////////////////////
-//           Context related functions
+///////////////////////////////////////////////////////////////////////////////////////////
+//           VFS Context related functions
 //////////////////////////////////////////////////////////////////////////////////////////
 
@@ -123,5 +123,5 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
-//           Inode related functions
+//           VFS inode descriptor related functions
 //////////////////////////////////////////////////////////////////////////////////////////
 
@@ -145,5 +145,4 @@
                           vfs_fs_type_t     fs_type,
                           vfs_inode_type_t  inode_type,
-                          void            * extend,
                           uint32_t          attr,
                           uint32_t          rights,
@@ -228,5 +227,5 @@
     inode->ctx        = ctx;
     inode->mapper     = mapper;
-    inode->extend     = extend;
+    inode->extend     = NULL;
 
     // initialise inode field in mapper
@@ -258,8 +257,10 @@
 }  // end vfs_inode_create()  
 
-////////////////////////////////////////////////
-error_t vfs_inode_destroy( vfs_inode_t * inode )
-{
-    assert( (inode->refcount == 0) , "inode refcount non zero\n" );
+/////////////////////////////////////////////
+void vfs_inode_destroy( vfs_inode_t * inode )
+{
+
+// check inode refcount
+assert( (inode->refcount == 0) , "inode refcount non zero\n" );
 
     // release memory allocated for mapper
@@ -272,58 +273,5 @@
 	kmem_free( &req );
 
-    return 0;
-
 }  // end vfs_inode_destroy()
-
-/////////////////////////////////////////////
-error_t vfs_inode_load( vfs_inode_t * parent,
-                        char        * name,
-                        xptr_t        child_xp )
-{
-
-#if DEBUG_VFS_INODE_LOAD
-uint32_t cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VFS_INODE_LOAD < cycle )
-printk("\n[%s] thread %x enter for <%s> / cycle %d\n",
-__FUNCTION__, CURRENT_THREAD , name , cycle );
-#endif
-
-    error_t error = 0;
-
-    assert( (parent != NULL) , "parent pointer is NULL\n");
-
-    assert( (child_xp != XPTR_NULL) , "child pointer is NULL\n");
-
-    // get parent inode FS type
-    vfs_fs_type_t fs_type = parent->ctx->type;
-
-    // call relevant FS function
-    if( fs_type == FS_TYPE_FATFS )
-    {
-        error = fatfs_inode_load( parent , name , child_xp );
-    }
-    else if( fs_type == FS_TYPE_RAMFS )
-    {
-        assert( false , "should not be called for RAMFS\n" );
-    }
-    else if( fs_type == FS_TYPE_DEVFS )
-    {
-        assert( false , "should not be called for DEVFS\n" );
-    }
-    else
-    {
-        assert( false , "undefined file system type\n" );
-    }
-
-#if DEBUG_VFS_INODE_LOAD
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VFS_INODE_LOAD < cycle )
-printk("\n[%s] thread %x exit for <%s> / cycle %d\n",
-__FUNCTION__, CURRENT_THREAD , name , cycle );
-#endif
-
-    return error;
-
-} // end vfs_inode_load()
 
 ////////////////////////////////////////////
@@ -429,6 +377,55 @@
 }  // end vfs_inode_get_name()
 
+///////////////////////////////////////////////////////
+error_t vfs_inode_load_all_pages( vfs_inode_t * inode )
+{
+
+assert( (inode != NULL) , "inode pointer is NULL\n" );
+
+    uint32_t   page_id;
+    xptr_t     page_xp;
+
+    mapper_t * mapper = inode->mapper;
+    uint32_t   size   = inode->size;
+
+assert( (mapper != NULL) , "mapper pointer is NULL\n" );
+
+#if DEBUG_VFS_INODE_LOAD_ALL
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+thread_t * this  = CURRENT_THREAD;
+char       name[CONFIG_VFS_MAX_NAME_LENGTH];
+vfs_inode_get_name( XPTR( local_cxy , inode ) , name );
+if( DEBUG_VFS_INODE_LOAD_ALL < cycle )
+printk("\n[%s] thread[%x,%x] enter for <%s> in cluster %x / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, name, local_cxy, cycle );
+#endif
+
+    // compute number of pages
+    uint32_t npages = size >> CONFIG_PPM_PAGE_SHIFT;
+    if( (size & CONFIG_PPM_PAGE_MASK) || (size == 0) ) npages++;
+
+    // loop on pages 
+    for( page_id = 0 ; page_id < npages ; page_id ++ )
+    {
+        // If the mage is missing, this function allocates the missing page,
+        // and load the page from IOC device into mapper
+        page_xp = mapper_remote_get_page( XPTR( local_cxy , mapper ), page_id );
+
+        if( page_xp == XPTR_NULL ) return -1;
+    }
+
+#if DEBUG_VFS_INODE_LOAD_ALL
+cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_VFS_INODE_LOAD_ALL < cycle )
+printk("\n[%s] thread[%x,%x] exit for <%x> in cluster %x / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, name, local_cxy, cycle );
+#endif
+
+    return 0;
+
+}  // end vfs_inode_load_all_pages()
+
 ////////////////////////////////////////////////////////////////////////////////////////////
-//           Dentry related functions
+//          VFS dentry descriptor related functions
 //////////////////////////////////////////////////////////////////////////////////////////
 
@@ -480,4 +477,5 @@
     dentry->length  = length;
     dentry->parent  = parent;
+    dentry->extend  = NULL;
     strcpy( dentry->name , name );
 
@@ -509,6 +507,6 @@
 cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_VFS_DENTRY_CREATE < cycle )
-printk("\n[%s] thread[%x,%x] exit for <%s> / dentry %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, name, dentry, cycle );
+printk("\n[%s] thread[%x,%x] exit for <%s> / dentry [%x,%x] / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, name, local_cxy, dentry, cycle );
 #endif
 
@@ -517,10 +515,10 @@
 }  // end vfs_dentry_create()
 
-///////////////////////////////////////////////////
-error_t vfs_dentry_destroy( vfs_dentry_t * dentry )
-{
-    error_t error;
-
-    assert( (dentry->refcount == 0) , __FUNCTION__ , "dentry refcount non zero\n" );
+////////////////////////////////////////////////
+void vfs_dentry_destroy( vfs_dentry_t * dentry )
+{
+
+// check dentry refcount
+assert( (dentry->refcount == 0) , "dentry refcount non zero\n" );
 
     // get pointer on parent inode
@@ -528,9 +526,7 @@
 
     // remove this dentry from parent inode htab
-    error = xhtab_remove( XPTR( local_cxy , &parent->children ),
-                          dentry->name,
-                          XPTR( local_cxy , &dentry->list ) ); 
-
-    if( error ) return EINVAL;     
+    xhtab_remove( XPTR( local_cxy , &parent->children ),
+                  dentry->name,
+                  XPTR( local_cxy , &dentry->list ) ); 
 
     // release memory allocated to dentry
@@ -540,11 +536,30 @@
 	kmem_free( &req );
 
-    return 0;
+}  // end vfs_dentry_destroy()
+
+//////////////////////////////////////////////
+void vfs_dentry_remote_up( xptr_t  dentry_xp )
+{
+    // get dentry cluster and local pointer
+    cxy_t          dentry_cxy = GET_CXY( dentry_xp );
+    vfs_dentry_t * dentry_ptr = GET_PTR( dentry_xp );
+
+    hal_remote_atomic_add( XPTR( dentry_cxy , &dentry_ptr->refcount ) , 1 );    
 }
 
+////////////////////////////////////////////////
+void vfs_dentry_remote_down( xptr_t  dentry_xp )
+{
+    // get dentry cluster and local pointer
+    cxy_t          dentry_cxy = GET_CXY( dentry_xp );
+    vfs_dentry_t * dentry_ptr = GET_PTR( dentry_xp );
+
+    hal_remote_atomic_add( XPTR( dentry_cxy , &dentry_ptr->refcount ) , -1 );    
+}
+
 
 
 //////////////////////////////////////////////////////////////////////////////////////////
-//           File descriptor related functions
+//       VFS file descriptor related functions
 //////////////////////////////////////////////////////////////////////////////////////////
 
@@ -645,5 +660,5 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
-//           File access related functions
+//           "syscalls" API related functions
 //////////////////////////////////////////////////////////////////////////////////////////
 
@@ -665,6 +680,10 @@
     uint32_t      file_id;      // created file descriptor index in reference fd_array
 
-    assert( (mode == 0), __FUNCTION__,
-    "the mode parameter is not supported yet\n" );
+
+    if( mode != 0 )
+    {
+        printk("\n[ERROR] in %s : the mode parameter is not supported yet\n" );
+        return -1;
+    }
 
 #if DEBUG_VFS_OPEN
@@ -736,6 +755,4 @@
                    uint32_t size )
 {
-    assert( ( file_xp != XPTR_NULL ) , "file_xp == XPTR_NULL" );
-
     cxy_t              file_cxy;     // remote file descriptor cluster 
     vfs_file_t       * file_ptr;     // remote file descriptor local pointer
@@ -745,4 +762,7 @@
     error_t            error;
 
+// check argument
+assert( (file_xp != XPTR_NULL), "file_xp == XPTR_NULL\n" );
+
     // get cluster and local pointer on remote file descriptor
     file_cxy  = GET_CXY( file_xp );
@@ -752,6 +772,6 @@
     inode_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type   ) );
    
-    assert( (inode_type == INODE_TYPE_FILE) ,
-    "inode type is not INODE_TYPE_FILE" );
+// check inode type
+assert( (inode_type == INODE_TYPE_FILE), "inode type is not INODE_TYPE_FILE" );
 
     // get mapper pointer and file offset from file descriptor
@@ -770,16 +790,22 @@
     else
     {
-        rpc_mapper_move_buffer_client( file_cxy,
-                                       mapper,
-                                       to_buffer,
-                                       true,          // user buffer
-                                       file_offset,
-                                       (uint64_t)(intptr_t)buffer,
-                                       size,
-                                       &error );
+        rpc_mapper_move_user_client( file_cxy,
+                                     mapper,
+                                     to_buffer,
+                                     file_offset,
+                                     buffer,
+                                     size,
+                                     &error );
     } 
 
-    if( error ) return -1;
-    else        return size;
+    // update file offset in file descriptor
+    hal_remote_atomic_add( XPTR( file_cxy , &file_ptr->offset ) , size );
+
+    if( error ) 
+    {
+        return -1;
+    }
+
+    return size;
 
 }  // end vfs_user_move()
@@ -791,12 +817,14 @@
                          uint32_t size )
 {
-    assert( ( file_xp != XPTR_NULL ) , "file_xp == XPTR_NULL" );
-
     cxy_t              file_cxy;     // remote file descriptor cluster 
     vfs_file_t       * file_ptr;     // remote file descriptor local pointer
-    vfs_inode_type_t   inode_type;
+    vfs_inode_type_t   inode_type;   // remote file type
     uint32_t           file_offset;  // current offset in file
-    mapper_t         * mapper;
+    mapper_t         * mapper_ptr;   // remote mapper local pointer
+    xptr_t             mapper_xp;    // remote mapper extended pointer
     error_t            error;
+
+// check argument
+assert( (file_xp != XPTR_NULL) , "file_xp == XPTR_NULL\n" );
 
     // get cluster and local pointer on remote file descriptor
@@ -810,31 +838,16 @@
     if( inode_type == INODE_TYPE_FILE )
     {
-        // get mapper pointer and file offset from file descriptor
+        // get mapper pointers and file offset from file descriptor
         file_offset = hal_remote_l32( XPTR( file_cxy , &file_ptr->offset ) );
-        mapper = (mapper_t *)hal_remote_lpt( XPTR( file_cxy , &file_ptr->mapper ) );
+        mapper_ptr  = hal_remote_lpt( XPTR( file_cxy , &file_ptr->mapper ) );
+        mapper_xp   = XPTR( file_cxy , mapper_ptr );
 
         // move data between mapper and buffer
-        if( file_cxy == local_cxy )
-        {
-            error = mapper_move_kernel( mapper,
-                                        to_buffer,
-                                        file_offset,
-                                        buffer_xp,
-                                        size );
-        }
-        else
-        {
-            rpc_mapper_move_buffer_client( file_cxy,
-                                           mapper,
-                                           to_buffer,
-                                           false,          // kernel buffer
-                                           file_offset,
-                                           buffer_xp,
-                                           size,
-                                           &error );
-        } 
-
+        error = mapper_move_kernel( mapper_xp,
+                                    to_buffer,
+                                    file_offset,
+                                    buffer_xp,
+                                    size );
         if( error ) return -1;
-        else        return 0;
     }
     else 
@@ -843,4 +856,7 @@
         return -1;
     }
+
+    return 0;
+
 }  // end vfs_kernel_move()
 
@@ -853,4 +869,5 @@
     xptr_t         offset_xp;
     xptr_t         lock_xp;
+    xptr_t         size_xp;
     cxy_t          file_cxy;
     vfs_file_t  *  file_ptr;
@@ -858,5 +875,6 @@
     uint32_t       new;
 
-    assert( (file_xp != XPTR_NULL) , "file_xp == XPTR_NULL" );
+// check argument
+assert( (file_xp != XPTR_NULL) , "file_xp == XPTR_NULL\n" );
 
     // get cluster and local pointer on remote file descriptor
@@ -864,7 +882,11 @@
     file_ptr = GET_PTR( file_xp );
 
-    // build extended pointers on lock and offset
+    // get local pointer on remote inode
+    inode_ptr = (vfs_inode_t *)hal_remote_lpt( XPTR( file_cxy , &file_ptr->inode ) );
+
+    // build extended pointers on lock, offset and size
     offset_xp = XPTR( file_cxy , &file_ptr->offset );
     lock_xp   = XPTR( file_cxy , &file_ptr->lock );
+    size_xp   = XPTR( file_cxy , &inode_ptr->size );
 
     // take file descriptor lock
@@ -881,8 +903,5 @@
     else if ( whence == SEEK_END )   // new = size + offset
     { 
-        // get local pointer on remote inode
-        inode_ptr = (vfs_inode_t *)hal_remote_lpt( XPTR( file_cxy , &file_ptr->inode ) );
-
-        new = hal_remote_l32( XPTR( file_cxy , &inode_ptr->size ) ) + offset;
+        new = hal_remote_l32( size_xp ) + offset;
     }
     else
@@ -893,4 +912,14 @@
     }
 
+#if DEBUG_VFS_LSEEK
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+thread_t * this  = CURRENT_THREAD;
+char       name[CONFIG_VFS_MAX_NAME_LENGTH];
+vfs_inode_get_name( XPTR( file_cxy , inode_ptr ) , name );
+if( cycle > DEBUG_VFS_LSEEK )
+printk("\n[%s] thread[%x,%x] for <%s> / new offset %d / cycle %d\n",
+__FUNCTION__ , this->process->pid, this->trdid, name, new, cycle );
+#endif
+
     // set new offset
     hal_remote_s32( offset_xp , new );
@@ -900,6 +929,5 @@
 
     // success
-    if ( new_offset != NULL )
-        *new_offset = new;
+    if ( new_offset != NULL ) *new_offset = new;
     return 0;
 
@@ -922,7 +950,7 @@
     process_t  * process_ptr;      // process copy local pointer
 
-    assert( (file_xp != XPTR_NULL) , "file_xp == XPTR_NULL" );
-
-    assert( (file_id < CONFIG_PROCESS_FILE_MAX_NR) , "illegal file_id" );
+// check arguments
+assert( (file_xp != XPTR_NULL) , "file_xp == XPTR_NULL\n" );
+assert( (file_id < CONFIG_PROCESS_FILE_MAX_NR) , "illegal file_id\n" );
 
     thread_t  * this    = CURRENT_THREAD;
@@ -1019,8 +1047,117 @@
                     char   * path )
 {
-    assert( false , "not implemented cwd_xp %x, path <%s> \n",
-      cwd_xp, path );   
-    return 0;
-} 
+    error_t           error;
+    xptr_t            inode_xp;           // extended pointer on target inode
+    cxy_t             inode_cxy;          // target inode cluster identifier       
+    vfs_inode_t     * inode_ptr;          // target inode local pointer
+    uint32_t          inode_refcount;     // target inode refcount
+    vfs_inode_type_t  type;               // target inode type
+    mapper_t        * mapper;             // pointer on target inode mapper
+    xptr_t            dentry_xp;          // extended pointer on target dentry
+    cxy_t             dentry_cxy;         // target dentry cluster identifier
+    vfs_dentry_t    * dentry_ptr;         // target dentry local pointer
+    uint32_t          dentry_refcount;    // target dentry refcount
+    vfs_inode_t     * dentry_parent_ptr;  // parent inode local pointer
+
+#if DEBUG_VFS_UNLINK
+thread_t * this  = CURRENT_THREAD;
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_VFS_UNLINK < cycle )
+printk("\n[%s] thread[%x,%x] enter for <%s> / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, path, cycle );
+#endif
+
+    // get extended pointer on target inode
+    error = vfs_lookup( cwd_xp , path , 0 , &inode_xp );
+
+    if( error ) return error;
+
+    // get inode cluster and local pointer
+    inode_cxy = GET_CXY( inode_xp );
+    inode_ptr = GET_PTR( inode_xp );
+
+    // get inode type, refcount, mapper, dentry_xp
+    type              = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->type ) );
+    inode_refcount    = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->refcount ) );
+    mapper            = hal_remote_lpt( XPTR( inode_cxy , &inode_ptr->mapper ) );
+    dentry_xp         = hal_remote_l64( XPTR( inode_cxy , &inode_ptr->parent_xp ) );
+
+    // get dentry cluster, local pointer, refcount, and pointers on parent inode
+    dentry_ptr        = GET_PTR( dentry_xp );
+    dentry_cxy        = GET_CXY( dentry_xp );
+    dentry_refcount   = hal_remote_l32( XPTR( dentry_cxy , &dentry_ptr->refcount ) );
+    dentry_parent_ptr = hal_remote_lpt( XPTR( dentry_cxy , &dentry_ptr->parent ) );
+
+// check inode & dentry refcount
+assert( (inode_refcount  == 1), "illegal inode refcount for <%s>\n", path );
+assert( (dentry_refcount == 1), "illegal dentry refcount for <%s>\n", path );
+
+    /////////////////////////////
+    if( type == INODE_TYPE_FILE )
+    {
+        // 1. release clusters allocated to file in the FAT mapper
+        //    synchronize the FAT on IOC device 
+        error = vfs_fs_release_inode( inode_xp ); 
+        if( error )
+        {
+            printk("\n[ERROR] in %s : cannot update FAT mapper <%s>\n", path );
+            return -1;
+        }
+
+#if(DEBUG_VFS_UNLINK & 1)
+if( DEBUG_VFS_UNLINK < cycle )
+printk("\n[%s] thread[%x,%x] removed <%s> inode from FAT (mapper and IOC device)\n",
+__FUNCTION__, this->process->pid, this->trdid, path );
+#endif
+
+        // 2. update parent directory in Inode Tree
+        //    synchronize the parent directory on IOC device
+        if (dentry_cxy == local_cxy)                           // dentry is local
+        {
+            error = vfs_fs_remove_dentry( dentry_parent_ptr,
+                                          dentry_ptr );
+        }
+        else                                                  // dentry is remote
+        {
+            rpc_vfs_fs_remove_dentry_client( dentry_cxy,
+                                             dentry_parent_ptr,
+                                             dentry_ptr,
+                                             &error );
+        }
+        if( error )
+        {
+            printk("\n[ERROR] in %s : cannot update dentry on device for <%s>\n", path );
+            return -1;
+        }
+
+#if(DEBUG_VFS_UNLINK & 1)
+if( DEBUG_VFS_UNLINK < cycle )
+printk("\n[%s] thread[%x,%x] removed <%s> inode from parent dir (mapper and IOC device)\n",
+__FUNCTION__, this->process->pid, this->trdid, path );
+#endif
+        // 3. remove inode (including mapper & dentry) from Inode Tree
+        vfs_remove_child_from_parent( inode_xp );
+
+#if DEBUG_VFS_UNLINK
+if( DEBUG_VFS_UNLINK < cycle )
+printk("\n[%s] thread[%x,%x] exit / removed <%s> inode from Inode Tree / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, path, cycle );
+#endif
+        return 0;
+    }
+    /////////////////////////////////
+    else if( type == INODE_TYPE_DIR )
+    {
+        printk("\n[ERROR] in %s : unsupported type %s\n", vfs_inode_type_str( type ) );
+        return -1;
+    }
+    ////
+    else
+    {
+        printk("\n[ERROR] in %s : unsupported type %s\n", vfs_inode_type_str( type ) );
+        return -1;
+    }
+
+}  // end vfs_unlink() 
 
 //////////////////////////////////////
@@ -1058,5 +1195,6 @@
 
     return 0;
-}
+
+}  // end vfs_stat()
 
 /////////////////////////////////////////////
@@ -1172,5 +1310,5 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
-//            Inode Tree functions
+//       Distributed Inode Tree access related functions
 //////////////////////////////////////////////////////////////////////////////////////////
 
@@ -1336,6 +1474,7 @@
 }  // end vfs_display()
 
+/*
 //////////////////////////////////////////////////////////////////////////////////////////
-// This function is used by the vfs_lookup() function.
+// This static function is used by the vfs_lookup() function.
 // It takes an extended pointer on a remote inode (parent directory inode),
 // and check access_rights violation for the calling thread.
@@ -1347,5 +1486,5 @@
 // @ return true if access rights are violated.
 //////////////////////////////////////////////////////////////////////////////////////////
-bool_t vfs_access_denied( xptr_t   inode_xp,
+static bool_t vfs_access_denied( xptr_t   inode_xp,
                           uint32_t client_uid,
                           uint32_t client_gid )
@@ -1364,4 +1503,5 @@
     else                                             return true;
 }
+*/
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -1465,7 +1605,9 @@
     cxy_t              parent_cxy;   // cluster for parent inode
     vfs_inode_t      * parent_ptr;   // local pointer on parent inode  
+    xptr_t             dentry_xp;    // extended pointer on dentry       
     xptr_t             child_xp;     // extended pointer on child inode
     cxy_t              child_cxy;    // cluster for child inode
-    vfs_inode_t      * child_ptr;    // local pointer on child inode  
+    vfs_inode_t      * child_ptr;    // local pointer on child inode
+    vfs_inode_type_t   child_type;   // child inode type
     vfs_fs_type_t      fs_type;      // File system type
     vfs_ctx_t        * ctx_ptr;      // local pointer on FS context
@@ -1519,6 +1661,6 @@
 #if (DEBUG_VFS_LOOKUP & 1)
 if( DEBUG_VFS_LOOKUP < cycle )
-printk("\n[%s]  look for <%s> / last = %d\n",
-__FUNCTION__ , name , last );
+printk("\n[%s] thread[%x,%x] look for <%s> in <%s> / last = %d\n",
+__FUNCTION__, process->pid, this->trdid, name, pathname, last );
 #endif
 
@@ -1533,6 +1675,6 @@
 #if (DEBUG_VFS_LOOKUP & 1)
 if( DEBUG_VFS_LOOKUP < cycle )
-printk("\n[%s]  miss <%s> node => try to create it\n",
-__FUNCTION__ , name );
+printk("\n[%s] thread[%x,%x] miss <%s> node => try to create it\n",
+__FUNCTION__, process->pid, this->trdid, name );
 #endif
             // if a child node is not found in the inode tree,
@@ -1544,82 +1686,87 @@
             // . if it is not found in the parent mapper:
             //   - if ( not last or not create ) an error is reported
-            //   - if (last and create and dir) a new directory is created
-            //   - if (last and create and not dir) a new file is created
+            //   - if (last and create) a new file or directory is created
 
             // release lock on parent inode
             vfs_inode_unlock( parent_xp );
  
-            // get parent inode FS type
+            // get parent inode cluster and local pointer
             parent_cxy = GET_CXY( parent_xp );
             parent_ptr = GET_PTR( parent_xp );
-            ctx_ptr    = (vfs_ctx_t *)hal_remote_lpt( XPTR( parent_cxy,&parent_ptr->ctx ) );
+
+            // get parent inode FS type
+            ctx_ptr    = hal_remote_lpt( XPTR( parent_cxy,&parent_ptr->ctx ) );
             fs_type    = hal_remote_l32( XPTR( parent_cxy , &ctx_ptr->type ) );
 
             // select a cluster for missing inode
             child_cxy = cluster_random_select();
+
+            // define child inode type
+            if( dir ) child_type = INODE_TYPE_DIR;
+            else      child_type = INODE_TYPE_FILE;
  
             // insert a new child dentry/inode in inode tree
             error = vfs_add_child_in_parent( child_cxy,
-                                             0,           // type will be updated later
+                                             child_type, 
                                              fs_type, 
                                              parent_xp, 
                                              name, 
-                                             NULL,        // fs_type_specific inode extend
+                                             &dentry_xp,
                                              &child_xp );
             if( error )
             {
-                printk("\n[ERROR] in %s : cannot create node %s for path <%s>\n",
+                printk("\n[ERROR] in %s : cannot create node <%s> in path <%s>\n",
                 __FUNCTION__ , name, pathname );
-                return ENOMEM;
+                return -1;
             }
 
-            // get child inode cluster and local pointer
-            child_cxy = GET_CXY( child_xp );
+            // get child inode local pointer
             child_ptr = GET_PTR( child_xp );
 
 #if (DEBUG_VFS_LOOKUP & 1)
 if( DEBUG_VFS_LOOKUP < cycle )
-printk("\n[%s]  missing <%s> inode speculatively created / cxy %x / ptr %x\n",
-__FUNCTION__ , name , child_cxy, child_ptr );
-#endif
-             // scan parent mapper to complete the missing inode
+printk("\n[%s] thread[%x,%x] created missing inode <%s> in cluster %x\n",
+__FUNCTION__, process->pid, this->trdid, name, child_cxy );
+#endif
+            // scan parent mapper to find the missing dentry, and complete 
+            // the initialisation of dentry and child inode desciptors
             if( parent_cxy == local_cxy )
+
             {
-                error = vfs_inode_load( parent_ptr,
-                                        name,
-                                        child_xp );
+                error = vfs_fs_child_init( parent_ptr,
+                                           name,
+                                           child_xp );
             }
             else
             {
-                rpc_vfs_inode_load_client( parent_cxy,
-                                           parent_ptr,
-                                           name,
-                                           child_xp,
-                                           &error );
+                rpc_vfs_fs_child_init_client( parent_cxy,
+                                              parent_ptr,
+                                              name,
+                                              child_xp,
+                                              &error );
             }
 
             if ( error )   // child not found in parent mapper
             {
-                if( last && create && dir )  // new directory  => update inode type
+                if ( last && create )  // add a new dentry in parent
                 {
-                     hal_remote_s32( XPTR( child_cxy, &child_ptr->type ), INODE_TYPE_DIR );
+                    error = vfs_new_child_init( parent_xp,                
+                                                dentry_xp,
+                                                child_xp );
+                    if ( error )
+                    {
+                        printk("\n[ERROR] in %s : cannot init inode <%s> in path <%s>\n",
+                        __FUNCTION__, name, pathname );
+                        vfs_remove_child_from_parent( child_xp );
+                        return -1;
+                    }
 
 #if (DEBUG_VFS_LOOKUP & 1)
 if( DEBUG_VFS_LOOKUP < cycle )
-printk("\n[%s]  created node <%s> in path %s / type DIR\n",
-__FUNCTION__ , name, pathname );
+printk("\n[%s] thread[%x,%x] created inode <%s> in path\n",
+__FUNCTION__, process->pid, this->trdid, name );
 #endif
                 }
-                else if ( last && create )   // new file => update inode type
-                {
-                     hal_remote_s32( XPTR( child_cxy, &child_ptr->type ), INODE_TYPE_FILE );
-
-#if (DEBUG_VFS_LOOKUP & 1)
-if( DEBUG_VFS_LOOKUP < cycle )
-printk("\n[%s]  created node <%s> in path %s / type FILE\n",
-__FUNCTION__ , name, pathname );
-#endif
-                }
-                else                         // not last or not create => remove created node 
+                else                   // not last or not create => error
                 {                       
                      printk("\n[ERROR] in %s : <%s> node not found in parent for <%s>\n",
@@ -1629,5 +1776,5 @@
                 }
             }
-            else          // child found in parent
+            else          // child found in parent mapper
             {
                 // load child mapper from device if child is a directory (prefetch)
@@ -1636,11 +1783,11 @@
                     if( child_cxy == local_cxy )
                     {
-                        error = vfs_mapper_load_all( child_ptr );
+                        error = vfs_inode_load_all_pages( child_ptr );
                     }
                     else
                     {
-                        rpc_vfs_mapper_load_all_client( child_cxy,
-                                                        child_ptr,
-                                                        &error );
+                        rpc_vfs_inode_load_all_pages_client( child_cxy,
+                                                             child_ptr,
+                                                             &error );
                     }
                     if ( error )
@@ -1654,6 +1801,6 @@
 #if (DEBUG_VFS_LOOKUP & 1)
 if( DEBUG_VFS_LOOKUP < cycle )
-printk("\n[%s]  load mapper from device for node <%s> in path %s\n",
-__FUNCTION__ , name, pathname );
+printk("\n[%s] thread[%x,%x] loaded from IOC device mapper for <%s> in <%s>\n",
+__FUNCTION__ , process->pid, this->trdid, name, pathname );
 #endif
                 }
@@ -1668,6 +1815,6 @@
 #if (DEBUG_VFS_LOOKUP & 1)
 if( DEBUG_VFS_LOOKUP < cycle )
-printk("\n[%s]  found <%s> / inode %x in cluster %x\n",
-__FUNCTION__ , name , GET_PTR(child_xp) , GET_CXY(child_xp) );
+printk("\n[%s] thread[%x,%x] found <%s> / inode %x in cluster %x\n",
+__FUNCTION__, process->pid, this->trdid, name, GET_PTR(child_xp), GET_CXY(child_xp) );
 #endif
             child_ptr  = GET_PTR( child_xp );
@@ -1710,8 +1857,6 @@
 cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_VFS_LOOKUP < cycle )
-printk("\n[%s] thread[%x,%x] exit for <%s>\n" 
-"     parent %x in cluster %x / child %x in cluster %x / cycle %d\n",
-__FUNCTION__ , process->pid, this->trdid, pathname, 
-parent_ptr, parent_cxy, child_ptr, child_cxy, cycle );
+printk("\n[%s] thread[%x,%x] exit for <%s> cycle %d\n",
+__FUNCTION__ , process->pid, this->trdid, pathname, cycle );
 #endif
 
@@ -1723,4 +1868,97 @@
 
 }  // end vfs_lookup()
+
+
+
+///////////////////////////////////////////////
+error_t vfs_new_child_init( xptr_t   parent_xp,
+                            xptr_t   dentry_xp,
+                            xptr_t   child_xp )
+{
+    error_t     error;
+    uint32_t    cluster;
+    uint32_t    child_type;
+    uint32_t    child_size;
+
+#if DEBUG_VFS_NEW_CHILD_INIT
+char parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
+char child_name[CONFIG_VFS_MAX_NAME_LENGTH];
+vfs_inode_get_name( parent_xp , parent_name );
+vfs_inode_get_name( child_xp  , child_name );
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+thread_t * this  = CURRENT_THREAD;
+if( DEBUG_VFS_NEW_CHILD_INIT < cycle )
+printk("\n[%s] thread[%x,%x] enter / parent <%s> / child <%s> / cycle %d\n",
+__FUNCTION__ , this->process->pid, this->trdid, parent_name, child_name, cycle );
+#endif
+
+    // get parent inode cluster and local pointer
+    cxy_t          parent_cxy = GET_CXY( parent_xp );
+    vfs_inode_t  * parent_ptr = GET_PTR( parent_xp );
+
+    // get dentry local pointer
+    vfs_dentry_t * dentry_ptr = GET_PTR( dentry_xp );
+
+    // get child inode cluster and local pointer
+    cxy_t          child_cxy  = GET_CXY( child_xp );
+    vfs_inode_t  * child_ptr  = GET_PTR( child_xp );
+
+    // 1. allocate one free cluster to child inode
+    // depending on the child inode FS type
+    vfs_ctx_t * ctx = hal_remote_lpt( XPTR( child_cxy , &child_ptr->ctx ) );
+
+    error = vfs_fs_cluster_alloc( ctx->type,
+                                  &cluster );
+    if ( error )
+    {
+        printk("\n[ERROR] in %s : cannot find a free VFS cluster\n",
+        __FUNCTION__ );
+        return -1;
+    }
+
+#if( DEBUG_VFS_NEW_CHILD_INIT & 1)
+if( DEBUG_VFS_NEW_CHILD_INIT < cycle )
+printk("\n[%s] thread[%x,%x] allocated one FAT cluster to <%s>\n",
+__FUNCTION__ , this->process->pid, this->trdid, child_name );
+#endif
+
+    // 2. update the child inode descriptor
+    child_type = hal_remote_l32( XPTR( child_cxy , &child_ptr->type ) );
+    child_size = (child_type == INODE_TYPE_DIR) ? 4096 : 0;
+    
+    hal_remote_s32( XPTR( child_cxy , &child_ptr->size )   , child_size );
+    hal_remote_spt( XPTR( child_cxy , &child_ptr->extend ) , (void*)(intptr_t)cluster );
+
+    // 3. update the parent inode mapper, and 
+    // update the dentry extension if required
+    if( local_cxy == parent_cxy )
+    {
+        error = vfs_fs_add_dentry( parent_ptr,
+                                   dentry_ptr );
+    }
+    else
+    {
+        rpc_vfs_fs_add_dentry_client( parent_cxy,
+                                      parent_ptr,
+                                      dentry_ptr,
+                                      &error );
+    }
+    if ( error )
+    {
+        printk("\n[ERROR] in %s : cannot register child in parent directory\n",
+        __FUNCTION__ );
+        return -1;
+    }
+
+#if DEBUG_VFS_NEW_CHILD_INIT
+cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_VFS_NEW_CHILD_INIT < cycle )
+printk("\n[%s] thread[%x,%x] exit / parent <%s> / child <%> / cycle %d\n",
+__FUNCTION__ , this->process->pid, this->trdid, parent_name, child_name, cycle );
+#endif
+
+    return 0;
+
+}  // end vfs_new_child_init()
 
 ////////////////////////////////////////////
@@ -1794,47 +2032,50 @@
 
       
-//////////////////////////////////////////////////////////////
-error_t vfs_add_child_in_parent( cxy_t              child_cxy,
-                                 vfs_inode_type_t   inode_type,
+////////////////////////////////////////////////////////////////////
+error_t vfs_add_child_in_parent( cxy_t              child_inode_cxy,
+                                 vfs_inode_type_t   child_inode_type,
                                  vfs_fs_type_t      fs_type,
-                                 xptr_t             parent_xp,
+                                 xptr_t             parent_inode_xp,
                                  char             * name,
-                                 void             * extend,
-                                 xptr_t           * child_xp )
+                                 xptr_t           * dentry_xp,
+                                 xptr_t           * child_inode_xp )
 {
     error_t         error;
-    xptr_t          dentry_xp;   // extended pointer on created dentry
-    xptr_t          inode_xp;    // extended pointer on created inode
-    cxy_t           parent_cxy;  // parent inode cluster identifier
-    vfs_inode_t   * parent_ptr;  // parent inode local pointer
+    xptr_t          new_dentry_xp;       // extended pointer on created dentry
+    vfs_dentry_t  * new_dentry_ptr;      // created dentry local pointer
+    xptr_t          new_inode_xp;        // extended pointer on created child inode
+    cxy_t           parent_inode_cxy;    // parent inode cluster identifier
+    vfs_inode_t   * parent_inode_ptr;    // parent inode local pointer
 
     // get parent inode cluster and local pointer
-    parent_cxy = GET_CXY( parent_xp );
-    parent_ptr = GET_PTR( parent_xp );
+    parent_inode_cxy = GET_CXY( parent_inode_xp );
+    parent_inode_ptr = GET_PTR( parent_inode_xp );
 
 #if DEBUG_VFS_ADD_CHILD
+char parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
+vfs_inode_get_name( parent_inode_xp , parent_name );
 uint32_t cycle = (uint32_t)hal_get_cycles();
 thread_t * this = CURRENT_THREAD; 
 if( DEBUG_VFS_ADD_CHILD < cycle )
-printk("\n[%s] thread[%x,%x] enter for <%s> / child_cxy %x / parent_cxy %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, name,
-child_cxy, parent_cxy, (uint32_t)hal_get_cycles() );
+printk("\n[%s] thread[%x,%x] enter / child <%s> cxy %x / parent <%s> cxy %x / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, name, child_inode_cxy,
+parent_name, parent_inode_cxy, (uint32_t)hal_get_cycles() );
 #endif
 
     // 1. create dentry
-    if( parent_cxy == local_cxy )      // parent cluster is the local cluster
+    if( parent_inode_cxy == local_cxy )      // parent cluster is the local cluster
     {
         error = vfs_dentry_create( fs_type,
                                    name,
-                                   parent_ptr,
-                                   &dentry_xp );
+                                   parent_inode_ptr,
+                                   &new_dentry_xp );
     }
     else                               // parent cluster is remote
     {
-        rpc_vfs_dentry_create_client( parent_cxy,
+        rpc_vfs_dentry_create_client( parent_inode_cxy,
                                       fs_type,
                                       name,
-                                      parent_ptr,
-                                      &dentry_xp,
+                                      parent_inode_ptr,
+                                      &new_dentry_xp,
                                       &error );
     }
@@ -1843,12 +2084,15 @@
     {
         printk("\n[ERROR] in %s : cannot create dentry <%s> in cluster %x\n",
-        __FUNCTION__ , name , parent_cxy );
-        return ENOMEM;
-    }
+        __FUNCTION__ , name , parent_inode_cxy );
+        return -1;
+    }
+
+    // get dentry local pointer
+    new_dentry_ptr = GET_PTR( new_dentry_xp );
 
 #if(DEBUG_VFS_ADD_CHILD & 1)
 if( DEBUG_VFS_ADD_CHILD < cycle )
 printk("\n[%s] thread[%x,%x] / dentry <%s> created in cluster %x\n",
-__FUNCTION__, this->process->pid, this->trdid, name, parent_cxy );
+__FUNCTION__, this->process->pid, this->trdid, name, parent_inode_cxy );
 #endif
 
@@ -1859,28 +2103,26 @@
     uint32_t gid  = 0;
     
-    if( child_cxy == local_cxy )      // child cluster is the local cluster
-    {
-        error = vfs_inode_create( dentry_xp,
+    if( child_inode_cxy == local_cxy )      // child cluster is the local cluster
+    {
+        error = vfs_inode_create( new_dentry_xp,
                                   fs_type,
-                                  inode_type,
-                                  extend,
+                                  child_inode_type,
                                   attr,
                                   mode,
                                   uid,
                                   gid,
-                                  &inode_xp );
+                                  &new_inode_xp );
     }
     else                              // child cluster is remote
     {
-        rpc_vfs_inode_create_client( child_cxy,
-                                     dentry_xp,
+        rpc_vfs_inode_create_client( child_inode_cxy,
+                                     new_dentry_xp,
                                      fs_type,
-                                     inode_type,
-                                     extend,
+                                     child_inode_type,
                                      attr,
                                      mode,
                                      uid,
                                      gid,
-                                     &inode_xp,
+                                     &new_inode_xp,
                                      &error );
     }
@@ -1889,10 +2131,9 @@
     {
         printk("\n[ERROR] in %s : cannot create inode in cluster %x\n",
-               __FUNCTION__ , child_cxy );
+               __FUNCTION__ , child_inode_cxy );
  
-        vfs_dentry_t * dentry = GET_PTR( dentry_xp );
-        if( parent_cxy == local_cxy ) vfs_dentry_destroy( dentry );
-        else rpc_vfs_dentry_destroy_client( parent_cxy , dentry , &error );
-        return ENOMEM;
+        if( parent_inode_cxy == local_cxy ) vfs_dentry_destroy( new_dentry_ptr );
+        else rpc_vfs_dentry_destroy_client( parent_inode_cxy , new_dentry_ptr );
+        return -1;
     }
 
@@ -1900,11 +2141,11 @@
 if( DEBUG_VFS_ADD_CHILD < cycle )
 printk("\n[%s] thread[%x,%x] / inode <%s> created in cluster %x\n",
-__FUNCTION__ , this->process->pid, this->trdid, name , child_cxy );
-#endif
-
-    // 3. update extended pointer on inode in dentry
-    cxy_t          dentry_cxy = GET_CXY( dentry_xp );
-    vfs_dentry_t * dentry_ptr = GET_PTR( dentry_xp );
-    hal_remote_s64( XPTR( dentry_cxy , &dentry_ptr->child_xp ) , inode_xp );
+__FUNCTION__ , this->process->pid, this->trdid, name , child_inode_cxy );
+#endif
+
+    // 3. update "child_xp" field in dentry and increment refcounts
+    hal_remote_s64( XPTR( parent_inode_cxy , &new_dentry_ptr->child_xp ) , new_inode_xp );
+    vfs_inode_remote_up( new_inode_xp );
+    vfs_dentry_remote_up( new_dentry_xp );
 
 #if DEBUG_VFS_ADD_CHILD
@@ -1915,14 +2156,13 @@
 #endif
 
-    // success : return extended pointer on child inode
-    *child_xp = inode_xp;
+    // return extended pointer on dentry & child inode
+    *dentry_xp      = new_dentry_xp;
+    *child_inode_xp = new_inode_xp;
     return 0;
 
-    // FIXME update the refcount fields in both inode and dentry
-
 }  // end vfs_add_child_in_parent()
 
-///////////////////////////////////////////////////////
-error_t vfs_remove_child_from_parent( xptr_t inode_xp )
+////////////////////////////////////////////////////
+void vfs_remove_child_from_parent( xptr_t inode_xp )
 {
     cxy_t          inode_cxy;
@@ -1931,5 +2171,4 @@
     cxy_t          dentry_cxy;
     vfs_dentry_t * dentry_ptr;
-    error_t        error;
    
     // get inode cluster and local pointer
@@ -1937,23 +2176,31 @@
     inode_ptr = GET_PTR( inode_xp );
 
-    // get cluster and pointers of associated dentry
+    // get associated dentry cluster and pointers 
     dentry_xp  = hal_remote_l64( XPTR( inode_cxy , &inode_ptr->parent_xp ) );
     dentry_cxy = GET_CXY( dentry_xp ); 
     dentry_ptr = GET_PTR( dentry_xp );
 
-    // FIXME update the refcount fields in both inode and dentry
+// check dentry refcount
+assert( ( hal_remote_l32( XPTR( dentry_cxy , &dentry_ptr->refcount ) ) == 1 ),
+"dentry refcount must be 1\n" );
+
+// check inode refcount
+assert( ( hal_remote_l32( XPTR( inode_cxy , &inode_ptr->refcount ) ) == 1 ),
+"inode refcount must be 1\n" );
+
+    // decrement refcount for inode and dentry
+    vfs_inode_remote_down( inode_xp );
+    vfs_dentry_remote_down( dentry_xp );
 
     // delete dentry
     if( dentry_cxy == local_cxy )
     {
-         error = vfs_dentry_destroy( dentry_ptr );
+         vfs_dentry_destroy( dentry_ptr );
     }
     else
     {
          rpc_vfs_dentry_destroy_client( dentry_cxy,
-                                        dentry_ptr,
-                                        &error );
-    }
-    if( error ) return EINVAL;
+                                        dentry_ptr );
+    }
 
     // delete inode
@@ -1965,36 +2212,66 @@
     {
          rpc_vfs_inode_destroy_client( inode_cxy,
-                                       inode_ptr,
-                                       &error );
-    }
-    if( error ) return EINVAL;
-
-    return 0;
+                                       inode_ptr );
+    }
 
 }  // end vfs_remove_child_from_parent()
 
 //////////////////////////////////////////////////////////////////////////////////////////
-//            Mapper related functions
+//    API used by VFS to access a specific FS  
 //////////////////////////////////////////////////////////////////////////////////////////
 
-////////////////////////////////////////////
-error_t vfs_mapper_move_page( page_t * page,
-                              bool_t   to_mapper )
+///////////////////////////////////////////
+error_t vfs_fs_move_page( xptr_t   page_xp,
+                          bool_t   to_mapper )
 {
     error_t error = 0;
 
-    assert( (page != NULL) , "page pointer is NULL\n" );
-
-    mapper_t    * mapper = page->mapper;
-
-    assert( (mapper != NULL) , "no mapper for page\n" );
-
-#if DEBUG_VFS_MAPPER_MOVE
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-thread_t * this  = CURRENT_THREAD;
-if( DEBUG_VFS_MAPPER_MOVE < cycle )
-printk("\n[%s] thread[%x,%x] enter for page %d / mapper %x / inode %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, page->index, mapper, mapper->inode, cycle );
-#endif
+assert( (page_xp != XPTR_NULL) , "page pointer is NULL\n" );
+
+    page_t * page_ptr = GET_PTR( page_xp );
+    cxy_t    page_cxy = GET_CXY( page_xp );
+
+    // get local pointer on page mapper
+    mapper_t * mapper = hal_remote_lpt( XPTR( page_cxy , &page_ptr->mapper ) );
+
+assert( (mapper != NULL) , "no mapper for page\n" );
+
+    // get FS type
+    vfs_fs_type_t fs_type = hal_remote_l32( XPTR( page_cxy , &mapper->type ) );
+
+    // call relevant FS function
+    if( fs_type == FS_TYPE_FATFS )
+    {
+        error = fatfs_move_page( page_xp , to_mapper ); 
+    }
+    else if( fs_type == FS_TYPE_RAMFS )
+    {
+        assert( false , "should not be called for RAMFS\n" );
+    }
+    else if( fs_type == FS_TYPE_DEVFS )
+    {
+        assert( false , "should not be called for DEVFS\n" );
+    }
+    else
+    {
+        assert( false , "undefined file system type\n" );
+    }
+
+    return error;
+
+}  // end vfs_fs_move_page()
+
+////////////////////////////////////////////////
+error_t vfs_fs_add_dentry( vfs_inode_t  * inode,
+                           vfs_dentry_t * dentry )
+{
+    error_t error = 0;
+
+assert( (inode  != NULL) , "inode  pointer is NULL\n" );
+assert( (dentry != NULL) , "dentry pointer is NULL\n" );
+
+    mapper_t * mapper = inode->mapper;
+
+assert( (mapper != NULL) , "mapper pointer is NULL\n" );
 
     // get FS type
@@ -2004,12 +2281,5 @@
     if( fs_type == FS_TYPE_FATFS )
     {
-        // enter mapper in write mode
-        rwlock_wr_acquire( &mapper->lock );
-
-        // move page to mapper
-        error = fatfs_mapper_move_page( page , to_mapper ); 
-
-        // exit mapper in write mode
-        rwlock_wr_release( &mapper->lock );
+        error = fatfs_add_dentry( inode , dentry ); 
     }
     else if( fs_type == FS_TYPE_RAMFS )
@@ -2026,59 +2296,149 @@
     }
 
-#if DEBUG_VFS_MAPPER_MOVE
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VFS_MAPPER_MOVE < cycle )
-printk("\n[%s] thread[%x,%x] exit for page %d / mapper %x / inode %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, page->index, mapper, mapper->inode, cycle );
-#endif
-
     return error;
 
-}  // end vfs_move_page()
-
-//////////////////////////////////////////////////
-error_t vfs_mapper_load_all( vfs_inode_t * inode )
-{
-    assert( (inode != NULL) , "inode pointer is NULL\n" );
-
-    uint32_t   index;
-    page_t   * page;
+}  // end vfs_fs_add_dentry()
+
+///////////////////////////////////////////////////
+error_t vfs_fs_remove_dentry( vfs_inode_t  * inode,
+                              vfs_dentry_t * dentry )
+{
+    error_t error = 0;
+
+assert( (inode  != NULL) , "inode  pointer is NULL\n" );
+assert( (dentry != NULL) , "dentry pointer is NULL\n" );
 
     mapper_t * mapper = inode->mapper;
-    uint32_t   size   = inode->size;
 
 assert( (mapper != NULL) , "mapper pointer is NULL\n" );
 
-#if DEBUG_VFS_MAPPER_LOAD
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-thread_t * this  = CURRENT_THREAD;
-if( DEBUG_VFS_MAPPER_MOVE < cycle )
-printk("\n[%s] thread[%x,%x] enter for inode %x in cluster %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, inode, local_cxy, cycle );
-#endif
-
-    // compute number of pages
-    uint32_t npages = size >> CONFIG_PPM_PAGE_SHIFT;
-    if( (size & CONFIG_PPM_PAGE_MASK) || (size == 0) ) npages++;
-
-    // loop on pages 
-    for( index = 0 ; index < npages ; index ++ )
-    {
-        // this function allocates the missing page in mapper,
-        // and call the vfs_mapper_move_page() to load the page from device
-        page = mapper_get_page( mapper , index );
-
-        if( page == NULL ) return EIO;
-    }
-
-#if DEBUG_VFS_MAPPER_LOAD
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VFS_MAPPER_MOVE < cycle )
-printk("\n[%s] thread[%x,%x] exit for inode %x in cluster %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, inode, local_cxy, cycle );
-#endif
-
-    return 0;
-
-}  // end vfs_mapper_load_all()
-
+    // get FS type
+    vfs_fs_type_t fs_type = mapper->type;
+
+    // call relevant FS function
+    if( fs_type == FS_TYPE_FATFS )
+    {
+        error = fatfs_remove_dentry( inode , dentry ); 
+    }
+    else if( fs_type == FS_TYPE_RAMFS )
+    {
+        assert( false , "should not be called for RAMFS\n" );
+    }
+    else if( fs_type == FS_TYPE_DEVFS )
+    {
+        assert( false , "should not be called for DEVFS\n" );
+    }
+    else
+    {
+        assert( false , "undefined file system type\n" );
+    }
+
+    return error;
+
+}  // end vfs_fs_remove_dentry()
+
+////////////////////////////////////////////////
+error_t vfs_fs_child_init( vfs_inode_t * parent,
+                           char        * name,
+                           xptr_t        child_xp )
+{
+    error_t error = 0;
+
+// check arguments
+assert( (parent != NULL) , "parent pointer is NULL\n");
+assert( (child_xp != XPTR_NULL) , "child pointer is NULL\n");
+
+    // get parent inode FS type
+    vfs_fs_type_t fs_type = parent->ctx->type;
+
+    // call relevant FS function
+    if( fs_type == FS_TYPE_FATFS )
+    {
+        error = fatfs_child_init( parent , name , child_xp );
+    }
+    else if( fs_type == FS_TYPE_RAMFS )
+    {
+        assert( false , "should not be called for RAMFS\n" );
+    }
+    else if( fs_type == FS_TYPE_DEVFS )
+    {
+        assert( false , "should not be called for DEVFS\n" );
+    }
+    else
+    {
+        assert( false , "undefined file system type\n" );
+    }
+
+    return error;
+
+} // end vfs_fs_child_init()
+
+/////////////////////////////////////////////////
+error_t vfs_fs_cluster_alloc( uint32_t   fs_type,
+                              uint32_t * cluster )
+{
+    error_t error = 0;
+
+    // call relevant FS function
+    if( fs_type == FS_TYPE_FATFS )
+    {
+        error = fatfs_cluster_alloc( cluster );
+    }
+    else if( fs_type == FS_TYPE_RAMFS )
+    {
+        assert( false , "should not be called for RAMFS\n" );
+    }
+    else if( fs_type == FS_TYPE_DEVFS )
+    {
+        assert( false , "should not be called for DEVFS\n" );
+    }
+    else
+    {
+        assert( false , "undefined file system type\n" );
+    }
+
+    return error;
+
+} // end vfs_fs_alloc_cluster()
+
+////////////////////////////////////////////////
+error_t vfs_fs_release_inode( xptr_t  inode_xp )
+{
+    error_t error = 0;
+
+assert( (inode_xp  != XPTR_NULL) , "inode pointer is NULL\n")        
+
+    vfs_inode_t * inode_ptr = GET_PTR( inode_xp );
+    cxy_t         inode_cxy = GET_CXY( inode_xp );
+
+    // get local pointer on page mapper 
+    mapper_t * mapper = hal_remote_lpt( XPTR( inode_cxy , &inode_ptr->mapper ) );
+
+assert( (mapper != NULL) , "mapper pointer is NULL\n")        
+
+    // get FS type from mapper
+    vfs_fs_type_t fs_type = hal_remote_l32( XPTR( inode_cxy , &mapper->type ) );
+
+    // call relevant FS function
+    if( fs_type == FS_TYPE_FATFS )
+    {
+        error = fatfs_release_inode( inode_xp ); 
+    }
+    else if( fs_type == FS_TYPE_RAMFS )
+    {
+        assert( false , "should not be called for RAMFS\n" );
+    }
+    else if( fs_type == FS_TYPE_DEVFS )
+    {
+        assert( false , "should not be called for DEVFS\n" );
+    }
+    else
+    {
+        assert( false , "undefined file system type\n" );
+    }
+
+    return error;
+    
+}  // end vfs_fs_release_inode()
+
+
