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

Last change on this file since 368 was 367, checked in by alain, 7 years ago

Change Time unit from cycle to TICK (in millisecond).
Fix several bugs in VFS.

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