source: trunk/kernel/vfs/vfs.c @ 406

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

This version executed successfully the user "init" process on a mono-processor TSAR architecture.

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