Index: trunk/kernel/vfs/vfs.c
===================================================================
--- trunk/kernel/vfs/vfs.c	(revision 222)
+++ trunk/kernel/vfs/vfs.c	(revision 238)
@@ -248,4 +248,40 @@
 }  // end vfs_inode_destroy()
 
+/////////////////////////////////////////////
+error_t vfs_inode_load( vfs_inode_t * parent,
+                        char        * name,
+                        xptr_t        child_xp )
+{
+    error_t error = 0;
+
+    assert( (parent != NULL) , __FUNCTION__ , "parent pointer is NULL\n");
+
+    assert( (child_xp != XPTR_NULL) , __FUNCTION__ , "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 , __FUNCTION__ , "should not be called for RAMFS\n" );
+    }
+    else if( fs_type == FS_TYPE_DEVFS )
+    {
+        assert( false , __FUNCTION__ , "should not be called for DEVFS\n" );
+    }
+    else
+    {
+        assert( false , __FUNCTION__ , "undefined file system type\n" );
+    }
+
+    return error;
+
+} // end vfs_load_inode()
+
 ////////////////////////////////////////////
 void vfs_inode_remote_up( xptr_t  inode_xp )
@@ -594,4 +630,7 @@
 
     if( error ) return error;
+
+    vfs_dmsg("\n[INFO] %s exit for %s / file_id = %d / file_xp = %l / at cycle %d\n",
+             __FUNCTION__ , path , file_id , file_xp , hal_get_cycles() );
 
     // success
@@ -1161,5 +1200,5 @@
     cxy_t              child_cxy;    // cluster for child inode
     vfs_inode_t      * child_ptr;    // local pointer on child inode  
-    vfs_inode_type_t   inode_type;   // child inode type
+    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
@@ -1206,5 +1245,13 @@
                                &child_xp );
 
-        if( found == false ) // child inode not found in inode tree => try to load it
+        // if a child inode is not found in the inode tree:
+        // - we create the missing inode/dentry couple in the inode tree,
+        // - we scan the parent mapper to complete the child inode (type and extension),
+        // - we return an error if child not found on device.
+        // - if the missing child is a directory, we load the child mapper from device
+
+        // for the last name, the behaviour depends on the "mode" argument:
+
+        if (found == false ) // directory node not found in inode tree 
         {
             vfs_dmsg("\n[INFO] %s : <%s> not found, try to load it\n",
@@ -1214,32 +1261,47 @@
             vfs_inode_unlock( parent_xp );
 
-            // get cluster and local pointer on parent inode
+            // get parent inode FS type
             parent_cxy = GET_CXY( parent_xp );
             parent_ptr = (vfs_inode_t *)GET_PTR( parent_xp );
 
-            // get local pointer on parent inode context
-            ctx_ptr = (vfs_ctx_t *)hal_remote_lpt( XPTR( parent_cxy , &parent_ptr->ctx ) );
-
-            // get parent inode FS type
-            fs_type = hal_remote_lw( XPTR( parent_cxy , &ctx_ptr->type ) );
-
-            // get child inode type
-            if( (last == false) || (mode & VFS_LOOKUP_DIR) ) inode_type = INODE_TYPE_DIR;
-            else                                             inode_type = INODE_TYPE_FILE;
-
-            // select a cluster for child inode
-            cxy_t child_cxy = vfs_cluster_random_select();
+            ctx_ptr    = (vfs_ctx_t *)hal_remote_lpt( XPTR( parent_cxy ,
+                                                            &parent_ptr->ctx ) );
+            fs_type    = hal_remote_lw( XPTR( parent_cxy , &ctx_ptr->type ) );
+
+            // select a cluster for missing inode
+            child_cxy = vfs_cluster_random_select();
                      
-printk("\n@@@ name not found : <%s>\n", name );
-
             // insert a new child dentry/inode in parent inode
             error = vfs_add_child_in_parent( child_cxy,
-                                             inode_type,
+                                             INODE_TYPE_DIR,
                                              fs_type, 
                                              parent_xp, 
                                              name, 
-                                             NULL,           // fs_type_specific inode extend
+                                             NULL,     // fs_type_specific inode extend
                                              &child_xp );
             if( error )
+            {
+                printk("\n[ERROR] in %s : no memory for inode %s in path %s\n",
+                       __FUNCTION__ , name , pathname );
+                return ENOMEM;
+            }
+
+            // scan parent mapper to complete the missing inode
+            if( parent_cxy == local_cxy )
+            {
+                error = vfs_inode_load( parent_ptr,
+                                        name,
+                                        child_xp );
+            }
+            else
+            {
+                rpc_vfs_inode_load_client( parent_cxy,
+                                           parent_ptr,
+                                           name,
+                                           child_xp,
+                                           &error );
+            }
+
+            if ( error )
             {
                 printk("\n[ERROR] in %s : node %s not found in path %s\n",
@@ -1248,14 +1310,38 @@
             }
 
+            // get child inode type
+            child_ptr  = (vfs_inode_t *)GET_PTR( child_xp );
+            child_type = hal_remote_lw( XPTR( child_cxy , &child_ptr->type ) );
+
+            // load child mapper from device if it is a directory
+            if( child_type == INODE_TYPE_DIR )
+            {
+                if( child_cxy == local_cxy )
+                {
+                    error = vfs_mapper_load_all( child_ptr );
+                }
+                else
+                {
+                    rpc_vfs_mapper_load_all_client( child_cxy,
+                                                    child_ptr,
+                                                    &error );
+                }
+
+                if ( error )
+                {
+                    printk("\n[ERROR] in %s : cannot access device for node %s in path %s\n",
+                           __FUNCTION__ , name , pathname );
+                    return EIO;
+                }
+            }
+
+            // TODO handle lookup mode here [AG]
+
             // take lock on parent inode
             vfs_inode_lock( parent_xp );
         }
 
-vfs_inode_display( child_xp );
-
-vfs_display( parent_xp );
-
         vfs_dmsg("\n[INFO] %s : found <%s> / parent = %l / child = %l / last = %d\n",
-                 __FUNCTION__ , name , parent_xp , child_xp , last );
+                     __FUNCTION__ , name , parent_xp , child_xp , last );
 
         // TODO check access rights
@@ -1269,10 +1355,6 @@
         // }
 
-        // TODO TODO TODO access device and load inode mapper if required...
-
-        // take lock on child inode if not last
-        if( last == false ) vfs_inode_lock( child_xp );
-
-        // release lock on parent inode
+        // take lock on child inode and release lock on parent
+        vfs_inode_lock( child_xp );
         vfs_inode_unlock( parent_xp );
 
@@ -1280,19 +1362,14 @@
         parent_xp = child_xp;
         current   = next;
-
-        vfs_dmsg("\n[INFO] %s : complete node <%s> / last = %d\n",
-                 __FUNCTION__ , name , last );
-
     }
     while( last == false );
 
