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

Last change on this file since 634 was 634, checked in by alain, 18 months ago

Fix a bug in hal_irqmask.c

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