source: trunk/kernel/fs/vfs.c @ 612

Last change on this file since 612 was 612, checked in by alain, 6 years ago

Fix several bugs in vfs.c, fatfs.c, and devfs.c to support
the <.> and <..> directory entries.

File size: 124.5 KB
Line 
1/*
2 * vfs.c - Virtual File System implementation.
3 *
4 * Author  Mohamed Lamine Karaoui (2015)
5 *         Alain Greiner (2016,2017,2018)
6 *
7 * Copyright (c) UPMC Sorbonne Universites
8 *
9 * This file is part of ALMOS-MKH.
10 *
11 * ALMOS-MKH is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2.0 of the License.
14 *
15 * ALMOS-MKH is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25#include <kernel_config.h>
26#include <hal_kernel_types.h>
27#include <hal_atomic.h>
28#include <hal_special.h>
29#include <printk.h>
30#include <list.h>
31#include <xlist.h>
32#include <slist.h>
33#include <xhtab.h>
34#include <string.h>
35#include <rpc.h>
36#include <errno.h>
37#include <kmem.h>
38#include <mapper.h>
39#include <thread.h>
40#include <chdev.h>
41#include <process.h>
42#include <cluster.h>
43#include <vfs.h>
44#include <fatfs.h>
45#include <ramfs.h>
46#include <devfs.h>
47#include <syscalls.h>
48
49//////////////////////////////////////////////////////////////////////////////////////////
50//           Extern variables         
51//////////////////////////////////////////////////////////////////////////////////////////
52
53extern vfs_ctx_t          fs_context[FS_TYPES_NR];    // allocated in kernel_init.c
54extern chdev_directory_t  chdev_dir;                  // allocated in kernel_init.c 
55extern char *             lock_type_str[];            // allocated in kernel_init.c
56 
57///////////////////////////////////////////////////////////////////////////////////////////
58//           VFS Context related functions
59//////////////////////////////////////////////////////////////////////////////////////////
60
61////////////////////////////////////////
62void vfs_ctx_init( vfs_fs_type_t   type,
63                   uint32_t        attr,
64                       uint32_t        total_clusters,
65                       uint32_t        cluster_size,
66                       xptr_t          vfs_root_xp,
67                   void          * extend )
68{
69    vfs_ctx_t * vfs_ctx = &fs_context[type];
70
71    vfs_ctx->type           = type;
72    vfs_ctx->attr           = attr;
73    vfs_ctx->total_clusters = total_clusters;
74    vfs_ctx->cluster_size   = cluster_size;
75    vfs_ctx->vfs_root_xp    = vfs_root_xp;
76    vfs_ctx->extend         = extend;
77
78    busylock_init( &vfs_ctx->lock , LOCK_VFS_CTX );
79
80    bitmap_init( vfs_ctx->bitmap , BITMAP_SIZE(CONFIG_VFS_MAX_INODES) ); 
81}
82
83////////////////////////////////////////////
84error_t vfs_ctx_inum_alloc( vfs_ctx_t * ctx,
85                            uint32_t  * inum )
86{
87    // get lock on inum allocator
88    busylock_acquire( &ctx->lock );
89
90    // get lid from local inum allocator
91    uint32_t lid = bitmap_ffc( ctx->bitmap , CONFIG_VFS_MAX_INODES );
92
93    if( lid == 0xFFFFFFFF )   // no more free slot => error
94    {
95        // release lock
96        busylock_release( &ctx->lock );
97
98        // return error
99        return 1;
100    }
101    else              // found => return inum
102    {
103        // set slot allocated
104        bitmap_set( ctx->bitmap , lid );
105
106        // release lock
107        busylock_release( &ctx->lock );
108
109        // return inum
110        *inum = (((uint32_t)local_cxy) << 16) | (lid & 0xFFFF);
111        return 0;
112    }
113}
114
115////////////////////////////////////////////
116void vfs_ctx_inum_release( vfs_ctx_t * ctx,
117                           uint32_t    inum )
118{
119    bitmap_clear( ctx->bitmap , inum & 0xFFFF ); 
120}
121
122//////////////////////////////////////////////////////////////////////////////////////////
123//           VFS inode descriptor related functions
124//////////////////////////////////////////////////////////////////////////////////////////
125
126const char * vfs_inode_type_str( vfs_inode_type_t type )
127{
128    switch ( type ) 
129    {
130        case INODE_TYPE_FILE: return "FILE";
131        case INODE_TYPE_DIR:  return "DIR ";
132        case INODE_TYPE_FIFO: return "FIFO";
133        case INODE_TYPE_PIPE: return "PIPE";
134        case INODE_TYPE_SOCK: return "SOCK";
135        case INODE_TYPE_DEV:  return "DEV ";
136        case INODE_TYPE_BLK:  return "BLK ";
137        case INODE_TYPE_SYML: return "SYML";
138        default:              return "undefined";
139    }
140}
141
142////////////////////////////////////////////////////
143error_t vfs_inode_create( vfs_fs_type_t     fs_type,
144                          vfs_inode_type_t  inode_type,
145                          uint32_t          attr,
146                          uint32_t          rights,
147                          uid_t             uid,
148                          gid_t             gid,
149                          xptr_t          * inode_xp )
150{
151    mapper_t         * mapper;     // associated mapper( to be allocated)
152    vfs_inode_t      * inode;      // inode descriptor (to be allocated)
153    uint32_t           inum;       // inode identifier (to be allocated)
154    vfs_ctx_t        * ctx;        // file system context
155        kmem_req_t         req;        // request to kernel memory allocator
156    error_t            error;
157
158#if DEBUG_VFS_INODE_CREATE
159char           name[CONFIG_VFS_MAX_NAME_LENGTH];
160uint32_t       cycle      = (uint32_t)hal_get_cycles();
161cxy_t          dentry_cxy = GET_CXY( dentry_xp );
162vfs_dentry_t * dentry_ptr = GET_PTR( dentry_xp );
163thread_t *     this       = CURRENT_THREAD;
164if( dentry_xp != XPTR_NULL ) hal_remote_strcpy( XPTR( local_cxy  , name ), 
165                                                XPTR( dentry_cxy , dentry_ptr->name ) );
166else                         strcpy( name , "/" );
167if( DEBUG_VFS_INODE_CREATE < cycle )
168printk("\n[%s] thread[%x,%x] enter for <%s> / cycle %d\n",
169__FUNCTION__, this->process->pid, this->trdid, name, cycle );
170#endif
171 
172    // check fs type and get pointer on context
173    if     ( fs_type == FS_TYPE_FATFS ) ctx = &fs_context[FS_TYPE_FATFS];
174    else if( fs_type == FS_TYPE_RAMFS ) ctx = &fs_context[FS_TYPE_RAMFS];
175    else if( fs_type == FS_TYPE_DEVFS ) ctx = &fs_context[FS_TYPE_DEVFS];
176    else
177    {
178        ctx = NULL;
179                assert( false , "illegal file system type = %d\n" , fs_type );
180    }
181
182    // allocate inum
183    error = vfs_ctx_inum_alloc( ctx , &inum );
184
185    if( error )
186    {
187        printk("\n[ERROR] in %s : cannot allocate inum\n", __FUNCTION__ );
188        return ENOMEM;
189    }
190
191    // allocate memory for mapper
192    mapper = mapper_create( fs_type );
193
194    if( mapper == NULL )
195    {
196        printk("\n[ERROR] in %s : cannot allocate mapper\n", __FUNCTION__ );
197        vfs_ctx_inum_release( ctx , inum );
198        return ENOMEM;
199    }
200
201    // allocate memory for VFS inode descriptor
202        req.type  = KMEM_VFS_INODE;
203        req.size  = sizeof(vfs_inode_t);
204    req.flags = AF_KERNEL | AF_ZERO;
205        inode     = (vfs_inode_t *)kmem_alloc( &req );
206
207    if( inode == NULL )
208    {
209        printk("\n[ERROR] in %s : cannot allocate inode descriptor\n", __FUNCTION__ );
210        vfs_ctx_inum_release( ctx , inum );
211        mapper_destroy( mapper );
212        return -1;
213    }
214
215    // initialize inode descriptor
216    inode->type       = inode_type;
217    inode->inum       = inum;
218    inode->attr       = attr;
219    inode->rights     = rights;
220    inode->uid        = uid;
221    inode->gid        = gid;
222    inode->ctx        = ctx;
223    inode->mapper     = mapper;
224    inode->extend     = NULL;
225    inode->links      = 0;
226
227    // initialise inode field in mapper
228    mapper->inode     = inode;
229 
230    // initialise threads waiting queue
231    // xlist_root_init( XPTR( local_cxy , &inode->wait_root ) );
232
233    // initialize chidren dentries xhtab
234    xhtab_init( &inode->children , XHTAB_DENTRY_TYPE );
235
236    // initialize parents dentries xlist
237    xlist_root_init( XPTR( local_cxy , &inode->parents ) );
238 
239    // initialize lock protecting size
240    remote_rwlock_init( XPTR( local_cxy , &inode->size_lock ), LOCK_VFS_SIZE );
241
242    // initialise lock protecting inode tree traversal
243    remote_rwlock_init( XPTR( local_cxy , &inode->main_lock ), LOCK_VFS_MAIN );
244
245    // return extended pointer on inode
246    *inode_xp = XPTR( local_cxy , inode );
247
248#if DEBUG_VFS_INODE_CREATE
249cycle      = (uint32_t)hal_get_cycles();
250if( DEBUG_VFS_INODE_CREATE < cycle )
251printk("\n[%s] thread[%x,%x] exit for <%s> / inode [%x,%x] / cycle %d\n",
252__FUNCTION__, this->process->pid, this->trdid, name, local_cxy, inode, cycle );
253#endif
254 
255    return 0;
256
257}  // end vfs_inode_create() 
258
259/////////////////////////////////////////////
260void vfs_inode_destroy( vfs_inode_t * inode )
261{
262    // release memory allocated for mapper
263    mapper_destroy( inode->mapper );
264
265    // release memory allocate for inode descriptor
266        kmem_req_t req;
267        req.ptr   = inode;
268        req.type  = KMEM_VFS_INODE;
269        kmem_free( &req );
270
271}  // end vfs_inode_destroy()
272
273//////////////////////////////////////////////
274uint32_t vfs_inode_get_size( xptr_t inode_xp )
275{
276    // get inode cluster and local pointer
277    cxy_t         cxy = GET_CXY( inode_xp );
278    vfs_inode_t * ptr = GET_PTR( inode_xp );
279
280    // get size
281    remote_rwlock_rd_acquire( XPTR( cxy , &ptr->size_lock ) );
282    uint32_t size = hal_remote_l32( XPTR( cxy , &ptr->size ) );
283    remote_rwlock_rd_release( XPTR( cxy , &ptr->size_lock ) );
284    return size;
285}
286
287////////////////////////////////////////////
288void vfs_inode_set_size( xptr_t    inode_xp,
289                         uint32_t  size )
290{
291    // get inode cluster and local pointer
292    cxy_t         cxy = GET_CXY( inode_xp );
293    vfs_inode_t * ptr = GET_PTR( inode_xp );
294
295    // set size
296    remote_rwlock_wr_release( XPTR( cxy , &ptr->size_lock ) );
297    hal_remote_s32( XPTR( cxy , &ptr->size ) , size );
298    remote_rwlock_wr_release( XPTR( cxy , &ptr->size_lock ) );
299}
300
301////////////////////////////////////////
302void vfs_inode_unlock( xptr_t inode_xp )
303{
304    // get inode cluster and local pointer
305    cxy_t         cxy = GET_CXY( inode_xp );
306    vfs_inode_t * ptr = GET_PTR( inode_xp );
307
308    // release the main lock
309    remote_busylock_release( XPTR( cxy , &ptr->main_lock ) );
310}
311
312//////////////////////////////////////
313void vfs_inode_lock( xptr_t inode_xp )
314{
315    // get inode cluster and local pointer
316    cxy_t         cxy = GET_CXY( inode_xp );
317    vfs_inode_t * ptr = GET_PTR( inode_xp );
318
319    // get the main lock
320    remote_busylock_acquire( XPTR( cxy , &ptr->main_lock ) );
321}
322
323///////////////////////////////////////////
324void vfs_inode_get_name( xptr_t   inode_xp,
325                         char   * name )
326{
327    cxy_t          inode_cxy;          // inode cluster identifier
328    vfs_inode_t  * inode_ptr;          // local pointer on inode
329    xptr_t         parents_root_xp;    // extended pointer on inode parents root
330   
331    // get inode cluster and local pointer
332    inode_cxy = GET_CXY( inode_xp );
333    inode_ptr = GET_PTR( inode_xp );
334
335    // build extended pointer on parents dentries root
336    parents_root_xp  = XPTR( inode_cxy , &inode_ptr->parents );
337
338    // check VFS root
339    if( xlist_is_empty( parents_root_xp ) )  // inode is the VFS root
340    {
341        strcpy( name , "/" );
342    }
343    else                                     // not the VFS root
344    {
345        xptr_t         dentry_xp;
346        cxy_t          dentry_cxy;
347        vfs_dentry_t * dentry_ptr;
348
349        // get first name in list of parents
350        dentry_xp  = XLIST_FIRST( parents_root_xp , vfs_dentry_t , parents );
351        dentry_cxy = GET_CXY( dentry_xp );
352        dentry_ptr = GET_PTR( dentry_xp );
353
354        hal_remote_strcpy( XPTR( local_cxy  , name ) , 
355                           XPTR( dentry_cxy , dentry_ptr->name ) );
356    }
357
358}  // end vfs_inode_get_name()
359
360///////////////////////////////////////////////////////
361error_t vfs_inode_load_all_pages( vfs_inode_t * inode )
362{
363
364assert( (inode != NULL) , "inode pointer is NULL\n" );
365
366    uint32_t   page_id;
367    xptr_t     page_xp;
368
369    mapper_t * mapper = inode->mapper;
370    uint32_t   size   = inode->size;
371
372assert( (mapper != NULL) , "mapper pointer is NULL\n" );
373
374#if DEBUG_VFS_INODE_LOAD_ALL
375uint32_t   cycle = (uint32_t)hal_get_cycles();
376thread_t * this  = CURRENT_THREAD;
377char       name[CONFIG_VFS_MAX_NAME_LENGTH];
378vfs_inode_get_name( XPTR( local_cxy , inode ) , name );
379if( DEBUG_VFS_INODE_LOAD_ALL < cycle )
380printk("\n[%s] thread[%x,%x] enter for <%s> in cluster %x / cycle %d\n",
381__FUNCTION__, this->process->pid, this->trdid, name, local_cxy, cycle );
382#endif
383
384    // compute number of pages
385    uint32_t npages = size >> CONFIG_PPM_PAGE_SHIFT;
386    if( (size & CONFIG_PPM_PAGE_MASK) || (size == 0) ) npages++;
387
388    // loop on pages
389    for( page_id = 0 ; page_id < npages ; page_id ++ )
390    {
391        // If the mage is missing, this function allocates the missing page,
392        // and load the page from IOC device into mapper
393        page_xp = mapper_remote_get_page( XPTR( local_cxy , mapper ), page_id );
394
395        if( page_xp == XPTR_NULL ) return -1;
396    }
397
398#if DEBUG_VFS_INODE_LOAD_ALL
399cycle = (uint32_t)hal_get_cycles();
400if( DEBUG_VFS_INODE_LOAD_ALL < cycle )
401printk("\n[%s] thread[%x,%x] exit for <%x> in cluster %x / cycle %d\n",
402__FUNCTION__, this->process->pid, this->trdid, name, local_cxy, cycle );
403#endif
404
405    return 0;
406
407}  // end vfs_inode_load_all_pages()
408
409////////////////////////////////////////////////////////////////////////////////////////////
410//          VFS dentry descriptor related functions
411//////////////////////////////////////////////////////////////////////////////////////////
412
413///////////////////////////////////////////////////
414error_t vfs_dentry_create( vfs_fs_type_t   fs_type,
415                           char          * name,
416                           xptr_t        * dentry_xp )
417{
418    vfs_ctx_t      * ctx;        // context descriptor
419    vfs_dentry_t   * dentry;     // dentry descriptor (to be allocated)
420        kmem_req_t       req;        // request to kernel memory allocator
421
422#if DEBUG_VFS_DENTRY_CREATE
423thread_t * this = CURRENT_THREAD;
424uint32_t cycle = (uint32_t)hal_get_cycles();
425if( DEBUG_VFS_DENTRY_CREATE < cycle )
426printk("\n[%s] thread[%x,%x] enter for <%s> / parent_inode %x / cycle %d\n",
427__FUNCTION__, this->process->pid, this->trdid, name, parent, cycle );
428#endif
429
430    // get pointer on context
431    if     ( fs_type == FS_TYPE_FATFS ) ctx = &fs_context[FS_TYPE_FATFS];
432    else if( fs_type == FS_TYPE_RAMFS ) ctx = &fs_context[FS_TYPE_RAMFS];
433    else if( fs_type == FS_TYPE_DEVFS ) ctx = &fs_context[FS_TYPE_DEVFS];
434    else 
435    {
436        ctx = NULL;
437        return -1;
438    }
439
440    // get name length
441    uint32_t length = strlen( name );
442
443    if( length >= CONFIG_VFS_MAX_NAME_LENGTH ) return EINVAL;
444
445    // allocate memory for dentry descriptor
446        req.type  = KMEM_VFS_DENTRY;
447        req.size  = sizeof(vfs_dentry_t);
448    req.flags = AF_KERNEL | AF_ZERO;
449        dentry     = (vfs_dentry_t *)kmem_alloc( &req );
450
451    if( dentry == NULL ) 
452    {
453        printk("\n[ERROR] in %s : cannot allocate dentry descriptor\n",
454        __FUNCTION__ );
455        return -1;
456    }
457
458    // initialize dentry descriptor
459    dentry->ctx     = ctx;
460    dentry->length  = length;
461    dentry->extend  = NULL;
462    strcpy( dentry->name , name );
463
464    // return extended pointer on dentry
465    *dentry_xp = XPTR( local_cxy , dentry );
466
467#if DEBUG_VFS_DENTRY_CREATE
468cycle = (uint32_t)hal_get_cycles();
469if( DEBUG_VFS_DENTRY_CREATE < cycle )
470printk("\n[%s] thread[%x,%x] exit for <%s> / dentry [%x,%x] / cycle %d\n",
471__FUNCTION__, this->process->pid, this->trdid, name, local_cxy, dentry, cycle );
472#endif
473
474    return 0;
475
476}  // end vfs_dentry_create()
477
478////////////////////////////////////////////////
479void vfs_dentry_destroy( vfs_dentry_t * dentry )
480{
481    // release memory allocated to dentry
482        kmem_req_t req;
483        req.ptr   = dentry;
484        req.type  = KMEM_VFS_DENTRY;
485        kmem_free( &req );
486
487}  // end vfs_dentry_destroy()
488
489
490//////////////////////////////////////////////////////////////////////////////////////////
491//       VFS file descriptor related functions
492//////////////////////////////////////////////////////////////////////////////////////////
493
494/////////////////////////////////////////////
495error_t vfs_file_create( vfs_inode_t * inode,
496                         uint32_t      attr,
497                         xptr_t      * file_xp )
498{
499    vfs_file_t  * file;
500        kmem_req_t    req;
501
502#if DEBUG_VFS_FILE_CREATE
503thread_t * this = CURRENT_THREAD;
504uint32_t cycle = (uint32_t)hal_get_cycles();
505if( DEBUG_VFS_OPEN < cycle )
506printk("\n[%s] thread[%x,%x] enter for inode %x in cluster %x / cycle %d\n",
507__FUNCTION__, this->process->pid, this->trdid, inode, local_cxy, cycle );
508#endif
509
510    // allocate memory for new file descriptor
511        req.type  = KMEM_VFS_FILE;
512        req.size  = sizeof(vfs_file_t);
513    req.flags = AF_KERNEL | AF_ZERO;
514        file      = (vfs_file_t *)kmem_alloc( &req );
515
516    if( file == NULL ) return ENOMEM;
517
518    // initializes new file descriptor
519    file->gc       = 0;
520    file->type     = inode->type;
521    file->attr     = attr;
522    file->offset   = 0;
523    file->refcount = 1;
524    file->inode    = inode;
525    file->ctx      = inode->ctx;
526    file->mapper   = inode->mapper;
527
528    remote_rwlock_init( XPTR( local_cxy , &file->lock ), LOCK_VFS_FILE );
529
530    *file_xp = XPTR( local_cxy , file );
531
532#if DEBUG_VFS_FILE_CREATE
533cycle = (uint32_t)hal_get_cycles();
534if( DEBUG_VFS_OPEN < cycle )
535printk("\n[%s] thread[%x,%x] created file %x in cluster %x / cycle %d\n",
536__FUNCTION__, this->process->pid, this->trdid, file, local_cxy, cycle );
537#endif
538
539    return 0;
540
541}  // end vfs_file_create()
542
543///////////////////////////////////////////
544void vfs_file_destroy( vfs_file_t *  file )
545{
546
547// check refcount
548assert( (file->refcount == 0) , "refcount non zero\n" );
549
550        kmem_req_t req;
551        req.ptr   = file;
552        req.type  = KMEM_VFS_FILE;
553        kmem_free( &req );
554
555#if DEBUG_VFS_CLOSE
556thread_t * this = CURRENT_THREAD;
557uint32_t cycle = (uint32_t)hal_get_cycles();
558if( DEBUG_VFS_CLOSE < cycle )
559printk("\n[%s] thread[%x,%x] deleted file %x in cluster %x / cycle %d\n",
560__FUNCTION__, this->process->pid, this->trdid, file, local_cxy, cycle );
561#endif
562
563}  // end vfs_file_destroy()
564
565
566////////////////////////////////////////
567void vfs_file_count_up( xptr_t file_xp )
568{
569    // get file cluster and local pointer
570    cxy_t        file_cxy = GET_CXY( file_xp );
571    vfs_file_t * file_ptr = GET_PTR( file_xp ); 
572
573    // atomically increment count
574    hal_remote_atomic_add( XPTR( file_cxy , &file_ptr->refcount ) , 1 ); 
575}
576
577//////////////////////////////////////////
578void vfs_file_count_down( xptr_t file_xp )
579{
580    // get file cluster and local pointer
581    cxy_t        file_cxy = GET_CXY( file_xp );
582    vfs_file_t * file_ptr = GET_PTR( file_xp ); 
583
584    // atomically decrement count
585    hal_remote_atomic_add( XPTR( file_cxy , &file_ptr->refcount ) , -1 ); 
586}
587
588//////////////////////////////////////////////////////////////////////////////////////////
589//           "syscalls" API related functions
590//////////////////////////////////////////////////////////////////////////////////////////
591
592//////////////////////////////////////
593error_t vfs_open( xptr_t      root_xp,
594                          char      * path,
595                  xptr_t      process_xp,
596                          uint32_t    flags,
597                  uint32_t    mode, 
598                          xptr_t    * new_file_xp,
599                  uint32_t  * new_file_id )
600{
601    error_t        error;
602    xptr_t         inode_xp;       // extended pointer on target inode
603    cxy_t          inode_cxy;      // inode cluster identifier       
604    vfs_inode_t  * inode_ptr;      // inode local pointer
605    uint32_t       file_attr;      // file descriptor attributes
606    uint32_t       lookup_mode;    // lookup working mode       
607    xptr_t         file_xp;        // extended pointer on created file descriptor
608    uint32_t       file_id;        // created file descriptor index in reference fd_array
609    xptr_t         vfs_root_xp;    // extended pointer on VFS root inode
610    vfs_inode_t  * vfs_root_ptr;   // local pointer on VFS root inode
611    cxy_t          vfs_root_cxy;   // VFS root inode cluster identifier
612    xptr_t         lock_xp;        // extended pointer on Inode Tree lock
613
614    if( mode != 0 )
615    {
616        printk("\n[ERROR] in %s : the mode parameter is not supported yet\n" );
617        return -1;
618    }
619
620    thread_t  * this    = CURRENT_THREAD;
621    process_t * process = this->process;
622
623#if DEBUG_VFS_OPEN
624uint32_t cycle = (uint32_t)hal_get_cycles();
625if( DEBUG_VFS_OPEN < cycle )
626printk("\n[%s] thread[%x,%x] enter for <%s> / root_inode (%x,%x) / cycle %d\n",
627__FUNCTION__, process->pid, this->trdid, path, GET_CXY(root_xp), GET_PTR(root_xp), cycle );
628#endif
629
630    // compute lookup working mode
631    lookup_mode = VFS_LOOKUP_OPEN;
632    if( (flags & O_DIR    )      )  lookup_mode |= VFS_LOOKUP_DIR;
633    if( (flags & O_CREAT  )      )  lookup_mode |= VFS_LOOKUP_CREATE;
634    if( (flags & O_EXCL   )      )  lookup_mode |= VFS_LOOKUP_EXCL;
635 
636    // compute attributes for the created file
637    file_attr = 0;
638    if( (flags & O_RDONLY ) == 0 )  file_attr |= FD_ATTR_WRITE_ENABLE;
639    if( (flags & O_WRONLY ) == 0 )  file_attr |= FD_ATTR_READ_ENABLE;
640    if( (flags & O_SYNC   )      )  file_attr |= FD_ATTR_SYNC;
641    if( (flags & O_APPEND )      )  file_attr |= FD_ATTR_APPEND;
642    if( (flags & O_CLOEXEC)      )  file_attr |= FD_ATTR_CLOSE_EXEC;
643
644    // build extended pointer on lock protecting Inode Tree
645    vfs_root_xp  = process->vfs_root_xp;
646    vfs_root_ptr = GET_PTR( vfs_root_xp );
647    vfs_root_cxy = GET_CXY( vfs_root_xp );
648    lock_xp      = XPTR( vfs_root_cxy , &vfs_root_ptr->main_lock );
649
650    // take lock protecting Inode Tree in read mode
651    remote_rwlock_rd_acquire( lock_xp );
652
653    // get extended pointer on target inode
654    error = vfs_lookup( root_xp,
655                        path,
656                        lookup_mode,
657                        &inode_xp,
658                        NULL );
659
660    // release lock protecting Inode Tree
661    remote_rwlock_rd_release( lock_xp );
662
663    if( error )
664    {
665        printk("\n[ERROR] in %s : cannot get inode <%s>\n",
666        __FUNCTION__ , path );
667        return -1;
668    }
669
670    // get target inode cluster and local pointer
671    inode_cxy = GET_CXY( inode_xp );
672    inode_ptr = GET_PTR( inode_xp );
673   
674#if (DEBUG_VFS_OPEN & 1)
675cycle = (uint32_t)hal_get_cycles();
676if( DEBUG_VFS_OPEN < cycle )
677printk("\n[%s] thread[%x,%x] found inode(%x,%x) for <%s>\n",
678__FUNCTION__, process->pid, this->trdid, inode_cxy, inode_ptr, path );
679#endif
680
681    // create a new file descriptor in cluster containing inode
682    if( inode_cxy == local_cxy )      // target cluster is local
683    {
684        error = vfs_file_create( inode_ptr , file_attr , &file_xp );
685    }
686    else                              // target cluster is remote
687    {
688        rpc_vfs_file_create_client( inode_cxy , inode_ptr , file_attr , &file_xp , &error );
689    }
690
691    if( error )  return error;
692
693#if (DEBUG_VFS_OPEN & 1)
694cycle = (uint32_t)hal_get_cycles();
695if( DEBUG_VFS_OPEN < cycle )
696printk("\n[%s] thread[%x,%x] created file descriptor (%x,%x) for <%s>\n",
697__FUNCTION__, process->pid, this->trdid, GET_CXY(file_xp), GET_PTR(file_xp), path );
698#endif
699
700    // allocate and register a new file descriptor index in reference process
701    error = process_fd_register( process_xp , file_xp , &file_id );
702
703    if( error ) return error;
704
705#if DEBUG_VFS_OPEN
706cycle = (uint32_t)hal_get_cycles();
707if( DEBUG_VFS_OPEN < cycle )
708printk("\n[%s] thread[%x,%x] exit for <%s> / fdid %d / cluster %x / cycle %d\n",
709__FUNCTION__, process->pid, this->trdid, path, file_id, GET_CXY( file_xp ), cycle );
710#endif
711
712    // success
713    *new_file_xp = file_xp;
714    *new_file_id = file_id;
715    return 0;
716
717}  // end vfs_open()
718
719//////////////////////////////////////
720int vfs_user_move( bool_t   to_buffer,
721                   xptr_t   file_xp,
722                   void   * buffer,
723                   uint32_t size )
724{
725    cxy_t              file_cxy;     // remote file descriptor cluster
726    vfs_file_t       * file_ptr;     // remote file descriptor local pointer
727    vfs_inode_type_t   inode_type;
728    uint32_t           file_offset;  // current offset in file
729    mapper_t         * mapper;
730    error_t            error;
731
732// check argument
733assert( (file_xp != XPTR_NULL), "file_xp == XPTR_NULL\n" );
734
735    // get cluster and local pointer on remote file descriptor
736    file_cxy  = GET_CXY( file_xp );
737    file_ptr  = GET_PTR( file_xp );
738
739    // get inode type from remote file descriptor
740    inode_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type   ) );
741   
742// check inode type
743assert( (inode_type == INODE_TYPE_FILE), "inode type is not INODE_TYPE_FILE" );
744
745    // get mapper pointer and file offset from file descriptor
746    file_offset = hal_remote_l32( XPTR( file_cxy , &file_ptr->offset ) );
747    mapper = (mapper_t *)hal_remote_lpt( XPTR( file_cxy , &file_ptr->mapper ) );
748
749    // move data between mapper and buffer
750    error = mapper_move_user( XPTR( file_cxy , mapper ),
751                              to_buffer,
752                              file_offset,
753                              buffer,
754                              size );
755
756    // update file offset in file descriptor
757    hal_remote_atomic_add( XPTR( file_cxy , &file_ptr->offset ) , size );
758
759    if( error ) 
760    {
761        return -1;
762    }
763
764    return size;
765
766}  // end vfs_user_move()
767
768////////////////////////////////////////////
769error_t vfs_kernel_move( bool_t   to_buffer,
770                         xptr_t   file_xp,
771                         xptr_t   buffer_xp,
772                         uint32_t size )
773{
774    cxy_t              file_cxy;     // remote file descriptor cluster
775    vfs_file_t       * file_ptr;     // remote file descriptor local pointer
776    vfs_inode_type_t   inode_type;   // remote file type
777    uint32_t           file_offset;  // current offset in file
778    mapper_t         * mapper_ptr;   // remote mapper local pointer
779    xptr_t             mapper_xp;    // remote mapper extended pointer
780    error_t            error;
781
782// check argument
783assert( (file_xp != XPTR_NULL) , "file_xp == XPTR_NULL\n" );
784
785    // get cluster and local pointer on remote file descriptor
786    file_cxy  = GET_CXY( file_xp );
787    file_ptr  = GET_PTR( file_xp );
788
789    // get inode type from remote file descriptor
790    inode_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type   ) );
791
792    // action depends on inode type
793    if( inode_type == INODE_TYPE_FILE )
794    {
795        // get mapper pointers and file offset from file descriptor
796        file_offset = hal_remote_l32( XPTR( file_cxy , &file_ptr->offset ) );
797        mapper_ptr  = hal_remote_lpt( XPTR( file_cxy , &file_ptr->mapper ) );
798        mapper_xp   = XPTR( file_cxy , mapper_ptr );
799
800        // move data between mapper and buffer
801        error = mapper_move_kernel( mapper_xp,
802                                    to_buffer,
803                                    file_offset,
804                                    buffer_xp,
805                                    size );
806        if( error ) return -1;
807    }
808    else 
809    {
810        printk("\n[ERROR] in %s : inode is not a file", __FUNCTION__ );
811        return -1;
812    }
813
814    return 0;
815
816}  // end vfs_kernel_move()
817
818//////////////////////////////////////
819error_t vfs_lseek( xptr_t     file_xp,
820                   uint32_t   offset,
821                   uint32_t   whence, 
822                   uint32_t * new_offset )
823{
824    xptr_t         offset_xp;
825    xptr_t         lock_xp;
826    xptr_t         size_xp;
827    cxy_t          file_cxy;
828    vfs_file_t  *  file_ptr;
829    vfs_inode_t *  inode_ptr;
830    uint32_t       new;
831
832// check argument
833assert( (file_xp != XPTR_NULL) , "file_xp == XPTR_NULL\n" );
834
835    // get cluster and local pointer on remote file descriptor
836    file_cxy = GET_CXY( file_xp );
837    file_ptr = GET_PTR( file_xp );
838
839    // get local pointer on remote inode
840    inode_ptr = (vfs_inode_t *)hal_remote_lpt( XPTR( file_cxy , &file_ptr->inode ) );
841
842    // build extended pointers on lock, offset and size
843    offset_xp = XPTR( file_cxy , &file_ptr->offset );
844    lock_xp   = XPTR( file_cxy , &file_ptr->lock );
845    size_xp   = XPTR( file_cxy , &inode_ptr->size );
846
847    // take file descriptor lock
848    remote_rwlock_wr_acquire( lock_xp );
849
850    if      ( whence == SEEK_CUR )   // new = current + offset
851    {
852        new = hal_remote_l32( offset_xp ) + offset;
853    }
854    else if ( whence == SEEK_SET )   // new = offset
855    {
856        new = offset;
857    }
858    else if ( whence == SEEK_END )   // new = size + offset
859    { 
860        new = hal_remote_l32( size_xp ) + offset;
861    }
862    else
863    {
864        printk("\n[ERROR] in %s : illegal whence value\n", __FUNCTION__ );
865        remote_rwlock_wr_release( lock_xp );
866        return -1;
867    }
868
869#if DEBUG_VFS_LSEEK
870uint32_t   cycle = (uint32_t)hal_get_cycles();
871thread_t * this  = CURRENT_THREAD;
872char       name[CONFIG_VFS_MAX_NAME_LENGTH];
873vfs_inode_get_name( XPTR( file_cxy , inode_ptr ) , name );
874if( cycle > DEBUG_VFS_LSEEK )
875printk("\n[%s] thread[%x,%x] for <%s> / new offset %d / cycle %d\n",
876__FUNCTION__ , this->process->pid, this->trdid, name, new, cycle );
877#endif
878
879    // set new offset
880    hal_remote_s32( offset_xp , new );
881
882    // release file descriptor lock
883    remote_rwlock_wr_release( lock_xp );
884
885    // success
886    if ( new_offset != NULL ) *new_offset = new;
887    return 0;
888
889}  // vfs_lseek()
890
891///////////////////////////////////
892error_t vfs_close( xptr_t   file_xp,
893                   uint32_t file_id )
894{
895    cluster_t  * cluster;          // local pointer on local cluster
896    cxy_t        file_cxy;         // cluster containing the file descriptor.
897    vfs_file_t * file_ptr;         // local ponter on file descriptor
898    cxy_t        owner_cxy;        // process owner cluster
899    lpid_t       lpid;             // process local index
900    xptr_t       root_xp;          // root of list of process copies
901    xptr_t       lock_xp;          // lock protecting the list of copies
902    xptr_t       iter_xp;          // iterator on list of process copies
903    xptr_t       process_xp;       // extended pointer on one process copy
904    cxy_t        process_cxy;      // process copy cluster
905    process_t  * process_ptr;      // process copy local pointer
906
907// check arguments
908assert( (file_xp != XPTR_NULL) , "file_xp == XPTR_NULL\n" );
909assert( (file_id < CONFIG_PROCESS_FILE_MAX_NR) , "illegal file_id\n" );
910
911    thread_t  * this    = CURRENT_THREAD;
912    process_t * process = this->process;
913
914#if DEBUG_VFS_CLOSE
915uint32_t cycle = (uint32_t)hal_get_cycles();
916if( DEBUG_VFS_CLOSE < cycle )
917printk("\n[%s] thread[%x,%x] enter / fdid %d / cycle %d\n",
918__FUNCTION__, process->pid, this->trdid, file_id, cycle );
919#endif
920
921    // get local pointer on local cluster manager
922    cluster = LOCAL_CLUSTER;
923
924    // get owner process cluster and lpid
925    owner_cxy  = CXY_FROM_PID( process->pid );
926    lpid       = LPID_FROM_PID( process->pid );
927
928    // get extended pointers on copies root and lock
929    root_xp = XPTR( owner_cxy , &cluster->pmgr.copies_root[lpid] );
930    lock_xp = XPTR( owner_cxy , &cluster->pmgr.copies_lock[lpid] );
931
932    // 1) loop on the process descriptor copies to reset all fd_array[file_id] entries
933
934    // take the lock protecting the list of copies
935    remote_queuelock_acquire( lock_xp );
936
937    XLIST_FOREACH( root_xp , iter_xp )
938    {
939        process_xp  = XLIST_ELEMENT( iter_xp , process_t , copies_list );
940        process_cxy = GET_CXY( process_xp );
941        process_ptr = GET_PTR( process_xp );
942
943#if (DEBUG_VFS_CLOSE & 1 )
944if( DEBUG_VFS_CLOSE < cycle )
945printk("\n[%s]  reset fd_array[%d] for process %x in cluster %x\n",
946__FUNCTION__, file_id, process_ptr, process_cxy );
947#endif
948
949// fd_array lock is required for atomic write of a 64 bits word
950// xptr_t fd_array_lock_xp = XPTR( process_cxy , &process_ptr->fd_array.lock );
951
952        xptr_t entry_xp         = XPTR( process_cxy , &process_ptr->fd_array.array[file_id] );
953
954// remote_rwlock_wr_acquire( fd_array_lock_xp );
955
956        hal_remote_s64( entry_xp , XPTR_NULL );
957       
958// remote_rwlock_wr_release( fd_array_lock_xp );
959
960        vfs_file_count_down( file_xp );
961
962        hal_fence();
963    }   
964
965    // release the lock protecting the list of copies
966    remote_queuelock_release( lock_xp );
967
968#if (DEBUG_VFS_CLOSE & 1)
969if( DEBUG_VFS_CLOSE < cycle )
970printk("\n[%s] thread[%x,%x] reset all fd-array copies\n",
971__FUNCTION__, process->pid, this->trdid );
972#endif
973
974    // 2) release memory allocated to file descriptor in remote cluster
975
976    // get cluster and local pointer on remote file descriptor
977    file_cxy = GET_CXY( file_xp );
978    file_ptr = GET_PTR( file_xp );
979
980    if( file_cxy == local_cxy )             // file cluster is local
981    {
982        vfs_file_destroy( file_ptr );
983    }
984    else                                    // file cluster is local
985    {
986        rpc_vfs_file_destroy_client( file_cxy , file_ptr );
987    }
988
989#if DEBUG_VFS_CLOSE
990cycle = (uint32_t)hal_get_cycles();
991if( DEBUG_VFS_CLOSE < cycle )
992printk("\n[%s] thread[%x,%x] exit / fdid %d closed / cycle %d\n",
993__FUNCTION__, process->pid, this->trdid, file_id, cycle );
994#endif
995
996    return 0;
997
998}  // end vfs_close()
999
1000////////////////////////////////////
1001error_t vfs_mkdir( xptr_t   root_xp,
1002                   char   * path,
1003                   uint32_t rights )
1004{
1005    error_t        error;
1006    xptr_t         vfs_root_xp;        // extended pointer on VFS root inode
1007    vfs_inode_t  * vfs_root_ptr;       // local pointer on VFS root inode
1008    cxy_t          vfs_root_cxy;       // VFS root inode cluster identifier
1009    xptr_t         lock_xp;            // extended pointer on lock protecting Inode Tree
1010    xptr_t         inode_xp;           // extended pointer on new directory inode
1011    vfs_inode_t  * inode_ptr;          // local pointer on new directory inode
1012    cxy_t          inode_cxy;          // new directory inode cluster identifier
1013    xptr_t         dentry_xp;          // extended pointer on new dentry
1014    vfs_dentry_t * dentry_ptr;         // new dentry local pointer
1015    xptr_t         parent_xp;          // extended pointer on parent inode
1016    vfs_inode_t  * parent_ptr;         // local pointer on parent inode 
1017    cxy_t          parent_cxy;         // parent inode cluster identifier
1018    vfs_ctx_t    * parent_ctx_ptr;     // local pointer on parent inode context
1019    uint32_t       parent_fs_type;     // parent inode file system type
1020
1021    xptr_t         parents_root_xp;    // extended pointer on parents field in inode (root)
1022    xptr_t         parents_entry_xp;   // extended pointer on parents field in dentry
1023    xptr_t         children_xhtab_xp;  // extended pointer on children field in inode (root)
1024    xptr_t         children_entry_xp;  // extended pointer on children field in dentry
1025
1026    char           last_name[CONFIG_VFS_MAX_NAME_LENGTH];
1027
1028    thread_t  * this    = CURRENT_THREAD;
1029    process_t * process = this->process;
1030
1031#if DEBUG_VFS_MKDIR
1032char root_name[CONFIG_VFS_MAX_NAME_LENGTH];
1033vfs_inode_get_name( root_xp , root_name );
1034uint32_t   cycle = (uint32_t)hal_get_cycles();
1035if( DEBUG_VFS_MKDIR < cycle )
1036printk("\n[%s] thread[%x,%x] enter / root <%s> / path <%s> / cycle %d\n",
1037__FUNCTION__, process->pid, this->trdid, root_name, path, cycle );
1038#endif
1039
1040    // build extended pointer on lock protecting Inode Tree (in VFS root inode)
1041    vfs_root_xp  = process->vfs_root_xp;
1042    vfs_root_ptr = GET_PTR( vfs_root_xp );
1043    vfs_root_cxy = GET_CXY( vfs_root_xp );
1044    lock_xp      = XPTR( vfs_root_cxy , &vfs_root_ptr->main_lock );
1045
1046    // take the lock protecting Inode Tree in write mode
1047    remote_rwlock_wr_acquire( lock_xp );
1048
1049    // 1. get pointers on parent inode
1050    error = vfs_lookup( root_xp,
1051                        path,
1052                        VFS_LOOKUP_DIR | VFS_LOOKUP_PARENT,
1053                        &parent_xp,
1054                        last_name );
1055    if( error )
1056    {
1057        remote_rwlock_wr_release( lock_xp );
1058        printk("\n[ERROR] in %s : cannot get parent inode for <%s>\n",
1059        __FUNCTION__, path );
1060        return -1;
1061    }
1062
1063    // get parent inode cluster and local pointer
1064    parent_cxy = GET_CXY( parent_xp );
1065    parent_ptr = GET_PTR( parent_xp );
1066
1067#if( DEBUG_VFS_MKDIR & 1 )
1068if( DEBUG_VFS_MKDIR < cycle )
1069printk("\n[%s] thread[%x,%x] get parent inode (%x,%x) for <%s>\n",
1070__FUNCTION__, process->pid, this->trdid, parent_cxy, parent_ptr, path );
1071#endif
1072
1073    // get parent inode context, and FS type
1074    parent_ctx_ptr = hal_remote_lpt( XPTR( parent_cxy , &parent_ptr->ctx ) );
1075    parent_fs_type = hal_remote_l32( XPTR( parent_cxy , &parent_ctx_ptr->type ) );
1076
1077    // 2. create one new dentry in parent cluster
1078    if( parent_cxy == local_cxy ) 
1079    {
1080        error = vfs_dentry_create( parent_fs_type,
1081                                   last_name,
1082                                   &dentry_xp );
1083    }
1084    else
1085    {
1086        rpc_vfs_dentry_create_client( parent_cxy,
1087                                      parent_fs_type,
1088                                      last_name,
1089                                      &dentry_xp,
1090                                      &error );
1091    }
1092
1093    if( error )
1094    {
1095        remote_rwlock_wr_release( lock_xp );
1096        printk("\n[ERROR] in %s : cannot create new dentry in cluster %x for <%s>\n",
1097        __FUNCTION__, parent_cxy, path );
1098        return -1;
1099    }
1100
1101    // get local pointer on dentry
1102    dentry_ptr = GET_PTR( dentry_xp );
1103
1104#if( DEBUG_VFS_MKDIR & 1 )
1105if( DEBUG_VFS_MKDIR < cycle )
1106printk("\n[%s] thread[%x,%x] created new dentry (%x,%x) for <%s>\n",
1107__FUNCTION__, process->pid, this->trdid, parent_cxy, dentry_ptr, path );
1108#endif
1109
1110    // 3. create new directory inode
1111    // TODO : define attr / uid / gid
1112    uint32_t attr = 0;
1113    uint32_t uid  = 0;
1114    uint32_t gid  = 0;
1115
1116    // select a target cluster for new inode
1117    inode_cxy = cluster_random_select();
1118   
1119    if( inode_cxy == local_cxy )      // target cluster is local
1120    {
1121        error = vfs_inode_create( parent_fs_type,
1122                                  INODE_TYPE_DIR,
1123                                  attr,
1124                                  rights,
1125                                  uid,
1126                                  gid,
1127                                  &inode_xp );
1128    }
1129    else                              // target cluster is remote
1130    {
1131        rpc_vfs_inode_create_client( inode_cxy,
1132                                     parent_fs_type,
1133                                     INODE_TYPE_DIR,
1134                                     attr,
1135                                     rights,
1136                                     uid,
1137                                     gid,
1138                                     &inode_xp,
1139                                     &error );
1140    }
1141                                     
1142    if( error )
1143    {
1144        remote_rwlock_wr_release( lock_xp );
1145        printk("\n[ERROR] in %s : cannot create new inode in cluster %x for <%s>\n",
1146               __FUNCTION__ , inode_cxy , path );
1147        if( parent_cxy == local_cxy ) vfs_dentry_destroy( dentry_ptr );
1148        else rpc_vfs_dentry_destroy_client( parent_cxy , dentry_ptr );
1149        return -1;
1150    }
1151
1152    // get new inode local pointer
1153    inode_ptr = GET_PTR( inode_xp );
1154   
1155#if(DEBUG_VFS_MKDIR & 1)
1156if( DEBUG_VFS_MKDIR < cycle )
1157printk("\n[%s] thread[%x,%x] created new inode (%x,%x) for <%s>\n",
1158__FUNCTION__ , process->pid, this->trdid, inode_cxy, inode_ptr, path );
1159#endif
1160
1161    // 4. register dentry in new inode list of parents
1162    parents_root_xp  = XPTR( inode_cxy  , &inode_ptr->parents );
1163    parents_entry_xp = XPTR( parent_cxy , &dentry_ptr->parents );
1164    xlist_add_first( parents_root_xp , parents_entry_xp );
1165    hal_remote_atomic_add( XPTR( inode_cxy , &inode_ptr->links ) , 1 );
1166
1167    // 5. register dentry in parent inode
1168    children_xhtab_xp = XPTR( parent_cxy , &parent_ptr->children );
1169    children_entry_xp = XPTR( parent_cxy , &dentry_ptr->children );
1170    xhtab_insert( children_xhtab_xp , last_name , children_entry_xp );
1171
1172    // 6. update "parent" and "child_xp" fields in dentry
1173    hal_remote_s64( XPTR( parent_cxy , &dentry_ptr->child_xp ) , inode_xp );
1174    hal_remote_spt( XPTR( parent_cxy , &dentry_ptr->parent ) , parent_ptr );
1175
1176#if(DEBUG_VFS_MKDIR & 1)
1177if( DEBUG_VFS_MKDIR < cycle )
1178printk("\n[%s] thread[%x,%x] updated Inode Tree for <%s>\n",
1179__FUNCTION__, process->pid, this->trdid, path );
1180#endif
1181
1182    // 7. create the two special dentries <.> and <..> in new directory
1183    // both the new directory mapper, and the Inode Tree are updated
1184    error = vfs_add_special_dentries( inode_xp,
1185                                      parent_xp );
1186
1187    if( error )
1188    {
1189        remote_rwlock_wr_release( lock_xp );
1190        printk("\n[ERROR] in %s : cannot create new inode in cluster %x for <%s>\n",
1191               __FUNCTION__ , inode_cxy , path );
1192        if( parent_cxy == local_cxy ) vfs_dentry_destroy( dentry_ptr );
1193        else rpc_vfs_dentry_destroy_client( parent_cxy , dentry_ptr );
1194        return -1;
1195    }
1196
1197    // release the lock protecting Inode Tree
1198    remote_rwlock_wr_release( lock_xp );
1199
1200    // 8. update parent directory mapper
1201    //    and synchronize the parent directory on IOC device
1202    if (parent_cxy == local_cxy)
1203    {
1204        error = vfs_fs_add_dentry( parent_ptr,
1205                                   dentry_ptr );
1206    }
1207    else
1208    {
1209        rpc_vfs_fs_add_dentry_client( parent_cxy,
1210                                      parent_ptr,
1211                                      dentry_ptr,
1212                                      &error );
1213    }
1214
1215    if( error )
1216    {
1217        printk("\n[ERROR] in %s : cannot update parent directory for <%s>\n",
1218        __FUNCTION__, path );
1219        return -1;
1220    }
1221
1222#if(DEBUG_VFS_MKDIR & 1)
1223if( DEBUG_VFS_MKDIR < cycle )
1224printk("\n[%s] thread[%x,%x] updated parent dir (mapper and IOC) for <%s>\n",
1225__FUNCTION__, process->pid, this->trdid, path );
1226#endif
1227
1228    return 0;
1229
1230}  // end vfs_mkdir()
1231
1232///////////////////////////////////////
1233error_t vfs_link( xptr_t   old_root_xp,
1234                  char   * old_path,
1235                  xptr_t   new_root_xp,
1236                  char   * new_path )
1237{
1238    error_t        error;
1239    xptr_t         vfs_root_xp;        // extended pointer on VFS root inode
1240    vfs_inode_t  * vfs_root_ptr;       // local pointer on VFS root inode
1241    cxy_t          vfs_root_cxy;       // VFS root inode cluster identifier
1242    xptr_t         lock_xp;            // extended pointer on lock protecting Inode Tree
1243    xptr_t         inode_xp;           // extended pointer on target inode
1244    vfs_inode_t  * inode_ptr;          // local pointer on target inode
1245    cxy_t          inode_cxy;          // target inode cluster identifier
1246    uint32_t       inode_type;         // target inode type
1247    vfs_ctx_t    * inode_ctx_ptr;      // local pointer on target inode context
1248    uint32_t       inode_fs_type;      // target inode file system type
1249    xptr_t         dentry_xp;          // extended pointer on new dentry
1250    vfs_dentry_t * dentry_ptr;         // target dentry local pointer
1251    xptr_t         new_parent_xp;      // extended pointer on new parent inode
1252    vfs_inode_t  * new_parent_ptr;     // local pointer on new parent inode 
1253    cxy_t          new_parent_cxy;     // new parent inode cluster identifier
1254
1255    xptr_t         parents_root_xp;    // extended pointer on parents field in inode (root)
1256    xptr_t         parents_entry_xp;   // extended pointer on parents field in dentry
1257    xptr_t         children_xhtab_xp;  // extended pointer on children field in inode (root)
1258    xptr_t         children_entry_xp;  // extended pointer on children field in dentry
1259
1260    char           new_name[CONFIG_VFS_MAX_NAME_LENGTH];
1261
1262    thread_t  * this    = CURRENT_THREAD;
1263    process_t * process = this->process;
1264
1265#if DEBUG_VFS_LINK
1266char old_root_name[CONFIG_VFS_MAX_NAME_LENGTH];
1267char new_root_name[CONFIG_VFS_MAX_NAME_LENGTH];
1268vfs_inode_get_name( old_root_xp , old_root_name );
1269vfs_inode_get_name( new_root_xp , new_root_name );
1270uint32_t   cycle = (uint32_t)hal_get_cycles();
1271if( DEBUG_VFS_LINK < cycle )
1272printk("\n[%s] thread[%x,%x] enter / old_root <%s> / old_path <%s> / "
1273"new_root <%s> / new_path <%s> / cycle %d\n",
1274__FUNCTION__, process->pid, this->trdid,
1275old_root_name, old_path, new_root_name, new_path, cycle );
1276#endif
1277
1278    // build extended pointer on lock protecting Inode Tree (in VFS root inode)
1279    vfs_root_xp  = process->vfs_root_xp;
1280    vfs_root_ptr = GET_PTR( vfs_root_xp );
1281    vfs_root_cxy = GET_CXY( vfs_root_xp );
1282    lock_xp      = XPTR( vfs_root_cxy , &vfs_root_ptr->main_lock );
1283
1284    // take the lock protecting Inode Tree in write mode
1285    remote_rwlock_wr_acquire( lock_xp );
1286
1287    // get extended pointer on target inode
1288    error = vfs_lookup( old_root_xp,
1289                        old_path,
1290                        0,
1291                        &inode_xp,
1292                        NULL );
1293    if( error )
1294    {
1295        remote_rwlock_wr_release( lock_xp );
1296        printk("\n[ERROR] in %s : cannot get target inode for <%s>\n",
1297        __FUNCTION__, old_path );
1298        return -1;
1299    }
1300
1301#if( DEBUG_VFS_LINK & 1 )
1302if( DEBUG_VFS_LINK < cycle )
1303printk("\n[%s] thread[%x,%x] get child inode (%x,%x) for <%s>\n",
1304__FUNCTION__, process->pid, this->trdid,
1305GET_CXY(inode_xp), GET_PTR(inode_xp), old_path, cycle );
1306#endif
1307
1308    // get extended pointer on parent inode in new path
1309    error = vfs_lookup( new_root_xp,
1310                        new_path,
1311                        VFS_LOOKUP_PARENT,
1312                        &new_parent_xp,
1313                        new_name );
1314    if( error )
1315    {
1316        remote_rwlock_wr_release( lock_xp );
1317        printk("\n[ERROR] in %s : cannot get parent inode for <%s>\n",
1318        __FUNCTION__, new_path );
1319        return -1;
1320    }
1321
1322#if( DEBUG_VFS_LINK & 1 )
1323if( DEBUG_VFS_LINK < cycle )
1324printk("\n[%s] thread[%x,%x] get parent inode (%x,%x) for <%s>\n",
1325__FUNCTION__, process->pid, this->trdid,
1326GET_CXY(new_parent_xp), GET_PTR(new_parent_xp), new_path );
1327#endif
1328
1329    // get target inode cluster and local pointer
1330    inode_cxy = GET_CXY( inode_xp );
1331    inode_ptr = GET_PTR( inode_xp );
1332
1333    // get target inode type, context, and FS type
1334    inode_type        = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->type ) );
1335    inode_ctx_ptr     = hal_remote_lpt( XPTR( inode_cxy , &inode_ptr->ctx ) );
1336    inode_fs_type     = hal_remote_l32( XPTR( inode_cxy , &inode_ctx_ptr->type ) );
1337
1338    // get new parent inode cluster an local pointer
1339    new_parent_ptr = GET_PTR( new_parent_xp );
1340    new_parent_cxy = GET_CXY( new_parent_xp );
1341
1342    ///////////////////////////////////////////////////////////////////////
1343    if( (inode_type == INODE_TYPE_FILE) || (inode_type == INODE_TYPE_DIR) )
1344    {
1345        // 1. create one new dentry
1346        if( new_parent_cxy == local_cxy ) 
1347        {
1348            error = vfs_dentry_create( inode_fs_type,
1349                                       new_name,
1350                                       &dentry_xp );
1351        }
1352        else
1353        {
1354            rpc_vfs_dentry_create_client( new_parent_cxy,
1355                                          inode_fs_type,
1356                                          new_name,
1357                                          &dentry_xp,
1358                                          &error );
1359        }
1360
1361        if( error )
1362        {
1363            remote_rwlock_wr_release( lock_xp );
1364            printk("\n[ERROR] in %s : cannot create new dentry for <%s>\n",
1365            __FUNCTION__, new_path );
1366            return -1;
1367        }
1368
1369        // get local pointer on dentry
1370        dentry_ptr = GET_PTR( dentry_xp );
1371
1372        // 2. register dentry in target inode
1373        parents_root_xp  = XPTR( inode_cxy      , &inode_ptr->parents );
1374        parents_entry_xp = XPTR( new_parent_cxy , &dentry_ptr->parents );
1375        xlist_add_first( parents_root_xp , parents_entry_xp );
1376        hal_remote_atomic_add( XPTR( inode_cxy , &inode_ptr->links ) , 1 );
1377
1378        // 3. register dentry in parent inode
1379        children_xhtab_xp = XPTR( new_parent_cxy , &new_parent_ptr->children );
1380        children_entry_xp = XPTR( new_parent_cxy , &dentry_ptr->children );
1381        xhtab_insert( children_xhtab_xp , new_name , children_entry_xp );
1382
1383        // 4. update "parent" and "child_xp" fields in dentry
1384        hal_remote_s64( XPTR( new_parent_cxy , &dentry_ptr->child_xp ) , inode_xp );
1385        hal_remote_spt( XPTR( new_parent_cxy , &dentry_ptr->parent ) , new_parent_ptr );
1386
1387#if(DEBUG_VFS_LINK & 1)
1388if( DEBUG_VFS_LINK < cycle )
1389printk("\n[%s] thread[%x,%x] updated Inode Tree / old <%s> / new <%s>\n",
1390__FUNCTION__, process->pid, this->trdid, old_path, new_path );
1391vfs_display( new_parent_xp ); 
1392#endif
1393
1394        // release the lock protecting Inode Tree
1395        remote_rwlock_wr_release( lock_xp );
1396
1397        // 5. update new parent directory mapper in Inode Tree
1398        //    and synchronize the parent directory on IOC device
1399        if (new_parent_cxy == local_cxy)
1400        {
1401            error = vfs_fs_add_dentry( new_parent_ptr,
1402                                       dentry_ptr );
1403        }
1404        else
1405        {
1406            rpc_vfs_fs_add_dentry_client( new_parent_cxy,
1407                                          new_parent_ptr,
1408                                          dentry_ptr,
1409                                          &error );
1410        }
1411        if( error )
1412        {
1413            printk("\n[ERROR] in %s : cannot update new parent directory for <%s>\n",
1414            __FUNCTION__, new_path );
1415            return -1;
1416        }
1417
1418#if(DEBUG_VFS_LINK & 1)
1419if( DEBUG_VFS_LINK < cycle )
1420printk("\n[%s] thread[%x,%x] updated new parent dir (mapper and IOC) / old <%s> / new <%s>\n",
1421__FUNCTION__, process->pid, this->trdid, old_path, new_path );
1422#endif
1423        return 0;
1424    }
1425    else
1426    {
1427        // release the lock protecting Inode Tree
1428        remote_rwlock_wr_release( lock_xp );
1429
1430        printk("\n[ERROR] in %s : unsupported inode type %s\n",
1431        __FUNCTION__ , vfs_inode_type_str( inode_type ) );
1432        return -1;
1433    }
1434
1435}  // end vfs_link()
1436
1437/////////////////////////////////////
1438error_t vfs_unlink( xptr_t   root_xp,
1439                    char   * path )
1440{
1441    error_t           error;
1442    xptr_t            vfs_root_xp;        // extended pointer on VFS root inode
1443    vfs_inode_t     * vfs_root_ptr;       // local_pointer on VFS root inode
1444    cxy_t             vfs_root_cxy;       // VFS root inode cluster identifier
1445    xptr_t            lock_xp;            // extended pointer on lock protecting Inode Tree
1446    xptr_t            parent_xp;          // extended pointer on target inode
1447    cxy_t             parent_cxy;         // target inode cluster identifier       
1448    vfs_inode_t     * parent_ptr;         // target inode local pointer
1449    xptr_t            inode_xp;           // extended pointer on target inode
1450    cxy_t             inode_cxy;          // target inode cluster identifier       
1451    vfs_inode_t     * inode_ptr;          // target inode local pointer
1452    uint32_t          inode_links;        // target inode links count
1453    vfs_inode_type_t  inode_type;         // target inode type
1454    uint32_t          inode_children;     // target inode number of children
1455    xptr_t            dentry_xp;          // extended pointer on dentry to unlink
1456    vfs_dentry_t    * dentry_ptr;         // local pointer on dentry to unlink
1457
1458    char              name[CONFIG_VFS_MAX_NAME_LENGTH];  // name of link to remove
1459
1460    thread_t  * this    = CURRENT_THREAD;
1461    process_t * process = this->process;
1462
1463#if DEBUG_VFS_UNLINK
1464uint32_t   cycle = (uint32_t)hal_get_cycles();
1465char root_name[CONFIG_VFS_MAX_NAME_LENGTH];
1466vfs_inode_get_name( root_xp , root_name );
1467if( DEBUG_VFS_UNLINK < cycle )
1468printk("\n[%s] thread[%x,%x] enter / root <%s> / path <%s> / cycle %d\n",
1469__FUNCTION__, process->pid, this->trdid, root_name, path, cycle );
1470#endif
1471
1472    // build extended pointer on lock protecting Inode Tree (in VFS root inode)
1473    vfs_root_xp  = process->vfs_root_xp;
1474    vfs_root_ptr = GET_PTR( root_xp );
1475    vfs_root_cxy = GET_CXY( root_xp );
1476    lock_xp      = XPTR( vfs_root_cxy , &vfs_root_ptr->main_lock );
1477
1478    // take the lock protecting Inode Tree
1479    remote_rwlock_wr_acquire( lock_xp );
1480
1481    // get extended pointer on parent inode
1482    error = vfs_lookup( root_xp,
1483                        path,
1484                        VFS_LOOKUP_PARENT,
1485                        &parent_xp,
1486                        name );
1487    if( error ) 
1488    {
1489        remote_rwlock_wr_release( lock_xp );
1490        printk("\n[ERROR] in %s : cannot get parent inode for <%s> in <%s>\n",
1491        __FUNCTION__, name, path );
1492        return -1;
1493    }
1494
1495    // get parent inode cluster and local pointer
1496    parent_cxy = GET_CXY( parent_xp );
1497    parent_ptr = GET_PTR( parent_xp );
1498 
1499#if( DEBUG_VFS_UNLINK & 1 )
1500char parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
1501vfs_inode_get_name( parent_xp , parent_name );
1502if( DEBUG_VFS_UNLINK < cycle )
1503printk("\n[%s] thread[%x,%x] parent inode <%s> is (%x,%x)\n",
1504__FUNCTION__, process->pid, this->trdid, parent_name, parent_cxy, parent_ptr );
1505#endif
1506
1507    // build extended pointer on parent inode "children" xhtab
1508    xptr_t children_xp = XPTR( parent_cxy , &parent_ptr->children );
1509
1510    // get extended pointer on dentry to unlink
1511    dentry_xp = xhtab_lookup( children_xp , name );
1512   
1513    if( dentry_xp == XPTR_NULL )
1514    {
1515        remote_rwlock_wr_release( lock_xp );
1516        printk("\n[ERROR] in %s : cannot get target dentry <%s> in <%s>\n",
1517        __FUNCTION__, name, path );
1518        return -1;
1519    }
1520   
1521    // get local pointer on dentry to unlink
1522    dentry_ptr = GET_PTR( dentry_xp );
1523
1524#if( DEBUG_VFS_UNLINK & 1 )
1525if( DEBUG_VFS_UNLINK < cycle )
1526printk("\n[%s] thread[%x,%x] dentry <%s> to unlink is (%x,%x)\n",
1527__FUNCTION__, process->pid, this->trdid, name, parent_cxy, dentry_ptr );
1528#endif
1529
1530    // get pointer on target inode
1531    inode_xp  = hal_remote_l64( XPTR( parent_cxy , &dentry_ptr->child_xp ) );
1532    inode_cxy = GET_CXY( inode_xp );
1533    inode_ptr = GET_PTR( inode_xp );
1534 
1535#if( DEBUG_VFS_UNLINK & 1 )
1536char inode_name[CONFIG_VFS_MAX_NAME_LENGTH];
1537vfs_inode_get_name( inode_xp , inode_name );
1538if( DEBUG_VFS_UNLINK < cycle )
1539printk("\n[%s] thread[%x,%x] target inode <%s> is (%x,%x) / cycle %d\n",
1540__FUNCTION__, process->pid, this->trdid, inode_name, inode_cxy, inode_ptr, cycle );
1541#endif
1542
1543    // get target inode "type" and "links"
1544    inode_type   = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->type ) );
1545    inode_links  = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->links ) );
1546
1547// check target inode links counter
1548assert( (inode_links >= 1), "illegal inode links count %d for <%s>\n", inode_links, path );
1549
1550    ///////////////////////////////////////////////////////////////////////
1551    if( (inode_type == INODE_TYPE_FILE) || (inode_type == INODE_TYPE_DIR) )
1552    {
1553        // 1. Release clusters allocated to target inode
1554        //    and synchronize the FAT on IOC device if last link.
1555        if( inode_links == 1 ) 
1556        {
1557            // build extended pointer on target inode "children" number
1558            xptr_t inode_children_xp = XPTR( inode_cxy , &inode_ptr->children.items );
1559
1560            // get target inode number of children
1561            inode_children = hal_remote_l32( inode_children_xp );
1562
1563            // check no children
1564            if( inode_children != 0 )
1565            {
1566                remote_rwlock_wr_release( lock_xp );
1567                printk("\n[ERROR] in %s : cannot remove <%s> inode that has children\n",
1568                __FUNCTION__, path );
1569                return -1;
1570            }
1571
1572            // release clusters on IOC device
1573            error = vfs_fs_release_inode( inode_xp ); 
1574
1575            if( error )
1576            {
1577                remote_rwlock_wr_release( lock_xp );
1578                printk("\n[ERROR] in %s : cannot update FAT mapper to remove <%s> inode\n",
1579                __FUNCTION__ , path );
1580                return -1;
1581            }
1582
1583#if(DEBUG_VFS_UNLINK & 1)
1584if( DEBUG_VFS_UNLINK < cycle )
1585printk("\n[%s] thread[%x,%x] removed <%s> inode from FAT (mapper and IOC device)\n",
1586__FUNCTION__, process->pid, this->trdid, path );
1587#endif
1588        }
1589
1590        // 2. update parent directory mapper
1591        //    and synchronize the parent directory on IOC device
1592        if (parent_cxy == local_cxy)
1593        {
1594            error = vfs_fs_remove_dentry( parent_ptr,
1595                                          dentry_ptr );
1596        }
1597        else           
1598        {
1599            rpc_vfs_fs_remove_dentry_client( parent_cxy,
1600                                             parent_ptr,
1601                                             dentry_ptr,
1602                                             &error );
1603        }
1604
1605        if( error )
1606        {
1607            remote_rwlock_wr_release( lock_xp );
1608            printk("\n[ERROR] in %s : cannot update dentry on device for <%s>\n",
1609            __FUNCTION__ , path );
1610            return -1;
1611        }
1612
1613#if(DEBUG_VFS_UNLINK & 1)
1614if( DEBUG_VFS_UNLINK < cycle )
1615printk("\n[%s] thread[%x,%x] removed <%s> inode from parent dir (mapper and IOC device)\n",
1616__FUNCTION__, process->pid, this->trdid, path );
1617#endif
1618        // 3. remove dentry from Inode Tree (and associated chils inode when last link)
1619        vfs_remove_child_from_parent( dentry_xp );
1620
1621        // release the lock protecting Inode Tree
1622        remote_rwlock_wr_release( lock_xp );
1623
1624#if DEBUG_VFS_UNLINK
1625if( DEBUG_VFS_UNLINK < cycle )
1626printk("\n[%s] thread[%x,%x] exit / removed <%s> inode from Inode Tree / cycle %d\n",
1627__FUNCTION__, process->pid, this->trdid, path, cycle );
1628#endif
1629        return 0;
1630    }
1631    else
1632    {
1633        remote_rwlock_wr_release( lock_xp );
1634        printk("\n[ERROR] in %s : unsupported inode type %s\n",
1635        __FUNCTION__ , vfs_inode_type_str( inode_type ) );
1636        return -1;
1637    }
1638
1639}  // end vfs_unlink()
1640
1641////////////////////////////////////////////////
1642error_t vfs_stat( xptr_t         root_inode_xp,
1643                  char         * path,
1644                  struct stat  * st )
1645{
1646    error_t       error;
1647    xptr_t        inode_xp;           // extended pointer on target inode
1648    vfs_inode_t * inode_ptr;          // local pointer on target inode
1649    cxy_t         inode_cxy;          // target inode cluster identifier
1650    xptr_t        vfs_root_xp;        // extended pointer on VFS root inode
1651    vfs_inode_t * vfs_root_ptr;       // local_pointer on VFS root inode
1652    cxy_t         vfs_root_cxy;       // VFS root inode cluster identifier
1653    xptr_t        lock_xp;            // extended pointer on lock protecting Inode Tree
1654
1655    thread_t  * this    = CURRENT_THREAD;
1656    process_t * process = this->process;
1657
1658    // build extended pointer on lock protecting Inode Tree (in VFS root inode)
1659    vfs_root_xp  = process->vfs_root_xp;
1660    vfs_root_ptr = GET_PTR( vfs_root_xp );
1661    vfs_root_cxy = GET_CXY( vfs_root_xp );
1662    lock_xp      = XPTR( vfs_root_cxy , &vfs_root_ptr->main_lock );
1663
1664    // get the lock protecting Inode Tree in read mode
1665    remote_rwlock_rd_acquire( lock_xp );
1666
1667    // get extended pointer on target inode
1668    error = vfs_lookup( root_inode_xp,
1669                        path,
1670                        0,
1671                        &inode_xp,
1672                        NULL );
1673
1674    // release the lock protecting Inode Tree
1675    remote_rwlock_rd_release( lock_xp );
1676
1677    if( error )
1678    {
1679        printk("\n[ERROR] in %s : cannot found inode <%s>\n",
1680        __FUNCTION__ , path );
1681        return -1;
1682    }
1683
1684    // get cluster and local pointer on inode descriptor
1685    inode_ptr = GET_PTR( inode_xp );
1686    inode_cxy = GET_CXY( inode_xp );
1687
1688    // get relevant infos from inode descriptor
1689    uint32_t inum   = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->inum   ) );
1690    uint32_t size   = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->size   ) );
1691    uint32_t uid    = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->uid    ) );
1692    uint32_t gid    = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->gid    ) );
1693    uint32_t type   = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->type   ) );
1694    uint32_t rights = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->rights ) );
1695
1696    // set stat structure fields
1697    st->st_ino  = inum;
1698    st->st_gid  = gid;
1699    st->st_uid  = uid;
1700    st->st_size = size;
1701    st->st_mode = (type << 16) | rights;
1702
1703#if DEBUG_VFS_STAT
1704uint32_t cycle  = (uint32_t)hal_get_cycles();
1705if( DEBUG_VFS_STAT < cycle )
1706printk("\n[%s] thread[%x,%x] set stat %x for inode %x in cluster %x / cycle %d\n"
1707       " %s / inum %d / size %d\n",
1708__FUNCTION__, process->pid, this->trdid, st, inode_ptr, inode_cxy, cycle,
1709vfs_inode_type_str( type ), inum, size );
1710#endif
1711
1712    return 0;
1713
1714}  // end vfs_stat()
1715
1716/////////////////////////////////////////////
1717error_t vfs_readdir( xptr_t          file_xp,
1718                     struct dirent * k_dirent )
1719{
1720    assert( false , "not implemented file_xp: %x, k_dirent ptr %x\n",
1721      file_xp, k_dirent );
1722    return 0;
1723}
1724
1725////////////////////////////////////
1726error_t vfs_rmdir( xptr_t   file_xp,
1727                   char   * path )
1728{
1729    assert( false , "not implemented file_xp: %x, path <%s>\n",
1730      file_xp, path );
1731    return 0;
1732}
1733
1734////////////////////////////////////
1735error_t vfs_chdir( xptr_t   root_xp,
1736                   char   * path )
1737{
1738    error_t           error;
1739    xptr_t            inode_xp;           // extended pointer on target inode
1740    cxy_t             inode_cxy;          // target inode cluster identifier       
1741    vfs_inode_t     * inode_ptr;          // target inode local pointer
1742    vfs_inode_type_t  inode_type;         // target inode type
1743    xptr_t            vfs_root_xp;        // extended pointer on VFS root inode
1744    vfs_inode_t     * vfs_root_ptr;       // local_pointer on VFS root inode
1745    cxy_t             vfs_root_cxy;       // VFS root inode cluster identifier
1746    xptr_t            main_lock_xp;       // extended pointer on lock protecting Inode Tree
1747    xptr_t            ref_xp;             // extended pointer on reference process
1748    process_t       * ref_ptr;            // local pointer on reference process
1749    cxy_t             ref_cxy;            // reference process cluster
1750    xptr_t            cwd_lock_xp;        // extended pointer on lock protecting CWD change
1751    xptr_t            cwd_xp_xp;          // extended pointer on cwd_xp in reference process
1752
1753    thread_t  * this    = CURRENT_THREAD;
1754    process_t * process = this->process;
1755
1756#if DEBUG_VFS_CHDIR
1757uint32_t cycle = (uint32_t)hal_get_cycles();
1758if( DEBUG_VFS_CHDIR < cycle )
1759printk("\n[%s] thread[%x,%x] enter for path <%s> / cycle %d\n",
1760__FUNCTION__, process->pid, this->trdid, path, cycle );
1761#endif
1762
1763    // build extended pointer on lock protecting Inode Tree (in VFS root inode)
1764    vfs_root_xp  = process->vfs_root_xp;
1765    vfs_root_ptr = GET_PTR( vfs_root_xp );
1766    vfs_root_cxy = GET_CXY( vfs_root_xp );
1767    main_lock_xp = XPTR( vfs_root_cxy , &vfs_root_ptr->main_lock );
1768
1769    // take lock protecting Inode Tree in read mode
1770    remote_rwlock_rd_acquire( main_lock_xp );
1771
1772    // get extended pointer on target inode
1773    error = vfs_lookup( root_xp,
1774                        path,
1775                        VFS_LOOKUP_DIR,
1776                        &inode_xp,
1777                        NULL );
1778
1779    // release lock protecting Inode Tree in read mode
1780    remote_rwlock_rd_release( main_lock_xp );
1781
1782    if( error ) 
1783    {
1784        printk("\n[ERROR] in %s : <%s> not found\n",
1785        __FUNCTION__, path );
1786        return -1;
1787    }
1788
1789    // get inode type from remote file
1790    inode_cxy = GET_CXY( inode_xp );
1791    inode_ptr = GET_PTR( inode_xp );
1792    inode_type = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->type ) );
1793
1794    if( inode_type != INODE_TYPE_DIR )
1795    {
1796        printk("\n[ERROR] in %s : <%s> is not a directory\n",
1797        __FUNCTION__, path );
1798        return -1;
1799    }
1800
1801    // build extended pointer on cwd_lock and cwd_xp
1802    ref_xp       = process->ref_xp;
1803    ref_ptr      = GET_PTR( ref_xp );
1804    ref_cxy      = GET_CXY( ref_xp );
1805    cwd_lock_xp  = XPTR( ref_cxy , &ref_ptr->cwd_lock );
1806    cwd_xp_xp    = XPTR( ref_cxy , &ref_ptr->cwd_xp );
1807
1808    // take lock protecting CWD changes
1809    remote_busylock_acquire( cwd_lock_xp );
1810
1811    // update cwd_xp field in reference process descriptor
1812    hal_remote_s64( cwd_xp_xp , inode_xp );
1813
1814    // release lock protecting CWD changes
1815    remote_busylock_release( cwd_lock_xp );
1816
1817#if DEBUG_VFS_CHDIR
1818cycle = (uint32_t)hal_get_cycles();
1819if( DEBUG_VFS_CHDIR < cycle )
1820printk("\n[%s] thread[%x,%x] exit : inode (%x,%x) / &cwd_xp (%x,%x) / cycle %d\n",
1821__FUNCTION__, process->pid, this->trdid, inode_cxy, inode_ptr, 
1822GET_CXY(cwd_xp_xp), GET_PTR(cwd_xp_xp), cycle );
1823#endif
1824
1825    return 0;
1826
1827}  // end vfs_chdir()
1828
1829///////////////////////////////////
1830error_t vfs_chmod( xptr_t   cwd_xp,
1831                   char   * path,
1832                   uint32_t rights )
1833{
1834    error_t           error;
1835    xptr_t            inode_xp;     // extended pointer on target inode
1836    cxy_t             inode_cxy;    // inode cluster identifier       
1837    vfs_inode_t     * inode_ptr;    // inode local pointer
1838    vfs_inode_type_t  inode_type;   // target inode type
1839
1840    // set lookup working mode
1841    assert( (rights == 0), __FUNCTION__,
1842    "access rights non implemented yet\n" );
1843 
1844    // get extended pointer on target inode
1845    error = vfs_lookup( cwd_xp,
1846                        path,
1847                        0,
1848                        &inode_xp,
1849                        NULL );
1850
1851    if( error ) return error;
1852
1853    // get inode cluster and local pointer
1854    inode_cxy = GET_CXY( inode_xp );
1855    inode_ptr = GET_PTR( inode_xp );
1856   
1857    // get inode type from remote inode
1858    inode_type = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->type ) );
1859
1860    // TODO implement this function
1861
1862assert( false , "not implemented\n" );
1863
1864    return 0;
1865}
1866
1867///////////////////////////////////
1868error_t vfs_mkfifo( xptr_t   cwd_xp,
1869                    char   * path,
1870                    uint32_t rights )
1871{
1872    assert( false , "not implemented cwd_xp: %x, path <%s>, rights %x\n",
1873      cwd_xp, path, rights );
1874    return 0;
1875}
1876
1877
1878
1879//////////////////////////////////////////////////////////////////////////////////////////
1880//       Distributed Inode Tree access related functions
1881//////////////////////////////////////////////////////////////////////////////////////////
1882
1883//////////////////////////////////////////////////////////////////////////
1884// This static function is called by the vfs_display() function.
1885// that is supposed to take the TXT0 lock.
1886//////////////////////////////////////////////////////////////////////////
1887static void vfs_recursive_display( xptr_t   inode_xp,
1888                                   xptr_t   name_xp,
1889                                   uint32_t indent )
1890{
1891    cxy_t              inode_cxy;
1892    vfs_inode_t      * inode_ptr;
1893    vfs_inode_type_t   inode_type;
1894    uint32_t           inode_size;
1895    uint32_t           inode_inum;
1896    uint32_t           inode_attr;
1897    uint32_t           inode_dirty;
1898    xptr_t             children_xp;    // extended pointer on children xhtab
1899
1900    xptr_t             child_dentry_xp;
1901    cxy_t              child_dentry_cxy;
1902    vfs_dentry_t     * child_dentry_ptr;
1903    xptr_t             child_inode_xp;
1904    xptr_t             child_dentry_name_xp;
1905    mapper_t         * mapper_ptr;
1906
1907    char               name[CONFIG_VFS_MAX_NAME_LENGTH];
1908
1909    char *             indent_str[] = { "",                                  // level 0
1910                                        "  ",                                // level 1
1911                                        "    ",                              // level 2
1912                                        "      ",                            // level 3
1913                                        "        ",                          // level 4
1914                                        "          ",                        // level 5
1915                                        "            ",                      // level 6
1916                                        "              ",                    // level 7
1917                                        "                ",                  // level 8
1918                                        "                  ",                // level 9
1919                                        "                    ",              // level 10
1920                                        "                      ",            // level 11
1921                                        "                        ",          // level 12
1922                                        "                          ",        // level 13
1923                                        "                            ",      // level 14
1924                                        "                              " };  // level 15
1925
1926assert( (inode_xp != XPTR_NULL) , "inode_xp cannot be NULL\n" );
1927assert( (name_xp  != XPTR_NULL) , "name_xp cannot be NULL\n" );
1928assert( (indent < 16)           , "depth cannot be larger than 15\n" );
1929   
1930    // get current inode cluster and local pointer
1931    inode_cxy = GET_CXY( inode_xp );
1932    inode_ptr = GET_PTR( inode_xp );
1933
1934    // get inode type, size, attr, mapper, and inum
1935    inode_type = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->type   ) );
1936    inode_size = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->size   ) );
1937    inode_inum = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->inum   ) );
1938    inode_attr = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->attr   ) );
1939    mapper_ptr = hal_remote_lpt( XPTR( inode_cxy , &inode_ptr->mapper ) );
1940
1941    // make a local copy of node name
1942    hal_remote_strcpy( XPTR( local_cxy , name ) , name_xp );
1943
1944    // compute dirty
1945    inode_dirty = ((inode_attr & INODE_ATTR_DIRTY) != 0);
1946
1947    // display inode
1948    nolock_printk("%s%s <%s> : inum %d / %d bytes / dirty %d / cxy %x (inode %x / mapper %x)\n",
1949                  indent_str[indent], vfs_inode_type_str( inode_type ), name,
1950                  inode_inum, inode_size, inode_dirty, inode_cxy, inode_ptr, mapper_ptr );
1951
1952    // scan directory entries when current inode is a directory
1953    // don't scan the the "." and ".." directories to break loops
1954    if( (inode_type == INODE_TYPE_DIR) && 
1955        (strcmp( name , "." ) != 0)    &&
1956        (strcmp( name , ".." ) != 0) )
1957    {
1958        // get extended pointer on directory entries xhtab
1959        children_xp =  XPTR( inode_cxy , &inode_ptr->children );
1960
1961        // get xhtab lock
1962        xhtab_lock( children_xp );
1963
1964        // get first dentry from xhtab
1965        child_dentry_xp = xhtab_get_first( children_xp );
1966
1967        while( child_dentry_xp != XPTR_NULL )
1968        {
1969            // get dentry cluster and local pointer
1970            child_dentry_cxy = GET_CXY( child_dentry_xp );
1971            child_dentry_ptr = GET_PTR( child_dentry_xp );
1972
1973            // get extended pointer on child inode
1974            child_inode_xp = hal_remote_l64( XPTR( child_dentry_cxy,
1975                                                   &child_dentry_ptr->child_xp ) );
1976
1977            // get extended pointer on dentry name
1978            child_dentry_name_xp = XPTR( child_dentry_cxy , &child_dentry_ptr->name );
1979
1980            // recursive call on inode display
1981            vfs_recursive_display( child_inode_xp,
1982                                   child_dentry_name_xp,
1983                                   indent+1 );
1984
1985            // get next dentry
1986            child_dentry_xp = xhtab_get_next( children_xp );
1987        }
1988
1989        // release xhtab lock
1990        xhtab_unlock( children_xp );
1991    }
1992}  // end vfs_recursive_display()
1993
1994///////////////////////////////////
1995void vfs_display( xptr_t inode_xp )
1996{
1997    xptr_t         name_xp;
1998    xptr_t         dentry_xp; 
1999    cxy_t          dentry_cxy;
2000    vfs_dentry_t * dentry_ptr;
2001    xptr_t         parents_root_xp;   // root of parent dentries xlist
2002
2003    // get target inode cluster and local pointer
2004    cxy_t         inode_cxy = GET_CXY( inode_xp );
2005    vfs_inode_t * inode_ptr = GET_PTR( inode_xp );
2006
2007    // build extended pointer on parents dentries root
2008    parents_root_xp = XPTR( inode_cxy , &inode_ptr->parents );
2009
2010    // check VFS root     
2011    if( xlist_is_empty( parents_root_xp ) )  // inode is the VFS root
2012    {
2013        // build extended pointer on root name
2014        name_xp = XPTR( local_cxy , "/" );
2015    }
2016    else
2017    {
2018        // get first parent dentry cluster and pointers
2019        dentry_xp  = XLIST_FIRST( parents_root_xp , vfs_dentry_t , parents );
2020        dentry_cxy = GET_CXY( dentry_xp );
2021        dentry_ptr = GET_PTR( dentry_xp );
2022
2023        // get extended pointer on dentry name
2024        name_xp = XPTR( dentry_cxy , &dentry_ptr->name );
2025    }
2026
2027    // get pointers on TXT0 chdev
2028    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
2029    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
2030    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
2031
2032    // get extended pointer on remote TXT0 chdev lock
2033    xptr_t  lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
2034
2035    // get TXT0 lock in busy waiting mode
2036    remote_busylock_acquire( lock_xp );
2037
2038    // print header
2039    nolock_printk("\n***** file system state\n\n");
2040
2041    // call recursive function
2042    vfs_recursive_display( inode_xp , name_xp , 0 );
2043
2044    // release lock
2045    remote_busylock_release( lock_xp );
2046
2047}  // end vfs_display()
2048
2049/*
2050//////////////////////////////////////////////////////////////////////////////////////////
2051// This static function is used by the vfs_lookup() function.
2052// It takes an extended pointer on a remote inode (parent directory inode),
2053// and check access_rights violation for the calling thread.
2054// It can be used by any thread running in any cluster.
2055//////////////////////////////////////////////////////////////////////////////////////////
2056// @ inode_xp    : extended pointer on inode.
2057// @ client_uid  : client thread user ID
2058// @ client_gid  : client thread group ID
2059// @ return true if access rights are violated.
2060//////////////////////////////////////////////////////////////////////////////////////////
2061static bool_t vfs_access_denied( xptr_t   inode_xp,
2062                          uint32_t client_uid,
2063                          uint32_t client_gid )
2064{
2065    // get found inode cluster and local pointer
2066    cxy_t         inode_cxy = GET_CXY( inode_xp );
2067    vfs_inode_t * inode_ptr = GET_PTR( inode_xp );
2068
2069    // get inode access mode, UID, and GID
2070    // TODO uint32_t  mode = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->mode ) );
2071    uid_t     uid  = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->uid  ) );
2072    gid_t     gid  = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->gid  ) );
2073
2074    // FIXME : me must use mode
2075    if( (uid == client_uid) || (gid == client_gid) ) return false;
2076    else                                             return true;
2077}
2078*/
2079
2080//////////////////////////////////////////////////////////////////////////////////////////
2081// This static function is used by the vfs_lookup() function.
2082// It takes an extended pointer on a remote parent directory inode, a directory
2083// entry name, and returns an extended pointer on the child inode.
2084// It can be used by any thread running in any cluster.
2085//////////////////////////////////////////////////////////////////////////////////////////
2086// @ parent_xp   : extended pointer on parent inode in remote cluster.
2087// @ name        : dentry name
2088// @ child_xp    : [out] buffer for extended pointer on child inode.
2089// @ return true if success / return false if not found.
2090//////////////////////////////////////////////////////////////////////////////////////////
2091static bool_t vfs_get_child( xptr_t   parent_xp,
2092                             char   * name,
2093                             xptr_t * child_xp )
2094{
2095    xptr_t         xhtab_xp;    // extended pointer on hash table for children dentries
2096    xptr_t         dentry_xp;   // extended pointer on children dentry
2097    cxy_t          dentry_cxy;
2098    vfs_dentry_t * dentry_ptr;
2099
2100    // get parent inode cluster and local pointer
2101    cxy_t         parent_cxy = GET_CXY( parent_xp );
2102    vfs_inode_t * parent_ptr = GET_PTR( parent_xp );
2103
2104    // get extended pointer on hash table of children directory entries
2105    xhtab_xp = XPTR( parent_cxy , &parent_ptr->children );
2106
2107    // get pointers on matching dentry
2108    dentry_xp  = xhtab_lookup( xhtab_xp , name );
2109    dentry_cxy = GET_CXY( dentry_xp );
2110    dentry_ptr = GET_PTR( dentry_xp );
2111
2112    if( dentry_xp == XPTR_NULL ) 
2113    {
2114        return false;
2115    }
2116    else
2117    {
2118        *child_xp = (xptr_t)hal_remote_l64( XPTR( dentry_cxy , &dentry_ptr->child_xp ) );
2119        return true;
2120    }
2121
2122}  // end vfs_get_child()
2123
2124//////////////////////////////////////////////////////////////////////////////////////////
2125// This static function is used by the vfs_lookup() function.
2126// It takes the <current> pointer on a buffer containing a complete pathname, and return
2127// in the <name> buffer, allocated by the caller, a single name in the path.
2128// It return also in the <next> pointer the next character to analyse in the path.
2129// Finally it returns a <last> boolean, that is true when the returned <name> is the
2130// last name in the path. The names are supposed to be separated by one or several '/'
2131// characters, that are not written in  the <name> buffer.
2132//
2133// WARNING: the leading characters '/' in the path are skiped before analysis.
2134//          The path "/" identifies the VFS root, and is therefore anaysed as an empty
2135//          string. This empty string is dignaled by the (-1) return value. 
2136//////////////////////////////////////////////////////////////////////////////////////////
2137// @ current   : pointer on first character to analyse in buffer containing the path.
2138// @ name      : [out] pointer on buffer allocated by the caller for the returned name.
2139// @ next      : [out] pointer on next character to analyse in buffer containing the path.
2140// @ last      : [out] true if the returned name is the last (NUL character found).
2141// @ return 0 if success / return -1 if string empty (first chracter is NUL).
2142//////////////////////////////////////////////////////////////////////////////////////////
2143static error_t vfs_get_name_from_path( char     * current,
2144                                       char     * name,
2145                                       char    ** next,
2146                                       bool_t   * last )
2147{
2148    char * ptr = current;
2149
2150    // skip leading '/' characters
2151    while( *ptr == '/' ) ptr++;
2152
2153    // signal empty string
2154    if( *ptr == 0 )
2155    {
2156        *last = true;
2157        return -1;
2158    }
2159
2160    // copy all characters in name until NUL or '/'
2161    while( (*ptr != 0) && (*ptr !='/') )  *(name++) = *(ptr++);
2162
2163    // set NUL terminating character in name buffer
2164    *(name++) = 0;
2165
2166    // return last an next
2167    if( *ptr == 0 )             // last found character is NUL => last name in path
2168    {
2169        *last = true;
2170    }
2171    else                        // last found character is '/' => skip it
2172    {
2173        *last = false;
2174        *next = ptr + 1;
2175    }
2176
2177    return 0;
2178
2179}  // end vfs_get name_from_path()
2180   
2181///////////////////////////////////////////////
2182error_t vfs_lookup( xptr_t             root_xp,
2183                    char             * pathname,
2184                    uint32_t           lookup_mode,
2185                                        xptr_t           * inode_xp,
2186                                        char             * last_name )
2187{
2188    char               name[CONFIG_VFS_MAX_NAME_LENGTH];   // one name in path
2189
2190    xptr_t             parent_xp;    // extended pointer on parent inode
2191    cxy_t              parent_cxy;   // cluster for parent inode
2192    vfs_inode_t      * parent_ptr;   // local pointer on parent inode 
2193    xptr_t             dentry_xp;    // extended pointer on dentry       
2194    xptr_t             child_xp;     // extended pointer on child inode
2195    cxy_t              child_cxy;    // cluster for child inode
2196    vfs_inode_t      * child_ptr;    // local pointer on child inode
2197    vfs_inode_type_t   child_type;   // child inode type
2198    vfs_fs_type_t      fs_type;      // File system type
2199    vfs_ctx_t        * ctx_ptr;      // local pointer on FS context
2200    char             * current;      // current pointer on path
2201    char             * next;         // next value for current pointer   
2202    bool_t             last;         // true when the name is the last in path
2203    bool_t             found;        // true when a child has been found
2204    bool_t             dir;          // searched inode is a directory
2205    bool_t             create;       // searched inode must be created if not found
2206    bool_t             excl;         // searched inode must not exist
2207    bool_t             par;          // searched inode is the parent
2208    thread_t         * this;         // pointer on calling thread descriptor
2209    process_t        * process;      // pointer on calling process descriptor
2210    error_t            error;
2211
2212    this    = CURRENT_THREAD;
2213    process = this->process;
2214
2215// check pathname / root_xp consistency
2216assert( ((pathname[0] != '/') || (root_xp == process->vfs_root_xp)), 
2217"root inode must be VFS root for path <%s>\n", pathname );
2218
2219#if DEBUG_VFS_LOOKUP
2220uint32_t cycle = (uint32_t)hal_get_cycles();
2221char     root_name[CONFIG_VFS_MAX_NAME_LENGTH];
2222vfs_inode_get_name( root_xp , root_name );
2223if( DEBUG_VFS_LOOKUP < cycle )
2224printk("\n[%s] thread[%x,%x] enter / root <%s> / path <%s> / mode %x / cycle %d\n",
2225__FUNCTION__, process->pid, this->trdid, root_name, pathname, lookup_mode, cycle );
2226#endif
2227
2228    // compute lookup flags
2229    dir    = (lookup_mode & VFS_LOOKUP_DIR)    == VFS_LOOKUP_DIR;
2230    create = (lookup_mode & VFS_LOOKUP_CREATE) == VFS_LOOKUP_CREATE;
2231    excl   = (lookup_mode & VFS_LOOKUP_EXCL)   == VFS_LOOKUP_EXCL;
2232    par    = (lookup_mode & VFS_LOOKUP_PARENT) == VFS_LOOKUP_PARENT;
2233
2234    // initialise loop variables
2235    parent_xp = root_xp;
2236    current   = pathname;
2237    next      = NULL;
2238    last      = false;
2239    child_xp  = XPTR_NULL;
2240
2241    // loop on nodes in pathname
2242    // load from device if one node in path not found in Inode Tree
2243    // exit loop when last name found (i.e. last == true)
2244    while( 1 )
2245    {
2246        // get parent inode cluster and local pointer
2247        parent_cxy = GET_CXY( parent_xp );
2248        parent_ptr = GET_PTR( parent_xp );
2249
2250        // get one "name" from path, and "last" flag
2251        error = vfs_get_name_from_path( current , name , &next , &last );
2252
2253        // handle VFS root case
2254        if ( error )
2255        {
2256
2257#if DEBUG_VFS_LOOKUP
2258cycle = (uint32_t)hal_get_cycles();
2259if( DEBUG_VFS_LOOKUP < cycle )
2260printk("\n[%s] thread[%x,%x] exit / parent inode(%x,%x) / <%s> / cycle %d\n",
2261__FUNCTION__ , process->pid, this->trdid, parent_cxy, parent_ptr, pathname, cycle );
2262#endif
2263            *inode_xp = process->vfs_root_xp;
2264            break;
2265        }
2266
2267#if (DEBUG_VFS_LOOKUP & 1)
2268if( DEBUG_VFS_LOOKUP < cycle )
2269printk("\n[%s] thread[%x,%x] look for <%s> in <%s> / last = %d\n",
2270__FUNCTION__, process->pid, this->trdid, name, pathname, last );
2271#endif
2272
2273        // search the child dentry matching name in parent inode
2274        found = vfs_get_child( parent_xp,
2275                               name,
2276                               &child_xp );
2277
2278        // get child inode local pointer and cluster
2279        child_ptr  = GET_PTR( child_xp );
2280        child_cxy  = GET_CXY( child_xp );
2281
2282        // analyse found & last, depending on lookup_mode
2283        if( found == false )                              // not found in Inode Tree
2284        {
2285            // when a inode is not found in the Inode Tree:
2286            // - if (last and par) the Inode Tree is not modified
2287            // - else we speculatively introduce a new (dentry/inode) in inode tree,
2288            //        and scan the parent directory mapper to initialise it.
2289            //     . if it is not found in the parent mapper:
2290            //         - if(last and create), a brand new file or directory is created
2291            //         - else, an error is reported
2292            //     . if it is found in parent mapper:
2293            //         - if( last and excl ), an error is reported
2294            //         - else the new child (inode & dentry) is initialised in Inode Tree
2295            //         - if the child is a directory, the child mapper is loaded from device
2296
2297            if( last && par )   //  does nothing
2298            {
2299
2300#if (DEBUG_VFS_LOOKUP & 1)
2301if( DEBUG_VFS_LOOKUP < cycle )
2302printk("\n[%s] thread[%x,%x] child not found but only parent requested in <%s>\n",
2303__FUNCTION__, process->pid, this->trdid, pathname );
2304#endif
2305            }
2306            else                                    // try to get it from parent mapper
2307            {
2308
2309#if (DEBUG_VFS_LOOKUP & 1)
2310if( DEBUG_VFS_LOOKUP < cycle )
2311printk("\n[%s] thread[%x,%x] miss <%s> inode in Inode Tree => build from parent mapper\n",
2312__FUNCTION__, process->pid, this->trdid, name );
2313#endif
2314                // get parent inode FS type
2315                ctx_ptr    = hal_remote_lpt( XPTR( parent_cxy,&parent_ptr->ctx ) );
2316                fs_type    = hal_remote_l32( XPTR( parent_cxy , &ctx_ptr->type ) );
2317
2318                // select a cluster for new inode
2319                child_cxy = cluster_random_select();
2320
2321                // define child inode type
2322                if( dir ) child_type = INODE_TYPE_DIR;
2323                else      child_type = INODE_TYPE_FILE;
2324 
2325                // insert a new child dentry/inode couple in inode tree
2326                error = vfs_add_child_in_parent( child_cxy,
2327                                                 child_type, 
2328                                                 fs_type, 
2329                                                 parent_xp, 
2330                                                 name, 
2331                                                 &dentry_xp,
2332                                                 &child_xp );
2333                if( error )
2334                {
2335                    printk("\n[ERROR] in %s : cannot create inode <%s> in path <%s>\n",
2336                    __FUNCTION__ , name, pathname );
2337                    return -1;
2338                }
2339
2340                // get child inode local pointer
2341                child_ptr = GET_PTR( child_xp );
2342
2343#if (DEBUG_VFS_LOOKUP & 1)
2344if( DEBUG_VFS_LOOKUP < cycle )
2345printk("\n[%s] thread[%x,%x] created missing inode <%s> in cluster %x\n",
2346__FUNCTION__, process->pid, this->trdid, name, child_cxy );
2347#endif
2348                // scan parent mapper to find the missing dentry, and complete
2349                // the initialisation of dentry and child inode descriptors
2350                if( parent_cxy == local_cxy )
2351                {
2352                    error = vfs_fs_get_dentry( parent_ptr,
2353                                               name,
2354                                               child_xp );
2355                }
2356                else
2357                {
2358                    rpc_vfs_fs_get_dentry_client( parent_cxy,
2359                                                  parent_ptr,
2360                                                  name,
2361                                                  child_xp,
2362                                                  &error );
2363                }
2364
2365                if ( error )   // child not found in parent mapper
2366                {
2367                    if ( last && create )  // add a brand new dentry in parent
2368                    {
2369                        error = vfs_new_dentry_init( parent_xp,               
2370                                                     dentry_xp,
2371                                                     child_xp );
2372                        if ( error )
2373                        {
2374                            printk("\n[ERROR] in %s : cannot init inode <%s> in path <%s>\n",
2375                            __FUNCTION__, name, pathname );
2376                            vfs_remove_child_from_parent( dentry_xp );
2377                            return -1;
2378                        }
2379
2380#if (DEBUG_VFS_LOOKUP & 1)
2381if( DEBUG_VFS_LOOKUP < cycle )
2382printk("\n[%s] thread[%x,%x] child <%s> not found in parent mapper => create it\n",
2383__FUNCTION__, process->pid, this->trdid, name );
2384#endif
2385                    }
2386                    else                   // not last or not create => error
2387                    {                       
2388                        printk("\n[ERROR] in %s : <%s> node not found in parent for <%s>\n",
2389                        __FUNCTION__ , name , pathname );
2390                        vfs_remove_child_from_parent( dentry_xp );
2391                        return -1;
2392                    }
2393                }
2394                else          // child has been found in parent mapper
2395                {
2396                    // check the excl
2397                    if( last && create && excl )
2398                    {
2399                        printk("\n[ERROR] in %s : node already exist <%s>\n",
2400                        __FUNCTION__, name );
2401                       return -1;
2402                    }
2403
2404#if (DEBUG_VFS_LOOKUP & 1)
2405if( DEBUG_VFS_LOOKUP < cycle )
2406printk("\n[%s] thread[%x,%x] initialised inode <%s> from parent mapper\n",
2407__FUNCTION__, process->pid, this->trdid, name );
2408#endif
2409                    // load child mapper from device if child is a directory (prefetch)
2410                    uint32_t type = hal_remote_l32( XPTR( child_cxy , &child_ptr->type ) );
2411                    if( type == INODE_TYPE_DIR ) 
2412                    {
2413                        if( child_cxy == local_cxy )
2414                        {
2415                            error = vfs_inode_load_all_pages( child_ptr );
2416                        }
2417                        else
2418                        {
2419                            rpc_vfs_inode_load_all_pages_client( child_cxy,
2420                                                                 child_ptr,
2421                                                                 &error );
2422                        }
2423                        if ( error )
2424                        {
2425                            printk("\n[ERROR] in %s : cannot load <%s> from device\n",
2426                            __FUNCTION__ , name );
2427                            vfs_remove_child_from_parent( dentry_xp );
2428                            return -1;
2429                        }
2430
2431#if (DEBUG_VFS_LOOKUP & 1)
2432if( DEBUG_VFS_LOOKUP < cycle )
2433printk("\n[%s] thread[%x,%x] loaded directory mapper for <%s> from IOC\n",
2434__FUNCTION__ , process->pid, this->trdid, name );
2435#endif
2436                    }
2437                }
2438            }
2439        }
2440        else                                    // child directly found in inode tree
2441        {
2442       
2443#if (DEBUG_VFS_LOOKUP & 1)
2444if( DEBUG_VFS_LOOKUP < cycle )
2445printk("\n[%s] thread[%x,%x] found <%s> in Inode Tree / inode (%x,%x)\n",
2446__FUNCTION__, process->pid, this->trdid, name, child_cxy, child_ptr );
2447#endif
2448            // check the excl flag
2449            if( last && create && excl )
2450            {
2451                printk("\n[ERROR] in %s : node <%s> already exist\n",
2452                __FUNCTION__, name );
2453                return -1;
2454            }
2455        }
2456
2457        // TODO check access rights here [AG]
2458        // error = vfs_access_denied( child_xp,
2459        //                            client_uid,
2460        //                            client_gid );
2461        // if( error )
2462        // {
2463        //     printk("\n[ERROR] in %s : thread %x / permission denied for %s\n",
2464        //     __FUNCTION__ , this , name );
2465        //     return EACCES;
2466        // }
2467
2468        // take lock on child inode and release lock on parent
2469        // vfs_inode_lock( child_xp );
2470        // vfs_inode_unlock( parent_xp );
2471
2472        // exit when last
2473        if ( last )           // last inode in path  => return relevant info
2474        {
2475            if ( par )  // return parent inode and child name
2476            {
2477
2478#if DEBUG_VFS_LOOKUP
2479cycle = (uint32_t)hal_get_cycles();
2480if( DEBUG_VFS_LOOKUP < cycle )
2481printk("\n[%s] thread[%x,%x] exit / parent inode(%x,%x) / <%s> / cycle %d\n",
2482__FUNCTION__ , process->pid, this->trdid, parent_cxy, parent_ptr, pathname, cycle );
2483#endif
2484                *inode_xp = parent_xp;
2485                strcpy( last_name , name );
2486                break; 
2487            }
2488            else        // return child inode name     
2489            {
2490
2491#if DEBUG_VFS_LOOKUP
2492cycle = (uint32_t)hal_get_cycles();
2493if( DEBUG_VFS_LOOKUP < cycle )
2494printk("\n[%s] thread[%x,%x] exit / child inode (%x,%x) / <%s> / cycle %d\n",
2495__FUNCTION__ , process->pid, this->trdid, child_cxy, child_ptr, pathname, cycle );
2496#endif
2497                *inode_xp = child_xp;
2498                break;
2499            }
2500        }
2501        else                     // not the last inode in path => update loop variables
2502        {
2503            parent_xp = child_xp;
2504            current   = next;
2505        }
2506    }
2507
2508    return 0;
2509
2510}  // end vfs_lookup()
2511
2512////////////////////////////////////////////////
2513error_t vfs_new_dentry_init( xptr_t   parent_xp,
2514                             xptr_t   dentry_xp,
2515                             xptr_t   child_xp )
2516{
2517    error_t     error;
2518    uint32_t    cluster;
2519    uint32_t    child_type;
2520    uint32_t    child_size;
2521
2522#if DEBUG_VFS_NEW_CHILD_INIT
2523char parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
2524char child_name[CONFIG_VFS_MAX_NAME_LENGTH];
2525vfs_inode_get_name( parent_xp , parent_name );
2526vfs_inode_get_name( child_xp  , child_name );
2527uint32_t   cycle = (uint32_t)hal_get_cycles();
2528thread_t * this  = CURRENT_THREAD;
2529if( DEBUG_VFS_NEW_CHILD_INIT < cycle )
2530printk("\n[%s] thread[%x,%x] enter / parent <%s> / child <%s> / cycle %d\n",
2531__FUNCTION__ , this->process->pid, this->trdid, parent_name, child_name, cycle );
2532#endif
2533
2534    // get parent inode cluster and local pointer
2535    cxy_t          parent_cxy = GET_CXY( parent_xp );
2536    vfs_inode_t  * parent_ptr = GET_PTR( parent_xp );
2537
2538    // get dentry local pointer
2539    vfs_dentry_t * dentry_ptr = GET_PTR( dentry_xp );
2540
2541    // get child inode cluster and local pointer
2542    cxy_t          child_cxy  = GET_CXY( child_xp );
2543    vfs_inode_t  * child_ptr  = GET_PTR( child_xp );
2544
2545    // 1. allocate one free cluster to child inode
2546    // depending on the child inode FS type
2547    vfs_ctx_t * ctx = hal_remote_lpt( XPTR( child_cxy , &child_ptr->ctx ) );
2548
2549    error = vfs_fs_cluster_alloc( ctx->type,
2550                                  &cluster );
2551    if ( error )
2552    {
2553        printk("\n[ERROR] in %s : cannot find a free VFS cluster\n",
2554        __FUNCTION__ );
2555        return -1;
2556    }
2557
2558#if( DEBUG_VFS_NEW_CHILD_INIT & 1)
2559if( DEBUG_VFS_NEW_CHILD_INIT < cycle )
2560printk("\n[%s] thread[%x,%x] allocated one FAT cluster to <%s>\n",
2561__FUNCTION__ , this->process->pid, this->trdid, child_name );
2562#endif
2563
2564    // 2. update the child inode descriptor
2565    child_type = hal_remote_l32( XPTR( child_cxy , &child_ptr->type ) );
2566    child_size = (child_type == INODE_TYPE_DIR) ? 4096 : 0;
2567   
2568    hal_remote_s32( XPTR( child_cxy , &child_ptr->size )   , child_size );
2569    hal_remote_spt( XPTR( child_cxy , &child_ptr->extend ) , (void*)(intptr_t)cluster );
2570
2571    // 3. update the parent inode mapper, and
2572    // update the dentry extension if required
2573    if( local_cxy == parent_cxy )
2574    {
2575        error = vfs_fs_add_dentry( parent_ptr,
2576                                   dentry_ptr );
2577    }
2578    else
2579    {
2580        rpc_vfs_fs_add_dentry_client( parent_cxy,
2581                                      parent_ptr,
2582                                      dentry_ptr,
2583                                      &error );
2584    }
2585    if ( error )
2586    {
2587        printk("\n[ERROR] in %s : cannot register child in parent directory\n",
2588        __FUNCTION__ );
2589        return -1;
2590    }
2591
2592#if DEBUG_VFS_NEW_CHILD_INIT
2593cycle = (uint32_t)hal_get_cycles();
2594if( DEBUG_VFS_NEW_CHILD_INIT < cycle )
2595printk("\n[%s] thread[%x,%x] exit / parent <%s> / child <%s> / cycle %d\n",
2596__FUNCTION__ , this->process->pid, this->trdid, parent_name, child_name, cycle );
2597#endif
2598
2599    return 0;
2600
2601}  // end vfs_new_dentry_init()
2602
2603///////////////////////////////////////////////////
2604error_t vfs_add_special_dentries( xptr_t  child_xp,
2605                                  xptr_t  parent_xp )
2606{
2607    error_t         error;
2608    vfs_inode_t   * child_ptr;         // local pointer on child inode directory
2609    cxy_t           child_cxy;         // child inode directory cluster identifier
2610    vfs_inode_t   * parent_ptr;        // local pointer on parent inode directory
2611    cxy_t           parent_cxy;        // parent inode directory cluster identifier
2612    vfs_ctx_t     * ctx_ptr;           // local pointer on child inode FS context
2613    vfs_fs_type_t   fs_type;           // FS type of child inode
2614    xptr_t          dentry_xp;         // extended pointer on dentry (used for . and ..)
2615    vfs_dentry_t  * dentry_ptr;        // local pointer on dentry (used for . and ..)
2616
2617    // xptr_t          parents_root_xp;   // extended pointer on inode "parents" field
2618    // xptr_t          parents_entry_xp;  // extended pointer on dentry "parents" field
2619    xptr_t          children_xhtab_xp; // extended pointer on inode "children" field
2620    xptr_t          children_entry_xp; // extended pointer on dentry "children" field
2621
2622#if DEBUG_VFS_ADD_SPECIAL
2623uint32_t   cycle = (uint32_t)hal_get_cycles();
2624thread_t * this  = CURRENT_THREAD;
2625char child_name[CONFIG_VFS_MAX_NAME_LENGTH];
2626char parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
2627vfs_inode_get_name( child_xp  , child_name );
2628vfs_inode_get_name( parent_xp , parent_name );
2629if( DEBUG_VFS_ADD_SPECIAL < cycle )
2630printk("\n[%s] thread[%x,%x] enter for child <%s> in parent <%s> / cycle %d\n",
2631__FUNCTION__, this->process->pid, this->trdid, child_name, parent_name, cycle );
2632#endif
2633
2634    // get new directory cluster and local pointer
2635    child_cxy  = GET_CXY( child_xp );
2636    child_ptr  = GET_PTR( child_xp );
2637
2638    // get parent directory cluster and local pointer
2639    parent_cxy = GET_CXY( parent_xp );
2640    parent_ptr = GET_PTR( parent_xp );
2641
2642    // get child inode FS type
2643    ctx_ptr    = hal_remote_lpt( XPTR( child_cxy , &child_ptr->ctx ) );
2644    fs_type    = hal_remote_l32( XPTR( child_cxy , &ctx_ptr->type ) );
2645
2646    //////////////////////////// create <.>
2647    if( child_cxy == local_cxy )     
2648    {
2649        error = vfs_dentry_create( fs_type,
2650                                   ".",
2651                                   &dentry_xp );
2652    }
2653    else
2654    {
2655        rpc_vfs_dentry_create_client( child_cxy,
2656                                      fs_type,
2657                                      ".",
2658                                      &dentry_xp,
2659                                      &error );
2660    }
2661    if( error )
2662    {
2663        printk("\n[ERROR] in %s : cannot create dentry <.> in cluster %x\n",
2664        __FUNCTION__ , child_cxy );
2665        return -1;
2666    }
2667
2668    // get <.> dentry local pointer
2669    dentry_ptr = GET_PTR( dentry_xp );
2670
2671#if(DEBUG_VFS_ADD_SPECIAL & 1)
2672if( DEBUG_VFS_ADD_SPECIAL < cycle )
2673printk("\n[%s] thread[%x,%x] created dentry <.> (%x,%x)\n",
2674__FUNCTION__, this->process->pid, this->trdid, child_cxy, dentry_ptr );
2675#endif
2676
2677    // register <.> dentry in child inode xhtab of children
2678    children_xhtab_xp = XPTR( child_cxy , &child_ptr->children );
2679    children_entry_xp = XPTR( child_cxy , &dentry_ptr->children );
2680    error = xhtab_insert( children_xhtab_xp , "." , children_entry_xp );
2681    if( error )
2682    {
2683        printk("\n[ERROR] in %s : cannot register dentry <.> in xhtab\n",
2684        __FUNCTION__ );
2685        return -1;
2686    }
2687
2688   
2689    // don't register <.> dentry in child_inode xlist of parents
2690    // parents_root_xp  = XPTR( child_cxy , &child_ptr->parents );
2691    // parents_entry_xp = XPTR( child_cxy , &dentry_ptr->parents );
2692    // xlist_add_first( parents_root_xp , parents_entry_xp );
2693    // hal_remote_atomic_add( XPTR( child_cxy , &child_ptr->links ) , 1 );
2694
2695    // update "parent" and "child_xp" fields in <.> dentry
2696    hal_remote_s64( XPTR( child_cxy , &dentry_ptr->child_xp ) , child_xp );
2697    hal_remote_spt( XPTR( child_cxy , &dentry_ptr->parent ) , child_ptr );
2698
2699#if(DEBUG_VFS_ADD_SPECIAL & 1)
2700if( DEBUG_VFS_ADD_SPECIAL < cycle )
2701printk("\n[%s] thread[%x,%x] linked dentry <.> to parent and child inodes\n", 
2702__FUNCTION__, this->process->pid, this->trdid ); 
2703#endif
2704
2705    // introduce <.> dentry into child directory mapper
2706    if( child_cxy == local_cxy )
2707    { 
2708        error = vfs_fs_add_dentry( child_ptr,
2709                                   dentry_ptr );
2710    }
2711    else
2712    {
2713        rpc_vfs_fs_add_dentry_client( child_cxy,
2714                                      child_ptr,
2715                                      dentry_ptr,
2716                                      &error );
2717    }
2718    if( error )
2719    {
2720        printk("\n[ERROR] in %s : cannot introduce dentry <..> in mapper %x\n",
2721        __FUNCTION__ );
2722        return -1;
2723    }
2724
2725#if(DEBUG_VFS_ADD_SPECIAL & 1)
2726if( DEBUG_VFS_ADD_SPECIAL < cycle )
2727printk("\n[%s] thread[%x,%x] registered dentry <.> in child mapper\n", 
2728__FUNCTION__, this->process->pid, this->trdid ); 
2729#endif
2730
2731    ///////////////////////////// create <..> dentry
2732    if( child_cxy == local_cxy )     
2733    {
2734        error = vfs_dentry_create( fs_type,
2735                                   "..",
2736                                   &dentry_xp );
2737    }
2738    else
2739    {
2740        rpc_vfs_dentry_create_client( child_cxy,
2741                                      fs_type,
2742                                      "..",
2743                                      &dentry_xp,
2744                                      &error );
2745    }
2746    if( error )
2747    {
2748        printk("\n[ERROR] in %s : cannot create dentry <..> in cluster %x\n",
2749        __FUNCTION__ , child_cxy );
2750        return -1;
2751    }
2752
2753    // get <..> dentry local pointer
2754    dentry_ptr = GET_PTR( dentry_xp );
2755
2756#if(DEBUG_VFS_ADD_SPECIAL & 1)
2757if( DEBUG_VFS_ADD_SPECIAL < cycle )
2758printk("\n[%s] thread[%x,%x] created dentry <..> (%x,%x)\n",
2759__FUNCTION__, this->process->pid, this->trdid, child_cxy, dentry_ptr );
2760#endif
2761
2762    // register <..> dentry in child_inode xhtab of children
2763    children_xhtab_xp = XPTR( child_cxy , &child_ptr->children );
2764    children_entry_xp = XPTR( child_cxy , &dentry_ptr->children );
2765    error = xhtab_insert( children_xhtab_xp , ".." , children_entry_xp );
2766    if( error )
2767    {
2768        printk("\n[ERROR] in %s : cannot register dentry <..> in xhtab\n",
2769        __FUNCTION__ );
2770        return -1;
2771    }
2772
2773    // don't register <..> dentry in parent_inode xlist of parents
2774    // parents_root_xp  = XPTR( parent_cxy , &parent_ptr->parents );
2775    // parents_entry_xp = XPTR( child_cxy  , &dentry_ptr->parents );
2776    // xlist_add_first( parents_root_xp , parents_entry_xp );
2777    // hal_remote_atomic_add( XPTR( parent_cxy , &parent_ptr->links ) , 1 );
2778
2779    // update "parent" and "child_xp" fields in <..> dentry
2780    hal_remote_s64( XPTR( child_cxy , &dentry_ptr->child_xp ) , parent_xp );
2781    hal_remote_spt( XPTR( child_cxy , &dentry_ptr->parent ) , child_ptr );
2782
2783#if(DEBUG_VFS_ADD_SPECIAL & 1)
2784if( DEBUG_VFS_ADD_SPECIAL < cycle )
2785printk("\n[%s] thread[%x,%x] linked dentry <..> to parent and child inodes\n", 
2786__FUNCTION__, this->process->pid, this->trdid ); 
2787#endif
2788
2789    // introduce <..> dentry into child directory mapper
2790    if( child_cxy == local_cxy )
2791    { 
2792        error = vfs_fs_add_dentry( child_ptr,
2793                                   dentry_ptr );
2794    }
2795    else
2796    {
2797        rpc_vfs_fs_add_dentry_client( child_cxy,
2798                                      child_ptr,
2799                                      dentry_ptr,
2800                                      &error );
2801    }
2802    if( error )
2803    {
2804        printk("\n[ERROR] in %s : cannot introduce dentry <..> in mapper %x\n",
2805        __FUNCTION__ );
2806        return -1;
2807    }
2808
2809#if(DEBUG_VFS_ADD_SPECIAL & 1)
2810if( DEBUG_VFS_ADD_SPECIAL < cycle )
2811printk("\n[%s] thread[%x,%x] registered dentry <..> in child mapper\n", 
2812__FUNCTION__, this->process->pid, this->trdid ); 
2813#endif
2814
2815#if DEBUG_VFS_ADD_SPECIAL
2816cycle = (uint32_t)hal_get_cycles();
2817if( DEBUG_VFS_ADD_SPECIAL < cycle )
2818printk("\n[%s] thread[%x,%x] exit for child <%s> in parent <%s> / cycle %d\n",
2819__FUNCTION__, this->process->pid, this->trdid, child_name, parent_name, cycle );
2820#endif
2821
2822    return 0;
2823
2824}  // end vfs_add_special_dentries()
2825
2826//////////////////////////////////////////
2827error_t vfs_get_path( xptr_t     inode_xp,
2828                      char     * buffer,
2829                      char    ** first,
2830                      uint32_t   max_size )
2831{
2832        xptr_t         dentry_xp;        // extended pointer on current dentry
2833    vfs_dentry_t * dentry_ptr;       // local pointer on current dentry
2834    cxy_t          dentry_cxy;       // current dentry cluster identifier
2835    xptr_t         name_xp;          // extended pointer on current dentry name
2836        uint32_t       length;           // length of current dentry name
2837        int32_t        index;            // slot index in buffer
2838    xptr_t         current_xp;       // extended pointer on current inode
2839    vfs_inode_t  * current_ptr;      // local pointer on current inode
2840    cxy_t          current_cxy;      // current inode cluster identifier
2841    xptr_t         vfs_root_xp;      // extended pointer on VFS root inode
2842    vfs_inode_t  * vfs_root_ptr;     // local pointer on VFS root inode
2843    cxy_t          vfs_root_cxy;     // VFS root inode cluster identifier
2844    xptr_t         lock_xp;          // extended pointer on Inode Tree lock
2845    xptr_t         parents_root_xp;  // extended pointer on current inode parents root
2846    bool_t         found;            // condition to exit the while loop
2847
2848    thread_t  * this    = CURRENT_THREAD;
2849    process_t * process = this->process;
2850
2851#if DEBUG_VFS_GET_PATH
2852uint32_t cycle = (uint32_t)hal_get_cycles();
2853if( DEBUG_VFS_GET_PATH < cycle )
2854printk("\n[%s] thread[%x,%x] enter : inode (%x,%x) / cycle %d\n",
2855__FUNCTION__ , process->pid, this->trdid,
2856GET_CXY( inode_xp ), GET_PTR( inode_xp ), cycle );
2857#endif
2858
2859        // set the NUL character in buffer / initialise buffer index
2860        buffer[max_size - 1] = 0;
2861    index    = (int32_t)(max_size - 1);
2862
2863    // initialize current inode
2864    current_xp  = inode_xp;
2865
2866    // build extended pointer on lock protecting Inode Tree
2867    vfs_root_xp  = process->vfs_root_xp;
2868    vfs_root_ptr = GET_PTR( vfs_root_xp );
2869    vfs_root_cxy = GET_CXY( vfs_root_xp );
2870    lock_xp      = XPTR( vfs_root_cxy , &vfs_root_ptr->main_lock );
2871
2872    // take lock protecting Inode Tree in read mode
2873    remote_rwlock_rd_acquire( lock_xp );
2874
2875    // traverse Inode Tree from target inode to VFS root
2876    // selecting always the first parent dentry
2877    // the buffer is written in "reverse order" (from target inode to root)
2878    // exit the while loop when the VFS root has been found
2879        do
2880    {
2881        // get current inode cluster and local pointer
2882        current_cxy = GET_CXY( current_xp );
2883        current_ptr = GET_PTR( current_xp );
2884
2885        // build extended pointer on parents dentries root
2886        parents_root_xp = XPTR( current_cxy , &current_ptr->parents );
2887
2888        // compute exit condition <=> current inode is VFS root   
2889        found = xlist_is_empty( parents_root_xp );
2890
2891        if( found )                              // parent is the VFS root
2892        {
2893            if( index == (int32_t)(max_size - 1) )
2894            {
2895                // update index
2896                index--;
2897                 
2898                // set separator 
2899                        buffer[index] = '/';
2900
2901// check buffer overflow
2902assert( (index >= 0) , "kernel buffer too small\n" );
2903
2904            }
2905        }
2906        else                                     // not the VFS root
2907        {
2908            // get first parent dentry cluster and pointers
2909            dentry_xp  = XLIST_FIRST( parents_root_xp , vfs_dentry_t , parents );
2910            dentry_cxy = GET_CXY( dentry_xp );
2911            dentry_ptr = GET_PTR( dentry_xp );
2912
2913            // get extended pointer on dentry name and name length
2914            name_xp = XPTR( dentry_cxy , dentry_ptr->name );
2915            length  = hal_remote_l32( XPTR( dentry_cxy , &dentry_ptr->length ) );
2916
2917#if (DEBUG_VFS_GET_PATH & 1)
2918char debug_name[CONFIG_VFS_MAX_NAME_LENGTH];
2919hal_remote_strcpy( XPTR( local_cxy , debug_name ) , name_xp );
2920if( DEBUG_VFS_GET_PATH < cycle )
2921printk("\n[%s] thread(%x,%s) get current dentry <%s> in cluster %x\n",
2922__FUNCTION__ , process->pid, this->trdid, debug_name, current_cxy );
2923#endif
2924            // update index
2925            index -= (length + 1); 
2926
2927// check buffer overflow
2928assert( (index >= 0) , "kernel buffer too small\n" );
2929
2930            // update pathname
2931            hal_remote_memcpy( XPTR( local_cxy , &buffer[index + 1] ) ,
2932                               name_xp , length );
2933
2934            // set separator 
2935                    buffer[index] = '/';
2936
2937            // get extended pointer on parent inode
2938            current_xp = XPTR( dentry_cxy , 
2939                               hal_remote_lpt( XPTR( dentry_cxy , &dentry_ptr->parent ) ) );
2940        }
2941    }
2942    while( found == false );
2943
2944    // release lock protecting Inode Tree in read mode
2945    remote_rwlock_rd_release( lock_xp );
2946
2947#if DEBUG_VFS_GET_PATH
2948cycle = (uint32_t)hal_get_cycles();
2949if( DEBUG_VFS_GET_PATH < cycle )
2950printk("\n[%s] thread[%x,%x] exit : path <%s> / cycle %d\n",
2951__FUNCTION__ , process->pid, this->trdid, &buffer[index], cycle );
2952#endif
2953
2954    // return pointer on first character in buffer
2955    *first = &buffer[index];
2956        return 0;
2957
2958}  // end vfs_get_path()
2959
2960     
2961////////////////////////////////////////////////////////////////////
2962error_t vfs_add_child_in_parent( cxy_t              child_cxy,
2963                                 vfs_inode_type_t   child_type,
2964                                 vfs_fs_type_t      fs_type,
2965                                 xptr_t             parent_inode_xp,
2966                                 char             * name,
2967                                 xptr_t           * child_dentry_xp,
2968                                 xptr_t           * child_inode_xp )
2969{
2970    error_t        error;
2971    cxy_t          parent_cxy;          // parent inode cluster identifier
2972    vfs_inode_t  * parent_inode_ptr;    // parent inode local pointer
2973    xptr_t         new_dentry_xp;       // extended pointer on created dentry
2974    vfs_dentry_t * new_dentry_ptr;      // created dentry local pointer
2975    xptr_t         new_inode_xp;        // extended pointer on created child inode
2976    vfs_inode_t  * new_inode_ptr;       // local pointer on created child inode
2977
2978    xptr_t         parents_root_xp;     // extended pointer on child inode  "parents" field
2979    xptr_t         parents_entry_xp;    // extended pointer on child dentry "parents" field
2980    xptr_t         children_xhtab_xp;   // extended pointer on parent inode "children" field
2981    xptr_t         children_entry_xp;   // extended pointer on child dentry "children" field
2982   
2983    // get parent inode cluster and pointer
2984    parent_cxy       = GET_CXY( parent_inode_xp );
2985    parent_inode_ptr = GET_PTR( parent_inode_xp );
2986
2987#if DEBUG_VFS_ADD_CHILD
2988char parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
2989vfs_inode_get_name( parent_inode_xp , parent_name );
2990uint32_t cycle = (uint32_t)hal_get_cycles();
2991thread_t * this = CURRENT_THREAD; 
2992if( DEBUG_VFS_ADD_CHILD < cycle )
2993printk("\n[%s] thread[%x,%x] enter / child <%s> / parent <%s> / cycle %d\n",
2994__FUNCTION__, this->process->pid, this->trdid, name,
2995parent_name, (uint32_t)hal_get_cycles() );
2996#endif
2997
2998    // 1. create dentry in parent cluster
2999    if( parent_cxy == local_cxy )           // parent cluster is local
3000    {
3001        error = vfs_dentry_create( fs_type,
3002                                   name,
3003                                   &new_dentry_xp );
3004    }
3005    else                                    // parent cluster is remote
3006    {
3007        rpc_vfs_dentry_create_client( parent_cxy,
3008                                      fs_type,
3009                                      name,
3010                                      &new_dentry_xp,
3011                                      &error );
3012    }
3013                                     
3014    if( error )
3015    {
3016        printk("\n[ERROR] in %s : cannot create dentry <%s> in cluster %x\n",
3017        __FUNCTION__ , name , parent_cxy );
3018        return -1;
3019    }
3020
3021    // get dentry local pointer
3022    new_dentry_ptr = GET_PTR( new_dentry_xp );
3023
3024#if(DEBUG_VFS_ADD_CHILD & 1)
3025if( DEBUG_VFS_ADD_CHILD < cycle )
3026printk("\n[%s] thread[%x,%x] / dentry <%s> created (%x,%x)\n",
3027__FUNCTION__, this->process->pid, this->trdid, name, parent_cxy, new_dentry_ptr );
3028#endif
3029
3030    // 2. create child inode in child cluster
3031    // TODO : define attr / mode / uid / gid
3032    uint32_t attr = 0;
3033    uint32_t mode = 0;
3034    uint32_t uid  = 0;
3035    uint32_t gid  = 0;
3036   
3037    if( child_cxy == local_cxy )      // child cluster is local
3038    {
3039        error = vfs_inode_create( fs_type,
3040                                  child_type,
3041                                  attr,
3042                                  mode,
3043                                  uid,
3044                                  gid,
3045                                  &new_inode_xp );
3046    }
3047    else                              // child cluster is remote
3048    {
3049        rpc_vfs_inode_create_client( child_cxy,
3050                                     fs_type,
3051                                     child_type,
3052                                     attr,
3053                                     mode,
3054                                     uid,
3055                                     gid,
3056                                     &new_inode_xp,
3057                                     &error );
3058    }
3059                                     
3060    if( error )
3061    {
3062        printk("\n[ERROR] in %s : cannot create inode in cluster %x\n",
3063               __FUNCTION__ , child_cxy );
3064 
3065        if( parent_cxy == local_cxy ) vfs_dentry_destroy( new_dentry_ptr );
3066        else rpc_vfs_dentry_destroy_client( parent_cxy , new_dentry_ptr );
3067        return -1;
3068    }
3069
3070    // get new inode local pointer
3071    new_inode_ptr = GET_PTR( new_inode_xp );
3072   
3073#if(DEBUG_VFS_ADD_CHILD & 1)
3074if( DEBUG_VFS_ADD_CHILD < cycle )
3075printk("\n[%s] thread[%x,%x] / inode <%s> created (%x,%x)\n",
3076__FUNCTION__ , this->process->pid, this->trdid, name , child_cxy, new_inode_ptr );
3077#endif
3078
3079    // 3. register new_dentry in new_inode xlist of parents
3080    parents_root_xp  = XPTR( child_cxy , &new_inode_ptr->parents );
3081    parents_entry_xp = XPTR( parent_cxy, &new_dentry_ptr->parents );
3082    xlist_add_first( parents_root_xp , parents_entry_xp );
3083    hal_remote_atomic_add( XPTR( child_cxy , &new_inode_ptr->links ) , 1 );
3084
3085#if(DEBUG_VFS_ADD_CHILD & 1)
3086if( DEBUG_VFS_ADD_CHILD < cycle )
3087printk("\n[%s] thread[%x,%x] / dentry (%x,%x) registered in child inode (%x,%x)\n",
3088__FUNCTION__, this->process->pid, this->trdid, 
3089parent_cxy, new_dentry_ptr, child_cxy, new_inode_ptr );
3090#endif
3091
3092    // register new_dentry in parent_inode xhtab of children
3093    children_xhtab_xp = XPTR( parent_cxy , &parent_inode_ptr->children );
3094    children_entry_xp = XPTR( parent_cxy , &new_dentry_ptr->children );
3095    xhtab_insert( children_xhtab_xp , name , children_entry_xp );
3096
3097#if(DEBUG_VFS_ADD_CHILD & 1)
3098if( DEBUG_VFS_ADD_CHILD < cycle )
3099printk("\n[%s] thread[%x,%x] / dentry (%x,%x) registered in parent inode (%x,%x)\n",
3100__FUNCTION__, this->process->pid, this->trdid, 
3101parent_cxy, new_dentry_ptr, parent_cxy, parent_inode_ptr );
3102#endif
3103
3104    // update "parent" and "child_xp" fields in new_dentry
3105    hal_remote_s64( XPTR( parent_cxy , &new_dentry_ptr->child_xp ) , new_inode_xp );
3106    hal_remote_spt( XPTR( parent_cxy , &new_dentry_ptr->parent ) , parent_inode_ptr );
3107
3108#if DEBUG_VFS_ADD_CHILD
3109cycle = (uint32_t)hal_get_cycles();
3110if( DEBUG_VFS_ADD_CHILD < cycle )
3111printk("\n[%s] thread[%x,%x] exit for <%s> / cycle %d\n",
3112__FUNCTION__, this->process->pid, this->trdid, name, (uint32_t)hal_get_cycles() );
3113#endif
3114
3115    // return extended pointer on dentry & child inode
3116    *child_dentry_xp = new_dentry_xp;
3117    *child_inode_xp  = new_inode_xp;
3118    return 0;
3119
3120}  // end vfs_add_child_in_parent()
3121
3122/////////////////////////////////////////////////////
3123void vfs_remove_child_from_parent( xptr_t dentry_xp )
3124{
3125    cxy_t          parent_cxy;         // parent inode cluster identifier
3126    cxy_t          child_cxy;          // child inode cluster identifier
3127    vfs_dentry_t * dentry_ptr;         // local pointer on dentry
3128    xptr_t         child_inode_xp;     // extended pointer on child inode
3129    vfs_inode_t  * child_inode_ptr;    // local pointer on child inode
3130    vfs_inode_t  * parent_inode_ptr;   // local pointer on parent inode
3131    uint32_t       links;              // number of child inode parents
3132
3133    char dentry_name[CONFIG_VFS_MAX_NAME_LENGTH];
3134   
3135    // get parent cluster and dentry local pointer
3136    parent_cxy = GET_CXY( dentry_xp );
3137    dentry_ptr = GET_PTR( dentry_xp );
3138
3139    // get a local copy of dentry name
3140    hal_remote_strcpy( XPTR( local_cxy  , dentry_name ),
3141                       XPTR( parent_cxy , &dentry_ptr->name ) );
3142
3143    // get parent_inode local pointer
3144    parent_inode_ptr = hal_remote_lpt( XPTR( parent_cxy , &dentry_ptr->parent ) );
3145 
3146    // get child cluster and child_inode pointers
3147    child_inode_xp   = hal_remote_l64( XPTR( parent_cxy , &dentry_ptr->child_xp ) );
3148    child_cxy        = GET_CXY( child_inode_xp ); 
3149    child_inode_ptr  = GET_PTR( child_inode_xp );
3150
3151    // remove dentry from parent_inode
3152    xhtab_remove( XPTR( parent_cxy , &parent_inode_ptr->children ),
3153                  dentry_name,
3154                  XPTR( parent_cxy , &dentry_ptr->children ) );
3155
3156    // remove dentry from child_inode
3157    xlist_unlink( XPTR( parent_cxy , &dentry_ptr->parents ) );
3158    links = hal_remote_atomic_add( XPTR( child_cxy , &child_inode_ptr->links ) , -1 );
3159
3160    // delete dentry descriptor
3161    if( parent_cxy == local_cxy )
3162    {
3163         vfs_dentry_destroy( dentry_ptr );
3164    }
3165    else
3166    {
3167         rpc_vfs_dentry_destroy_client( parent_cxy,
3168                                        dentry_ptr );
3169    }
3170
3171    // delete child_inode descriptor if last link
3172    if( links == 1 )
3173    {
3174        if( child_cxy == local_cxy )
3175        {
3176            vfs_inode_destroy( child_inode_ptr );
3177        }
3178        else
3179        {
3180            rpc_vfs_inode_destroy_client( child_cxy , child_inode_ptr );
3181        }
3182    }
3183
3184}  // end vfs_remove_child_from_parent()
3185
3186
3187
3188
3189//////////////////////////////////////////////////////////////////////////////////////////
3190//    API used by VFS to access a specific FS 
3191//////////////////////////////////////////////////////////////////////////////////////////
3192
3193///////////////////////////////////////////
3194error_t vfs_fs_move_page( xptr_t   page_xp,
3195                          bool_t   to_mapper )
3196{
3197    error_t error = 0;
3198
3199assert( (page_xp != XPTR_NULL) , "page pointer is NULL\n" );
3200
3201    page_t * page_ptr = GET_PTR( page_xp );
3202    cxy_t    page_cxy = GET_CXY( page_xp );
3203
3204    // get local pointer on page mapper
3205    mapper_t * mapper = hal_remote_lpt( XPTR( page_cxy , &page_ptr->mapper ) );
3206
3207assert( (mapper != NULL) , "no mapper for page\n" );
3208
3209    // get FS type
3210    vfs_fs_type_t fs_type = hal_remote_l32( XPTR( page_cxy , &mapper->type ) );
3211
3212    // call relevant FS function
3213    if( fs_type == FS_TYPE_FATFS )
3214    {
3215        error = fatfs_move_page( page_xp , to_mapper ); 
3216    }
3217    else if( fs_type == FS_TYPE_RAMFS )
3218    {
3219        assert( false , "should not be called for RAMFS\n" );
3220    }
3221    else if( fs_type == FS_TYPE_DEVFS )
3222    {
3223        assert( false , "should not be called for DEVFS\n" );
3224    }
3225    else
3226    {
3227        assert( false , "undefined file system type\n" );
3228    }
3229
3230    return error;
3231
3232}  // end vfs_fs_move_page()
3233
3234////////////////////////////////////////////////
3235error_t vfs_fs_add_dentry( vfs_inode_t  * inode,
3236                           vfs_dentry_t * dentry )
3237{
3238    error_t error = 0;
3239
3240assert( (inode  != NULL) , "inode  pointer is NULL\n" );
3241assert( (dentry != NULL) , "dentry pointer is NULL\n" );
3242
3243    mapper_t * mapper = inode->mapper;
3244
3245assert( (mapper != NULL) , "mapper pointer is NULL\n" );
3246
3247    // get FS type
3248    vfs_fs_type_t fs_type = mapper->type;
3249
3250    // call relevant FS function
3251    if( fs_type == FS_TYPE_FATFS )
3252    {
3253        error = fatfs_add_dentry( inode , dentry ); 
3254    }
3255    else if( fs_type == FS_TYPE_RAMFS )
3256    {
3257        error = 0;     // does nothing for RAMFS
3258    }
3259    else if( fs_type == FS_TYPE_DEVFS )
3260    {
3261        error = 0;     // does nothing for DEVFS
3262    }
3263    else
3264    {
3265        assert( false , "undefined file system type\n" );
3266    }
3267
3268    return error;
3269
3270}  // end vfs_fs_add_dentry()
3271
3272///////////////////////////////////////////////////
3273error_t vfs_fs_remove_dentry( vfs_inode_t  * inode,
3274                              vfs_dentry_t * dentry )
3275{
3276    error_t error = 0;
3277
3278assert( (inode  != NULL) , "inode  pointer is NULL\n" );
3279assert( (dentry != NULL) , "dentry pointer is NULL\n" );
3280
3281    mapper_t * mapper = inode->mapper;
3282
3283assert( (mapper != NULL) , "mapper pointer is NULL\n" );
3284
3285    // get FS type
3286    vfs_fs_type_t fs_type = mapper->type;
3287
3288    // call relevant FS function
3289    if( fs_type == FS_TYPE_FATFS )
3290    {
3291        error = fatfs_remove_dentry( inode , dentry ); 
3292    }
3293    else if( fs_type == FS_TYPE_RAMFS )
3294    {
3295        error = 0;     // does nothing for RAMFS
3296    }
3297    else if( fs_type == FS_TYPE_DEVFS )
3298    {
3299        error = 0;     // does nothing for DEVFS
3300    }
3301    else
3302    {
3303        assert( false , "undefined file system type\n" );
3304    }
3305
3306    return error;
3307
3308}  // end vfs_fs_remove_dentry()
3309
3310////////////////////////////////////////////////
3311error_t vfs_fs_get_dentry( vfs_inode_t * parent,
3312                           char        * name,
3313                           xptr_t        child_xp )
3314{
3315    error_t error = 0;
3316
3317// check arguments
3318assert( (parent != NULL) , "parent pointer is NULL\n");
3319assert( (child_xp != XPTR_NULL) , "child pointer is NULL\n");
3320
3321    // get parent inode FS type
3322    vfs_fs_type_t fs_type = parent->ctx->type;
3323
3324    // call relevant FS function
3325    if( fs_type == FS_TYPE_FATFS )
3326    {
3327        error = fatfs_get_dentry( parent , name , child_xp );
3328    }
3329    else if( fs_type == FS_TYPE_RAMFS )
3330    {
3331        assert( false , "should not be called for RAMFS\n" );
3332    }
3333    else if( fs_type == FS_TYPE_DEVFS )
3334    {
3335        assert( false , "should not be called for DEVFS\n" );
3336    }
3337    else
3338    {
3339        assert( false , "undefined file system type\n" );
3340    }
3341
3342    return error;
3343
3344} // end vfs_fs_get_dentry()
3345
3346///////////////////////////////////////////////////
3347error_t vfs_fs_get_user_dir( vfs_inode_t   * inode,
3348                             struct dirent * array,
3349                             uint32_t        max_dirent,
3350                             uint32_t        min_dentry,
3351                             bool_t          detailed,
3352                             uint32_t      * entries,
3353                             bool_t        * done )
3354{
3355    error_t error = 0;
3356
3357// check arguments
3358assert( (inode != NULL) , "parent pointer is NULL\n");
3359assert( (array != NULL) , "child pointer is NULL\n");
3360assert( (detailed == false) , "detailed argument not supported\n");
3361
3362    // check inode type
3363    if( inode->type != INODE_TYPE_DIR )
3364    {
3365        printk("\n[ERROR] in %s : target inode is not a directory\n",
3366        __FUNCTION__ );
3367        return -1;
3368    }
3369
3370    // get parent inode FS type
3371    vfs_fs_type_t fs_type = inode->ctx->type;
3372
3373    // call relevant FS function
3374    if( fs_type == FS_TYPE_FATFS )
3375    {
3376        error = fatfs_get_user_dir( inode, 
3377                                    array,
3378                                    max_dirent,
3379                                    min_dentry,
3380                                    detailed,
3381                                    entries,
3382                                    done );
3383    }
3384    else if( fs_type == FS_TYPE_RAMFS )
3385    {
3386        assert( false , "should not be called for RAMFS\n" );
3387    }
3388    else if( fs_type == FS_TYPE_DEVFS )
3389    {
3390        error = devfs_get_user_dir( inode,
3391                                    array,
3392                                    max_dirent,
3393                                    min_dentry,
3394                                    detailed,
3395                                    entries,
3396                                    done );
3397    }
3398    else
3399    {
3400        assert( false , "undefined file system type\n" );
3401    }
3402
3403    return error;
3404
3405}  // end vfs_fs_get_user_dir()
3406 
3407////////////////////////////////////////////////
3408error_t vfs_fs_sync_inode( vfs_inode_t * inode )
3409{
3410    error_t error = 0;
3411
3412// check arguments
3413assert( (inode != NULL) , "inode pointer is NULL\n");
3414
3415    // get inode FS type
3416    vfs_fs_type_t fs_type = inode->ctx->type;
3417
3418    // call relevant FS function
3419    if( fs_type == FS_TYPE_FATFS )
3420    {
3421        error = fatfs_sync_inode( inode );
3422    }
3423    else if( fs_type == FS_TYPE_RAMFS )
3424    {
3425        assert( false , "should not be called for RAMFS\n" );
3426    }
3427    else if( fs_type == FS_TYPE_DEVFS )
3428    {
3429        assert( false , "should not be called for DEVFS\n" );
3430    }
3431    else
3432    {
3433        assert( false , "undefined file system type\n" );
3434    }
3435
3436    return error;
3437
3438}  // end vfs_fs_sync_inode()
3439
3440////////////////////////////////////////////////
3441error_t vfs_fs_sync_fat( vfs_fs_type_t fs_type )
3442{
3443    error_t error = 0;
3444
3445    // call relevant FS function
3446    if( fs_type == FS_TYPE_FATFS )
3447    {
3448        error = fatfs_sync_fat();
3449    }
3450    else if( fs_type == FS_TYPE_RAMFS )
3451    {
3452        assert( false , "should not be called for RAMFS\n" );
3453    }
3454    else if( fs_type == FS_TYPE_DEVFS )
3455    {
3456        assert( false , "should not be called for DEVFS\n" );
3457    }
3458    else
3459    {
3460        assert( false , "undefined file system type\n" );
3461    }
3462
3463    return error;
3464
3465}  // end vfs_fs_sync_fat()
3466
3467//////////////////////////////////////////////////////
3468error_t vfs_fs_sync_free_info( vfs_fs_type_t fs_type )
3469{
3470    error_t error = 0;
3471
3472    // call relevant FS function
3473    if( fs_type == FS_TYPE_FATFS )
3474    {
3475        error = fatfs_sync_free_info();
3476    }
3477    else if( fs_type == FS_TYPE_RAMFS )
3478    {
3479        assert( false , "should not be called for RAMFS\n" );
3480    }
3481    else if( fs_type == FS_TYPE_DEVFS )
3482    {
3483        assert( false , "should not be called for DEVFS\n" );
3484    }
3485    else
3486    {
3487        assert( false , "undefined file system type\n" );
3488    }
3489
3490    return error;
3491
3492}  // end vfs_fs_sync_fat()
3493
3494/////////////////////////////////////////////////
3495error_t vfs_fs_cluster_alloc( uint32_t   fs_type,
3496                              uint32_t * cluster )
3497{
3498    error_t error = 0;
3499
3500    // call relevant FS function
3501    if( fs_type == FS_TYPE_FATFS )
3502    {
3503        error = fatfs_cluster_alloc( cluster );
3504    }
3505    else if( fs_type == FS_TYPE_RAMFS )
3506    {
3507        assert( false , "should not be called for RAMFS\n" );
3508    }
3509    else if( fs_type == FS_TYPE_DEVFS )
3510    {
3511        assert( false , "should not be called for DEVFS\n" );
3512    }
3513    else
3514    {
3515        assert( false , "undefined file system type\n" );
3516    }
3517
3518    return error;
3519
3520} // end vfs_fs_alloc_cluster()
3521
3522////////////////////////////////////////////////
3523error_t vfs_fs_release_inode( xptr_t  inode_xp )
3524{
3525    error_t error = 0;
3526
3527assert( (inode_xp  != XPTR_NULL) , "inode pointer is NULL\n")       
3528
3529    vfs_inode_t * inode_ptr = GET_PTR( inode_xp );
3530    cxy_t         inode_cxy = GET_CXY( inode_xp );
3531
3532    // get local pointer on page mapper
3533    mapper_t * mapper = hal_remote_lpt( XPTR( inode_cxy , &inode_ptr->mapper ) );
3534
3535assert( (mapper != NULL) , "mapper pointer is NULL\n")       
3536
3537    // get FS type from mapper
3538    vfs_fs_type_t fs_type = hal_remote_l32( XPTR( inode_cxy , &mapper->type ) );
3539
3540    // call relevant FS function
3541    if( fs_type == FS_TYPE_FATFS )
3542    {
3543        error = fatfs_release_inode( inode_xp ); 
3544    }
3545    else if( fs_type == FS_TYPE_RAMFS )
3546    {
3547        assert( false , "should not be called for RAMFS\n" );
3548    }
3549    else if( fs_type == FS_TYPE_DEVFS )
3550    {
3551        assert( false , "should not be called for DEVFS\n" );
3552    }
3553    else
3554    {
3555        assert( false , "undefined file system type\n" );
3556    }
3557
3558    return error;
3559   
3560}  // end vfs_fs_release_inode()
3561
3562
Note: See TracBrowser for help on using the repository browser.