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

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

fix inverted arguments

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