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

Last change on this file since 625 was 625, checked in by alain, 2 years ago

Fix a bug in the vmm_remove_vseg() function: the physical pages
associated to an user DATA vseg were released to the kernel when
the target process descriptor was in the reference cluster.
This physical pages release should be done only when the page
forks counter value is zero.
All other modifications are cosmetic.

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