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

Last change on this file since 651 was 651, checked in by alain, 4 years ago

1) Improve the VMM MMAP allocator: implement the "buddy" algorithm
to allocate only aligned blocks.
2) fix a bug in the pthread_join() / pthread_exit() mmechanism.

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