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

Last change on this file since 334 was 333, checked in by max@…, 7 years ago

vfs_user_move() returns an error_t, so don't return a count.

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