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

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

1) Fix a bug in the vfs_add_special_dentries() function:
The <.> and <..> dentries must not be created on IOC and on the mapper
for the VFS root directory.
2) Fix a bug in the hal_gpt_allocate_pt2 function, related to the
use of the TSAR_LOCKED attribute to avoid concurrent mapping of the PTD1.

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