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

Last change on this file since 638 was 635, checked in by alain, 5 years ago

This version is a major evolution: The physical memory allocators,
defined in the kmem.c, ppm.c, and kcm.c files have been modified
to support remote accesses. The RPCs that were previously user
to allocate physical memory in a remote cluster have been removed.
This has been done to cure a dead-lock in case of concurrent page-faults.

This version 2.2 has been tested on a (4 clusters / 2 cores per cluster)
TSAR architecture, for both the "sort" and the "fft" applications.

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