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

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

1) improve the threads and process destruction mechanism.
2) introduce FIFOs in the soclib_tty driver.

File size: 62.8 KB
Line 
1/*
2 * vfs.c - Virtual File System implementation.
3 *
4 * Author  Mohamed Lamine Karaoui (2015)
5 *         Alain Greiner (2016,2017)
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_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 CONFIG_DEBUG_VFS_INODE_CREATE
160uint32_t cycle = (uint32_t)hal_get_cycles();
161if( CONFIG_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 CONFIG_DEBUG_VFS_INODE_CREATE
237cycle = (uint32_t)hal_get_cycles();
238if( CONFIG_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/////////////////////////////////////////////
250void vfs_inode_destroy( vfs_inode_t * inode )
251{
252    if( inode->refcount )
253    {
254        assert( false , __FUNCTION__ , "inode refcount non zero\n" );
255    }       
256
257    // release memory allocated for mapper
258    mapper_destroy( inode->mapper );
259
260    // release memory allocate for inode descriptor
261        kmem_req_t req;
262        req.ptr   = inode;
263        req.type  = KMEM_VFS_INODE;
264        kmem_free( &req );
265
266}  // end vfs_inode_destroy()
267
268/////////////////////////////////////////////
269error_t vfs_inode_load( vfs_inode_t * parent,
270                        char        * name,
271                        xptr_t        child_xp )
272{
273
274#if CONFIG_DEBUG_VFS_INODE_LOAD
275uint32_t cycle = (uint32_t)hal_get_cycles();
276if( CONFIG_DEBUG_VFS_INODE_LOAD < cycle )
277printk("\n[DBG] %s : thread %x enter for <%s> / cycle %d\n",
278__FUNCTION__, CURRENT_THREAD , name , cycle );
279#endif
280
281    error_t error = 0;
282
283    assert( (parent != NULL) , __FUNCTION__ , "parent pointer is NULL\n");
284
285    assert( (child_xp != XPTR_NULL) , __FUNCTION__ , "child pointer is NULL\n");
286
287    // get parent inode FS type
288    vfs_fs_type_t fs_type = parent->ctx->type;
289
290    // call relevant FS function
291    if( fs_type == FS_TYPE_FATFS )
292    {
293        error = fatfs_inode_load( parent , name , child_xp );
294    }
295    else if( fs_type == FS_TYPE_RAMFS )
296    {
297        assert( false , __FUNCTION__ , "should not be called for RAMFS\n" );
298    }
299    else if( fs_type == FS_TYPE_DEVFS )
300    {
301        assert( false , __FUNCTION__ , "should not be called for DEVFS\n" );
302    }
303    else
304    {
305        assert( false , __FUNCTION__ , "undefined file system type\n" );
306    }
307
308#if CONFIG_DEBUG_VFS_INODE_LOAD
309cycle = (uint32_t)hal_get_cycles();
310if( CONFIG_DEBUG_VFS_INODE_LOAD < cycle )
311printk("\n[DBG] %s : thread %x exit for <%s> / cycle %d\n",
312__FUNCTION__, CURRENT_THREAD , name , cycle );
313#endif
314
315    return error;
316
317} // end vfs_load_inode()
318
319////////////////////////////////////////////
320void vfs_inode_remote_up( xptr_t  inode_xp )
321{
322    // get inode cluster and local pointer
323    cxy_t         inode_cxy = GET_CXY( inode_xp );
324    vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
325
326    hal_remote_atomic_add( XPTR( inode_cxy , &inode_ptr->refcount ) , 1 );   
327}
328
329//////////////////////////////////////////////
330void vfs_inode_remote_down( xptr_t  inode_xp )
331{
332    // get inode cluster and local pointer
333    cxy_t         inode_cxy = GET_CXY( inode_xp );
334    vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
335
336    hal_remote_atomic_add( XPTR( inode_cxy , &inode_ptr->refcount ) , -1 );   
337}
338
339//////////////////////////////////////////////
340uint32_t vfs_inode_get_size( xptr_t inode_xp )
341{
342    // get inode cluster and local pointer
343    cxy_t         cxy = GET_CXY( inode_xp );
344    vfs_inode_t * ptr = (vfs_inode_t *)GET_PTR( inode_xp );
345
346    // get size
347    remote_rwlock_rd_lock( XPTR( cxy , &ptr->data_lock ) );
348    uint32_t size = hal_remote_lw( XPTR( cxy , &ptr->size ) );
349    remote_rwlock_rd_unlock( XPTR( cxy , &ptr->data_lock ) );
350    return size;
351}
352
353////////////////////////////////////////////
354void vfs_inode_set_size( xptr_t    inode_xp,
355                         uint32_t  size )
356{
357    // get inode cluster and local pointer
358    cxy_t         cxy = GET_CXY( inode_xp );
359    vfs_inode_t * ptr = (vfs_inode_t *)GET_PTR( inode_xp );
360
361    // set size
362    remote_rwlock_wr_unlock( XPTR( cxy , &ptr->data_lock ) );
363    hal_remote_sw( XPTR( cxy , &ptr->size ) , size );
364    remote_rwlock_wr_unlock( XPTR( cxy , &ptr->data_lock ) );
365}
366
367////////////////////////////////////////
368void vfs_inode_unlock( xptr_t inode_xp )
369{
370    // get inode cluster and local pointer
371    cxy_t         cxy = GET_CXY( inode_xp );
372    vfs_inode_t * ptr = (vfs_inode_t *)GET_PTR( inode_xp );
373
374    // release the main lock
375    remote_spinlock_unlock( XPTR( cxy , &ptr->main_lock ) );
376}
377
378//////////////////////////////////////
379void vfs_inode_lock( xptr_t inode_xp )
380{
381    // get inode cluster and local pointer
382    cxy_t         cxy = GET_CXY( inode_xp );
383    vfs_inode_t * ptr = (vfs_inode_t *)GET_PTR( inode_xp );
384
385    // get the main lock
386    remote_spinlock_lock( XPTR( cxy , &ptr->main_lock ) );
387}
388
389/////////////////////////////////////////
390void vfs_inode_get_name( xptr_t inode_xp,
391                         char * name )
392{
393    cxy_t          inode_cxy;
394    vfs_inode_t  * inode_ptr;
395    xptr_t         dentry_xp;
396    cxy_t          dentry_cxy;
397    vfs_dentry_t * dentry_ptr;
398   
399    // get inode cluster and local pointer
400    inode_cxy = GET_CXY( inode_xp );
401    inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
402
403    // get parent dentry
404    dentry_xp  = hal_remote_lwd( XPTR( inode_cxy , &inode_ptr->parent_xp ) );
405
406    // get local copy of name
407    if( dentry_xp == XPTR_NULL )  // it is the VFS root
408    {
409        strcpy( name , "/" );
410    }
411    else                          // not the VFS root
412    {
413        dentry_cxy = GET_CXY( dentry_xp );
414        dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
415
416        hal_remote_strcpy( XPTR( local_cxy  , name ) , 
417                           XPTR( dentry_cxy , &dentry_ptr->name ) );
418    }
419}  // end vfs_inode_get_name()
420
421////////////////////////////////////////////////////////////////////////////////////////////
422//           Dentry related functions
423//////////////////////////////////////////////////////////////////////////////////////////
424
425///////////////////////////////////////////////////
426error_t vfs_dentry_create( vfs_fs_type_t   fs_type,
427                           char          * name,
428                           vfs_inode_t   * parent,
429                           xptr_t        * dentry_xp )
430{
431    vfs_ctx_t      * ctx;        // context descriptor
432    vfs_dentry_t   * dentry;     // dentry descriptor (to be allocated)
433        kmem_req_t       req;        // request to kernel memory allocator
434
435#if CONFIG_DEBUG_VFS_DENTRY_CREATE
436uint32_t cycle = (uint32_t)hal_get_cycles();
437if( CONFIG_DEBUG_VFS_DENTRY_CREATE < cycle )
438printk("\n[DBG] %s : thread %x enter for <%s> / parent_inode %x / cycle %d\n",
439__FUNCTION__, CURRENT_THREAD , 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        assert( false , __FUNCTION__ , "undefined file system type\n" );
450    }
451
452    // get name length
453    uint32_t length = strlen( name );
454
455    if( length >= CONFIG_VFS_MAX_NAME_LENGTH )
456    {
457        printk("\n[ERROR] in %s : name too long\n", __FUNCTION__ );
458        return EINVAL;
459    }
460
461    // allocate memory for dentry descriptor
462        req.type  = KMEM_VFS_DENTRY;
463        req.size  = sizeof(vfs_dentry_t);
464    req.flags = AF_KERNEL | AF_ZERO;
465        dentry     = (vfs_dentry_t *)kmem_alloc( &req );
466
467    if( dentry == NULL )
468    {
469        printk("\n[ERROR] in %s : cannot allocate dentry descriptor\n", __FUNCTION__ );
470        return ENOMEM;
471    }
472
473    // initialize dentry descriptor
474
475    dentry->ctx     = ctx;
476    dentry->length  = length;
477    dentry->parent  = parent;
478    strcpy( dentry->name , name );
479
480    // register dentry in hash table rooted in parent inode
481    xhtab_insert( XPTR( local_cxy , &parent->children ),
482                  name, 
483                  XPTR( local_cxy , &dentry->list ) );
484
485    // return extended pointer on dentry
486    *dentry_xp = XPTR( local_cxy , dentry );
487
488#if CONFIG_DEBUG_VFS_DENTRY_CREATE
489cycle = (uint32_t)hal_get_cycles();
490if( CONFIG_DEBUG_VFS_DENTRY_CREATE < cycle )
491printk("\n[DBG] %s : thread %x exit for <%s> / dentry %x / cycle %d\n",
492__FUNCTION__, CURRENT_THREAD , name , dentry , cycle );
493#endif
494
495    return 0;
496
497}  // end vfs_dentry_create()
498
499////////////////////////////////////////////////
500void vfs_dentry_destroy( vfs_dentry_t * dentry )
501{
502    if( dentry->refcount )
503    {
504        assert( false , __FUNCTION__ , "dentry refcount non zero\n" );
505    }       
506
507        kmem_req_t req;
508        req.ptr   = dentry;
509        req.type  = KMEM_VFS_DENTRY;
510        kmem_free( &req );
511}
512
513
514
515//////////////////////////////////////////////////////////////////////////////////////////
516//           File descriptor related functions
517//////////////////////////////////////////////////////////////////////////////////////////
518
519/////////////////////////////////////////////
520error_t vfs_file_create( vfs_inode_t * inode,
521                         uint32_t      attr,
522                         xptr_t      * file_xp )
523{
524    vfs_file_t  * file;
525        kmem_req_t    req;
526
527    // allocate memory for new file descriptor
528        req.type  = KMEM_VFS_FILE;
529        req.size  = sizeof(vfs_file_t);
530    req.flags = AF_KERNEL | AF_ZERO;
531        file      = (vfs_file_t *)kmem_alloc( &req );
532
533    if( file == NULL ) return ENOMEM;
534
535    // initializes new file descriptor
536    file->gc       = 0;
537    file->type     = inode->type;
538    file->attr     = attr;
539    file->offset   = 0;
540    file->refcount = 1;
541    file->inode    = inode;
542    file->ctx      = inode->ctx;
543    file->mapper   = inode->mapper;
544
545    remote_rwlock_init( XPTR( local_cxy , &file->lock ) );
546
547    *file_xp = XPTR( local_cxy , file );
548    return 0;
549
550}  // end vfs_file_create()
551
552///////////////////////////////////////////
553void vfs_file_destroy( vfs_file_t *  file )
554{
555    if( file->refcount )
556    {
557        assert( false , __FUNCTION__ , "refcount non zero\n" );
558    }       
559
560        kmem_req_t req;
561        req.ptr   = file;
562        req.type  = KMEM_VFS_FILE;
563        kmem_free( &req );
564
565}  // end vfs_file_destroy()
566
567
568////////////////////////////////////////
569void vfs_file_count_up( xptr_t file_xp )
570{
571    // get file cluster and local pointer
572    cxy_t        file_cxy = GET_CXY( file_xp );
573    vfs_file_t * file_ptr = (vfs_file_t *)GET_PTR( file_xp ); 
574
575    // atomically increment count
576    hal_remote_atomic_add( XPTR( file_cxy , &file_ptr->refcount ) , 1 ); 
577}
578
579//////////////////////////////////////////
580void vfs_file_count_down( xptr_t file_xp )
581{
582    // get file cluster and local pointer
583    cxy_t        file_cxy = GET_CXY( file_xp );
584    vfs_file_t * file_ptr = (vfs_file_t *)GET_PTR( file_xp ); 
585
586    // atomically decrement count
587    hal_remote_atomic_add( XPTR( file_cxy , &file_ptr->refcount ) , -1 ); 
588}
589
590//////////////////////////////////////////////////////////////////////////////////////////
591//           File access related functions
592//////////////////////////////////////////////////////////////////////////////////////////
593
594//////////////////////////////////////
595error_t vfs_open( process_t * process,
596                          char      * path,
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
611#if CONFIG_DEBUG_VFS_OPEN
612uint32_t cycle = (uint32_t)hal_get_cycles();
613if( CONFIG_DEBUG_VFS_OPEN < cycle )
614printk("\n[DBG] %s :  thread %x enter for <%s> / cycle %d\n",
615__FUNCTION__, CURRENT_THREAD, path, cycle );
616#endif
617
618    // compute lookup working mode
619    lookup_mode = VFS_LOOKUP_OPEN;
620    if( (flags & O_DIR    )      )  lookup_mode |= VFS_LOOKUP_DIR;
621    if( (flags & O_CREAT  )      )  lookup_mode |= VFS_LOOKUP_CREATE;
622    if( (flags & O_EXCL   )      )  lookup_mode |= VFS_LOOKUP_EXCL;
623 
624    // compute attributes for the created file
625    file_attr = 0;
626    if( (flags & O_RDONLY ) == 0 )  file_attr |= FD_ATTR_WRITE_ENABLE;
627    if( (flags & O_WRONLY ) == 0 )  file_attr |= FD_ATTR_READ_ENABLE;
628    if( (flags & O_SYNC   )      )  file_attr |= FD_ATTR_SYNC;
629    if( (flags & O_APPEND )      )  file_attr |= FD_ATTR_APPEND;
630    if( (flags & O_CLOEXEC)      )  file_attr |= FD_ATTR_CLOSE_EXEC;
631
632    // get extended pointer on target inode
633    error = vfs_lookup( process->vfs_cwd_xp , path , lookup_mode , &inode_xp );
634
635    if( error ) return error;
636
637    // get target inode cluster and local pointer
638    inode_cxy = GET_CXY( inode_xp );
639    inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
640   
641    // create a new file descriptor in cluster containing inode
642    if( inode_cxy == local_cxy )      // target cluster is local
643    {
644        error = vfs_file_create( inode_ptr , file_attr , &file_xp );
645    }
646    else                              // target cluster is remote
647    {
648        rpc_vfs_file_create_client( inode_cxy , inode_ptr , file_attr , &file_xp , &error );
649    }
650
651    if( error )  return error;
652
653    // allocate and register a new file descriptor index in reference process
654    error = process_fd_register( process , file_xp , &file_id );
655
656    if( error ) return error;
657
658#if CONFIG_DEBUG_VFS_OPEN
659cycle = (uint32_t)hal_get_cycles();
660if( CONFIG_DEBUG_VFS_OPEN < cycle )
661printk("\n[DBG] %s : thread %x exit for <%s> / file %x in cluster %x / cycle %d\n",
662__FUNCTION__, CURRENT_THREAD, path, GET_PTR(file_xp), GET_CXY(file_xp), cycle );
663#endif
664
665    // success
666    *new_file_xp = file_xp;
667    *new_file_id = file_id;
668    return 0;
669
670}  // end vfs_open()
671
672//////////////////////////////////////
673int vfs_user_move( bool_t   to_buffer,
674                   xptr_t   file_xp,
675                   void   * buffer,
676                   uint32_t size )
677{
678    assert( ( file_xp != XPTR_NULL ) , __FUNCTION__ , "file_xp == XPTR_NULL" );
679
680    cxy_t              file_cxy;     // remote file descriptor cluster
681    vfs_file_t       * file_ptr;     // remote file descriptor local pointer
682    vfs_inode_type_t   inode_type;
683    uint32_t           file_offset;  // current offset in file
684    mapper_t         * mapper;
685    error_t            error;
686
687    // get cluster and local pointer on remote file descriptor
688    file_cxy  = GET_CXY( file_xp );
689    file_ptr  = (vfs_file_t *)GET_PTR( file_xp );
690
691    // get inode type from remote file descriptor
692    inode_type = hal_remote_lw( XPTR( file_cxy , &file_ptr->type   ) );
693   
694    assert( (inode_type == INODE_TYPE_FILE) , __FUNCTION__ ,
695    "inode type is not INODE_TYPE_FILE" );
696
697    // get mapper pointer and file offset from file descriptor
698    file_offset = hal_remote_lw( XPTR( file_cxy , &file_ptr->offset ) );
699    mapper = (mapper_t *)hal_remote_lpt( XPTR( file_cxy , &file_ptr->mapper ) );
700
701    // move data between mapper and buffer
702    if( file_cxy == local_cxy )
703    {
704        error = mapper_move_user( mapper,
705                                  to_buffer,
706                                  file_offset,
707                                  buffer,
708                                  size );
709    }
710    else
711    {
712        rpc_mapper_move_buffer_client( file_cxy,
713                                       mapper,
714                                       to_buffer,
715                                       true,          // user buffer
716                                       file_offset,
717                                       (uint64_t)(intptr_t)buffer,
718                                       size,
719                                       &error );
720    } 
721
722    if( error ) return -1;
723    else        return size;
724
725}  // end vfs_user_move()
726
727////////////////////////////////////////////
728error_t vfs_kernel_move( bool_t   to_buffer,
729                         xptr_t   file_xp,
730                         xptr_t   buffer_xp,
731                         uint32_t size )
732{
733    assert( ( file_xp != XPTR_NULL ) , __FUNCTION__ , "file_xp == XPTR_NULL" );
734
735    cxy_t              file_cxy;     // remote file descriptor cluster
736    vfs_file_t       * file_ptr;     // remote file descriptor local pointer
737    vfs_inode_type_t   inode_type;
738    uint32_t           file_offset;  // current offset in file
739    mapper_t         * mapper;
740    error_t            error;
741
742    // get cluster and local pointer on remote file descriptor
743    file_cxy  = GET_CXY( file_xp );
744    file_ptr  = (vfs_file_t *)GET_PTR( file_xp );
745
746    // get inode type from remote file descriptor
747    inode_type = hal_remote_lw( XPTR( file_cxy , &file_ptr->type   ) );
748   
749    // action depends on inode type
750    if( inode_type == INODE_TYPE_FILE )
751    {
752        // get mapper pointer and file offset from file descriptor
753        file_offset = hal_remote_lw( XPTR( file_cxy , &file_ptr->offset ) );
754        mapper = (mapper_t *)hal_remote_lpt( XPTR( file_cxy , &file_ptr->mapper ) );
755
756        // move data between mapper and buffer
757        if( file_cxy == local_cxy )
758        {
759            error = mapper_move_kernel( mapper,
760                                        to_buffer,
761                                        file_offset,
762                                        buffer_xp,
763                                        size );
764        }
765        else
766        {
767            rpc_mapper_move_buffer_client( file_cxy,
768                                           mapper,
769                                           to_buffer,
770                                           false,          // kernel buffer
771                                           file_offset,
772                                           buffer_xp,
773                                           size,
774                                           &error );
775        } 
776
777        if( error ) return -1;
778        else        return 0;
779    }
780    else 
781    {
782        printk("\n[ERROR] in %s : inode is not a file", __FUNCTION__ );
783        return -1;
784    }
785}  // end vfs_kernel_move()
786
787//////////////////////////////////////
788error_t vfs_lseek( xptr_t     file_xp,
789                   uint32_t   offset,
790                   uint32_t   whence, 
791                   uint32_t * new_offset )
792{
793    xptr_t         offset_xp;
794    xptr_t         lock_xp;
795    cxy_t          file_cxy;
796    vfs_file_t  *  file_ptr;
797    vfs_inode_t *  inode_ptr;
798    uint32_t       new;
799
800    assert( (file_xp != XPTR_NULL) , __FUNCTION__ , "file_xp == XPTR_NULL" );
801
802    // get cluster and local pointer on remote file descriptor
803    file_cxy = GET_CXY( file_xp );
804    file_ptr = (vfs_file_t *)GET_PTR( file_xp );
805
806    // build extended pointers on lock and offset
807    offset_xp = XPTR( file_cxy , &file_ptr->offset );
808    lock_xp   = XPTR( file_cxy , &file_ptr->lock );
809
810    // take file descriptor lock
811    remote_rwlock_wr_lock( lock_xp );
812
813    if      ( whence == SEEK_CUR )   // new = current + offset
814    {
815        new = hal_remote_lw( offset_xp ) + offset;
816    }
817    else if ( whence == SEEK_SET )   // new = offset
818    {
819        new = offset;
820    }
821    else if ( whence == SEEK_END )   // new = size + offset
822    { 
823        // get local pointer on remote inode
824        inode_ptr = (vfs_inode_t *)hal_remote_lpt( XPTR( file_cxy , &file_ptr->inode ) );
825
826        new = hal_remote_lw( XPTR( file_cxy , &inode_ptr->size ) ) + offset;
827    }
828    else
829    {
830        printk("\n[ERROR] in %s : illegal whence value\n", __FUNCTION__ );
831        remote_rwlock_wr_unlock( lock_xp );
832        return -1;
833    }
834
835    // set new offset
836    hal_remote_sw( offset_xp , new );
837
838    // release file descriptor lock
839    remote_rwlock_wr_unlock( lock_xp );
840
841    // success
842    if ( new_offset != NULL )
843        *new_offset = new;
844    return 0;
845
846}  // vfs_lseek()
847
848///////////////////////////////////
849error_t vfs_close( xptr_t   file_xp,
850                   uint32_t file_id )
851{
852    assert( (file_xp != XPTR_NULL) , __FUNCTION__ , "file_xp == XPTR_NULL" );
853
854    assert( (file_id < CONFIG_PROCESS_FILE_MAX_NR) , __FUNCTION__ , "illegal file_id" );
855
856    thread_t  * this    = CURRENT_THREAD;
857    process_t * process = this->process;
858
859    // get cluster and local pointer on remote file descriptor
860    cxy_t        file_cxy = GET_CXY( file_xp );
861    vfs_file_t * file_ptr = (vfs_file_t *)GET_PTR( file_xp );
862
863    // get local pointer on local cluster manager
864    cluster_t * cluster = LOCAL_CLUSTER;
865
866    // get owner process cluster and lpid
867    cxy_t   owner_cxy  = CXY_FROM_PID( process->pid );
868    lpid_t  lpid       = LPID_FROM_PID( process->pid );
869
870    // get extended pointers on copies root and lock
871    xptr_t root_xp = XPTR( owner_cxy , &cluster->pmgr.copies_root[lpid] );
872    xptr_t lock_xp = XPTR( owner_cxy , &cluster->pmgr.copies_lock[lpid] );
873
874    // take the lock protecting the copies
875    remote_spinlock_lock( lock_xp );
876
877    // 1) loop on the process descriptor copies to cancel all fd_array[file_id] entries
878    xptr_t  iter_xp;
879    XLIST_FOREACH( root_xp , iter_xp )
880    {
881        xptr_t      process_xp  = XLIST_ELEMENT( iter_xp , process_t , copies_list );
882        cxy_t       process_cxy = GET_CXY( process_xp );
883        process_t * process_ptr = (process_t *)GET_PTR( process_xp );
884
885        xptr_t lock_xp  = XPTR( process_cxy , &process_ptr->fd_array.lock );
886        xptr_t entry_xp = XPTR( process_cxy , &process_ptr->fd_array.array[file_id] );
887
888        // lock is required for atomic write of a 64 bits word
889        remote_rwlock_wr_lock( lock_xp );
890        hal_remote_swd( entry_xp , XPTR_NULL );
891        remote_rwlock_wr_unlock( lock_xp );
892
893        hal_fence();
894    }   
895
896    // 2) release memory allocated to file descriptor in remote cluster
897    if( file_cxy == local_cxy )             // file cluster is local
898    {
899        vfs_file_destroy( file_ptr );
900    }
901    else                                    // file cluster is local
902    {
903        rpc_vfs_file_destroy_client( file_cxy , file_ptr );
904    }
905
906    return 0;
907
908}  // end vfs_close()
909
910////////////////////////////////////
911error_t vfs_unlink( xptr_t   cwd_xp,
912                    char   * path )
913{
914    assert( false , __FUNCTION__ , "not implemented\n" );
915    return 0;
916} 
917
918////////////////////////////////////////
919error_t vfs_stat( xptr_t        file_xp,
920                  struct stat * k_stat )
921{
922    assert( false , __FUNCTION__ , "not implemented\n" );
923    return 0;
924}
925
926/////////////////////////////////////////////
927error_t vfs_readdir( xptr_t          file_xp,
928                     struct dirent * k_dirent )
929{
930    assert( false , __FUNCTION__ , "not implemented\n" );
931    return 0;
932}
933
934//////////////////////////////////////
935error_t vfs_mkdir( xptr_t     file_xp,
936                   char     * path,
937                   uint32_t   mode )
938{
939    assert( false , __FUNCTION__ , "not implemented\n" );
940    return 0;
941}
942
943////////////////////////////////////
944error_t vfs_rmdir( xptr_t   file_xp,
945                   char   * path )
946{
947    assert( false , __FUNCTION__ , "not implemented\n" );
948    return 0;
949}
950
951///////////////////////////////////
952error_t vfs_chdir( xptr_t   cwd_xp,
953                   char   * path )
954{
955    error_t           error;
956    xptr_t            inode_xp;     // extended pointer on target inode
957    cxy_t             inode_cxy;    // target inode cluster identifier       
958    vfs_inode_t     * inode_ptr;    // target inode local pointer
959    uint32_t          mode;         // lookup working mode       
960    vfs_inode_type_t  inode_type;   // target inode type
961
962    // set lookup working mode
963    mode = 0;
964
965    // get extended pointer on target inode
966    error = vfs_lookup( cwd_xp , path , mode , &inode_xp );
967
968    if( error ) return error;
969
970    // get inode cluster and local pointer
971    inode_cxy = GET_CXY( inode_xp );
972    inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
973
974    // get inode type from remote file
975    inode_type = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->type ) );
976
977    if( inode_type != INODE_TYPE_DIR )
978    {
979        CURRENT_THREAD->errno = ENOTDIR;
980        return -1;
981    }
982
983    assert( false , __FUNCTION__ , "not implemented\n" );
984    return 0;
985}
986
987///////////////////////////////////
988error_t vfs_chmod( xptr_t   cwd_xp,
989                   char   * path,
990                   uint32_t rights )
991{
992    error_t           error;
993    xptr_t            inode_xp;     // extended pointer on target inode
994    cxy_t             inode_cxy;    // inode cluster identifier       
995    vfs_inode_t     * inode_ptr;    // inode local pointer
996    uint32_t          mode;         // lookup working mode
997    vfs_inode_type_t  inode_type;   // target inode type
998
999    // set lookup working mode
1000    mode = 0;
1001 
1002    // get extended pointer on target inode
1003    error = vfs_lookup( cwd_xp , path , mode , &inode_xp );
1004
1005    if( error ) return error;
1006
1007    // get inode cluster and local pointer
1008    inode_cxy = GET_CXY( inode_xp );
1009    inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
1010   
1011    // get inode type from remote inode
1012    inode_type = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->type ) );
1013
1014   
1015    assert( false , __FUNCTION__ , "not implemented\n" );
1016    return 0;
1017}
1018
1019///////////////////////////////////
1020error_t vfs_mkfifo( xptr_t   cwd_xp,
1021                    char   * path,
1022                    uint32_t rights )
1023{
1024    assert( false , __FUNCTION__ , "not implemented\n" );
1025    return 0;
1026}
1027
1028
1029
1030//////////////////////////////////////////////////////////////////////////////////////////
1031//            Inode Tree functions
1032//////////////////////////////////////////////////////////////////////////////////////////
1033
1034/////////////////////////////////
1035cxy_t vfs_cluster_random_select()
1036{
1037    uint32_t  x_size    = LOCAL_CLUSTER->x_size;
1038    uint32_t  y_size    = LOCAL_CLUSTER->y_size;
1039    uint32_t  y_width   = LOCAL_CLUSTER->y_width;
1040    uint32_t  index     = ( hal_get_cycles() + hal_get_gid() ) % (x_size * y_size);
1041    uint32_t  x         = index / y_size;   
1042    uint32_t  y         = index % y_size;
1043
1044    return (x<<y_width) + y;
1045}
1046
1047
1048//////////////////////////////////////////////////////////////////////////
1049// This static function is called by the vfs_display() function.
1050// that is supposed to take the TXT0 lock.
1051//////////////////////////////////////////////////////////////////////////
1052static void vfs_recursive_display( xptr_t   inode_xp,
1053                                   xptr_t   name_xp,
1054                                   xptr_t   dentry_xp,
1055                                   uint32_t indent )
1056{
1057    cxy_t              inode_cxy;
1058    vfs_inode_t      * inode_ptr;
1059    vfs_inode_type_t   inode_type;
1060    xptr_t             children_xp;    // extended pointer on children xhtab
1061
1062    xptr_t             child_dentry_xp;
1063    cxy_t              child_dentry_cxy;
1064    vfs_dentry_t     * child_dentry_ptr;
1065    xptr_t             child_inode_xp;
1066    xptr_t             child_dentry_name_xp;
1067
1068    char               name[CONFIG_VFS_MAX_NAME_LENGTH];
1069
1070    char *             indent_str[] = { "",                                  // level 0
1071                                        "  ",                                // level 1
1072                                        "    ",                              // level 2
1073                                        "      ",                            // level 3
1074                                        "        ",                          // level 4
1075                                        "          ",                        // level 5
1076                                        "            ",                      // level 6
1077                                        "              ",                    // level 7
1078                                        "                ",                  // level 8
1079                                        "                  ",                // level 9
1080                                        "                    ",              // level 10
1081                                        "                      ",            // level 11
1082                                        "                        ",          // level 12
1083                                        "                          ",        // level 13
1084                                        "                            ",      // level 14
1085                                        "                              " };  // level 15
1086
1087    assert( (inode_xp != XPTR_NULL) , __FUNCTION__ , "inode_xp cannot be NULL\n" );
1088    assert( (name_xp  != XPTR_NULL) , __FUNCTION__ , "name_xp cannot be NULL\n" );
1089    assert( (indent < 16)           , __FUNCTION__ , "depth cannot be larger than 15\n" );
1090   
1091    // get inode cluster and local pointer
1092    inode_cxy = GET_CXY( inode_xp );
1093    inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
1094
1095    // get inode type
1096    inode_type = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->type ) );
1097
1098    // get local pointer on associated mapper
1099    mapper_t * mapper_ptr = hal_remote_lpt( XPTR( inode_cxy , &inode_ptr->mapper ) );
1100
1101    // make a local copy of node name
1102    hal_remote_strcpy( XPTR( local_cxy , name ) , name_xp );
1103
1104    // display inode
1105    nolock_printk("%s%s <%s> : inode = %x / mapper = %x / cluster %x\n",
1106                  indent_str[indent], vfs_inode_type_str( inode_type ), name,
1107                  inode_ptr , mapper_ptr , inode_cxy );
1108
1109    // scan directory entries 
1110    if( inode_type == INODE_TYPE_DIR )
1111    {
1112        // get extended pointer on directory entries xhtab
1113        children_xp =  XPTR( inode_cxy , &inode_ptr->children );
1114
1115        // get xhtab lock
1116        xhtab_read_lock( children_xp );
1117
1118        // get first dentry from xhtab
1119        child_dentry_xp = xhtab_get_first( children_xp );
1120
1121        while( child_dentry_xp != XPTR_NULL )
1122        {
1123            // get dentry cluster and local pointer
1124            child_dentry_cxy = GET_CXY( child_dentry_xp );
1125            child_dentry_ptr = (vfs_dentry_t *)GET_PTR( child_dentry_xp );
1126
1127            // get extended pointer on child inode
1128            child_inode_xp = hal_remote_lwd( XPTR( child_dentry_cxy,
1129                                                   &child_dentry_ptr->child_xp ) );
1130
1131            // get extended pointer on dentry name
1132            child_dentry_name_xp = XPTR( child_dentry_cxy , &child_dentry_ptr->name );
1133
1134            // recursive call on child inode
1135            vfs_recursive_display( child_inode_xp,
1136                                   child_dentry_name_xp,
1137                                   child_dentry_xp,
1138                                   indent+1 );
1139
1140            // get next dentry
1141            child_dentry_xp = xhtab_get_next( children_xp );
1142        }
1143
1144        // release xhtab lock
1145        xhtab_read_unlock( children_xp );
1146    }
1147}  // end vfs_recursive_display()
1148
1149///////////////////////////////////
1150void vfs_display( xptr_t inode_xp )
1151{
1152    xptr_t         name_xp;
1153    xptr_t         dentry_xp; 
1154    cxy_t          dentry_cxy;
1155    vfs_dentry_t * dentry_ptr;
1156    uint32_t       save_sr;
1157
1158    // get target inode cluster and local pointer
1159    cxy_t         inode_cxy = GET_CXY( inode_xp );
1160    vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
1161
1162    // get extended pointer on associated dentry
1163    dentry_xp   = hal_remote_lwd( XPTR( inode_cxy , &inode_ptr->parent_xp ) );
1164
1165    // check if target inode is the File System root
1166    if( dentry_xp == XPTR_NULL )
1167    {
1168        // build extended pointer on root name
1169        name_xp = XPTR( local_cxy , "/" );
1170    }
1171    else
1172    {
1173        // get dentry cluster and local pointer
1174        dentry_cxy = GET_CXY( dentry_xp );
1175        dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
1176
1177        // get extended pointer on dentry name
1178        name_xp = XPTR( dentry_cxy , &dentry_ptr->name );
1179    }
1180
1181    // get pointers on TXT0 chdev
1182    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
1183    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
1184    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
1185
1186    // get extended pointer on remote TXT0 chdev lock
1187    xptr_t  lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
1188
1189    // get TXT0 lock in busy waiting mode
1190    remote_spinlock_lock_busy( lock_xp , &save_sr );
1191
1192    // print header
1193    nolock_printk("\n***** file system state\n\n");
1194
1195    // call recursive function
1196    vfs_recursive_display( inode_xp , name_xp , dentry_xp , 0 );
1197
1198    // release lock
1199    remote_spinlock_unlock_busy( lock_xp , save_sr );
1200
1201}  // end vfs_display()
1202
1203//////////////////////////////////////////////////////////////////////////////////////////
1204// This function is used by the vfs_lookup() function.
1205// It takes an extended pointer on a remote inode (parent directory inode),
1206// and check access_rights violation for the calling thread.
1207// It can be used by any thread running in any cluster.
1208//////////////////////////////////////////////////////////////////////////////////////////
1209// @ inode_xp    : extended pointer on inode.
1210// @ client_uid  : client thread user ID
1211// @ client_gid  : client thread group ID
1212// @ return true if access rights are violated.
1213//////////////////////////////////////////////////////////////////////////////////////////
1214bool_t vfs_access_denied( xptr_t   inode_xp,
1215                          uint32_t client_uid,
1216                          uint32_t client_gid )
1217{
1218    // get found inode cluster and local pointer
1219    cxy_t         inode_cxy = GET_CXY( inode_xp );
1220    vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
1221
1222    // get inode access mode, UID, and GID
1223    // TODO uint32_t  mode = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->mode ) );
1224    uid_t     uid  = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->uid  ) );
1225    gid_t     gid  = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->gid  ) );
1226
1227    // FIXME : me must use mode
1228    if( (uid == client_uid) || (gid == client_gid) ) return false;
1229    else                                             return true;
1230}
1231
1232//////////////////////////////////////////////////////////////////////////////////////////
1233// This static function is used by the vfs_lookup() function.
1234// It takes an extended pointer on a remote parent directory inode, a directory
1235// entry name, and returns an extended pointer on the child inode.
1236// It can be used by any thread running in any cluster.
1237//////////////////////////////////////////////////////////////////////////////////////////
1238// @ parent_xp   : extended pointer on parent inode in remote cluster.
1239// @ name        : dentry name
1240// @ child_xp    : [out] buffer for extended pointer on child inode.
1241// @ return true if success / return false if not found.
1242//////////////////////////////////////////////////////////////////////////////////////////
1243static bool_t vfs_get_child( xptr_t   parent_xp,
1244                             char   * name,
1245                             xptr_t * child_xp )
1246{
1247    xptr_t  xhtab_xp;    // extended pointer on hash table containing children dentries
1248    xptr_t  dentry_xp;   // extended pointer on children dentry
1249
1250    // get parent inode cluster and local pointer
1251    cxy_t         parent_cxy = GET_CXY( parent_xp );
1252    vfs_inode_t * parent_ptr = (vfs_inode_t *)GET_PTR( parent_xp );
1253
1254    // get extended pointer on hash table of children directory entries
1255    xhtab_xp = XPTR( parent_cxy , &parent_ptr->children );
1256
1257    // search extended pointer on matching dentry
1258    dentry_xp = xhtab_lookup( xhtab_xp , name );
1259
1260    if( dentry_xp == XPTR_NULL ) return false;
1261
1262    // get dentry cluster and local pointer
1263    cxy_t          dentry_cxy = GET_CXY( dentry_xp );
1264    vfs_dentry_t * dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
1265
1266    // return child inode
1267    *child_xp = (xptr_t)hal_remote_lwd( XPTR( dentry_cxy , &dentry_ptr->child_xp ) );
1268    return true;
1269
1270}  // end vfs_get_child()
1271
1272//////////////////////////////////////////////////////////////////////////////////////////
1273// This static function is used by the vfs_lookup() function.
1274// It takes the <current> pointer on a buffer containing a complete pathname, and return
1275// in the <name> buffer, allocated by the caller, a single name in the path.
1276// It return also in the <next> pointer the next character to analyse in the path.
1277// Finally it returns a <last> boolean, that is true when the returned <name> is the
1278// last name in the path. The names are supposed to be separated by one or several '/'
1279// characters, that are not written in  the <name> buffer.
1280//////////////////////////////////////////////////////////////////////////////////////////
1281// @ current   : pointer on first character to analyse in buffer containing the path.
1282// @ name      : [out] pointer on buffer allocated by the caller for the returned name.
1283// @ next      : [out] pointer on next character to analyse in buffer containing the path.
1284// @ last      : [out] true if the returned name is the last (NUL character found).
1285// @ return 0 if success / return EINVAL if string empty (first chracter is NUL).
1286//////////////////////////////////////////////////////////////////////////////////////////
1287static error_t vfs_get_name_from_path( char     * current,
1288                                       char     * name,
1289                                       char    ** next,
1290                                       bool_t   * last )
1291{
1292    char * ptr = current;
1293
1294    // skip leading '/' characters
1295    while( *ptr == '/' ) ptr++;
1296
1297    // return EINVAL if string empty
1298    if( *ptr == 0 ) return EINVAL;
1299
1300    // copy all characters in name until NUL or '/'
1301    while( (*ptr != 0) && (*ptr !='/') )  *(name++) = *(ptr++);
1302
1303    // set NUL terminating character in name buffer
1304    *(name++) = 0;
1305
1306    // return last an next
1307    if( *ptr == 0 )             // last found character is NUL => last name in path
1308    {
1309        *last = true;
1310    }
1311    else                        // last found character is '/' => skip it
1312    {
1313        *last = false;
1314        *next = ptr + 1;
1315    }
1316
1317    return 0;
1318
1319}  // end vfs_get name_from_path()
1320   
1321//////////////////////////////////////////////
1322error_t vfs_lookup( xptr_t             cwd_xp,
1323                    char             * pathname,
1324                    uint32_t           mode,
1325                                        xptr_t           * inode_xp )
1326{
1327    char               name[CONFIG_VFS_MAX_NAME_LENGTH];   // one name in path
1328
1329    xptr_t             parent_xp;    // extended pointer on parent inode
1330    cxy_t              parent_cxy;   // cluster for parent inode
1331    vfs_inode_t      * parent_ptr;   // local pointer on parent inode 
1332    xptr_t             child_xp;     // extended pointer on child inode
1333    cxy_t              child_cxy;    // cluster for child inode
1334    vfs_inode_t      * child_ptr;    // local pointer on child inode 
1335    vfs_inode_type_t   child_type;   // child inode type
1336    vfs_fs_type_t      fs_type;      // File system type
1337    vfs_ctx_t        * ctx_ptr;      // local pointer on FS context
1338    char             * current;      // current pointer on path
1339    char             * next;         // next value for current pointer   
1340    bool_t             last;         // true when the name is the last in path
1341    bool_t             found;        // true when a child has been found
1342    thread_t         * this;         // pointer on calling thread descriptor
1343    process_t        * process;      // pointer on calling process descriptor
1344    error_t            error;
1345
1346    this    = CURRENT_THREAD;
1347    process = this->process;
1348
1349#if CONFIG_DEBUG_VFS_LOOKUP
1350uint32_t cycle = (uint32_t)hal_get_cycles();
1351if( CONFIG_DEBUG_VFS_LOOKUP < cycle )
1352printk("\n[DBG] %s : thread %x enter for <%s> / cycle %d\n",
1353__FUNCTION__, CURRENT_THREAD, pathname, cycle );
1354#endif
1355
1356    // get extended pointer on first inode to search
1357    if( pathname[0] == '/' ) parent_xp = process->vfs_root_xp;
1358    else                     parent_xp = cwd_xp;
1359
1360    // initialise other loop variables
1361    current  = pathname;
1362    next     = NULL;
1363    last     = false;
1364    child_xp = XPTR_NULL;
1365
1366    // take lock on parent inode
1367    vfs_inode_lock( parent_xp );
1368
1369    // sequencially loop on nodes in pathname
1370    // load from device if one node not found in inode tree
1371    // exit loop when last name found (i.e. last == true)
1372    do
1373    {
1374        // get one name from path, and "last" flag
1375        vfs_get_name_from_path( current , name , &next , &last );
1376
1377#if (CONFIG_DEBUG_VFS_LOOKUP & 1)
1378if( CONFIG_DEBUG_VFS_LOOKUP < cycle )
1379printk("\n[DBG] %s : look for <%s> / last = %d\n", __FUNCTION__ , name , last );
1380#endif
1381
1382        // search a child dentry matching name in parent inode
1383        found = vfs_get_child( parent_xp,
1384                               name,
1385                               &child_xp );
1386
1387        // if a child inode is not found in the inode tree:
1388        // - we create the missing inode/dentry couple in the inode tree,
1389        // - we scan the parent mapper to complete the child inode (type and extension),
1390        // - we return an error if child not found on device.
1391        // - if the missing child is a directory, we load the child mapper from device
1392
1393        // for the last name, the behaviour depends on the "mode" argument:
1394
1395        if (found == false ) // child node not found in inode tree
1396        {
1397
1398#if (CONFIG_DEBUG_VFS_LOOKUP & 1)
1399if( CONFIG_DEBUG_VFS_LOOKUP < cycle )
1400printk("\n[DBG] %s : miss <%s> => load it\n", __FUNCTION__ , name );
1401#endif
1402
1403            // release lock on parent inode
1404            vfs_inode_unlock( parent_xp );
1405
1406            // get parent inode FS type
1407            parent_cxy = GET_CXY( parent_xp );
1408            parent_ptr = (vfs_inode_t *)GET_PTR( parent_xp );
1409            ctx_ptr    = (vfs_ctx_t *)hal_remote_lpt( XPTR( parent_cxy , &parent_ptr->ctx ) );
1410            fs_type    = hal_remote_lw( XPTR( parent_cxy , &ctx_ptr->type ) );
1411
1412            // select a cluster for missing inode
1413            child_cxy = vfs_cluster_random_select();
1414 
1415            // insert a new child dentry/inode in parent inode
1416            error = vfs_add_child_in_parent( child_cxy,
1417                                             INODE_TYPE_DIR,
1418                                             fs_type, 
1419                                             parent_xp, 
1420                                             name, 
1421                                             NULL,     // fs_type_specific inode extend
1422                                             &child_xp );
1423            if( error )
1424            {
1425                printk("\n[ERROR] in %s : no memory for inode <%s> in path <%s>\n",
1426                __FUNCTION__ , name , pathname );
1427                return ENOMEM;
1428            }
1429
1430            // scan parent mapper to complete the missing inode
1431            if( parent_cxy == local_cxy )
1432            {
1433                error = vfs_inode_load( parent_ptr,
1434                                        name,
1435                                        child_xp );
1436            }
1437            else
1438            {
1439                rpc_vfs_inode_load_client( parent_cxy,
1440                                           parent_ptr,
1441                                           name,
1442                                           child_xp,
1443                                           &error );
1444            }
1445
1446            if ( error )
1447            {
1448                printk("\n[ERROR] in %s : core[%x,%d] / <%s> node not found in <%s>\n",
1449                __FUNCTION__ , local_cxy , this->core->lid , name , pathname );
1450                return ENOENT;
1451            }
1452
1453            // get child inode type
1454            child_ptr  = (vfs_inode_t *)GET_PTR( child_xp );
1455            child_type = hal_remote_lw( XPTR( child_cxy , &child_ptr->type ) );
1456
1457            // load child mapper from device if it is a directory
1458            if( child_type == INODE_TYPE_DIR )
1459            {
1460                if( child_cxy == local_cxy )
1461                {
1462                    error = vfs_mapper_load_all( child_ptr );
1463                }
1464                else
1465                {
1466                    rpc_vfs_mapper_load_all_client( child_cxy,
1467                                                    child_ptr,
1468                                                    &error );
1469                }
1470
1471                if ( error )
1472                {
1473                    printk("\n[ERROR] in %s : core[%x,%d] cannot access device for <%s>\n",
1474                    __FUNCTION__ , local_cxy , this->core->lid , name );
1475                    return EIO;
1476                }
1477            }
1478
1479            // TODO handle lookup mode here [AG]
1480
1481            // take lock on parent inode
1482            vfs_inode_lock( parent_xp );
1483
1484#if (CONFIG_DEBUG_VFS_LOOKUP & 1)
1485if( CONFIG_DEBUG_VFS_LOOKUP < cycle )
1486printk("\n[DBG] %s : created node <%s>\n", __FUNCTION__ , name );
1487#endif
1488
1489        }
1490
1491#if (CONFIG_DEBUG_VFS_LOOKUP & 1)
1492if( CONFIG_DEBUG_VFS_LOOKUP < cycle )
1493printk("\n[DBG] %s : found <%s> / inode %x in cluster %x\n",
1494__FUNCTION__ , name , GET_PTR(child_xp) , GET_CXY(child_xp) );
1495#endif
1496
1497        // TODO check access rights here [AG]
1498        // error = vfs_access_denied( child_xp,
1499        //                            client_uid,
1500        //                            client_gid );
1501        // if( error )
1502        // {
1503        //     printk("\n[ERROR] in %s : permission denied for %s\n", __FUNCTION__ , name );
1504        //     return EACCES;
1505        // }
1506
1507        // take lock on child inode and release lock on parent
1508        vfs_inode_lock( child_xp );
1509        vfs_inode_unlock( parent_xp );
1510
1511        // update loop variables
1512        parent_xp = child_xp;
1513        current   = next;
1514    }
1515    while( last == false );
1516
1517    // release lock
1518    vfs_inode_unlock( parent_xp );
1519
1520#if CONFIG_DEBUG_VFS_LOOKUP
1521cycle = (uint32_t)hal_get_cycles();
1522if( CONFIG_DEBUG_VFS_LOOKUP < cycle )
1523printk("\n[DBG] %s : thread %x exit for <%s> / inode %x in cluster %x / cycle %d\n",
1524__FUNCTION__, CURRENT_THREAD, pathname, GET_PTR(child_xp), GET_CXY(child_xp), cycle );
1525#endif
1526
1527    // return searched pointer
1528    *inode_xp = child_xp;
1529
1530    return 0;
1531
1532}  // end vfs_lookup()
1533
1534////////////////////////////////////////////
1535error_t vfs_get_path( xptr_t    searched_xp,
1536                      char    * buffer,
1537                      uint32_t  max_size )
1538{
1539        xptr_t       dentry_xp;   // extended pointer on current dentry
1540    char       * name;        // local pointer on current dentry name
1541        uint32_t     length;      // length of current dentry name
1542        uint32_t     count;       // number of characters written in buffer
1543        uint32_t     index;       // slot index in buffer
1544    xptr_t       inode_xp;    // extended pointer on   
1545
1546    // implementation note:
1547    // we use two variables "index" and "count" because the buffer
1548    // is written in decreasing index order (from leaf to root)
1549    // TODO  : handle conflict with a concurrent rename [AG]
1550    // FIXME : handle synchro in the loop  [AG]
1551
1552        // set the NUL character in buffer / initialise buffer index and count
1553        buffer[max_size - 1] = 0;
1554        count    = 1;
1555    index    = max_size - 2;
1556
1557    // initialize current inode
1558    inode_xp  = searched_xp;
1559
1560    // exit when root inode found (i.e. dentry_xp == XPTR_NULL)
1561        do
1562    {
1563        // get inode cluster and local pointer
1564        cxy_t         inode_cxy = GET_CXY( inode_xp );
1565        vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
1566
1567        // get extended pointer on parent dentry               
1568        dentry_xp = (xptr_t)hal_remote_lwd( XPTR( inode_cxy , inode_ptr->parent_xp ) );
1569
1570        // get dentry cluster and local pointer
1571        cxy_t          dentry_cxy = GET_CXY( dentry_xp );
1572        vfs_dentry_t * dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
1573
1574        // get dentry name length and pointer
1575        length =  hal_remote_lw( XPTR( dentry_cxy , &dentry_ptr->length ) );
1576        name   = (char *)hal_remote_lpt( XPTR( dentry_cxy , &dentry_ptr->name ) );
1577
1578        // update index and count
1579        index -= (length + 1); 
1580        count += (length + 1);
1581
1582        // check buffer overflow
1583        if( count >= max_size )
1584        {
1585            printk("\n[ERROR] in %s : kernel buffer too small\n", __FUNCTION__ );
1586            return EINVAL;
1587        }
1588
1589        // update pathname
1590        hal_remote_memcpy( XPTR( local_cxy , &buffer[index + 1] ) ,
1591                           XPTR( dentry_cxy , name ) , length );
1592                buffer[index] = '/';
1593
1594                // get extended pointer on next inode
1595        inode_xp = (xptr_t)hal_remote_lwd( XPTR( dentry_cxy , dentry_ptr->parent ) );
1596    }
1597    while( (dentry_xp != XPTR_NULL) );
1598
1599        return 0;
1600
1601}  // end vfs_get_path()
1602
1603     
1604//////////////////////////////////////////////////////////////
1605error_t vfs_add_child_in_parent( cxy_t              child_cxy,
1606                                 vfs_inode_type_t   inode_type,
1607                                 vfs_fs_type_t      fs_type,
1608                                 xptr_t             parent_xp,
1609                                 char             * name,
1610                                 void             * extend,
1611                                 xptr_t           * child_xp )
1612{
1613    error_t         error;
1614    xptr_t          dentry_xp;   // extended pointer on created dentry
1615    xptr_t          inode_xp;    // extended pointer on created inode
1616    cxy_t           parent_cxy;  // parent inode cluster identifier
1617    vfs_inode_t   * parent_ptr;  // parent inode local pointer
1618
1619    // get parent inode cluster and local pointer
1620    parent_cxy = GET_CXY( parent_xp );
1621    parent_ptr = (vfs_inode_t *)GET_PTR( parent_xp );
1622
1623#if CONFIG_DEBUG_VFS_ADD_CHILD
1624uint32_t cycle = (uint32_t)hal_get_cycles();
1625if( CONFIG_DEBUG_VFS_ADD_CHILD < cycle )
1626printk("\n[DBG] %s : thread %x enter for <%s> / child_cxy = %x / parent_cxy = %x\n",
1627__FUNCTION__ , CURRENT_THREAD , name , child_cxy , parent_cxy );
1628#endif
1629
1630    // 1. create dentry
1631    if( parent_cxy == local_cxy )      // parent cluster is the local cluster
1632    {
1633        error = vfs_dentry_create( fs_type,
1634                                   name,
1635                                   parent_ptr,
1636                                   &dentry_xp );
1637
1638#if (CONFIG_DEBUG_VFS_ADD_CHILD & 1)
1639if( CONFIG_DEBUG_VFS_ADD_CHILD < cycle )
1640printk("\n[DBG] %s : dentry <%s> created in cluster %x\n", __FUNCTION__, name, local_cxy );
1641#endif
1642
1643    }
1644    else                               // parent cluster is remote
1645    {
1646        rpc_vfs_dentry_create_client( parent_cxy,
1647                                      fs_type,
1648                                      name,
1649                                      parent_ptr,
1650                                      &dentry_xp,
1651                                      &error );
1652
1653#if (CONFIG_DEBUG_VFS_ADD_CHILD & 1)
1654if( CONFIG_DEBUG_VFS_ADD_CHILD < cycle )
1655printk("\n[DBG] %s : dentry <%s> created in cluster %x\n", __FUNCTION__, name, parent_cxy );
1656#endif
1657
1658    }
1659                                     
1660    if( error )
1661    {
1662        printk("\n[ERROR] in %s : cannot create dentry in cluster %x\n",
1663        __FUNCTION__ , parent_cxy );
1664        return ENOMEM;
1665    }
1666
1667    // 2. create child inode TODO : define attr / mode / uid / gid
1668    uint32_t attr = 0;
1669    uint32_t mode = 0;
1670    uint32_t uid  = 0;
1671    uint32_t gid  = 0;
1672   
1673    if( child_cxy == local_cxy )      // child cluster is the local cluster
1674    {
1675        error = vfs_inode_create( dentry_xp,
1676                                  fs_type,
1677                                  inode_type,
1678                                  extend,
1679                                  attr,
1680                                  mode,
1681                                  uid,
1682                                  gid,
1683                                  &inode_xp );
1684
1685#if (CONFIG_DEBUG_VFS_ADD_CHILD & 1)
1686if( CONFIG_DEBUG_VFS_ADD_CHILD < cycle )
1687printk("\n[DBG] %s : inode <%x> created in cluster %x\n",
1688__FUNCTION__ , GET_PTR(inode_xp) , local_cxy );
1689#endif
1690
1691vfs_dmsg("\n[DBG] %s : inode %x created in local cluster %x\n",
1692__FUNCTION__ , GET_PTR(inode_xp) , local_cxy );
1693
1694    }
1695    else                              // child cluster is remote
1696    {
1697        rpc_vfs_inode_create_client( child_cxy,
1698                                     dentry_xp,
1699                                     fs_type,
1700                                     inode_type,
1701                                     extend,
1702                                     attr,
1703                                     mode,
1704                                     uid,
1705                                     gid,
1706                                     &inode_xp,
1707                                     &error );
1708
1709#if (CONFIG_DEBUG_VFS_ADD_CHILD & 1)
1710if( CONFIG_DEBUG_VFS_ADD_CHILD < cycle )
1711printk("\n[DBG] %s : inode <%s> created in cluster %x\n",
1712__FUNCTION__ , GET_PTR(inode_xp) , child_cxy );
1713#endif
1714
1715    }
1716                                     
1717    if( error )
1718    {
1719        printk("\n[ERROR] in %s : cannot create inode in cluster %x\n",
1720               __FUNCTION__ , child_cxy );
1721 
1722        vfs_dentry_t * dentry = (vfs_dentry_t *)GET_PTR( dentry_xp );
1723        if( parent_cxy == local_cxy ) vfs_dentry_destroy( dentry );
1724        else rpc_vfs_dentry_destroy_client( parent_cxy , dentry );
1725        return ENOMEM;
1726    }
1727
1728    // 3. update extended pointer on inode in dentry
1729    cxy_t          dentry_cxy = GET_CXY( dentry_xp );
1730    vfs_dentry_t * dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
1731    hal_remote_swd( XPTR( dentry_cxy , &dentry_ptr->child_xp ) , inode_xp );
1732
1733#if CONFIG_DEBUG_VFS_ADD_CHILD
1734cycle = (uint32_t)hal_get_cycles();
1735if( CONFIG_DEBUG_VFS_ADD_CHILD < cycle )
1736printk("\n[DBG] %s : thread %x exit for <%s>\n",
1737__FUNCTION__ , CURRENT_THREAD , name );
1738#endif
1739
1740    // success : return extended pointer on child inode
1741    *child_xp = inode_xp;
1742    return 0;
1743
1744}  // end vfs_add_child_in_parent()
1745
1746//////////////////////////////////////////////////////////////////////////////////////////
1747//            Mapper related functions
1748//////////////////////////////////////////////////////////////////////////////////////////
1749
1750////////////////////////////////////////////
1751error_t vfs_mapper_move_page( page_t * page,
1752                              bool_t   to_mapper )
1753{
1754    error_t error = 0;
1755
1756    assert( (page != NULL) , __FUNCTION__ , "page pointer is NULL\n" );
1757
1758    mapper_t    * mapper = page->mapper;
1759
1760    assert( (mapper != NULL) , __FUNCTION__ , "no mapper for page\n" );
1761
1762#if CONFIG_DEBUG_VFS_MAPPER_MOVE
1763uint32_t cycle = (uint32_t)hal_get_cycles();
1764if( CONFIG_DEBUG_VFS_MAPPER_MOVE < cycle )
1765printk("\n[DBG] %s : thread %x enter for page %d / mapper %x / inode %x / cycle %d\n",
1766__FUNCTION__, CURRENT_THREAD, page->index, mapper, mapper->inode, cycle );
1767#endif
1768
1769    // get FS type
1770    vfs_fs_type_t fs_type = mapper->type;
1771
1772    // call relevant FS function
1773    if( fs_type == FS_TYPE_FATFS )
1774    {
1775        rwlock_wr_lock( &mapper->lock );
1776        error = fatfs_mapper_move_page( page , to_mapper ); 
1777        rwlock_wr_unlock( &mapper->lock );
1778    }
1779    else if( fs_type == FS_TYPE_RAMFS )
1780    {
1781        assert( false , __FUNCTION__ , "should not be called for RAMFS\n" );
1782    }
1783    else if( fs_type == FS_TYPE_DEVFS )
1784    {
1785        assert( false , __FUNCTION__ , "should not be called for DEVFS\n" );
1786    }
1787    else
1788    {
1789        assert( false , __FUNCTION__ , "undefined file system type\n" );
1790    }
1791
1792#if CONFIG_DEBUG_VFS_MAPPER_MOVE
1793cycle = (uint32_t)hal_get_cycles();
1794if( CONFIG_DEBUG_VFS_MAPPER_MOVE < cycle )
1795printk("\n[DBG] %s : thread %x exit for page %d / mapper %x / inode %x / cycle %d\n",
1796__FUNCTION__, CURRENT_THREAD, page->index, mapper, mapper->inode, cycle );
1797#endif
1798
1799    return error;
1800
1801}  // end vfs_move_page()
1802
1803//////////////////////////////////////////////////
1804error_t vfs_mapper_load_all( vfs_inode_t * inode )
1805{
1806    assert( (inode != NULL) , __FUNCTION__ , "inode pointer is NULL\n" );
1807
1808    uint32_t   index;
1809    page_t   * page;
1810
1811    mapper_t * mapper = inode->mapper;
1812    uint32_t   size   = inode->size;
1813
1814    assert( (mapper != NULL) , __FUNCTION__ , "mapper pointer is NULL\n" );
1815
1816#if CONFIG_DEBUG_VFS_MAPPER_LOAD
1817uint32_t cycle = (uint32_t)hal_get_cycles();
1818if( CONFIG_DEBUG_VFS_MAPPER_MOVE < cycle )
1819printk("\n[DBG] %s : thread %x enter for inode %x in cluster %x / cycle %d\n",
1820__FUNCTION__, CURRENT_THREAD, inode, local_cxy, cycle );
1821#endif
1822
1823    // compute number of pages
1824    uint32_t npages = size >> CONFIG_PPM_PAGE_SHIFT;
1825    if( (size & CONFIG_PPM_PAGE_MASK) || (size == 0) ) npages++;
1826
1827    // loop on pages
1828    for( index = 0 ; index < npages ; index ++ )
1829    {
1830        // this function allocates the missing page in mapper,
1831        // and call the vfs_mapper_move_page() to load the page from device
1832        page = mapper_get_page( mapper , index );
1833
1834        if( page == NULL ) return EIO;
1835    }
1836
1837#if CONFIG_DEBUG_VFS_MAPPER_LOAD
1838cycle = (uint32_t)hal_get_cycles();
1839if( CONFIG_DEBUG_VFS_MAPPER_MOVE < cycle )
1840printk("\n[DBG] %s : thread %x exit for inode %x in cluster %x / cycle %d\n",
1841__FUNCTION__, CURRENT_THREAD, inode, local_cxy, cycle );
1842#endif
1843
1844    return 0;
1845
1846}  // end vfs_mapper_load_all()
1847
Note: See TracBrowser for help on using the repository browser.