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

Last change on this file since 568 was 568, checked in by alain, 3 years ago

omplete restructuration of kernel locks.

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