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

Last change on this file since 244 was 238, checked in by alain, 7 years ago

Fixing bugs in vfs_lookup()

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