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

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

blop

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