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

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

Introduce three new types of vsegs (KCODE,KDATA,KDEV)
to map the kernel vsegs in the process VSL and GPT.
This now used by both the TSAR and the I86 architectures.

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