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

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

Fix several bugs in VFS to support the following
ksh commandis : cp, mv, rm, mkdir, cd, pwd

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