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

Last change on this file since 472 was 459, checked in by alain, 6 years ago

Introduce the math library, to support the floating point
data used by the multi-thread fft application.
Fix several bugs regarding the FPU context save/restore.
Introduce support for the %f format in printf.

File size: 69.4 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 <readlock.h>
31#include <spinlock.h>
32#include <printk.h>
33#include <list.h>
34#include <xlist.h>
35#include <slist.h>
36#include <xhtab.h>
37#include <string.h>
38#include <rpc.h>
39#include <errno.h>
40#include <kmem.h>
41#include <mapper.h>
42#include <thread.h>
43#include <chdev.h>
44#include <process.h>
45#include <vfs.h>
46#include <fatfs.h>
47#include <ramfs.h>
48#include <devfs.h>
49#include <syscalls.h>
50
51
52//////////////////////////////////////////////////////////////////////////////////////////
53//           Extern variables         
54//////////////////////////////////////////////////////////////////////////////////////////
55
56extern vfs_ctx_t          fs_context[FS_TYPES_NR];    // allocated in kernel_init.c
57
58extern chdev_directory_t  chdev_dir;                  // allocated in kernel_init.c 
59 
60//////////////////////////////////////////////////////////////////////////////////////////
61//           Context related functions
62//////////////////////////////////////////////////////////////////////////////////////////
63
64////////////////////////////////////////
65void vfs_ctx_init( vfs_fs_type_t   type,
66                   uint32_t        attr,
67                       uint32_t        total_clusters,
68                       uint32_t        cluster_size,
69                       xptr_t          vfs_root_xp,
70                   void          * extend )
71{
72    vfs_ctx_t * vfs_ctx = &fs_context[type];
73
74    vfs_ctx->type           = type;
75    vfs_ctx->attr           = attr;
76    vfs_ctx->total_clusters = total_clusters;
77    vfs_ctx->cluster_size   = cluster_size;
78    vfs_ctx->vfs_root_xp    = vfs_root_xp;
79    vfs_ctx->extend         = extend;
80
81    spinlock_init( &vfs_ctx->lock );
82
83    bitmap_init( vfs_ctx->bitmap , BITMAP_SIZE(CONFIG_VFS_MAX_INODES) ); 
84}
85
86////////////////////////////////////////////
87error_t vfs_ctx_inum_alloc( vfs_ctx_t * ctx,
88                            uint32_t  * inum )
89{
90    // get lock on inum allocator
91    spinlock_lock( &ctx->lock );
92
93    // get lid from local inum allocator
94    uint32_t lid = bitmap_ffc( ctx->bitmap , CONFIG_VFS_MAX_INODES );
95
96    if( lid == -1 )   // no more free slot => error
97    {
98        // release lock
99        spinlock_unlock( &ctx->lock );
100
101        // return error
102        return 1;
103    }
104    else              // found => return inum
105    {
106        // set slot allocated
107        bitmap_set( ctx->bitmap , lid );
108
109        // release lock
110        spinlock_unlock( &ctx->lock );
111
112        // return inum
113        *inum = (((uint32_t)local_cxy) << 16) | (lid & 0xFFFF);
114        return 0;
115    }
116}
117
118////////////////////////////////////////////
119void vfs_ctx_inum_release( vfs_ctx_t * ctx,
120                           uint32_t    inum )
121{
122    bitmap_clear( ctx->bitmap , inum & 0xFFFF ); 
123}
124
125//////////////////////////////////////////////////////////////////////////////////////////
126//           Inode related functions
127//////////////////////////////////////////////////////////////////////////////////////////
128
129char * vfs_inode_type_str( uint32_t type )
130{
131    if     ( type == INODE_TYPE_FILE ) return "FILE";
132    else if( type == INODE_TYPE_DIR  ) return "DIR ";
133    else if( type == INODE_TYPE_FIFO ) return "FIFO";
134    else if( type == INODE_TYPE_PIPE ) return "PIPE";
135    else if( type == INODE_TYPE_SOCK ) return "SOCK";
136    else if( type == INODE_TYPE_DEV  ) return "DEV ";
137    else if( type == INODE_TYPE_SYML ) return "SYML";
138    else                               return "undefined";
139}
140
141//////////////////////////////////////////////////////
142error_t vfs_inode_create( xptr_t            dentry_xp,
143                          vfs_fs_type_t     fs_type,
144                          vfs_inode_type_t  inode_type,
145                          void            * extend,
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
160uint32_t cycle = (uint32_t)hal_get_cycles();
161if( DEBUG_VFS_INODE_CREATE < cycle )
162printk("\n[DBG] %s : thread %x enter / dentry = %x in cluster %x / cycle %d\n",
163__FUNCTION__, CURRENT_THREAD, GET_PTR(dentry_xp), GET_CXY(dentry_xp), cycle );
164#endif
165 
166    // check fs type and get pointer on context
167    if     ( fs_type == FS_TYPE_FATFS ) ctx = &fs_context[FS_TYPE_FATFS];
168    else if( fs_type == FS_TYPE_RAMFS ) ctx = &fs_context[FS_TYPE_RAMFS];
169    else if( fs_type == FS_TYPE_DEVFS ) ctx = &fs_context[FS_TYPE_DEVFS];
170    else
171    {
172        ctx = NULL;
173                assert( false , __FUNCTION__ , "illegal file system type = %d\n" , fs_type );
174    }
175
176    // allocate inum
177    error = vfs_ctx_inum_alloc( ctx , &inum );
178
179    if( error )
180    {
181        printk("\n[ERROR] in %s : cannot allocate inum\n", __FUNCTION__ );
182        return ENOMEM;
183    }
184
185    // allocate memory for mapper
186    mapper = mapper_create( fs_type );
187
188    if( mapper == NULL )
189    {
190        printk("\n[ERROR] in %s : cannot allocate mapper\n", __FUNCTION__ );
191        vfs_ctx_inum_release( ctx , inum );
192        return ENOMEM;
193    }
194
195    // allocate memory for VFS inode descriptor
196        req.type  = KMEM_VFS_INODE;
197        req.size  = sizeof(vfs_inode_t);
198    req.flags = AF_KERNEL | AF_ZERO;
199        inode     = (vfs_inode_t *)kmem_alloc( &req );
200
201    if( inode == NULL )
202    {
203        printk("\n[ERROR] in %s : cannot allocate inode descriptor\n", __FUNCTION__ );
204        vfs_ctx_inum_release( ctx , inum );
205        mapper_destroy( mapper );
206        return ENOMEM;
207    }
208
209    // initialize inode descriptor
210    inode->gc         = 0;
211    inode->type       = inode_type;
212    inode->inum       = inum;
213    inode->attr       = attr;
214    inode->rights     = rights;
215    inode->uid        = uid;
216    inode->gid        = gid;
217    inode->refcount   = 0;
218    inode->parent_xp  = dentry_xp;
219    inode->ctx        = ctx;
220    inode->mapper     = mapper;
221    inode->extend     = extend;
222
223    // initialise inode field in mapper
224    mapper->inode     = inode;
225 
226    // initialise threads waiting queue
227    xlist_root_init( XPTR( local_cxy , &inode->wait_root ) );
228
229    // initialize dentries hash table
230    xhtab_init( &inode->children , XHTAB_DENTRY_TYPE );
231
232    // initialize inode locks
233    remote_rwlock_init( XPTR( local_cxy , &inode->data_lock ) );
234    remote_spinlock_init( XPTR( local_cxy , &inode->main_lock ) );
235
236#if DEBUG_VFS_INODE_CREATE
237cycle = (uint32_t)hal_get_cycles();
238if( DEBUG_VFS_INODE_CREATE < cycle )
239printk("\n[DBG] %s : thread %x exit / inode = %x in cluster %x / cycle %d\n",
240__FUNCTION__, CURRENT_THREAD, inode, local_cxy, cycle );
241#endif
242 
243    // return extended pointer on inode
244    *inode_xp = XPTR( local_cxy , inode );
245    return 0;
246
247}  // end vfs_inode_create() 
248
249////////////////////////////////////////////////
250error_t vfs_inode_destroy( vfs_inode_t * inode )
251{
252    assert( (inode->refcount == 0), __FUNCTION__ , "inode refcount non zero\n" );
253
254    // release memory allocated for mapper
255    mapper_destroy( inode->mapper );
256
257    // release memory allocate for inode descriptor
258        kmem_req_t req;
259        req.ptr   = inode;
260        req.type  = KMEM_VFS_INODE;
261        kmem_free( &req );
262
263    return 0;
264
265}  // end vfs_inode_destroy()
266
267/////////////////////////////////////////////
268error_t vfs_inode_load( vfs_inode_t * parent,
269                        char        * name,
270                        xptr_t        child_xp )
271{
272
273#if DEBUG_VFS_INODE_LOAD
274uint32_t cycle = (uint32_t)hal_get_cycles();
275if( DEBUG_VFS_INODE_LOAD < cycle )
276printk("\n[DBG] %s : thread %x enter for <%s> / cycle %d\n",
277__FUNCTION__, CURRENT_THREAD , name , cycle );
278#endif
279
280    error_t error = 0;
281
282    assert( (parent != NULL) , __FUNCTION__ , "parent pointer is NULL\n");
283
284    assert( (child_xp != XPTR_NULL) , __FUNCTION__ , "child pointer is NULL\n");
285
286    // get parent inode FS type
287    vfs_fs_type_t fs_type = parent->ctx->type;
288
289    // call relevant FS function
290    if( fs_type == FS_TYPE_FATFS )
291    {
292        error = fatfs_inode_load( parent , name , child_xp );
293    }
294    else if( fs_type == FS_TYPE_RAMFS )
295    {
296        assert( false , __FUNCTION__ , "should not be called for RAMFS\n" );
297    }
298    else if( fs_type == FS_TYPE_DEVFS )
299    {
300        assert( false , __FUNCTION__ , "should not be called for DEVFS\n" );
301    }
302    else
303    {
304        assert( false , __FUNCTION__ , "undefined file system type\n" );
305    }
306
307#if DEBUG_VFS_INODE_LOAD
308cycle = (uint32_t)hal_get_cycles();
309if( DEBUG_VFS_INODE_LOAD < cycle )
310printk("\n[DBG] %s : thread %x exit for <%s> / cycle %d\n",
311__FUNCTION__, CURRENT_THREAD , name , cycle );
312#endif
313
314    return error;
315
316} // end vfs_inode_load()
317
318////////////////////////////////////////////
319void vfs_inode_remote_up( xptr_t  inode_xp )
320{
321    // get inode cluster and local pointer
322    cxy_t         inode_cxy = GET_CXY( inode_xp );
323    vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
324
325    hal_remote_atomic_add( XPTR( inode_cxy , &inode_ptr->refcount ) , 1 );   
326}
327
328//////////////////////////////////////////////
329void vfs_inode_remote_down( xptr_t  inode_xp )
330{
331    // get inode cluster and local pointer
332    cxy_t         inode_cxy = GET_CXY( inode_xp );
333    vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
334
335    hal_remote_atomic_add( XPTR( inode_cxy , &inode_ptr->refcount ) , -1 );   
336}
337
338//////////////////////////////////////////////
339uint32_t vfs_inode_get_size( xptr_t inode_xp )
340{
341    // get inode cluster and local pointer
342    cxy_t         cxy = GET_CXY( inode_xp );
343    vfs_inode_t * ptr = (vfs_inode_t *)GET_PTR( inode_xp );
344
345    // get size
346    remote_rwlock_rd_lock( XPTR( cxy , &ptr->data_lock ) );
347    uint32_t size = hal_remote_lw( XPTR( cxy , &ptr->size ) );
348    remote_rwlock_rd_unlock( XPTR( cxy , &ptr->data_lock ) );
349    return size;
350}
351
352////////////////////////////////////////////
353void vfs_inode_set_size( xptr_t    inode_xp,
354                         uint32_t  size )
355{
356    // get inode cluster and local pointer
357    cxy_t         cxy = GET_CXY( inode_xp );
358    vfs_inode_t * ptr = (vfs_inode_t *)GET_PTR( inode_xp );
359
360    // set size
361    remote_rwlock_wr_unlock( XPTR( cxy , &ptr->data_lock ) );
362    hal_remote_sw( XPTR( cxy , &ptr->size ) , size );
363    remote_rwlock_wr_unlock( XPTR( cxy , &ptr->data_lock ) );
364}
365
366////////////////////////////////////////
367void vfs_inode_unlock( xptr_t inode_xp )
368{
369    // get inode cluster and local pointer
370    cxy_t         cxy = GET_CXY( inode_xp );
371    vfs_inode_t * ptr = (vfs_inode_t *)GET_PTR( inode_xp );
372
373    // release the main lock
374    remote_spinlock_unlock( XPTR( cxy , &ptr->main_lock ) );
375}
376
377//////////////////////////////////////
378void vfs_inode_lock( xptr_t inode_xp )
379{
380    // get inode cluster and local pointer
381    cxy_t         cxy = GET_CXY( inode_xp );
382    vfs_inode_t * ptr = (vfs_inode_t *)GET_PTR( inode_xp );
383
384    // get the main lock
385    remote_spinlock_lock( XPTR( cxy , &ptr->main_lock ) );
386}
387
388/////////////////////////////////////////
389void vfs_inode_get_name( xptr_t inode_xp,
390                         char * name )
391{
392    cxy_t          inode_cxy;
393    vfs_inode_t  * inode_ptr;
394    xptr_t         dentry_xp;
395    cxy_t          dentry_cxy;
396    vfs_dentry_t * dentry_ptr;
397   
398    // get inode cluster and local pointer
399    inode_cxy = GET_CXY( inode_xp );
400    inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
401
402    // get parent dentry
403    dentry_xp  = hal_remote_lwd( XPTR( inode_cxy , &inode_ptr->parent_xp ) );
404
405    // get local copy of name
406    if( dentry_xp == XPTR_NULL )  // it is the VFS root
407    {
408        strcpy( name , "/" );
409    }
410    else                          // not the VFS root
411    {
412        dentry_cxy = GET_CXY( dentry_xp );
413        dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
414
415        hal_remote_strcpy( XPTR( local_cxy  , name ) , 
416                           XPTR( dentry_cxy , &dentry_ptr->name ) );
417    }
418}  // end vfs_inode_get_name()
419
420////////////////////////////////////////////////////////////////////////////////////////////
421//           Dentry related functions
422//////////////////////////////////////////////////////////////////////////////////////////
423
424///////////////////////////////////////////////////
425error_t vfs_dentry_create( vfs_fs_type_t   fs_type,
426                           char          * name,
427                           vfs_inode_t   * parent,
428                           xptr_t        * dentry_xp )
429{
430    vfs_ctx_t      * ctx;        // context descriptor
431    vfs_dentry_t   * dentry;     // dentry descriptor (to be allocated)
432        kmem_req_t       req;        // request to kernel memory allocator
433    error_t          error;
434
435#if DEBUG_VFS_DENTRY_CREATE
436uint32_t cycle = (uint32_t)hal_get_cycles();
437if( DEBUG_VFS_DENTRY_CREATE < cycle )
438printk("\n[DBG] %s : thread %x in process %x enter for <%s> / parent_inode %x / cycle %d\n",
439__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, name, parent, cycle );
440#endif
441
442    // get pointer on context
443    if     ( fs_type == FS_TYPE_FATFS ) ctx = &fs_context[FS_TYPE_FATFS];
444    else if( fs_type == FS_TYPE_RAMFS ) ctx = &fs_context[FS_TYPE_RAMFS];
445    else if( fs_type == FS_TYPE_DEVFS ) ctx = &fs_context[FS_TYPE_DEVFS];
446    else 
447    {
448        ctx = NULL;
449        return EINVAL;
450    }
451
452    // get name length
453    uint32_t length = strlen( name );
454
455    if( length >= CONFIG_VFS_MAX_NAME_LENGTH ) return EINVAL;
456
457    // allocate memory for dentry descriptor
458        req.type  = KMEM_VFS_DENTRY;
459        req.size  = sizeof(vfs_dentry_t);
460    req.flags = AF_KERNEL | AF_ZERO;
461        dentry     = (vfs_dentry_t *)kmem_alloc( &req );
462
463    if( dentry == NULL ) return ENOMEM;
464
465    // initialize dentry descriptor
466
467    dentry->ctx     = ctx;
468    dentry->length  = length;
469    dentry->parent  = parent;
470    strcpy( dentry->name , name );
471
472#if( DEBUG_VFS_DENTRY_CREATE & 1 )
473cycle = (uint32_t)hal_get_cycles();
474if( DEBUG_VFS_DENTRY_CREATE < cycle )
475printk("\n[DBG] %s : dentry initialised\n", __FUNCTION__ );
476#endif
477
478    // register dentry in hash table rooted in parent inode
479    error = xhtab_insert( XPTR( local_cxy , &parent->children ),
480                          name, 
481                          XPTR( local_cxy , &dentry->list ) );
482
483    if( error ) return EINVAL;
484
485#if( DEBUG_VFS_DENTRY_CREATE & 1 )
486cycle = (uint32_t)hal_get_cycles();
487if( DEBUG_VFS_DENTRY_CREATE < cycle )
488printk("\n[DBG] %s : dentry registerd in htab\n", __FUNCTION__ );
489#endif
490
491    // return extended pointer on dentry
492    *dentry_xp = XPTR( local_cxy , dentry );
493
494#if DEBUG_VFS_DENTRY_CREATE
495cycle = (uint32_t)hal_get_cycles();
496if( DEBUG_VFS_DENTRY_CREATE < cycle )
497printk("\n[DBG] %s : thread %x in process %x exit for <%s> / dentry %x / cycle %d\n",
498__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, name, dentry, cycle );
499#endif
500
501    return 0;
502
503}  // end vfs_dentry_create()
504
505///////////////////////////////////////////////////
506error_t vfs_dentry_destroy( vfs_dentry_t * dentry )
507{
508    error_t error;
509
510    assert( (dentry->refcount == 0) , __FUNCTION__ , "dentry refcount non zero\n" );
511
512    // get pointer on parent inode
513    vfs_inode_t * parent = dentry->parent;
514
515    // remove this dentry from parent inode htab
516    error = xhtab_remove( XPTR( local_cxy , &parent->children ),
517                          dentry->name,
518                          XPTR( local_cxy , &dentry->list ) ); 
519
520    if( error ) return EINVAL;     
521
522    // release memory allocated to dentry
523        kmem_req_t req;
524        req.ptr   = dentry;
525        req.type  = KMEM_VFS_DENTRY;
526        kmem_free( &req );
527
528    return 0;
529}
530
531
532
533//////////////////////////////////////////////////////////////////////////////////////////
534//           File descriptor related functions
535//////////////////////////////////////////////////////////////////////////////////////////
536
537/////////////////////////////////////////////
538error_t vfs_file_create( vfs_inode_t * inode,
539                         uint32_t      attr,
540                         xptr_t      * file_xp )
541{
542    vfs_file_t  * file;
543        kmem_req_t    req;
544
545    // allocate memory for new file descriptor
546        req.type  = KMEM_VFS_FILE;
547        req.size  = sizeof(vfs_file_t);
548    req.flags = AF_KERNEL | AF_ZERO;
549        file      = (vfs_file_t *)kmem_alloc( &req );
550
551    if( file == NULL ) return ENOMEM;
552
553    // initializes new file descriptor
554    file->gc       = 0;
555    file->type     = inode->type;
556    file->attr     = attr;
557    file->offset   = 0;
558    file->refcount = 1;
559    file->inode    = inode;
560    file->ctx      = inode->ctx;
561    file->mapper   = inode->mapper;
562
563    remote_rwlock_init( XPTR( local_cxy , &file->lock ) );
564
565    *file_xp = XPTR( local_cxy , file );
566
567#if DEBUG_VFS_OPEN
568uint32_t cycle = (uint32_t)hal_get_cycles();
569if( DEBUG_VFS_OPEN < cycle )
570printk("\n[DBG] %s : thread %x in process %x created file %x in cluster %x / cycle %d\n",
571__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, file, local_cxy, cycle );
572#endif
573
574    return 0;
575
576}  // end vfs_file_create()
577
578///////////////////////////////////////////
579void vfs_file_destroy( vfs_file_t *  file )
580{
581    if( file->refcount )
582    {
583        assert( false , __FUNCTION__ , "refcount non zero\n" );
584    }       
585
586        kmem_req_t req;
587        req.ptr   = file;
588        req.type  = KMEM_VFS_FILE;
589        kmem_free( &req );
590
591#if DEBUG_VFS_CLOSE
592uint32_t cycle = (uint32_t)hal_get_cycles();
593if( DEBUG_VFS_CLOSE < cycle )
594printk("\n[DBG] %s : thread %x in process %x deleted file %x in cluster %x / cycle %d\n",
595__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, file, local_cxy, cycle );
596#endif
597
598}  // end vfs_file_destroy()
599
600
601////////////////////////////////////////
602void vfs_file_count_up( xptr_t file_xp )
603{
604    // get file cluster and local pointer
605    cxy_t        file_cxy = GET_CXY( file_xp );
606    vfs_file_t * file_ptr = GET_PTR( file_xp ); 
607
608    // atomically increment count
609    hal_remote_atomic_add( XPTR( file_cxy , &file_ptr->refcount ) , 1 ); 
610}
611
612//////////////////////////////////////////
613void vfs_file_count_down( xptr_t file_xp )
614{
615    // get file cluster and local pointer
616    cxy_t        file_cxy = GET_CXY( file_xp );
617    vfs_file_t * file_ptr = GET_PTR( file_xp ); 
618
619    // atomically decrement count
620    hal_remote_atomic_add( XPTR( file_cxy , &file_ptr->refcount ) , -1 ); 
621}
622
623//////////////////////////////////////////////////////////////////////////////////////////
624//           File access related functions
625//////////////////////////////////////////////////////////////////////////////////////////
626
627//////////////////////////////////////
628error_t vfs_open( process_t * process,
629                          char      * path,
630                          uint32_t    flags,
631                  uint32_t    mode, 
632                          xptr_t    * new_file_xp,
633                  uint32_t  * new_file_id )
634{
635    error_t       error;
636    xptr_t        inode_xp;     // extended pointer on target inode
637    cxy_t         inode_cxy;    // inode cluster identifier       
638    vfs_inode_t * inode_ptr;    // inode local pointer
639    uint32_t      file_attr;    // file descriptor attributes
640    uint32_t      lookup_mode;  // lookup working mode       
641    xptr_t        file_xp;      // extended pointer on created file descriptor
642    uint32_t      file_id;      // created file descriptor index in reference fd_array
643
644#if DEBUG_VFS_OPEN
645uint32_t cycle = (uint32_t)hal_get_cycles();
646if( DEBUG_VFS_OPEN < cycle )
647printk("\n[DBG] %s :  thread %x in process %x enter for <%s> / cycle %d\n",
648__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, path, cycle );
649#endif
650
651    // compute lookup working mode
652    lookup_mode = VFS_LOOKUP_OPEN;
653    if( (flags & O_DIR    )      )  lookup_mode |= VFS_LOOKUP_DIR;
654    if( (flags & O_CREAT  )      )  lookup_mode |= VFS_LOOKUP_CREATE;
655    if( (flags & O_EXCL   )      )  lookup_mode |= VFS_LOOKUP_EXCL;
656 
657    // compute attributes for the created file
658    file_attr = 0;
659    if( (flags & O_RDONLY ) == 0 )  file_attr |= FD_ATTR_WRITE_ENABLE;
660    if( (flags & O_WRONLY ) == 0 )  file_attr |= FD_ATTR_READ_ENABLE;
661    if( (flags & O_SYNC   )      )  file_attr |= FD_ATTR_SYNC;
662    if( (flags & O_APPEND )      )  file_attr |= FD_ATTR_APPEND;
663    if( (flags & O_CLOEXEC)      )  file_attr |= FD_ATTR_CLOSE_EXEC;
664
665    // get extended pointer on target inode
666    error = vfs_lookup( process->vfs_cwd_xp , path , lookup_mode , &inode_xp );
667
668    if( error ) return error;
669
670    // get target inode cluster and local pointer
671    inode_cxy = GET_CXY( inode_xp );
672    inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
673   
674    // create a new file descriptor in cluster containing inode
675    if( inode_cxy == local_cxy )      // target cluster is local
676    {
677        error = vfs_file_create( inode_ptr , file_attr , &file_xp );
678    }
679    else                              // target cluster is remote
680    {
681        rpc_vfs_file_create_client( inode_cxy , inode_ptr , file_attr , &file_xp , &error );
682    }
683
684    if( error )  return error;
685
686    // allocate and register a new file descriptor index in reference process
687    error = process_fd_register( process , file_xp , &file_id );
688
689    if( error ) return error;
690
691#if DEBUG_VFS_OPEN
692cycle = (uint32_t)hal_get_cycles();
693if( DEBUG_VFS_OPEN < cycle )
694printk("\n[DBG] %s :  thread %x in process %x exit for <%s> / fdid %d / cluster %x / cycle %d\n",
695__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, path,
696file_id, GET_CXY( file_xp ), cycle );
697#endif
698
699    // success
700    *new_file_xp = file_xp;
701    *new_file_id = file_id;
702    return 0;
703
704}  // end vfs_open()
705
706//////////////////////////////////////
707int vfs_user_move( bool_t   to_buffer,
708                   xptr_t   file_xp,
709                   void   * buffer,
710                   uint32_t size )
711{
712    assert( ( file_xp != XPTR_NULL ) , __FUNCTION__ , "file_xp == XPTR_NULL" );
713
714    cxy_t              file_cxy;     // remote file descriptor cluster
715    vfs_file_t       * file_ptr;     // remote file descriptor local pointer
716    vfs_inode_type_t   inode_type;
717    uint32_t           file_offset;  // current offset in file
718    mapper_t         * mapper;
719    error_t            error;
720
721    // get cluster and local pointer on remote file descriptor
722    file_cxy  = GET_CXY( file_xp );
723    file_ptr  = (vfs_file_t *)GET_PTR( file_xp );
724
725    // get inode type from remote file descriptor
726    inode_type = hal_remote_lw( XPTR( file_cxy , &file_ptr->type   ) );
727   
728    assert( (inode_type == INODE_TYPE_FILE) , __FUNCTION__ ,
729    "inode type is not INODE_TYPE_FILE" );
730
731    // get mapper pointer and file offset from file descriptor
732    file_offset = hal_remote_lw( XPTR( file_cxy , &file_ptr->offset ) );
733    mapper = (mapper_t *)hal_remote_lpt( XPTR( file_cxy , &file_ptr->mapper ) );
734
735    // move data between mapper and buffer
736    if( file_cxy == local_cxy )
737    {
738        error = mapper_move_user( mapper,
739                                  to_buffer,
740                                  file_offset,
741                                  buffer,
742                                  size );
743    }
744    else
745    {
746        rpc_mapper_move_buffer_client( file_cxy,
747                                       mapper,
748                                       to_buffer,
749                                       true,          // user buffer
750                                       file_offset,
751                                       (uint64_t)(intptr_t)buffer,
752                                       size,
753                                       &error );
754    } 
755
756    if( error ) return -1;
757    else        return size;
758
759}  // end vfs_user_move()
760
761////////////////////////////////////////////
762error_t vfs_kernel_move( bool_t   to_buffer,
763                         xptr_t   file_xp,
764                         xptr_t   buffer_xp,
765                         uint32_t size )
766{
767    assert( ( file_xp != XPTR_NULL ) , __FUNCTION__ , "file_xp == XPTR_NULL" );
768
769    cxy_t              file_cxy;     // remote file descriptor cluster
770    vfs_file_t       * file_ptr;     // remote file descriptor local pointer
771    vfs_inode_type_t   inode_type;
772    uint32_t           file_offset;  // current offset in file
773    mapper_t         * mapper;
774    error_t            error;
775
776    // get cluster and local pointer on remote file descriptor
777    file_cxy  = GET_CXY( file_xp );
778    file_ptr  = (vfs_file_t *)GET_PTR( file_xp );
779
780    // get inode type from remote file descriptor
781    inode_type = hal_remote_lw( XPTR( file_cxy , &file_ptr->type   ) );
782   
783    // action depends on inode type
784    if( inode_type == INODE_TYPE_FILE )
785    {
786        // get mapper pointer and file offset from file descriptor
787        file_offset = hal_remote_lw( XPTR( file_cxy , &file_ptr->offset ) );
788        mapper = (mapper_t *)hal_remote_lpt( XPTR( file_cxy , &file_ptr->mapper ) );
789
790        // move data between mapper and buffer
791        if( file_cxy == local_cxy )
792        {
793            error = mapper_move_kernel( mapper,
794                                        to_buffer,
795                                        file_offset,
796                                        buffer_xp,
797                                        size );
798        }
799        else
800        {
801            rpc_mapper_move_buffer_client( file_cxy,
802                                           mapper,
803                                           to_buffer,
804                                           false,          // kernel buffer
805                                           file_offset,
806                                           buffer_xp,
807                                           size,
808                                           &error );
809        } 
810
811        if( error ) return -1;
812        else        return 0;
813    }
814    else 
815    {
816        printk("\n[ERROR] in %s : inode is not a file", __FUNCTION__ );
817        return -1;
818    }
819}  // end vfs_kernel_move()
820
821//////////////////////////////////////
822error_t vfs_lseek( xptr_t     file_xp,
823                   uint32_t   offset,
824                   uint32_t   whence, 
825                   uint32_t * new_offset )
826{
827    xptr_t         offset_xp;
828    xptr_t         lock_xp;
829    cxy_t          file_cxy;
830    vfs_file_t  *  file_ptr;
831    vfs_inode_t *  inode_ptr;
832    uint32_t       new;
833
834    assert( (file_xp != XPTR_NULL) , __FUNCTION__ , "file_xp == XPTR_NULL" );
835
836    // get cluster and local pointer on remote file descriptor
837    file_cxy = GET_CXY( file_xp );
838    file_ptr = (vfs_file_t *)GET_PTR( file_xp );
839
840    // build extended pointers on lock and offset
841    offset_xp = XPTR( file_cxy , &file_ptr->offset );
842    lock_xp   = XPTR( file_cxy , &file_ptr->lock );
843
844    // take file descriptor lock
845    remote_rwlock_wr_lock( lock_xp );
846
847    if      ( whence == SEEK_CUR )   // new = current + offset
848    {
849        new = hal_remote_lw( offset_xp ) + offset;
850    }
851    else if ( whence == SEEK_SET )   // new = offset
852    {
853        new = offset;
854    }
855    else if ( whence == SEEK_END )   // new = size + offset
856    { 
857        // get local pointer on remote inode
858        inode_ptr = (vfs_inode_t *)hal_remote_lpt( XPTR( file_cxy , &file_ptr->inode ) );
859
860        new = hal_remote_lw( XPTR( file_cxy , &inode_ptr->size ) ) + offset;
861    }
862    else
863    {
864        printk("\n[ERROR] in %s : illegal whence value\n", __FUNCTION__ );
865        remote_rwlock_wr_unlock( lock_xp );
866        return -1;
867    }
868
869    // set new offset
870    hal_remote_sw( offset_xp , new );
871
872    // release file descriptor lock
873    remote_rwlock_wr_unlock( lock_xp );
874
875    // success
876    if ( new_offset != NULL )
877        *new_offset = new;
878    return 0;
879
880}  // vfs_lseek()
881
882///////////////////////////////////
883error_t vfs_close( xptr_t   file_xp,
884                   uint32_t file_id )
885{
886    cluster_t  * cluster;          // local pointer on local cluster
887    cxy_t        file_cxy;         // cluster containing the file descriptor.
888    vfs_file_t * file_ptr;         // local ponter on file descriptor
889    cxy_t        owner_cxy;        // process owner cluster
890    lpid_t       lpid;             // process local index
891    xptr_t       root_xp;          // root of list of process copies
892    xptr_t       lock_xp;          // lock protecting the list of copies
893    xptr_t       iter_xp;          // iterator on list of process copies
894    xptr_t       process_xp;       // extended pointer on one process copy
895    cxy_t        process_cxy;      // process copy cluster
896    process_t  * process_ptr;      // process copy local pointer
897
898    assert( (file_xp != XPTR_NULL) , __FUNCTION__ , "file_xp == XPTR_NULL" );
899
900    assert( (file_id < CONFIG_PROCESS_FILE_MAX_NR) , __FUNCTION__ , "illegal file_id" );
901
902    thread_t  * this    = CURRENT_THREAD;
903    process_t * process = this->process;
904
905#if DEBUG_VFS_CLOSE
906uint32_t cycle = (uint32_t)hal_get_cycles();
907if( DEBUG_VFS_CLOSE < cycle )
908printk("\n[DBG] %s : thread %x in process %x enter / fdid %d / cycle %d\n",
909__FUNCTION__, this->trdid, process->pid, file_id, cycle );
910#endif
911
912    // get local pointer on local cluster manager
913    cluster = LOCAL_CLUSTER;
914
915    // get owner process cluster and lpid
916    owner_cxy  = CXY_FROM_PID( process->pid );
917    lpid       = LPID_FROM_PID( process->pid );
918
919    // get extended pointers on copies root and lock
920    root_xp = XPTR( owner_cxy , &cluster->pmgr.copies_root[lpid] );
921    lock_xp = XPTR( owner_cxy , &cluster->pmgr.copies_lock[lpid] );
922
923    // 1) loop on the process descriptor copies to reset all fd_array[file_id] entries
924
925    // take the lock protecting the list of copies
926    remote_spinlock_lock( lock_xp );
927
928    XLIST_FOREACH( root_xp , iter_xp )
929    {
930        process_xp  = XLIST_ELEMENT( iter_xp , process_t , copies_list );
931        process_cxy = GET_CXY( process_xp );
932        process_ptr = GET_PTR( process_xp );
933
934#if (DEBUG_VFS_CLOSE & 1 )
935if( DEBUG_VFS_CLOSE < cycle )
936printk("\n[DBG] %s : reset fd_array[%d] for process %x in cluster %x\n",
937__FUNCTION__, file_id, process_ptr, process_cxy );
938#endif
939
940// fd_array lock is required for atomic write of a 64 bits word
941// xptr_t fd_array_lock_xp = XPTR( process_cxy , &process_ptr->fd_array.lock );
942
943        xptr_t entry_xp         = XPTR( process_cxy , &process_ptr->fd_array.array[file_id] );
944
945// remote_rwlock_wr_lock( fd_array_lock_xp );
946
947        hal_remote_swd( entry_xp , XPTR_NULL );
948       
949// remote_rwlock_wr_unlock( fd_array_lock_xp );
950
951        vfs_file_count_down( file_xp );
952
953        hal_fence();
954    }   
955
956    // release the lock protecting the list of copies
957    remote_spinlock_unlock( lock_xp );
958
959#if (DEBUG_VFS_CLOSE & 1)
960if( DEBUG_VFS_CLOSE < cycle )
961printk("\n[DBG] %s : thread %x in process %x reset all fd-array copies\n",
962__FUNCTION__, this->trdid, process->pid );
963#endif
964
965    // 2) release memory allocated to file descriptor in remote cluster
966
967    // get cluster and local pointer on remote file descriptor
968    file_cxy = GET_CXY( file_xp );
969    file_ptr = GET_PTR( file_xp );
970
971    if( file_cxy == local_cxy )             // file cluster is local
972    {
973        vfs_file_destroy( file_ptr );
974    }
975    else                                    // file cluster is local
976    {
977        rpc_vfs_file_destroy_client( file_cxy , file_ptr );
978    }
979
980#if DEBUG_VFS_CLOSE
981cycle = (uint32_t)hal_get_cycles();
982if( DEBUG_VFS_CLOSE < cycle )
983printk("\n[DBG] %s : thread %x in process %x exit / fdid %d closed / cycle %d\n",
984__FUNCTION__, this->trdid, process->pid, file_id, cycle );
985#endif
986
987    return 0;
988
989}  // end vfs_close()
990
991////////////////////////////////////
992error_t vfs_unlink( xptr_t   cwd_xp,
993                    char   * path )
994{
995    assert( false , __FUNCTION__ , "not implemented\n" );
996    return 0;
997} 
998
999////////////////////////////////////////
1000error_t vfs_stat( xptr_t        file_xp,
1001                  struct stat * k_stat )
1002{
1003    assert( false , __FUNCTION__ , "not implemented\n" );
1004    return 0;
1005}
1006
1007/////////////////////////////////////////////
1008error_t vfs_readdir( xptr_t          file_xp,
1009                     struct dirent * k_dirent )
1010{
1011    assert( false , __FUNCTION__ , "not implemented\n" );
1012    return 0;
1013}
1014
1015//////////////////////////////////////
1016error_t vfs_mkdir( xptr_t     file_xp,
1017                   char     * path,
1018                   uint32_t   mode )
1019{
1020    assert( false , __FUNCTION__ , "not implemented\n" );
1021    return 0;
1022}
1023
1024////////////////////////////////////
1025error_t vfs_rmdir( xptr_t   file_xp,
1026                   char   * path )
1027{
1028    assert( false , __FUNCTION__ , "not implemented\n" );
1029    return 0;
1030}
1031
1032///////////////////////////////////
1033error_t vfs_chdir( xptr_t   cwd_xp,
1034                   char   * path )
1035{
1036    error_t           error;
1037    xptr_t            inode_xp;     // extended pointer on target inode
1038    cxy_t             inode_cxy;    // target inode cluster identifier       
1039    vfs_inode_t     * inode_ptr;    // target inode local pointer
1040    uint32_t          mode;         // lookup working mode       
1041    vfs_inode_type_t  inode_type;   // target inode type
1042
1043    // set lookup working mode
1044    mode = 0;
1045
1046    // get extended pointer on target inode
1047    error = vfs_lookup( cwd_xp , path , mode , &inode_xp );
1048
1049    if( error ) return error;
1050
1051    // get inode cluster and local pointer
1052    inode_cxy = GET_CXY( inode_xp );
1053    inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
1054
1055    // get inode type from remote file
1056    inode_type = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->type ) );
1057
1058    if( inode_type != INODE_TYPE_DIR )
1059    {
1060        CURRENT_THREAD->errno = ENOTDIR;
1061        return -1;
1062    }
1063
1064    assert( false , __FUNCTION__ , "not implemented\n" );
1065    return 0;
1066}
1067
1068///////////////////////////////////
1069error_t vfs_chmod( xptr_t   cwd_xp,
1070                   char   * path,
1071                   uint32_t rights )
1072{
1073    error_t           error;
1074    xptr_t            inode_xp;     // extended pointer on target inode
1075    cxy_t             inode_cxy;    // inode cluster identifier       
1076    vfs_inode_t     * inode_ptr;    // inode local pointer
1077    uint32_t          mode;         // lookup working mode
1078    vfs_inode_type_t  inode_type;   // target inode type
1079
1080    // set lookup working mode
1081    mode = 0;
1082 
1083    // get extended pointer on target inode
1084    error = vfs_lookup( cwd_xp , path , mode , &inode_xp );
1085
1086    if( error ) return error;
1087
1088    // get inode cluster and local pointer
1089    inode_cxy = GET_CXY( inode_xp );
1090    inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
1091   
1092    // get inode type from remote inode
1093    inode_type = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->type ) );
1094
1095   
1096    assert( false , __FUNCTION__ , "not implemented\n" );
1097    return 0;
1098}
1099
1100///////////////////////////////////
1101error_t vfs_mkfifo( xptr_t   cwd_xp,
1102                    char   * path,
1103                    uint32_t rights )
1104{
1105    assert( false , __FUNCTION__ , "not implemented\n" );
1106    return 0;
1107}
1108
1109
1110
1111//////////////////////////////////////////////////////////////////////////////////////////
1112//            Inode Tree functions
1113//////////////////////////////////////////////////////////////////////////////////////////
1114
1115/////////////////////////////////
1116cxy_t vfs_cluster_random_select()
1117{
1118    uint32_t  x_size    = LOCAL_CLUSTER->x_size;
1119    uint32_t  y_size    = LOCAL_CLUSTER->y_size;
1120    uint32_t  y_width   = LOCAL_CLUSTER->y_width;
1121    uint32_t  index     = ( hal_get_cycles() + hal_get_gid() ) % (x_size * y_size);
1122    uint32_t  x         = index / y_size;   
1123    uint32_t  y         = index % y_size;
1124
1125    return (x<<y_width) + y;
1126}
1127
1128
1129//////////////////////////////////////////////////////////////////////////
1130// This static function is called by the vfs_display() function.
1131// that is supposed to take the TXT0 lock.
1132//////////////////////////////////////////////////////////////////////////
1133static void vfs_recursive_display( xptr_t   inode_xp,
1134                                   xptr_t   name_xp,
1135                                   xptr_t   dentry_xp,
1136                                   uint32_t indent )
1137{
1138    cxy_t              inode_cxy;
1139    vfs_inode_t      * inode_ptr;
1140    vfs_inode_type_t   inode_type;
1141    xptr_t             children_xp;    // extended pointer on children xhtab
1142
1143    xptr_t             child_dentry_xp;
1144    cxy_t              child_dentry_cxy;
1145    vfs_dentry_t     * child_dentry_ptr;
1146    xptr_t             child_inode_xp;
1147    xptr_t             child_dentry_name_xp;
1148
1149    char               name[CONFIG_VFS_MAX_NAME_LENGTH];
1150
1151    char *             indent_str[] = { "",                                  // level 0
1152                                        "  ",                                // level 1
1153                                        "    ",                              // level 2
1154                                        "      ",                            // level 3
1155                                        "        ",                          // level 4
1156                                        "          ",                        // level 5
1157                                        "            ",                      // level 6
1158                                        "              ",                    // level 7
1159                                        "                ",                  // level 8
1160                                        "                  ",                // level 9
1161                                        "                    ",              // level 10
1162                                        "                      ",            // level 11
1163                                        "                        ",          // level 12
1164                                        "                          ",        // level 13
1165                                        "                            ",      // level 14
1166                                        "                              " };  // level 15
1167
1168    assert( (inode_xp != XPTR_NULL) , __FUNCTION__ , "inode_xp cannot be NULL\n" );
1169    assert( (name_xp  != XPTR_NULL) , __FUNCTION__ , "name_xp cannot be NULL\n" );
1170    assert( (indent < 16)           , __FUNCTION__ , "depth cannot be larger than 15\n" );
1171   
1172    // get inode cluster and local pointer
1173    inode_cxy = GET_CXY( inode_xp );
1174    inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
1175
1176    // get inode type
1177    inode_type = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->type ) );
1178
1179    // get local pointer on associated mapper
1180    mapper_t * mapper_ptr = hal_remote_lpt( XPTR( inode_cxy , &inode_ptr->mapper ) );
1181
1182    // make a local copy of node name
1183    hal_remote_strcpy( XPTR( local_cxy , name ) , name_xp );
1184
1185    // display inode
1186    nolock_printk("%s%s <%s> : inode = %x / mapper = %x / cluster %x\n",
1187                  indent_str[indent], vfs_inode_type_str( inode_type ), name,
1188                  inode_ptr , mapper_ptr , inode_cxy );
1189
1190    // scan directory entries 
1191    if( inode_type == INODE_TYPE_DIR )
1192    {
1193        // get extended pointer on directory entries xhtab
1194        children_xp =  XPTR( inode_cxy , &inode_ptr->children );
1195
1196        // get xhtab lock
1197        xhtab_read_lock( children_xp );
1198
1199        // get first dentry from xhtab
1200        child_dentry_xp = xhtab_get_first( children_xp );
1201
1202        while( child_dentry_xp != XPTR_NULL )
1203        {
1204            // get dentry cluster and local pointer
1205            child_dentry_cxy = GET_CXY( child_dentry_xp );
1206            child_dentry_ptr = (vfs_dentry_t *)GET_PTR( child_dentry_xp );
1207
1208            // get extended pointer on child inode
1209            child_inode_xp = hal_remote_lwd( XPTR( child_dentry_cxy,
1210                                                   &child_dentry_ptr->child_xp ) );
1211
1212            // get extended pointer on dentry name
1213            child_dentry_name_xp = XPTR( child_dentry_cxy , &child_dentry_ptr->name );
1214
1215            // recursive call on child inode
1216            vfs_recursive_display( child_inode_xp,
1217                                   child_dentry_name_xp,
1218                                   child_dentry_xp,
1219                                   indent+1 );
1220
1221            // get next dentry
1222            child_dentry_xp = xhtab_get_next( children_xp );
1223        }
1224
1225        // release xhtab lock
1226        xhtab_read_unlock( children_xp );
1227    }
1228}  // end vfs_recursive_display()
1229
1230///////////////////////////////////
1231void vfs_display( xptr_t inode_xp )
1232{
1233    xptr_t         name_xp;
1234    xptr_t         dentry_xp; 
1235    cxy_t          dentry_cxy;
1236    vfs_dentry_t * dentry_ptr;
1237    uint32_t       save_sr;
1238
1239    // get target inode cluster and local pointer
1240    cxy_t         inode_cxy = GET_CXY( inode_xp );
1241    vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
1242
1243    // get extended pointer on associated dentry
1244    dentry_xp   = hal_remote_lwd( XPTR( inode_cxy , &inode_ptr->parent_xp ) );
1245
1246    // check if target inode is the File System root
1247    if( dentry_xp == XPTR_NULL )
1248    {
1249        // build extended pointer on root name
1250        name_xp = XPTR( local_cxy , "/" );
1251    }
1252    else
1253    {
1254        // get dentry cluster and local pointer
1255        dentry_cxy = GET_CXY( dentry_xp );
1256        dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
1257
1258        // get extended pointer on dentry name
1259        name_xp = XPTR( dentry_cxy , &dentry_ptr->name );
1260    }
1261
1262    // get pointers on TXT0 chdev
1263    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
1264    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
1265    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
1266
1267    // get extended pointer on remote TXT0 chdev lock
1268    xptr_t  lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
1269
1270    // get TXT0 lock in busy waiting mode
1271    remote_spinlock_lock_busy( lock_xp , &save_sr );
1272
1273    // print header
1274    nolock_printk("\n***** file system state\n\n");
1275
1276    // call recursive function
1277    vfs_recursive_display( inode_xp , name_xp , dentry_xp , 0 );
1278
1279    // release lock
1280    remote_spinlock_unlock_busy( lock_xp , save_sr );
1281
1282}  // end vfs_display()
1283
1284//////////////////////////////////////////////////////////////////////////////////////////
1285// This function is used by the vfs_lookup() function.
1286// It takes an extended pointer on a remote inode (parent directory inode),
1287// and check access_rights violation for the calling thread.
1288// It can be used by any thread running in any cluster.
1289//////////////////////////////////////////////////////////////////////////////////////////
1290// @ inode_xp    : extended pointer on inode.
1291// @ client_uid  : client thread user ID
1292// @ client_gid  : client thread group ID
1293// @ return true if access rights are violated.
1294//////////////////////////////////////////////////////////////////////////////////////////
1295bool_t vfs_access_denied( xptr_t   inode_xp,
1296                          uint32_t client_uid,
1297                          uint32_t client_gid )
1298{
1299    // get found inode cluster and local pointer
1300    cxy_t         inode_cxy = GET_CXY( inode_xp );
1301    vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
1302
1303    // get inode access mode, UID, and GID
1304    // TODO uint32_t  mode = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->mode ) );
1305    uid_t     uid  = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->uid  ) );
1306    gid_t     gid  = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->gid  ) );
1307
1308    // FIXME : me must use mode
1309    if( (uid == client_uid) || (gid == client_gid) ) return false;
1310    else                                             return true;
1311}
1312
1313//////////////////////////////////////////////////////////////////////////////////////////
1314// This static function is used by the vfs_lookup() function.
1315// It takes an extended pointer on a remote parent directory inode, a directory
1316// entry name, and returns an extended pointer on the child inode.
1317// It can be used by any thread running in any cluster.
1318//////////////////////////////////////////////////////////////////////////////////////////
1319// @ parent_xp   : extended pointer on parent inode in remote cluster.
1320// @ name        : dentry name
1321// @ child_xp    : [out] buffer for extended pointer on child inode.
1322// @ return true if success / return false if not found.
1323//////////////////////////////////////////////////////////////////////////////////////////
1324static bool_t vfs_get_child( xptr_t   parent_xp,
1325                             char   * name,
1326                             xptr_t * child_xp )
1327{
1328    xptr_t  xhtab_xp;    // extended pointer on hash table containing children dentries
1329    xptr_t  dentry_xp;   // extended pointer on children dentry
1330
1331    // get parent inode cluster and local pointer
1332    cxy_t         parent_cxy = GET_CXY( parent_xp );
1333    vfs_inode_t * parent_ptr = (vfs_inode_t *)GET_PTR( parent_xp );
1334
1335    // get extended pointer on hash table of children directory entries
1336    xhtab_xp = XPTR( parent_cxy , &parent_ptr->children );
1337
1338    // search extended pointer on matching dentry
1339    dentry_xp = xhtab_lookup( xhtab_xp , name );
1340
1341    if( dentry_xp == XPTR_NULL ) return false;
1342
1343    // get dentry cluster and local pointer
1344    cxy_t          dentry_cxy = GET_CXY( dentry_xp );
1345    vfs_dentry_t * dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
1346
1347    // return child inode
1348    *child_xp = (xptr_t)hal_remote_lwd( XPTR( dentry_cxy , &dentry_ptr->child_xp ) );
1349    return true;
1350
1351}  // end vfs_get_child()
1352
1353//////////////////////////////////////////////////////////////////////////////////////////
1354// This static function is used by the vfs_lookup() function.
1355// It takes the <current> pointer on a buffer containing a complete pathname, and return
1356// in the <name> buffer, allocated by the caller, a single name in the path.
1357// It return also in the <next> pointer the next character to analyse in the path.
1358// Finally it returns a <last> boolean, that is true when the returned <name> is the
1359// last name in the path. The names are supposed to be separated by one or several '/'
1360// characters, that are not written in  the <name> buffer.
1361//////////////////////////////////////////////////////////////////////////////////////////
1362// @ current   : pointer on first character to analyse in buffer containing the path.
1363// @ name      : [out] pointer on buffer allocated by the caller for the returned name.
1364// @ next      : [out] pointer on next character to analyse in buffer containing the path.
1365// @ last      : [out] true if the returned name is the last (NUL character found).
1366// @ return 0 if success / return EINVAL if string empty (first chracter is NUL).
1367//////////////////////////////////////////////////////////////////////////////////////////
1368static error_t vfs_get_name_from_path( char     * current,
1369                                       char     * name,
1370                                       char    ** next,
1371                                       bool_t   * last )
1372{
1373    char * ptr = current;
1374
1375    // skip leading '/' characters
1376    while( *ptr == '/' ) ptr++;
1377
1378    // return EINVAL if string empty
1379    if( *ptr == 0 ) return EINVAL;
1380
1381    // copy all characters in name until NUL or '/'
1382    while( (*ptr != 0) && (*ptr !='/') )  *(name++) = *(ptr++);
1383
1384    // set NUL terminating character in name buffer
1385    *(name++) = 0;
1386
1387    // return last an next
1388    if( *ptr == 0 )             // last found character is NUL => last name in path
1389    {
1390        *last = true;
1391    }
1392    else                        // last found character is '/' => skip it
1393    {
1394        *last = false;
1395        *next = ptr + 1;
1396    }
1397
1398    return 0;
1399
1400}  // end vfs_get name_from_path()
1401   
1402//////////////////////////////////////////////
1403error_t vfs_lookup( xptr_t             cwd_xp,
1404                    char             * pathname,
1405                    uint32_t           mode,
1406                                        xptr_t           * inode_xp )
1407{
1408    char               name[CONFIG_VFS_MAX_NAME_LENGTH];   // one name in path
1409
1410    xptr_t             parent_xp;    // extended pointer on parent inode
1411    cxy_t              parent_cxy;   // cluster for parent inode
1412    vfs_inode_t      * parent_ptr;   // local pointer on parent inode 
1413    xptr_t             child_xp;     // extended pointer on child inode
1414    cxy_t              child_cxy;    // cluster for child inode
1415    vfs_inode_t      * child_ptr;    // local pointer on child inode 
1416    vfs_fs_type_t      fs_type;      // File system type
1417    vfs_ctx_t        * ctx_ptr;      // local pointer on FS context
1418    char             * current;      // current pointer on path
1419    char             * next;         // next value for current pointer   
1420    bool_t             last;         // true when the name is the last in path
1421    bool_t             found;        // true when a child has been found
1422    bool_t             dir;          // searched inode is a directory
1423    bool_t             create;       // searched inode must be created if not found
1424    bool_t             excl;         // searched inode must not exist
1425    thread_t         * this;         // pointer on calling thread descriptor
1426    process_t        * process;      // pointer on calling process descriptor
1427    error_t            error;
1428
1429    this    = CURRENT_THREAD;
1430    process = this->process;
1431
1432#if DEBUG_VFS_LOOKUP
1433uint32_t cycle = (uint32_t)hal_get_cycles();
1434if( DEBUG_VFS_LOOKUP < cycle )
1435printk("\n[DBG] %s : thread %x in process %x enter for <%s> / cycle %d\n",
1436__FUNCTION__, this->trdid, process->pid, pathname, cycle );
1437#endif
1438
1439    // compute lookup flags
1440    dir    = mode & VFS_LOOKUP_DIR;
1441    create = mode & VFS_LOOKUP_CREATE;
1442    excl   = mode & VFS_LOOKUP_EXCL;
1443   
1444    // get extended pointer on first inode to search
1445    if( pathname[0] == '/' ) parent_xp = process->vfs_root_xp;
1446    else                     parent_xp = cwd_xp;
1447
1448    // initialise other loop variables
1449    current  = pathname;
1450    next     = NULL;
1451    last     = false;
1452    child_xp = XPTR_NULL;
1453
1454    // take lock on parent inode
1455    vfs_inode_lock( parent_xp );
1456
1457    // sequencially loop on nodes in pathname
1458    // load from device if one node in path not found in inode tree
1459    // exit loop when last name found (i.e. last == true)
1460    do
1461    {
1462        // get one name from path, and "last" flag
1463        vfs_get_name_from_path( current , name , &next , &last );
1464
1465#if (DEBUG_VFS_LOOKUP & 1)
1466if( DEBUG_VFS_LOOKUP < cycle )
1467printk("\n[DBG] %s : look for <%s> / last = %d\n",
1468__FUNCTION__ , name , last );
1469#endif
1470
1471        // search a child dentry matching name in parent inode
1472        found = vfs_get_child( parent_xp,
1473                               name,
1474                               &child_xp );
1475
1476        if (found == false )  // child not found in inode tree
1477        {
1478
1479#if (DEBUG_VFS_LOOKUP & 1)
1480if( DEBUG_VFS_LOOKUP < cycle )
1481printk("\n[DBG] %s : miss <%s> node => try to create it\n",
1482__FUNCTION__ , name );
1483#endif
1484            // if a child node is not found in the inode tree,
1485            // we introduce a new (dentry/inode) in inode tree,
1486            // and try to find it by scanning the parent directory mapper.
1487            // . if it is found in parent mapper:
1488            //   - if the child is a directory, the child mapper is loaded from device
1489            //   - if the child is not a directory, the search is completed
1490            // . if it is not found in the parent mapper:
1491            //   - if ( not last or not create ) an error is reported
1492            //   - if (last and create and dir) a new directory is created
1493            //   - if (last and create and not dir) a new file is created
1494
1495            // release lock on parent inode
1496            vfs_inode_unlock( parent_xp );
1497 
1498            // get parent inode FS type
1499            parent_cxy = GET_CXY( parent_xp );
1500            parent_ptr = GET_PTR( parent_xp );
1501            ctx_ptr    = (vfs_ctx_t *)hal_remote_lpt( XPTR( parent_cxy,&parent_ptr->ctx ) );
1502            fs_type    = hal_remote_lw( XPTR( parent_cxy , &ctx_ptr->type ) );
1503
1504            // select a cluster for missing inode
1505            child_cxy = vfs_cluster_random_select();
1506 
1507            // insert a new child dentry/inode in inode tree
1508            error = vfs_add_child_in_parent( child_cxy,
1509                                             0,           // type will be updated later
1510                                             fs_type, 
1511                                             parent_xp, 
1512                                             name, 
1513                                             NULL,        // fs_type_specific inode extend
1514                                             &child_xp );
1515            if( error )
1516            {
1517                printk("\n[ERROR] in %s : cannot create node %s for path <%s>\n",
1518                __FUNCTION__ , name, pathname );
1519                return ENOMEM;
1520            }
1521
1522            // get child inode cluster and local pointer
1523            child_cxy = GET_CXY( child_xp );
1524            child_ptr = GET_PTR( child_xp );
1525
1526#if (DEBUG_VFS_LOOKUP & 1)
1527if( DEBUG_VFS_LOOKUP < cycle )
1528printk("\n[DBG] %s : missing <%s> inode speculatively created / cxy %x / ptr %x\n",
1529__FUNCTION__ , name , child_cxy, child_ptr );
1530#endif
1531             // scan parent mapper to complete the missing inode
1532            if( parent_cxy == local_cxy )
1533            {
1534                error = vfs_inode_load( parent_ptr,
1535                                        name,
1536                                        child_xp );
1537            }
1538            else
1539            {
1540                rpc_vfs_inode_load_client( parent_cxy,
1541                                           parent_ptr,
1542                                           name,
1543                                           child_xp,
1544                                           &error );
1545            }
1546
1547            if ( error )   // child not found in parent mapper
1548            {
1549                if( last && create && dir )  // new directory  => update inode type
1550                {
1551                     hal_remote_sw( XPTR( child_cxy, &child_ptr->type ), INODE_TYPE_DIR );
1552
1553#if (DEBUG_VFS_LOOKUP & 1)
1554if( DEBUG_VFS_LOOKUP < cycle )
1555printk("\n[DBG] %s : created node <%s> in path %s / type DIR\n",
1556__FUNCTION__ , name, pathname );
1557#endif
1558                }
1559                else if ( last && create )   // new file => update inode type
1560                {
1561                     hal_remote_sw( XPTR( child_cxy, &child_ptr->type ), INODE_TYPE_FILE );
1562
1563#if (DEBUG_VFS_LOOKUP & 1)
1564if( DEBUG_VFS_LOOKUP < cycle )
1565printk("\n[DBG] %s : created node <%s> in path %s / type FILE\n",
1566__FUNCTION__ , name, pathname );
1567#endif
1568                }
1569                else                         // not last or not create => remove created node
1570                {                       
1571                     printk("\n[ERROR] in %s : <%s> node not found in parent for <%s>\n",
1572                     __FUNCTION__ , name , pathname );
1573                     vfs_remove_child_from_parent( child_xp );
1574                     return ENOENT;
1575                }
1576            }
1577            else          // child found in parent
1578            {
1579                // load child mapper from device if child is a directory (prefetch)
1580                if( hal_remote_lw( XPTR( child_cxy , &child_ptr->type ) ) == INODE_TYPE_DIR ) 
1581                {
1582                    if( child_cxy == local_cxy )
1583                    {
1584                        error = vfs_mapper_load_all( child_ptr );
1585                    }
1586                    else
1587                    {
1588                        rpc_vfs_mapper_load_all_client( child_cxy,
1589                                                        child_ptr,
1590                                                        &error );
1591                    }
1592                    if ( error )
1593                    {
1594                        printk("\n[ERROR] in %s : cannot load <%s> from device\n",
1595                        __FUNCTION__ , name );
1596                        vfs_remove_child_from_parent( child_xp );
1597                        return EIO;
1598                    }
1599
1600#if (DEBUG_VFS_LOOKUP & 1)
1601if( DEBUG_VFS_LOOKUP < cycle )
1602printk("\n[DBG] %s : load mapper from device for node <%s> in path %s\n",
1603__FUNCTION__ , name, pathname );
1604#endif
1605                }
1606            }
1607
1608            // take lock on parent inode
1609            vfs_inode_lock( parent_xp );
1610        }
1611        else   // child found in inode tree
1612        {
1613       
1614#if (DEBUG_VFS_LOOKUP & 1)
1615if( DEBUG_VFS_LOOKUP < cycle )
1616printk("\n[DBG] %s : found <%s> / inode %x in cluster %x\n",
1617__FUNCTION__ , name , GET_PTR(child_xp) , GET_CXY(child_xp) );
1618#endif
1619            child_ptr  = GET_PTR( child_xp );
1620            child_cxy  = GET_CXY( child_xp );
1621            parent_cxy = GET_CXY( parent_xp );
1622            parent_ptr = GET_PTR( parent_xp );
1623
1624            if( last && (mode & VFS_LOOKUP_CREATE) && (mode & VFS_LOOKUP_EXCL) )
1625            {
1626                printk("\n[ERROR] in %s : node already exist <%s>\n", __FUNCTION__, name );
1627                return EINVAL;
1628            }
1629        }
1630
1631        // TODO check access rights here [AG]
1632        // error = vfs_access_denied( child_xp,
1633        //                            client_uid,
1634        //                            client_gid );
1635        // if( error )
1636        // {
1637        //     printk("\n[ERROR] in %s : thread %x / permission denied for %s\n",
1638        //     __FUNCTION__ , this , name );
1639        //     return EACCES;
1640        // }
1641
1642        // take lock on child inode and release lock on parent
1643        vfs_inode_lock( child_xp );
1644        vfs_inode_unlock( parent_xp );
1645
1646        // update loop variables
1647        parent_xp = child_xp;
1648        current   = next;
1649    }
1650    while( last == false );
1651
1652    // release lock
1653    vfs_inode_unlock( parent_xp );
1654
1655#if DEBUG_VFS_LOOKUP
1656cycle = (uint32_t)hal_get_cycles();
1657if( DEBUG_VFS_LOOKUP < cycle )
1658printk("\n[DBG] %s : thread %x in process %x exit for <%s>\n" 
1659"     parent %x in cluster %x / child %x in cluster %x / cycle %d\n",
1660__FUNCTION__ , this->trdid, process->pid, pathname, 
1661parent_ptr, parent_cxy, child_ptr, child_cxy, cycle );
1662#endif
1663
1664    // return searched pointer
1665    if( mode & VFS_LOOKUP_PARENT ) *inode_xp = parent_xp;
1666    else                           *inode_xp = child_xp;
1667
1668    return 0;
1669
1670}  // end vfs_lookup()
1671
1672////////////////////////////////////////////
1673error_t vfs_get_path( xptr_t    searched_xp,
1674                      char    * buffer,
1675                      uint32_t  max_size )
1676{
1677        xptr_t       dentry_xp;   // extended pointer on current dentry
1678    char       * name;        // local pointer on current dentry name
1679        uint32_t     length;      // length of current dentry name
1680        uint32_t     count;       // number of characters written in buffer
1681        uint32_t     index;       // slot index in buffer
1682    xptr_t       inode_xp;    // extended pointer on   
1683
1684    // implementation note:
1685    // we use two variables "index" and "count" because the buffer
1686    // is written in decreasing index order (from leaf to root)
1687    // TODO  : handle conflict with a concurrent rename [AG]
1688    // FIXME : handle synchro in the loop  [AG]
1689
1690        // set the NUL character in buffer / initialise buffer index and count
1691        buffer[max_size - 1] = 0;
1692        count    = 1;
1693    index    = max_size - 2;
1694
1695    // initialize current inode
1696    inode_xp  = searched_xp;
1697
1698    // exit when root inode found (i.e. dentry_xp == XPTR_NULL)
1699        do
1700    {
1701        // get inode cluster and local pointer
1702        cxy_t         inode_cxy = GET_CXY( inode_xp );
1703        vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
1704
1705        // get extended pointer on parent dentry               
1706        dentry_xp = (xptr_t)hal_remote_lwd( XPTR( inode_cxy , inode_ptr->parent_xp ) );
1707
1708        // get dentry cluster and local pointer
1709        cxy_t          dentry_cxy = GET_CXY( dentry_xp );
1710        vfs_dentry_t * dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
1711
1712        // get dentry name length and pointer
1713        length =  hal_remote_lw( XPTR( dentry_cxy , &dentry_ptr->length ) );
1714        name   = (char *)hal_remote_lpt( XPTR( dentry_cxy , &dentry_ptr->name ) );
1715
1716        // update index and count
1717        index -= (length + 1); 
1718        count += (length + 1);
1719
1720        // check buffer overflow
1721        if( count >= max_size )
1722        {
1723            printk("\n[ERROR] in %s : kernel buffer too small\n", __FUNCTION__ );
1724            return EINVAL;
1725        }
1726
1727        // update pathname
1728        hal_remote_memcpy( XPTR( local_cxy , &buffer[index + 1] ) ,
1729                           XPTR( dentry_cxy , name ) , length );
1730                buffer[index] = '/';
1731
1732                // get extended pointer on next inode
1733        inode_xp = (xptr_t)hal_remote_lwd( XPTR( dentry_cxy , dentry_ptr->parent ) );
1734    }
1735    while( (dentry_xp != XPTR_NULL) );
1736
1737        return 0;
1738
1739}  // end vfs_get_path()
1740
1741     
1742//////////////////////////////////////////////////////////////
1743error_t vfs_add_child_in_parent( cxy_t              child_cxy,
1744                                 vfs_inode_type_t   inode_type,
1745                                 vfs_fs_type_t      fs_type,
1746                                 xptr_t             parent_xp,
1747                                 char             * name,
1748                                 void             * extend,
1749                                 xptr_t           * child_xp )
1750{
1751    error_t         error;
1752    xptr_t          dentry_xp;   // extended pointer on created dentry
1753    xptr_t          inode_xp;    // extended pointer on created inode
1754    cxy_t           parent_cxy;  // parent inode cluster identifier
1755    vfs_inode_t   * parent_ptr;  // parent inode local pointer
1756
1757    // get parent inode cluster and local pointer
1758    parent_cxy = GET_CXY( parent_xp );
1759    parent_ptr = GET_PTR( parent_xp );
1760
1761#if DEBUG_VFS_ADD_CHILD
1762uint32_t cycle = (uint32_t)hal_get_cycles();
1763if( DEBUG_VFS_ADD_CHILD < cycle )
1764printk("\n[DBG] %s : thread %x enter for <%s> / child_cxy = %x / parent_cxy = %x / cycle %d\n",
1765__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, name,
1766child_cxy, parent_cxy, (uint32_t)hal_get_cycles() );
1767#endif
1768
1769    // 1. create dentry
1770    if( parent_cxy == local_cxy )      // parent cluster is the local cluster
1771    {
1772        error = vfs_dentry_create( fs_type,
1773                                   name,
1774                                   parent_ptr,
1775                                   &dentry_xp );
1776
1777#if (DEBUG_VFS_ADD_CHILD & 1)
1778if( (DEBUG_VFS_ADD_CHILD < cycle) && (error == 0) )
1779printk("\n[DBG] %s : dentry <%s> created in cluster %x\n", __FUNCTION__, name, local_cxy );
1780#endif
1781
1782    }
1783    else                               // parent cluster is remote
1784    {
1785        rpc_vfs_dentry_create_client( parent_cxy,
1786                                      fs_type,
1787                                      name,
1788                                      parent_ptr,
1789                                      &dentry_xp,
1790                                      &error );
1791
1792#if (DEBUG_VFS_ADD_CHILD & 1)
1793if( (DEBUG_VFS_ADD_CHILD < cycle) && (error == 0) )
1794printk("\n[DBG] %s : dentry <%s> created in cluster %x\n", __FUNCTION__, name, parent_cxy );
1795#endif
1796
1797    }
1798                                     
1799    if( error )
1800    {
1801        printk("\n[ERROR] in %s : cannot create dentry <%s> in cluster %x\n",
1802        __FUNCTION__ , name , parent_cxy );
1803        return ENOMEM;
1804    }
1805
1806    // 2. create child inode TODO : define attr / mode / uid / gid
1807    uint32_t attr = 0;
1808    uint32_t mode = 0;
1809    uint32_t uid  = 0;
1810    uint32_t gid  = 0;
1811   
1812    if( child_cxy == local_cxy )      // child cluster is the local cluster
1813    {
1814        error = vfs_inode_create( dentry_xp,
1815                                  fs_type,
1816                                  inode_type,
1817                                  extend,
1818                                  attr,
1819                                  mode,
1820                                  uid,
1821                                  gid,
1822                                  &inode_xp );
1823
1824#if (DEBUG_VFS_ADD_CHILD & 1)
1825if( DEBUG_VFS_ADD_CHILD < cycle )
1826printk("\n[DBG] %s : inode <%x> created in cluster %x\n",
1827__FUNCTION__ , GET_PTR(inode_xp) , local_cxy );
1828#endif
1829
1830    }
1831    else                              // child cluster is remote
1832    {
1833        rpc_vfs_inode_create_client( child_cxy,
1834                                     dentry_xp,
1835                                     fs_type,
1836                                     inode_type,
1837                                     extend,
1838                                     attr,
1839                                     mode,
1840                                     uid,
1841                                     gid,
1842                                     &inode_xp,
1843                                     &error );
1844
1845#if (DEBUG_VFS_ADD_CHILD & 1)
1846if( DEBUG_VFS_ADD_CHILD < cycle )
1847printk("\n[DBG] %s : inode <%s> created in cluster %x\n",
1848__FUNCTION__ , GET_PTR(inode_xp) , child_cxy );
1849#endif
1850
1851    }
1852                                     
1853    if( error )
1854    {
1855        printk("\n[ERROR] in %s : cannot create inode in cluster %x\n",
1856               __FUNCTION__ , child_cxy );
1857 
1858        vfs_dentry_t * dentry = GET_PTR( dentry_xp );
1859        if( parent_cxy == local_cxy ) vfs_dentry_destroy( dentry );
1860        else rpc_vfs_dentry_destroy_client( parent_cxy , dentry , &error );
1861        return ENOMEM;
1862    }
1863
1864    // 3. update extended pointer on inode in dentry
1865    cxy_t          dentry_cxy = GET_CXY( dentry_xp );
1866    vfs_dentry_t * dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
1867    hal_remote_swd( XPTR( dentry_cxy , &dentry_ptr->child_xp ) , inode_xp );
1868
1869#if DEBUG_VFS_ADD_CHILD
1870cycle = (uint32_t)hal_get_cycles();
1871if( DEBUG_VFS_ADD_CHILD < cycle )
1872printk("\n[DBG] %s : thread %x in process %x exit for <%s>\n",
1873__FUNCTION__, CURRENT_THREAD, CURRENT_THREAD->process->pid, name );
1874#endif
1875
1876    // success : return extended pointer on child inode
1877    *child_xp = inode_xp;
1878    return 0;
1879
1880    // FIXME update the refcount fields in both inode and dentry
1881
1882}  // end vfs_add_child_in_parent()
1883
1884///////////////////////////////////////////////////////
1885error_t vfs_remove_child_from_parent( xptr_t inode_xp )
1886{
1887    cxy_t          inode_cxy;
1888    vfs_inode_t  * inode_ptr;
1889    xptr_t         dentry_xp;
1890    cxy_t          dentry_cxy;
1891    vfs_dentry_t * dentry_ptr;
1892    error_t        error;
1893   
1894    // get inode cluster and local pointer
1895    inode_cxy = GET_CXY( inode_xp );
1896    inode_ptr = GET_PTR( inode_xp );
1897
1898    // get cluster and pointers of associated dentry
1899    dentry_xp  = hal_remote_lwd( XPTR( inode_cxy , &inode_ptr->parent_xp ) );
1900    dentry_cxy = GET_CXY( dentry_xp ); 
1901    dentry_ptr = GET_PTR( dentry_xp );
1902
1903    // FIXME update the refcount fields in both inode and dentry
1904
1905    // delete dentry
1906    if( dentry_cxy == local_cxy )
1907    {
1908         error = vfs_dentry_destroy( dentry_ptr );
1909    }
1910    else
1911    {
1912         rpc_vfs_dentry_destroy_client( dentry_cxy,
1913                                        dentry_ptr,
1914                                        &error );
1915    }
1916    if( error ) return EINVAL;
1917
1918    // delete inode
1919    if( inode_cxy == local_cxy )
1920    {
1921         vfs_inode_destroy( inode_ptr );
1922    }
1923    else
1924    {
1925         rpc_vfs_inode_destroy_client( inode_cxy,
1926                                       inode_ptr,
1927                                       &error );
1928    }
1929    if( error ) return EINVAL;
1930
1931    return 0;
1932
1933}  // end vfs_remove_child_from_parent()
1934
1935//////////////////////////////////////////////////////////////////////////////////////////
1936//            Mapper related functions
1937//////////////////////////////////////////////////////////////////////////////////////////
1938
1939////////////////////////////////////////////
1940error_t vfs_mapper_move_page( page_t * page,
1941                              bool_t   to_mapper )
1942{
1943    error_t error = 0;
1944
1945    assert( (page != NULL) , __FUNCTION__ , "page pointer is NULL\n" );
1946
1947    mapper_t    * mapper = page->mapper;
1948
1949    assert( (mapper != NULL) , __FUNCTION__ , "no mapper for page\n" );
1950
1951#if DEBUG_VFS_MAPPER_MOVE
1952uint32_t cycle = (uint32_t)hal_get_cycles();
1953if( DEBUG_VFS_MAPPER_MOVE < cycle )
1954printk("\n[DBG] %s : thread %x enter for page %d / mapper %x / inode %x / cycle %d\n",
1955__FUNCTION__, CURRENT_THREAD, page->index, mapper, mapper->inode, cycle );
1956#endif
1957
1958    // get FS type
1959    vfs_fs_type_t fs_type = mapper->type;
1960
1961    // call relevant FS function
1962    if( fs_type == FS_TYPE_FATFS )
1963    {
1964        rwlock_wr_lock( &mapper->lock );
1965        error = fatfs_mapper_move_page( page , to_mapper ); 
1966        rwlock_wr_unlock( &mapper->lock );
1967    }
1968    else if( fs_type == FS_TYPE_RAMFS )
1969    {
1970        assert( false , __FUNCTION__ , "should not be called for RAMFS\n" );
1971    }
1972    else if( fs_type == FS_TYPE_DEVFS )
1973    {
1974        assert( false , __FUNCTION__ , "should not be called for DEVFS\n" );
1975    }
1976    else
1977    {
1978        assert( false , __FUNCTION__ , "undefined file system type\n" );
1979    }
1980
1981#if DEBUG_VFS_MAPPER_MOVE
1982cycle = (uint32_t)hal_get_cycles();
1983if( DEBUG_VFS_MAPPER_MOVE < cycle )
1984printk("\n[DBG] %s : thread %x exit for page %d / mapper %x / inode %x / cycle %d\n",
1985__FUNCTION__, CURRENT_THREAD, page->index, mapper, mapper->inode, cycle );
1986#endif
1987
1988    return error;
1989
1990}  // end vfs_move_page()
1991
1992//////////////////////////////////////////////////
1993error_t vfs_mapper_load_all( vfs_inode_t * inode )
1994{
1995    assert( (inode != NULL) , __FUNCTION__ , "inode pointer is NULL\n" );
1996
1997    uint32_t   index;
1998    page_t   * page;
1999
2000    mapper_t * mapper = inode->mapper;
2001    uint32_t   size   = inode->size;
2002
2003    assert( (mapper != NULL) , __FUNCTION__ , "mapper pointer is NULL\n" );
2004
2005#if DEBUG_VFS_MAPPER_LOAD
2006uint32_t cycle = (uint32_t)hal_get_cycles();
2007if( DEBUG_VFS_MAPPER_MOVE < cycle )
2008printk("\n[DBG] %s : thread %x enter for inode %x in cluster %x / cycle %d\n",
2009__FUNCTION__, CURRENT_THREAD, inode, local_cxy, cycle );
2010#endif
2011
2012    // compute number of pages
2013    uint32_t npages = size >> CONFIG_PPM_PAGE_SHIFT;
2014    if( (size & CONFIG_PPM_PAGE_MASK) || (size == 0) ) npages++;
2015
2016    // loop on pages
2017    for( index = 0 ; index < npages ; index ++ )
2018    {
2019        // this function allocates the missing page in mapper,
2020        // and call the vfs_mapper_move_page() to load the page from device
2021        page = mapper_get_page( mapper , index );
2022
2023        if( page == NULL ) return EIO;
2024    }
2025
2026#if DEBUG_VFS_MAPPER_LOAD
2027cycle = (uint32_t)hal_get_cycles();
2028if( DEBUG_VFS_MAPPER_MOVE < cycle )
2029printk("\n[DBG] %s : thread %x exit for inode %x in cluster %x / cycle %d\n",
2030__FUNCTION__, CURRENT_THREAD, inode, local_cxy, cycle );
2031#endif
2032
2033    return 0;
2034
2035}  // end vfs_mapper_load_all()
2036
Note: See TracBrowser for help on using the repository browser.