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

Last change on this file since 673 was 673, checked in by alain, 3 years ago

Introduce the DEBUG_VFS_ERROR in kernel_config to make
error messges display conditional.

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