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

Last change on this file since 598 was 598, checked in by alain, 5 years ago

1) Modify the devfs_user_move() function to support large user buffer transfer to/from TXT device.
2) Cosmetic: Improve debug.

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