-    vfs_dmsg("\n[INFO] in %s : searched inode found for %s\n",
-                 __FUNCTION__ , pathname );
-
-    // get cluster and local pointer on child inode
-    child_cxy = GET_CXY( child_xp );
-    child_ptr = (vfs_inode_t *)GET_PTR( child_xp );
-
-    // return searched pointers
+    // release lock 
+    vfs_inode_unlock( parent_xp );
+
+    vfs_dmsg("\n[INFO] in %s : exit / %s found / inode = %l\n",
+                 __FUNCTION__ , pathname , child_xp );
+
+    // return searched pointer
     *inode_xp = child_xp;
 
@@ -1385,5 +1462,4 @@
     cxy_t           parent_cxy;  // parent inode cluster identifier
     vfs_inode_t   * parent_ptr;  // parent inode local pointer
-    vfs_ctx_t     * parent_ctx;  // parent inode context local pointer
 
     // get parent inode cluster and local pointer
@@ -1471,13 +1547,11 @@
 }  // end vfs_add_child_in_parent()
 
-
-
-
 //////////////////////////////////////////////////////////////////////////////////////////
 //            Mapper related functions
 //////////////////////////////////////////////////////////////////////////////////////////
 
-////////////////////////////////////////////////
-error_t vfs_move_page_to_mapper( page_t * page )
+////////////////////////////////////////////
+error_t vfs_mapper_move_page( page_t * page,
+                              bool_t   to_mapper )
 {
     error_t error = 0;
@@ -1492,13 +1566,9 @@
     vfs_fs_type_t fs_type = mapper->inode->ctx->type;
 
-    // update mapper if permitted by file system type
+    // call relevant FS function
     if( fs_type == FS_TYPE_FATFS )
     {
-        // get mapper lock in WRITE_MODE
         rwlock_wr_lock( &mapper->lock );
-
-        error = fatfs_read_page( page ); 
-
-        // release mapper lock 
+        error = fatfs_move_page( page , to_mapper ); 
         rwlock_wr_unlock( &mapper->lock );
     }
@@ -1518,53 +1588,36 @@
     return error;
 
-}  // end vfs_move_page_to_mapper()
+}  // end vfs_move_page()
 
 //////////////////////////////////////////////////
-error_t vfs_move_page_from_mapper( page_t * page )
-{
-    error_t         error = 0;
-
-    assert( (page != NULL) , __FUNCTION__ , "page pointer is NULL\n" );
-
-    mapper_t * mapper = page->mapper;
+error_t vfs_mapper_load_all( vfs_inode_t * inode )
+{
+    assert( (inode != NULL) , __FUNCTION__ , "page pointer is NULL\n" );
+
+    uint32_t   index;
+    page_t   * page;
+
+    mapper_t * mapper = inode->mapper;
+    uint32_t   size   = inode->size;
 
     assert( (mapper != NULL) , __FUNCTION__ , "no mapper for page\n" );
 
-    // get FS type
-    vfs_fs_type_t  fs_type = mapper->inode->ctx->type;
-
-    // update file system if permitted by file system type
-    if( fs_type == FS_TYPE_FATFS )
-    {
-	    if( page_is_flag( page , PG_DIRTY ) ) 
-	    {
-            // get mapper lock in READ_MODE
-            rwlock_rd_lock( &mapper->lock );
-
-            error = fatfs_write_page( page );
-
-            // release mapper lock from READ_MODE
-            rwlock_rd_unlock( &mapper->lock );
-
-            // clear dirty bit if success
-		    if( error == 0 ) page_undo_dirty( page );
-         }
-    }
-    else if( fs_type == FS_TYPE_RAMFS )
-    {
-        assert( false , __FUNCTION__ , "should not be called for RAMFS\n" );
-    }
-    else if( fs_type == FS_TYPE_DEVFS )
-    {
-        assert( false , __FUNCTION__ , "should not be called for DEVFS\n" );
-    }
-    else
-    {
-        assert( false , __FUNCTION__ , "undefined file system type\n" );
-    }
-	
-    return error;
-
-}  // end vfs_move_page_from_mapper()
-
-
+    assert( (size != 0) , __FUNCTION__ , "size cannot be 0\n");
+
+    uint32_t npages = size >> CONFIG_PPM_PAGE_SHIFT;
+    if( size & CONFIG_PPM_PAGE_MASK ) npages++;
+
+    // loop on all 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;
+    }
+
+    return 0;
+
+}  // end vfs_mapper_load_all()
+
