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

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

This version is a major evolution: The physical memory allocators,
defined in the kmem.c, ppm.c, and kcm.c files have been modified
to support remote accesses. The RPCs that were previously user
to allocate physical memory in a remote cluster have been removed.
This has been done to cure a dead-lock in case of concurrent page-faults.

This version 2.2 has been tested on a (4 clusters / 2 cores per cluster)
TSAR architecture, for both the "sort" and the "fft" applications.

File size: 134.1 KB
RevLine 
[1]1/*
2 * vfs.c - Virtual File System implementation.
3 *
4 * Author  Mohamed Lamine Karaoui (2015)
[623]5 *         Alain Greiner (2016,2017,2018,2019)
[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
[14]25#include <kernel_config.h>
[457]26#include <hal_kernel_types.h>
[1]27#include <hal_atomic.h>
28#include <hal_special.h>
29#include <printk.h>
30#include <list.h>
31#include <xlist.h>
32#include <slist.h>
33#include <xhtab.h>
[430]34#include <string.h>
[23]35#include <rpc.h>
[1]36#include <errno.h>
37#include <kmem.h>
38#include <mapper.h>
39#include <thread.h>
[337]40#include <chdev.h>
[1]41#include <process.h>
[568]42#include <cluster.h>
[23]43#include <vfs.h>
[1]44#include <fatfs.h>
45#include <ramfs.h>
[23]46#include <devfs.h>
47#include <syscalls.h>
[1]48
49//////////////////////////////////////////////////////////////////////////////////////////
[50]50//           Extern variables         
[1]51//////////////////////////////////////////////////////////////////////////////////////////
52
[337]53extern vfs_ctx_t          fs_context[FS_TYPES_NR];    // allocated in kernel_init.c
54extern chdev_directory_t  chdev_dir;                  // allocated in kernel_init.c 
[568]55extern char *             lock_type_str[];            // allocated in kernel_init.c
[50]56 
[602]57///////////////////////////////////////////////////////////////////////////////////////////
58//           VFS Context related functions
[1]59//////////////////////////////////////////////////////////////////////////////////////////
60
[188]61////////////////////////////////////////
62void vfs_ctx_init( vfs_fs_type_t   type,
63                   uint32_t        attr,
64                       uint32_t        total_clusters,
65                       uint32_t        cluster_size,
66                       xptr_t          vfs_root_xp,
67                   void          * extend )
68{
69    vfs_ctx_t * vfs_ctx = &fs_context[type];
70
71    vfs_ctx->type           = type;
72    vfs_ctx->attr           = attr;
73    vfs_ctx->total_clusters = total_clusters;
74    vfs_ctx->cluster_size   = cluster_size;
75    vfs_ctx->vfs_root_xp    = vfs_root_xp;
76    vfs_ctx->extend         = extend;
77
[568]78    busylock_init( &vfs_ctx->lock , LOCK_VFS_CTX );
[188]79
80    bitmap_init( vfs_ctx->bitmap , BITMAP_SIZE(CONFIG_VFS_MAX_INODES) ); 
81}
82
[23]83////////////////////////////////////////////
[1]84error_t vfs_ctx_inum_alloc( vfs_ctx_t * ctx,
85                            uint32_t  * inum )
86{
87    // get lock on inum allocator
[568]88    busylock_acquire( &ctx->lock );
[1]89
90    // get lid from local inum allocator
[23]91    uint32_t lid = bitmap_ffc( ctx->bitmap , CONFIG_VFS_MAX_INODES );
[1]92
[473]93    if( lid == 0xFFFFFFFF )   // no more free slot => error
[1]94    {
95        // release lock
[568]96        busylock_release( &ctx->lock );
[1]97
98        // return error
99        return 1;
100    }
101    else              // found => return inum
102    {
103        // set slot allocated
[23]104        bitmap_set( ctx->bitmap , lid );
[1]105
106        // release lock
[568]107        busylock_release( &ctx->lock );
[1]108
109        // return inum
110        *inum = (((uint32_t)local_cxy) << 16) | (lid & 0xFFFF);
111        return 0;
112    }
113}
114
115////////////////////////////////////////////
116void vfs_ctx_inum_release( vfs_ctx_t * ctx,
117                           uint32_t    inum )
118{
[23]119    bitmap_clear( ctx->bitmap , inum & 0xFFFF ); 
[1]120}
121
122//////////////////////////////////////////////////////////////////////////////////////////
[602]123//           VFS inode descriptor related functions
[1]124//////////////////////////////////////////////////////////////////////////////////////////
125
[598]126const char * vfs_inode_type_str( vfs_inode_type_t type )
[188]127{
[598]128    switch ( type ) 
129    {
130        case INODE_TYPE_FILE: return "FILE";
131        case INODE_TYPE_DIR:  return "DIR ";
132        case INODE_TYPE_FIFO: return "FIFO";
133        case INODE_TYPE_PIPE: return "PIPE";
134        case INODE_TYPE_SOCK: return "SOCK";
135        case INODE_TYPE_DEV:  return "DEV ";
[611]136        case INODE_TYPE_BLK:  return "BLK ";
[598]137        case INODE_TYPE_SYML: return "SYML";
138        default:              return "undefined";
[527]139    }
[188]140}
141
[610]142////////////////////////////////////////////////////
143error_t vfs_inode_create( vfs_fs_type_t     fs_type,
[23]144                          uint32_t          attr,
145                          uint32_t          rights,
146                          uid_t             uid,
147                          gid_t             gid,
148                          xptr_t          * inode_xp )
[1]149{
150    mapper_t         * mapper;     // associated mapper( to be allocated)
151    vfs_inode_t      * inode;      // inode descriptor (to be allocated)
[635]152   
[1]153    uint32_t           inum;       // inode identifier (to be allocated)
154    vfs_ctx_t        * ctx;        // file system context
155        kmem_req_t         req;        // request to kernel memory allocator
156    error_t            error;
157
[23]158    // check fs type and get pointer on context
159    if     ( fs_type == FS_TYPE_FATFS ) ctx = &fs_context[FS_TYPE_FATFS];
160    else if( fs_type == FS_TYPE_RAMFS ) ctx = &fs_context[FS_TYPE_RAMFS];
161    else if( fs_type == FS_TYPE_DEVFS ) ctx = &fs_context[FS_TYPE_DEVFS];
[1]162    else
163    {
[625]164        printk("\n[ERROR] in %s : illegal FS type\n", __FUNCTION__ );
165        return -1;
[1]166    }
167
168    // allocate inum
169    error = vfs_ctx_inum_alloc( ctx , &inum );
170
171    if( error )
172    {
173        printk("\n[ERROR] in %s : cannot allocate inum\n", __FUNCTION__ );
[625]174        return -1;
[1]175    }
176
177    // allocate memory for mapper
[246]178    mapper = mapper_create( fs_type );
[1]179
180    if( mapper == NULL )
181    {
182        printk("\n[ERROR] in %s : cannot allocate mapper\n", __FUNCTION__ );
183        vfs_ctx_inum_release( ctx , inum );
184        return ENOMEM;
185    }
186
[635]187// check inode descriptor contained in one page
188assert( (sizeof(vfs_inode_t) <= CONFIG_PPM_PAGE_SIZE),
189"inode descriptor must fit in one page" );
190
191    // allocate one page for VFS inode descriptor
192    // because the embedded "children xhtab footprint
193        req.type  = KMEM_PPM;
194        req.order = 0;
[1]195    req.flags = AF_KERNEL | AF_ZERO;
[635]196        inode     = kmem_alloc( &req );
[1]197
198    if( inode == NULL )
199    {
200        printk("\n[ERROR] in %s : cannot allocate inode descriptor\n", __FUNCTION__ );
201        vfs_ctx_inum_release( ctx , inum );
202        mapper_destroy( mapper );
[610]203        return -1;
[1]204    }
205
206    // initialize inode descriptor
[623]207    inode->type       = INODE_TYPE_FILE;     // default value
[1]208    inode->inum       = inum;
209    inode->attr       = attr;
[23]210    inode->rights     = rights;
[1]211    inode->uid        = uid;
212    inode->gid        = gid;
213    inode->ctx        = ctx;
[246]214    inode->mapper     = mapper;
[602]215    inode->extend     = NULL;
[610]216    inode->links      = 0;
[1]217
[246]218    // initialise inode field in mapper
219    mapper->inode     = inode;
220 
[610]221    // initialize chidren dentries xhtab
[204]222    xhtab_init( &inode->children , XHTAB_DENTRY_TYPE );
[1]223
[610]224    // initialize parents dentries xlist
225    xlist_root_init( XPTR( local_cxy , &inode->parents ) );
226 
227    // initialize lock protecting size
228    remote_rwlock_init( XPTR( local_cxy , &inode->size_lock ), LOCK_VFS_SIZE );
[1]229
[610]230    // initialise lock protecting inode tree traversal
231    remote_rwlock_init( XPTR( local_cxy , &inode->main_lock ), LOCK_VFS_MAIN );
[568]232
[610]233    // return extended pointer on inode
234    *inode_xp = XPTR( local_cxy , inode );
235
[438]236#if DEBUG_VFS_INODE_CREATE
[635]237char           name[CONFIG_VFS_MAX_NAME_LENGTH];
238uint32_t       cycle      = (uint32_t)hal_get_cycles();
239thread_t *     this       = CURRENT_THREAD;
240vfs_inode_get_name( *inode_xp , name );
[438]241if( DEBUG_VFS_INODE_CREATE < cycle )
[635]242printk("\n[%s] thread[%x,%x] created <%s> / inode [%x,%x] / cycle %d\n",
[598]243__FUNCTION__, this->process->pid, this->trdid, name, local_cxy, inode, cycle );
[433]244#endif
[401]245 
[1]246    return 0;
247
248}  // end vfs_inode_create() 
249
[602]250/////////////////////////////////////////////
251void vfs_inode_destroy( vfs_inode_t * inode )
[1]252{
253    // release memory allocated for mapper
254    mapper_destroy( inode->mapper );
255
256    // release memory allocate for inode descriptor
257        kmem_req_t req;
[635]258        req.type  = KMEM_PPM;
[1]259        req.ptr   = inode;
260        kmem_free( &req );
261
262}  // end vfs_inode_destroy()
263
264//////////////////////////////////////////////
265uint32_t vfs_inode_get_size( xptr_t inode_xp )
266{
267    // get inode cluster and local pointer
268    cxy_t         cxy = GET_CXY( inode_xp );
[473]269    vfs_inode_t * ptr = GET_PTR( inode_xp );
[1]270
[623]271    // build extended pointers on lock & size
272    xptr_t   lock_xp = XPTR( cxy , &ptr->size_lock );
273    xptr_t   size_xp = XPTR( cxy , &ptr->size );
274
275    // take lock in read mode
276    remote_rwlock_rd_acquire( lock_xp );
277
[1]278    // get size
[623]279    uint32_t size = hal_remote_l32( size_xp );
280
281    // release lock from read mode
282    remote_rwlock_rd_release( lock_xp );
283
[1]284    return size;
285}
286
[623]287///////////////////////////////////////////////
288void vfs_inode_update_size( xptr_t    inode_xp,
289                            uint32_t  size )
[1]290{
291    // get inode cluster and local pointer
292    cxy_t         cxy = GET_CXY( inode_xp );
[473]293    vfs_inode_t * ptr = GET_PTR( inode_xp );
[1]294
[623]295    // build extended pointers on lock & size
296    xptr_t   lock_xp = XPTR( cxy , &ptr->size_lock );
297    xptr_t   size_xp = XPTR( cxy , &ptr->size );
298
299    // take lock in write mode
300    remote_rwlock_wr_acquire( lock_xp );
301
302    // get current size
303    uint32_t current_size = hal_remote_l32( size_xp );
304
305    // set size if required
306    if( current_size < size ) hal_remote_s32( size_xp , size );
307
308    // release lock from write mode
309    remote_rwlock_wr_release( lock_xp );
[1]310}
311
[101]312////////////////////////////////////////
313void vfs_inode_unlock( xptr_t inode_xp )
[1]314{
315    // get inode cluster and local pointer
316    cxy_t         cxy = GET_CXY( inode_xp );
[473]317    vfs_inode_t * ptr = GET_PTR( inode_xp );
[1]318
319    // release the main lock
[568]320    remote_busylock_release( XPTR( cxy , &ptr->main_lock ) );
[1]321}
322
[101]323//////////////////////////////////////
324void vfs_inode_lock( xptr_t inode_xp )
[1]325{
326    // get inode cluster and local pointer
327    cxy_t         cxy = GET_CXY( inode_xp );
[473]328    vfs_inode_t * ptr = GET_PTR( inode_xp );
[1]329
330    // get the main lock
[568]331    remote_busylock_acquire( XPTR( cxy , &ptr->main_lock ) );
[1]332}
333
[610]334///////////////////////////////////////////
335void vfs_inode_get_name( xptr_t   inode_xp,
336                         char   * name )
[101]337{
[610]338    cxy_t          inode_cxy;          // inode cluster identifier
339    vfs_inode_t  * inode_ptr;          // local pointer on inode
340    xptr_t         parents_root_xp;    // extended pointer on inode parents root
[204]341   
342    // get inode cluster and local pointer
343    inode_cxy = GET_CXY( inode_xp );
[473]344    inode_ptr = GET_PTR( inode_xp );
[204]345
[610]346    // build extended pointer on parents dentries root
347    parents_root_xp  = XPTR( inode_cxy , &inode_ptr->parents );
[204]348
[610]349    // check VFS root
350    if( xlist_is_empty( parents_root_xp ) )  // inode is the VFS root
[204]351    {
352        strcpy( name , "/" );
353    }
[610]354    else                                     // not the VFS root
[204]355    {
[610]356        xptr_t         dentry_xp;
357        cxy_t          dentry_cxy;
358        vfs_dentry_t * dentry_ptr;
359
360        // get first name in list of parents
361        dentry_xp  = XLIST_FIRST( parents_root_xp , vfs_dentry_t , parents );
[204]362        dentry_cxy = GET_CXY( dentry_xp );
[473]363        dentry_ptr = GET_PTR( dentry_xp );
[204]364
365        hal_remote_strcpy( XPTR( local_cxy  , name ) , 
[610]366                           XPTR( dentry_cxy , dentry_ptr->name ) );
[204]367    }
[610]368
[409]369}  // end vfs_inode_get_name()
[204]370
[602]371///////////////////////////////////////////////////////
372error_t vfs_inode_load_all_pages( vfs_inode_t * inode )
373{
374
[625]375assert( (inode != NULL) , "inode pointer is NULL" );
[602]376
377    uint32_t   page_id;
378    xptr_t     page_xp;
379
380    mapper_t * mapper = inode->mapper;
381    uint32_t   size   = inode->size;
382
[625]383assert( (mapper != NULL) , "mapper pointer is NULL" );
[602]384
385#if DEBUG_VFS_INODE_LOAD_ALL
386uint32_t   cycle = (uint32_t)hal_get_cycles();
387thread_t * this  = CURRENT_THREAD;
388char       name[CONFIG_VFS_MAX_NAME_LENGTH];
389vfs_inode_get_name( XPTR( local_cxy , inode ) , name );
390if( DEBUG_VFS_INODE_LOAD_ALL < cycle )
391printk("\n[%s] thread[%x,%x] enter for <%s> in cluster %x / cycle %d\n",
392__FUNCTION__, this->process->pid, this->trdid, name, local_cxy, cycle );
393#endif
394
395    // compute number of pages
396    uint32_t npages = size >> CONFIG_PPM_PAGE_SHIFT;
397    if( (size & CONFIG_PPM_PAGE_MASK) || (size == 0) ) npages++;
398
399    // loop on pages
400    for( page_id = 0 ; page_id < npages ; page_id ++ )
401    {
402        // If the mage is missing, this function allocates the missing page,
403        // and load the page from IOC device into mapper
404        page_xp = mapper_remote_get_page( XPTR( local_cxy , mapper ), page_id );
405
406        if( page_xp == XPTR_NULL ) return -1;
407    }
408
409#if DEBUG_VFS_INODE_LOAD_ALL
410cycle = (uint32_t)hal_get_cycles();
411if( DEBUG_VFS_INODE_LOAD_ALL < cycle )
412printk("\n[%s] thread[%x,%x] exit for <%x> in cluster %x / cycle %d\n",
413__FUNCTION__, this->process->pid, this->trdid, name, local_cxy, cycle );
414#endif
415
416    return 0;
417
418}  // end vfs_inode_load_all_pages()
419
[626]420/////////////////////////////////////////
421void vfs_inode_display( xptr_t inode_xp )
422{
423    assert( (inode_xp != XPTR_NULL), "inode pointer is NULL");
424
425    char  name[CONFIG_VFS_MAX_NAME_LENGTH];
426
427    vfs_inode_get_name( inode_xp , name );
428
429    cxy_t         inode_cxy = GET_CXY( inode_xp );
430    vfs_inode_t * inode_ptr = GET_PTR( inode_xp );
431
432    vfs_inode_type_t type    = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->type ) );
433    uint32_t         attr    = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->attr ) );
434    uint32_t         size    = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->size ) );
435    uint32_t         parents = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->links ) );
436    mapper_t       * mapper  = hal_remote_lpt( XPTR( inode_cxy , &inode_ptr->mapper ) );
437    void           * extend  = hal_remote_lpt( XPTR( inode_cxy , &inode_ptr->extend ) );
438
439    printk("\n**** inode <%s>\n"
440           " - type    = %s\n"
441           " - attr    = %x\n"
442           " - size    = %d\n"
443           " - parents = %d\n"
444           " - cxy     = %x\n"
445           " - inode   = %x\n"
446           " - mapper  = %x\n"
447           " - extend  = %x\n",
448           name,
449           vfs_inode_type_str( type ),
450           attr,
451           size,
452           parents,
453           inode_cxy,
454           inode_ptr,
455           mapper,
456           extend );
457
458}  // end vfs_inode_display()
459
460
[204]461////////////////////////////////////////////////////////////////////////////////////////////
[602]462//          VFS dentry descriptor related functions
[1]463//////////////////////////////////////////////////////////////////////////////////////////
464
[23]465///////////////////////////////////////////////////
466error_t vfs_dentry_create( vfs_fs_type_t   fs_type,
467                           char          * name,
468                           xptr_t        * dentry_xp )
[1]469{
470    vfs_ctx_t      * ctx;        // context descriptor
471    vfs_dentry_t   * dentry;     // dentry descriptor (to be allocated)
472        kmem_req_t       req;        // request to kernel memory allocator
473
[188]474    // get pointer on context
[23]475    if     ( fs_type == FS_TYPE_FATFS ) ctx = &fs_context[FS_TYPE_FATFS];
476    else if( fs_type == FS_TYPE_RAMFS ) ctx = &fs_context[FS_TYPE_RAMFS];
477    else if( fs_type == FS_TYPE_DEVFS ) ctx = &fs_context[FS_TYPE_DEVFS];
[459]478    else 
[1]479    {
480        ctx = NULL;
[610]481        return -1;
[1]482    }
483
484    // get name length
485    uint32_t length = strlen( name );
486
[459]487    if( length >= CONFIG_VFS_MAX_NAME_LENGTH ) return EINVAL;
[437]488
[1]489    // allocate memory for dentry descriptor
[635]490        req.type  = KMEM_KCM;
491        req.order = bits_log2( sizeof(vfs_dentry_t) );
[1]492    req.flags = AF_KERNEL | AF_ZERO;
[635]493        dentry    = kmem_alloc( &req );
[1]494
[610]495    if( dentry == NULL ) 
496    {
497        printk("\n[ERROR] in %s : cannot allocate dentry descriptor\n",
498        __FUNCTION__ );
499        return -1;
500    }
[437]501
[1]502    // initialize dentry descriptor
503    dentry->ctx     = ctx;
504    dentry->length  = length;
[602]505    dentry->extend  = NULL;
[1]506    strcpy( dentry->name , name );
507
[23]508    // return extended pointer on dentry
[1]509    *dentry_xp = XPTR( local_cxy , dentry );
510
[438]511#if DEBUG_VFS_DENTRY_CREATE
[635]512thread_t * this  = CURRENT_THREAD;
513uint32_t   cycle = (uint32_t)hal_get_cycles();
[438]514if( DEBUG_VFS_DENTRY_CREATE < cycle )
[635]515printk("\n[%s] thread[%x,%x] created <%s> / dentry [%x,%x] / cycle %d\n",
[602]516__FUNCTION__, this->process->pid, this->trdid, name, local_cxy, dentry, cycle );
[433]517#endif
[296]518
[1]519    return 0;
520
521}  // end vfs_dentry_create()
522
[602]523////////////////////////////////////////////////
524void vfs_dentry_destroy( vfs_dentry_t * dentry )
[1]525{
[459]526    // release memory allocated to dentry
[1]527        kmem_req_t req;
[635]528        req.type  = KMEM_KCM;
[1]529        req.ptr   = dentry;
530        kmem_free( &req );
[459]531
[602]532}  // end vfs_dentry_destroy()
533
534
[1]535//////////////////////////////////////////////////////////////////////////////////////////
[602]536//       VFS file descriptor related functions
[1]537//////////////////////////////////////////////////////////////////////////////////////////
538
[23]539/////////////////////////////////////////////
540error_t vfs_file_create( vfs_inode_t * inode,
541                         uint32_t      attr,
542                         xptr_t      * file_xp )
543{
544    vfs_file_t  * file;
545        kmem_req_t    req;
546
[568]547#if DEBUG_VFS_FILE_CREATE
[598]548thread_t * this = CURRENT_THREAD;
[568]549uint32_t cycle = (uint32_t)hal_get_cycles();
550if( DEBUG_VFS_OPEN < cycle )
[598]551printk("\n[%s] thread[%x,%x] enter for inode %x in cluster %x / cycle %d\n",
552__FUNCTION__, this->process->pid, this->trdid, inode, local_cxy, cycle );
[568]553#endif
554
[23]555    // allocate memory for new file descriptor
[635]556        req.type  = KMEM_KCM;
557        req.order = bits_log2( sizeof(vfs_file_t) );
[23]558    req.flags = AF_KERNEL | AF_ZERO;
[635]559        file      = kmem_alloc( &req );
[23]560
561    if( file == NULL ) return ENOMEM;
562
563    // initializes new file descriptor
564    file->gc       = 0;
565    file->type     = inode->type;
566    file->attr     = attr;
567    file->offset   = 0;
[337]568    file->refcount = 1;
[23]569    file->inode    = inode;
570    file->ctx      = inode->ctx;
571    file->mapper   = inode->mapper;
572
[568]573    remote_rwlock_init( XPTR( local_cxy , &file->lock ), LOCK_VFS_FILE );
[23]574
575    *file_xp = XPTR( local_cxy , file );
[459]576
[568]577#if DEBUG_VFS_FILE_CREATE
578cycle = (uint32_t)hal_get_cycles();
[459]579if( DEBUG_VFS_OPEN < cycle )
[598]580printk("\n[%s] thread[%x,%x] created file %x in cluster %x / cycle %d\n",
581__FUNCTION__, this->process->pid, this->trdid, file, local_cxy, cycle );
[459]582#endif
583
[23]584    return 0;
585
586}  // end vfs_file_create()
587
588///////////////////////////////////////////
589void vfs_file_destroy( vfs_file_t *  file )
590{
591        kmem_req_t req;
[635]592        req.type  = KMEM_KCM;
[23]593        req.ptr   = file;
594        kmem_free( &req );
595
[459]596#if DEBUG_VFS_CLOSE
[623]597char name[CONFIG_VFS_MAX_NAME_LENGTH];
598vfs_file_get_name( XPTR( local_cxy , file ) , name );
[598]599thread_t * this = CURRENT_THREAD;
[459]600uint32_t cycle = (uint32_t)hal_get_cycles();
601if( DEBUG_VFS_CLOSE < cycle )
[623]602printk("\n[%s] thread[%x,%x] deleted file <%s> in cluster %x / cycle %d\n",
603__FUNCTION__, this->process->pid, this->trdid, name, local_cxy, cycle );
[459]604#endif
605
[23]606}  // end vfs_file_destroy()
607
608
[1]609////////////////////////////////////////
610void vfs_file_count_up( xptr_t file_xp )
611{
612    // get file cluster and local pointer
613    cxy_t        file_cxy = GET_CXY( file_xp );
[459]614    vfs_file_t * file_ptr = GET_PTR( file_xp ); 
[1]615
616    // atomically increment count
617    hal_remote_atomic_add( XPTR( file_cxy , &file_ptr->refcount ) , 1 ); 
618}
619
620//////////////////////////////////////////
621void vfs_file_count_down( 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 decrement count
628    hal_remote_atomic_add( XPTR( file_cxy , &file_ptr->refcount ) , -1 ); 
629}
630
[623]631///////////////////////////////////////
632void vfs_file_get_name( xptr_t file_xp,
633                        char * name )
634{
635    // get cluster and local pointer on remote file
636    vfs_file_t * file_ptr = GET_PTR( file_xp );
637    cxy_t        file_cxy = GET_CXY( file_xp );
638
639    // get pointers on remote inode
640    vfs_inode_t * inode_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->inode ) ); 
641    xptr_t        inode_xp  = XPTR( file_cxy , inode_ptr );
642
643    // call the relevant function
644    vfs_inode_get_name( inode_xp , name );
645}
646
647
[23]648//////////////////////////////////////////////////////////////////////////////////////////
[602]649//           "syscalls" API related functions
[23]650//////////////////////////////////////////////////////////////////////////////////////////
651
[407]652//////////////////////////////////////
[610]653error_t vfs_open( xptr_t      root_xp,
[407]654                          char      * path,
[610]655                  xptr_t      process_xp,
[407]656                          uint32_t    flags,
657                  uint32_t    mode, 
658                          xptr_t    * new_file_xp,
659                  uint32_t  * new_file_id )
[1]660{
[610]661    error_t        error;
662    xptr_t         inode_xp;       // extended pointer on target inode
663    cxy_t          inode_cxy;      // inode cluster identifier       
664    vfs_inode_t  * inode_ptr;      // inode local pointer
665    uint32_t       file_attr;      // file descriptor attributes
666    uint32_t       lookup_mode;    // lookup working mode       
667    xptr_t         file_xp;        // extended pointer on created file descriptor
668    uint32_t       file_id;        // created file descriptor index in reference fd_array
669    xptr_t         vfs_root_xp;    // extended pointer on VFS root inode
670    vfs_inode_t  * vfs_root_ptr;   // local pointer on VFS root inode
671    cxy_t          vfs_root_cxy;   // VFS root inode cluster identifier
672    xptr_t         lock_xp;        // extended pointer on Inode Tree lock
[1]673
[602]674    if( mode != 0 )
675    {
676        printk("\n[ERROR] in %s : the mode parameter is not supported yet\n" );
677        return -1;
678    }
679
[610]680    thread_t  * this    = CURRENT_THREAD;
681    process_t * process = this->process;
682
[438]683#if DEBUG_VFS_OPEN
[433]684uint32_t cycle = (uint32_t)hal_get_cycles();
[438]685if( DEBUG_VFS_OPEN < cycle )
[610]686printk("\n[%s] thread[%x,%x] enter for <%s> / root_inode (%x,%x) / cycle %d\n",
687__FUNCTION__, process->pid, this->trdid, path, GET_CXY(root_xp), GET_PTR(root_xp), cycle );
[433]688#endif
[101]689
[23]690    // compute lookup working mode
691    lookup_mode = VFS_LOOKUP_OPEN;
692    if( (flags & O_DIR    )      )  lookup_mode |= VFS_LOOKUP_DIR;
693    if( (flags & O_CREAT  )      )  lookup_mode |= VFS_LOOKUP_CREATE;
694    if( (flags & O_EXCL   )      )  lookup_mode |= VFS_LOOKUP_EXCL;
695 
696    // compute attributes for the created file
697    file_attr = 0;
[407]698    if( (flags & O_RDONLY ) == 0 )  file_attr |= FD_ATTR_WRITE_ENABLE;
699    if( (flags & O_WRONLY ) == 0 )  file_attr |= FD_ATTR_READ_ENABLE;
[23]700    if( (flags & O_SYNC   )      )  file_attr |= FD_ATTR_SYNC;
701    if( (flags & O_APPEND )      )  file_attr |= FD_ATTR_APPEND;
702    if( (flags & O_CLOEXEC)      )  file_attr |= FD_ATTR_CLOSE_EXEC;
[1]703
[610]704    // build extended pointer on lock protecting Inode Tree
705    vfs_root_xp  = process->vfs_root_xp;
706    vfs_root_ptr = GET_PTR( vfs_root_xp );
707    vfs_root_cxy = GET_CXY( vfs_root_xp );
708    lock_xp      = XPTR( vfs_root_cxy , &vfs_root_ptr->main_lock );
709
710    // take lock protecting Inode Tree in read mode
711    remote_rwlock_rd_acquire( lock_xp );
712
[23]713    // get extended pointer on target inode
[610]714    error = vfs_lookup( root_xp,
715                        path,
716                        lookup_mode,
717                        &inode_xp,
718                        NULL );
[23]719
[610]720    // release lock protecting Inode Tree
721    remote_rwlock_rd_release( lock_xp );
[23]722
[610]723    if( error )
724    {
725        printk("\n[ERROR] in %s : cannot get inode <%s>\n",
726        __FUNCTION__ , path );
727        return -1;
728    }
729
[23]730    // get target inode cluster and local pointer
731    inode_cxy = GET_CXY( inode_xp );
[473]732    inode_ptr = GET_PTR( inode_xp );
[23]733   
[610]734#if (DEBUG_VFS_OPEN & 1)
735cycle = (uint32_t)hal_get_cycles();
736if( DEBUG_VFS_OPEN < cycle )
737printk("\n[%s] thread[%x,%x] found inode(%x,%x) for <%s>\n",
738__FUNCTION__, process->pid, this->trdid, inode_cxy, inode_ptr, path );
739#endif
740
[23]741    // create a new file descriptor in cluster containing inode
742    if( inode_cxy == local_cxy )      // target cluster is local
[1]743    {
[23]744        error = vfs_file_create( inode_ptr , file_attr , &file_xp );
[1]745    }
[23]746    else                              // target cluster is remote
747    {
748        rpc_vfs_file_create_client( inode_cxy , inode_ptr , file_attr , &file_xp , &error );
749    }
[1]750
[23]751    if( error )  return error;
[1]752
[610]753#if (DEBUG_VFS_OPEN & 1)
754cycle = (uint32_t)hal_get_cycles();
755if( DEBUG_VFS_OPEN < cycle )
756printk("\n[%s] thread[%x,%x] created file descriptor (%x,%x) for <%s>\n",
757__FUNCTION__, process->pid, this->trdid, GET_CXY(file_xp), GET_PTR(file_xp), path );
758#endif
759
[407]760    // allocate and register a new file descriptor index in reference process
[610]761    error = process_fd_register( process_xp , file_xp , &file_id );
[1]762
[23]763    if( error ) return error;
[1]764
[438]765#if DEBUG_VFS_OPEN
[433]766cycle = (uint32_t)hal_get_cycles();
[438]767if( DEBUG_VFS_OPEN < cycle )
[626]768printk("\n[%s] thread[%x,%x] exit for <%s> / fdid %d / cxy %x / cycle %d\n",
[610]769__FUNCTION__, process->pid, this->trdid, path, file_id, GET_CXY( file_xp ), cycle );
[433]770#endif
[238]771
[23]772    // success
773    *new_file_xp = file_xp;
774    *new_file_id = file_id;
775    return 0;
[1]776
[23]777}  // end vfs_open()
778
[407]779//////////////////////////////////////
780int vfs_user_move( bool_t   to_buffer,
781                   xptr_t   file_xp,
782                   void   * buffer,
783                   uint32_t size )
[23]784{
785    cxy_t              file_cxy;     // remote file descriptor cluster
786    vfs_file_t       * file_ptr;     // remote file descriptor local pointer
787    vfs_inode_type_t   inode_type;
788    uint32_t           file_offset;  // current offset in file
789    mapper_t         * mapper;
790    error_t            error;
791
[602]792// check argument
[625]793assert( (file_xp != XPTR_NULL), "file_xp == XPTR_NULL" );
[602]794
[23]795    // get cluster and local pointer on remote file descriptor
796    file_cxy  = GET_CXY( file_xp );
[473]797    file_ptr  = GET_PTR( file_xp );
[23]798
799    // get inode type from remote file descriptor
[568]800    inode_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type   ) );
[23]801   
[602]802// check inode type
[625]803assert( (inode_type == INODE_TYPE_FILE), "bad inode type" );
[23]804
[628]805    // get mapper pointer and file offset from file descriptor
806    file_offset = hal_remote_l32( XPTR( file_cxy , &file_ptr->offset ) );
807    mapper      = hal_remote_lpt( XPTR( file_cxy , &file_ptr->mapper ) );
808
[626]809#if DEBUG_VFS_USER_MOVE
810char          name[CONFIG_VFS_MAX_NAME_LENGTH];
811uint32_t      cycle      = (uint32_t)hal_get_cycles();
812thread_t    * this       = CURRENT_THREAD;
813vfs_inode_t * inode      = hal_remote_lpt( XPTR( file_cxy , &file_ptr->inode ) );
814vfs_inode_get_name( XPTR( file_cxy , inode ) , name );
815if( cycle > DEBUG_VFS_USER_MOVE )
816{
817    if( to_buffer ) 
[628]818    printk("\n[%s] thread[%x,%x] enter / %d bytes / map(%s) -> buf(%x) / offset %d / cycle %d\n",
819    __FUNCTION__ , this->process->pid, this->trdid, size, name, buffer, file_offset, cycle );
[626]820    else           
[628]821    printk("\n[%s] thread[%x,%x] enter / %d bytes / buf(%x) -> map(%s) / offset %d / cycle %d\n",
822    __FUNCTION__ , this->process->pid, this->trdid, size, buffer, name, file_offset, cycle );
[626]823}
824#endif
825
[407]826    // move data between mapper and buffer
[610]827    error = mapper_move_user( XPTR( file_cxy , mapper ),
828                              to_buffer,
829                              file_offset,
830                              buffer,
831                              size );
[602]832    if( error ) 
833    {
[625]834        printk("\n[ERROR] in %s : cannot move data", __FUNCTION__ );
[602]835        return -1;
836    }
837
[625]838    // update file offset in file descriptor
839    hal_remote_atomic_add( XPTR( file_cxy , &file_ptr->offset ) , size );
840
841#if DEBUG_VFS_USER_MOVE
[626]842cycle = (uint32_t)hal_get_cycles();
[625]843if( cycle > DEBUG_VFS_USER_MOVE )
844{
845    if( to_buffer ) 
[628]846    printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
847    __FUNCTION__ , this->process->pid, cycle );
[625]848    else           
[628]849    printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
850    __FUNCTION__ , this->process->pid, cycle );
[625]851}
852#endif
853
[602]854    return size;
855
[313]856}  // end vfs_user_move()
[23]857
[317]858////////////////////////////////////////////
859error_t vfs_kernel_move( bool_t   to_buffer,
860                         xptr_t   file_xp,
861                         xptr_t   buffer_xp,
862                         uint32_t size )
863{
864    cxy_t              file_cxy;     // remote file descriptor cluster
865    vfs_file_t       * file_ptr;     // remote file descriptor local pointer
[602]866    vfs_inode_type_t   inode_type;   // remote file type
[317]867    uint32_t           file_offset;  // current offset in file
[602]868    mapper_t         * mapper_ptr;   // remote mapper local pointer
869    xptr_t             mapper_xp;    // remote mapper extended pointer
[317]870    error_t            error;
871
[602]872// check argument
[625]873assert( (file_xp != XPTR_NULL) , "file_xp == XPTR_NULL" );
[602]874
[317]875    // get cluster and local pointer on remote file descriptor
876    file_cxy  = GET_CXY( file_xp );
[473]877    file_ptr  = GET_PTR( file_xp );
[317]878
879    // get inode type from remote file descriptor
[568]880    inode_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type   ) );
[610]881
[625]882// check inode type
883assert( (inode_type == INODE_TYPE_FILE), "bad file type" );
[317]884
[625]885    // get mapper pointers and file offset from file descriptor
886    file_offset = hal_remote_l32( XPTR( file_cxy , &file_ptr->offset ) );
887    mapper_ptr  = hal_remote_lpt( XPTR( file_cxy , &file_ptr->mapper ) );
888    mapper_xp   = XPTR( file_cxy , mapper_ptr );
889
890    // move data between mapper and buffer
891    error = mapper_move_kernel( mapper_xp,
892                                to_buffer,
893                                file_offset,
894                                buffer_xp,
895                                size );
896    if( error ) 
[317]897    {
[625]898        printk("\n[ERROR] in %s : cannot move data", __FUNCTION__ );
[317]899        return -1;
900    }
[602]901
[625]902#if DEBUG_VFS_KERNEL_MOVE
903char          name[CONFIG_VFS_MAX_NAME_LENGTH];
904uint32_t      cycle      = (uint32_t)hal_get_cycles();
905thread_t    * this       = CURRENT_THREAD;
906cxy_t         buffer_cxy = GET_CXY( buffer_xp );
907void        * buffer_ptr = GET_PTR( buffer_xp );
908vfs_inode_t * inode      = hal_remote_lpt( XPTR( file_cxy , &file_ptr->inode ) );
909vfs_inode_get_name( XPTR( file_cxy , inode ) , name );
910if( cycle > DEBUG_VFS_KERNEL_MOVE )
911{
912    if( to_buffer ) 
913    printk("\n[%s] thread[%x,%x] moves %d bytes from <%s> mapper to buffer(%x,%x) / cycle %d\n",
914    __FUNCTION__ , this->process->pid, this->trdid, size, name, buffer_cxy, buffer_ptr );
915    else           
916    printk("\n[%s] thread[%x,%x] moves %d bytes from buffer(%x,%x) to <%s> mapper / cycle %d\n",
917    __FUNCTION__ , this->process->pid, this->trdid, size, buffer_cxy, buffer_ptr, name );
918}
919#endif
920
[602]921    return 0;
922
[317]923}  // end vfs_kernel_move()
924
[23]925//////////////////////////////////////
926error_t vfs_lseek( xptr_t     file_xp,
927                   uint32_t   offset,
928                   uint32_t   whence, 
929                   uint32_t * new_offset )
930{
[266]931    xptr_t         offset_xp;
932    xptr_t         lock_xp;
[602]933    xptr_t         size_xp;
[266]934    cxy_t          file_cxy;
935    vfs_file_t  *  file_ptr;
936    vfs_inode_t *  inode_ptr;
937    uint32_t       new;
938
[602]939// check argument
[625]940assert( (file_xp != XPTR_NULL) , "file_xp == XPTR_NULL" );
[266]941
942    // get cluster and local pointer on remote file descriptor
943    file_cxy = GET_CXY( file_xp );
[473]944    file_ptr = GET_PTR( file_xp );
[266]945
[602]946    // get local pointer on remote inode
947    inode_ptr = (vfs_inode_t *)hal_remote_lpt( XPTR( file_cxy , &file_ptr->inode ) );
948
949    // build extended pointers on lock, offset and size
[266]950    offset_xp = XPTR( file_cxy , &file_ptr->offset );
951    lock_xp   = XPTR( file_cxy , &file_ptr->lock );
[602]952    size_xp   = XPTR( file_cxy , &inode_ptr->size );
[266]953
954    // take file descriptor lock
[568]955    remote_rwlock_wr_acquire( lock_xp );
[266]956
957    if      ( whence == SEEK_CUR )   // new = current + offset
958    {
[568]959        new = hal_remote_l32( offset_xp ) + offset;
[266]960    }
961    else if ( whence == SEEK_SET )   // new = offset
962    {
963        new = offset;
964    }
965    else if ( whence == SEEK_END )   // new = size + offset
966    { 
[602]967        new = hal_remote_l32( size_xp ) + offset;
[266]968    }
969    else
970    {
971        printk("\n[ERROR] in %s : illegal whence value\n", __FUNCTION__ );
[568]972        remote_rwlock_wr_release( lock_xp );
[266]973        return -1;
974    }
975
[602]976#if DEBUG_VFS_LSEEK
977uint32_t   cycle = (uint32_t)hal_get_cycles();
978thread_t * this  = CURRENT_THREAD;
979char       name[CONFIG_VFS_MAX_NAME_LENGTH];
980vfs_inode_get_name( XPTR( file_cxy , inode_ptr ) , name );
981if( cycle > DEBUG_VFS_LSEEK )
982printk("\n[%s] thread[%x,%x] for <%s> / new offset %d / cycle %d\n",
983__FUNCTION__ , this->process->pid, this->trdid, name, new, cycle );
984#endif
985
[266]986    // set new offset
[568]987    hal_remote_s32( offset_xp , new );
[266]988
989    // release file descriptor lock
[568]990    remote_rwlock_wr_release( lock_xp );
[266]991
992    // success
[602]993    if ( new_offset != NULL ) *new_offset = new;
[1]994    return 0;
995
[23]996}  // vfs_lseek()
997
[623]998////////////////////////////////////
[23]999error_t vfs_close( xptr_t   file_xp,
1000                   uint32_t file_id )
[1]1001{
[623]1002    cxy_t         file_cxy;         // cluster containing the file descriptor.
1003    vfs_file_t  * file_ptr;         // local ponter on file descriptor
1004    cxy_t         owner_cxy;        // process owner cluster
1005    pid_t         pid;              // process identifier
1006    lpid_t        lpid;             // process local index
1007    xptr_t        root_xp;          // root of xlist (processes , or dentries)
1008    xptr_t        lock_xp;          // lock protecting the xlist
1009    xptr_t        iter_xp;          // iterator on xlist
1010    mapper_t    * mapper_ptr;       // local pointer on associated mapper
1011    vfs_inode_t * inode_ptr;        // local pointer on associated inode
1012    uint32_t      size;             // current file size (from inode descriptor)
1013    error_t       error;
[459]1014
[623]1015    char          name[CONFIG_VFS_MAX_NAME_LENGTH];  // file name
[23]1016
[623]1017// check argument
[625]1018assert( (file_xp != XPTR_NULL) , "file_xp is XPTR_NULL" );
[623]1019
[23]1020    thread_t  * this    = CURRENT_THREAD;
1021    process_t * process = this->process;
[623]1022    cluster_t * cluster = LOCAL_CLUSTER;
[23]1023
[623]1024    // get file name
1025    vfs_file_get_name( file_xp , name );
1026   
[459]1027#if DEBUG_VFS_CLOSE
1028uint32_t cycle = (uint32_t)hal_get_cycles();
1029if( DEBUG_VFS_CLOSE < cycle )
[623]1030printk("\n[%s] thread[%x,%x] enter for <%s> / cycle %d\n",
1031__FUNCTION__, process->pid, this->trdid, name, cycle );
[459]1032#endif
[1]1033
[623]1034    // get cluster and local pointer on remote file descriptor
1035    file_cxy = GET_CXY( file_xp );
1036    file_ptr = GET_PTR( file_xp );
[23]1037
[623]1038    //////// 1) update all dirty pages from mapper to device
[23]1039
[633]1040    // get local pointer on mapper associated to file
[623]1041    mapper_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->mapper ) );
[23]1042
[623]1043    // copy all dirty pages from mapper to device
1044    if( file_cxy == local_cxy )
1045    {
1046        error = mapper_sync( mapper_ptr );
1047    }
1048    else
1049    {
1050        rpc_mapper_sync_client( file_cxy,
1051                                mapper_ptr,
1052                                &error );
1053    }
[459]1054
[623]1055    if( error )
1056    {
1057        printk("\n[ERROR] in %s : cannot synchronise dirty pages for <%s>\n",
1058        __FUNCTION__, name ); 
1059        return -1;
1060    }
[23]1061
[623]1062#if DEBUG_VFS_CLOSE
1063if( DEBUG_VFS_CLOSE < cycle )
1064printk("\n[%s] thread[%x,%x] synchronised mapper of <%s> to device\n",
1065__FUNCTION__, process->pid, this->trdid, name );
1066#endif
1067
[625]1068    //////// 2) update file size in all parent directory mapper(s) and update device
[623]1069
[633]1070    // get local pointer on remote inode
[623]1071    inode_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->inode ) );
1072
1073    // get file size from remote inode
1074    size = hal_remote_l32( XPTR( file_cxy , &inode_ptr->size ) );
1075
1076    // get root of list of parents dentry
1077    root_xp = XPTR( file_cxy , &inode_ptr->parents );
1078
1079    // loop on all parents
[23]1080    XLIST_FOREACH( root_xp , iter_xp )
[1]1081    {
[623]1082        // get pointers on parent directory dentry
1083        xptr_t         parent_dentry_xp  = XLIST_ELEMENT( iter_xp , vfs_dentry_t , parents );
1084        cxy_t          parent_cxy        = GET_CXY( parent_dentry_xp );
1085        vfs_dentry_t * parent_dentry_ptr = GET_PTR( parent_dentry_xp );
[1]1086
[623]1087        // get local pointer on parent directory inode
1088        vfs_inode_t * parent_inode_ptr = hal_remote_lpt( XPTR( parent_cxy, 
1089                                                         &parent_dentry_ptr->parent ) );
1090
1091        // get local pointer on parent directory mapper
1092        mapper_t * parent_mapper_ptr = hal_remote_lpt( XPTR( parent_cxy,
1093                                                       &parent_inode_ptr->mapper ) );
1094 
1095        // update dentry size in parent directory mapper
1096        if( parent_cxy == local_cxy )
1097        {
1098            error = vfs_fs_update_dentry( parent_inode_ptr,
1099                                          parent_dentry_ptr,
1100                                          size );
1101        }
1102        else
1103        {
1104            rpc_vfs_fs_update_dentry_client( parent_cxy,
1105                                             parent_inode_ptr,
1106                                             parent_dentry_ptr,
1107                                             size,
1108                                             &error );
1109        }
1110
1111        if( error )
1112        {
1113            printk("\n[ERROR] in %s : cannot update size in parent\n",
1114            __FUNCTION__ ); 
1115            return -1;
1116        }
1117
1118#if DEBUG_VFS_CLOSE
1119char parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
1120vfs_inode_get_name( XPTR( parent_cxy , parent_inode_ptr ) , parent_name );
[459]1121if( DEBUG_VFS_CLOSE < cycle )
[625]1122printk("\n[%s] thread[%x,%x] updated <%s> in <%s> / size = %d bytes\n",
1123__FUNCTION__, process->pid, this->trdid, name, parent_name, size );
[459]1124#endif
[23]1125
[623]1126        // copy all dirty pages from parent mapper to device
1127        if( parent_cxy == local_cxy )
1128        {
1129            error = mapper_sync( parent_mapper_ptr );
1130        }
1131        else
1132        {
1133            rpc_mapper_sync_client( parent_cxy,
1134                                    parent_mapper_ptr,
1135                                    &error );
1136        }
[459]1137
[623]1138        if( error )
1139        {
1140            printk("\n[ERROR] in %s : cannot synchronise parent mapper to device\n",
1141            __FUNCTION__ ); 
1142            return -1;
1143        }
[459]1144
[623]1145#if DEBUG_VFS_CLOSE
1146if( DEBUG_VFS_CLOSE < cycle )
1147printk("\n[%s] thread[%x,%x] synchonized mapper of parent <%s> to device\n",
1148__FUNCTION__, process->pid, this->trdid, parent_name );
1149#endif
[459]1150
[623]1151    }
1152
1153    //////// 3) loop on the process copies to reset all fd_array[file_id] entries
1154
1155    // get owner process cluster and lpid
1156    pid        = process->pid;
1157    owner_cxy  = CXY_FROM_PID( pid );
1158    lpid       = LPID_FROM_PID( pid );
1159
1160    // get extended pointers on copies root and lock
1161    root_xp = XPTR( owner_cxy , &cluster->pmgr.copies_root[lpid] );
1162    lock_xp = XPTR( owner_cxy , &cluster->pmgr.copies_lock[lpid] );
1163
1164    // take the lock protecting the list of copies
1165    remote_queuelock_acquire( lock_xp );
1166
1167    XLIST_FOREACH( root_xp , iter_xp )
1168    {
1169        xptr_t      process_xp  = XLIST_ELEMENT( iter_xp , process_t , copies_list );
1170        cxy_t       process_cxy = GET_CXY( process_xp );
1171        process_t * process_ptr = GET_PTR( process_xp );
1172
1173        xptr_t entry_xp = XPTR( process_cxy , &process_ptr->fd_array.array[file_id] );
[568]1174        hal_remote_s64( entry_xp , XPTR_NULL );
[459]1175        vfs_file_count_down( file_xp );
[124]1176        hal_fence();
[23]1177    }   
1178
[459]1179    // release the lock protecting the list of copies
[568]1180    remote_queuelock_release( lock_xp );
[459]1181
[623]1182#if DEBUG_VFS_CLOSE
[459]1183if( DEBUG_VFS_CLOSE < cycle )
[625]1184printk("\n[%s] thread[%x,%x] reset all fd-array copies for <%s>\n",
[623]1185__FUNCTION__, process->pid, this->trdid, name );
[459]1186#endif
1187
[623]1188    //////// 4) release memory allocated to file descriptor in remote cluster
[459]1189
[23]1190    if( file_cxy == local_cxy )             // file cluster is local
[1]1191    {
[23]1192        vfs_file_destroy( file_ptr );
1193    }
1194    else                                    // file cluster is local
1195    {
1196        rpc_vfs_file_destroy_client( file_cxy , file_ptr );
1197    }
[1]1198
[459]1199#if DEBUG_VFS_CLOSE
1200cycle = (uint32_t)hal_get_cycles();
1201if( DEBUG_VFS_CLOSE < cycle )
[625]1202printk("\n[%s] thread[%x,%x] exit / closed <%s> in process %x / cycle %d\n",
1203__FUNCTION__, process->pid, this->trdid, name, process->pid, cycle );
[459]1204#endif
1205
[23]1206    return 0;
[1]1207
[23]1208}  // end vfs_close()
[1]1209
1210////////////////////////////////////
[610]1211error_t vfs_mkdir( xptr_t   root_xp,
1212                   char   * path,
1213                   uint32_t rights )
1214{
1215    error_t        error;
1216    xptr_t         vfs_root_xp;        // extended pointer on VFS root inode
1217    vfs_inode_t  * vfs_root_ptr;       // local pointer on VFS root inode
1218    cxy_t          vfs_root_cxy;       // VFS root inode cluster identifier
1219    xptr_t         lock_xp;            // extended pointer on lock protecting Inode Tree
[611]1220    xptr_t         inode_xp;           // extended pointer on new directory inode
1221    vfs_inode_t  * inode_ptr;          // local pointer on new directory inode
1222    cxy_t          inode_cxy;          // new directory inode cluster identifier
[610]1223    xptr_t         dentry_xp;          // extended pointer on new dentry
[611]1224    vfs_dentry_t * dentry_ptr;         // new dentry local pointer
1225    xptr_t         parent_xp;          // extended pointer on parent inode
1226    vfs_inode_t  * parent_ptr;         // local pointer on parent inode 
1227    cxy_t          parent_cxy;         // parent inode cluster identifier
1228    vfs_ctx_t    * parent_ctx_ptr;     // local pointer on parent inode context
1229    uint32_t       parent_fs_type;     // parent inode file system type
[610]1230
1231    xptr_t         parents_root_xp;    // extended pointer on parents field in inode (root)
1232    xptr_t         parents_entry_xp;   // extended pointer on parents field in dentry
1233    xptr_t         children_xhtab_xp;  // extended pointer on children field in inode (root)
1234    xptr_t         children_entry_xp;  // extended pointer on children field in dentry
1235
1236    char           last_name[CONFIG_VFS_MAX_NAME_LENGTH];
1237
1238    thread_t  * this    = CURRENT_THREAD;
1239    process_t * process = this->process;
1240
1241#if DEBUG_VFS_MKDIR
1242char root_name[CONFIG_VFS_MAX_NAME_LENGTH];
1243vfs_inode_get_name( root_xp , root_name );
1244uint32_t   cycle = (uint32_t)hal_get_cycles();
1245if( DEBUG_VFS_MKDIR < cycle )
1246printk("\n[%s] thread[%x,%x] enter / root <%s> / path <%s> / cycle %d\n",
1247__FUNCTION__, process->pid, this->trdid, root_name, path, cycle );
1248#endif
1249
1250    // build extended pointer on lock protecting Inode Tree (in VFS root inode)
1251    vfs_root_xp  = process->vfs_root_xp;
1252    vfs_root_ptr = GET_PTR( vfs_root_xp );
1253    vfs_root_cxy = GET_CXY( vfs_root_xp );
1254    lock_xp      = XPTR( vfs_root_cxy , &vfs_root_ptr->main_lock );
1255
1256    // take the lock protecting Inode Tree in write mode
1257    remote_rwlock_wr_acquire( lock_xp );
1258
1259    // 1. get pointers on parent inode
1260    error = vfs_lookup( root_xp,
1261                        path,
1262                        VFS_LOOKUP_DIR | VFS_LOOKUP_PARENT,
1263                        &parent_xp,
1264                        last_name );
1265    if( error )
1266    {
1267        remote_rwlock_wr_release( lock_xp );
1268        printk("\n[ERROR] in %s : cannot get parent inode for <%s>\n",
1269        __FUNCTION__, path );
1270        return -1;
1271    }
1272
1273    // get parent inode cluster and local pointer
1274    parent_cxy = GET_CXY( parent_xp );
1275    parent_ptr = GET_PTR( parent_xp );
1276
1277#if( DEBUG_VFS_MKDIR & 1 )
1278if( DEBUG_VFS_MKDIR < cycle )
1279printk("\n[%s] thread[%x,%x] get parent inode (%x,%x) for <%s>\n",
1280__FUNCTION__, process->pid, this->trdid, parent_cxy, parent_ptr, path );
1281#endif
1282
1283    // get parent inode context, and FS type
1284    parent_ctx_ptr = hal_remote_lpt( XPTR( parent_cxy , &parent_ptr->ctx ) );
1285    parent_fs_type = hal_remote_l32( XPTR( parent_cxy , &parent_ctx_ptr->type ) );
1286
1287    // 2. create one new dentry in parent cluster
1288    if( parent_cxy == local_cxy ) 
1289    {
1290        error = vfs_dentry_create( parent_fs_type,
1291                                   last_name,
1292                                   &dentry_xp );
1293    }
1294    else
1295    {
1296        rpc_vfs_dentry_create_client( parent_cxy,
1297                                      parent_fs_type,
1298                                      last_name,
1299                                      &dentry_xp,
1300                                      &error );
1301    }
1302
1303    if( error )
1304    {
1305        remote_rwlock_wr_release( lock_xp );
1306        printk("\n[ERROR] in %s : cannot create new dentry in cluster %x for <%s>\n",
1307        __FUNCTION__, parent_cxy, path );
1308        return -1;
1309    }
1310
1311    // get local pointer on dentry
1312    dentry_ptr = GET_PTR( dentry_xp );
1313
1314#if( DEBUG_VFS_MKDIR & 1 )
1315if( DEBUG_VFS_MKDIR < cycle )
1316printk("\n[%s] thread[%x,%x] created new dentry (%x,%x) for <%s>\n",
1317__FUNCTION__, process->pid, this->trdid, parent_cxy, dentry_ptr, path );
1318#endif
1319
[611]1320    // 3. create new directory inode
[610]1321    // TODO : define attr / uid / gid
1322    uint32_t attr = 0;
1323    uint32_t uid  = 0;
1324    uint32_t gid  = 0;
1325
1326    // select a target cluster for new inode
1327    inode_cxy = cluster_random_select();
1328   
[611]1329    if( inode_cxy == local_cxy )      // target cluster is local
[610]1330    {
1331        error = vfs_inode_create( parent_fs_type,
1332                                  attr,
1333                                  rights,
1334                                  uid,
1335                                  gid,
1336                                  &inode_xp );
1337    }
[611]1338    else                              // target cluster is remote
[610]1339    {
1340        rpc_vfs_inode_create_client( inode_cxy,
1341                                     parent_fs_type,
1342                                     attr,
1343                                     rights,
1344                                     uid,
1345                                     gid,
1346                                     &inode_xp,
1347                                     &error );
1348    }
1349                                     
1350    if( error )
1351    {
[611]1352        remote_rwlock_wr_release( lock_xp );
[610]1353        printk("\n[ERROR] in %s : cannot create new inode in cluster %x for <%s>\n",
1354               __FUNCTION__ , inode_cxy , path );
1355        if( parent_cxy == local_cxy ) vfs_dentry_destroy( dentry_ptr );
1356        else rpc_vfs_dentry_destroy_client( parent_cxy , dentry_ptr );
1357        return -1;
1358    }
1359
1360    // get new inode local pointer
1361    inode_ptr = GET_PTR( inode_xp );
[623]1362
1363    // update inode "type" field
1364    hal_remote_s32( XPTR( inode_cxy , &inode_ptr->type ) , INODE_TYPE_DIR ); 
[610]1365   
1366#if(DEBUG_VFS_MKDIR & 1)
1367if( DEBUG_VFS_MKDIR < cycle )
1368printk("\n[%s] thread[%x,%x] created new inode (%x,%x) for <%s>\n",
1369__FUNCTION__ , process->pid, this->trdid, inode_cxy, inode_ptr, path );
1370#endif
1371
1372    // 4. register dentry in new inode list of parents
1373    parents_root_xp  = XPTR( inode_cxy  , &inode_ptr->parents );
1374    parents_entry_xp = XPTR( parent_cxy , &dentry_ptr->parents );
1375    xlist_add_first( parents_root_xp , parents_entry_xp );
1376    hal_remote_atomic_add( XPTR( inode_cxy , &inode_ptr->links ) , 1 );
1377
1378    // 5. register dentry in parent inode
1379    children_xhtab_xp = XPTR( parent_cxy , &parent_ptr->children );
1380    children_entry_xp = XPTR( parent_cxy , &dentry_ptr->children );
1381    xhtab_insert( children_xhtab_xp , last_name , children_entry_xp );
1382
1383    // 6. update "parent" and "child_xp" fields in dentry
1384    hal_remote_s64( XPTR( parent_cxy , &dentry_ptr->child_xp ) , inode_xp );
1385    hal_remote_spt( XPTR( parent_cxy , &dentry_ptr->parent ) , parent_ptr );
1386
1387#if(DEBUG_VFS_MKDIR & 1)
1388if( DEBUG_VFS_MKDIR < cycle )
1389printk("\n[%s] thread[%x,%x] updated Inode Tree for <%s>\n",
1390__FUNCTION__, process->pid, this->trdid, path );
1391#endif
1392
[611]1393    // 7. create the two special dentries <.> and <..> in new directory
1394    // both the new directory mapper, and the Inode Tree are updated
1395    error = vfs_add_special_dentries( inode_xp,
1396                                      parent_xp );
1397
1398    if( error )
1399    {
1400        remote_rwlock_wr_release( lock_xp );
1401        printk("\n[ERROR] in %s : cannot create new inode in cluster %x for <%s>\n",
1402               __FUNCTION__ , inode_cxy , path );
1403        if( parent_cxy == local_cxy ) vfs_dentry_destroy( dentry_ptr );
1404        else rpc_vfs_dentry_destroy_client( parent_cxy , dentry_ptr );
1405        return -1;
1406    }
1407
[610]1408    // release the lock protecting Inode Tree
1409    remote_rwlock_wr_release( lock_xp );
1410
[611]1411    // 8. update parent directory mapper
[610]1412    //    and synchronize the parent directory on IOC device
1413    if (parent_cxy == local_cxy)
1414    {
1415        error = vfs_fs_add_dentry( parent_ptr,
1416                                   dentry_ptr );
1417    }
1418    else
1419    {
1420        rpc_vfs_fs_add_dentry_client( parent_cxy,
1421                                      parent_ptr,
1422                                      dentry_ptr,
1423                                      &error );
1424    }
1425
1426    if( error )
1427    {
1428        printk("\n[ERROR] in %s : cannot update parent directory for <%s>\n",
1429        __FUNCTION__, path );
1430        return -1;
1431    }
1432
1433#if(DEBUG_VFS_MKDIR & 1)
1434if( DEBUG_VFS_MKDIR < cycle )
1435printk("\n[%s] thread[%x,%x] updated parent dir (mapper and IOC) for <%s>\n",
1436__FUNCTION__, process->pid, this->trdid, path );
1437#endif
1438
1439    return 0;
1440
1441}  // end vfs_mkdir()
1442
1443///////////////////////////////////////
1444error_t vfs_link( xptr_t   old_root_xp,
1445                  char   * old_path,
1446                  xptr_t   new_root_xp,
1447                  char   * new_path )
1448{
1449    error_t        error;
1450    xptr_t         vfs_root_xp;        // extended pointer on VFS root inode
1451    vfs_inode_t  * vfs_root_ptr;       // local pointer on VFS root inode
1452    cxy_t          vfs_root_cxy;       // VFS root inode cluster identifier
1453    xptr_t         lock_xp;            // extended pointer on lock protecting Inode Tree
1454    xptr_t         inode_xp;           // extended pointer on target inode
1455    vfs_inode_t  * inode_ptr;          // local pointer on target inode
1456    cxy_t          inode_cxy;          // target inode cluster identifier
1457    uint32_t       inode_type;         // target inode type
1458    vfs_ctx_t    * inode_ctx_ptr;      // local pointer on target inode context
1459    uint32_t       inode_fs_type;      // target inode file system type
1460    xptr_t         dentry_xp;          // extended pointer on new dentry
1461    vfs_dentry_t * dentry_ptr;         // target dentry local pointer
1462    xptr_t         new_parent_xp;      // extended pointer on new parent inode
1463    vfs_inode_t  * new_parent_ptr;     // local pointer on new parent inode 
1464    cxy_t          new_parent_cxy;     // new parent inode cluster identifier
1465
1466    xptr_t         parents_root_xp;    // extended pointer on parents field in inode (root)
1467    xptr_t         parents_entry_xp;   // extended pointer on parents field in dentry
1468    xptr_t         children_xhtab_xp;  // extended pointer on children field in inode (root)
1469    xptr_t         children_entry_xp;  // extended pointer on children field in dentry
1470
1471    char           new_name[CONFIG_VFS_MAX_NAME_LENGTH];
1472
1473    thread_t  * this    = CURRENT_THREAD;
1474    process_t * process = this->process;
1475
1476#if DEBUG_VFS_LINK
1477char old_root_name[CONFIG_VFS_MAX_NAME_LENGTH];
1478char new_root_name[CONFIG_VFS_MAX_NAME_LENGTH];
1479vfs_inode_get_name( old_root_xp , old_root_name );
1480vfs_inode_get_name( new_root_xp , new_root_name );
1481uint32_t   cycle = (uint32_t)hal_get_cycles();
1482if( DEBUG_VFS_LINK < cycle )
1483printk("\n[%s] thread[%x,%x] enter / old_root <%s> / old_path <%s> / "
1484"new_root <%s> / new_path <%s> / cycle %d\n",
1485__FUNCTION__, process->pid, this->trdid,
1486old_root_name, old_path, new_root_name, new_path, cycle );
1487#endif
1488
1489    // build extended pointer on lock protecting Inode Tree (in VFS root inode)
1490    vfs_root_xp  = process->vfs_root_xp;
1491    vfs_root_ptr = GET_PTR( vfs_root_xp );
1492    vfs_root_cxy = GET_CXY( vfs_root_xp );
1493    lock_xp      = XPTR( vfs_root_cxy , &vfs_root_ptr->main_lock );
1494
1495    // take the lock protecting Inode Tree in write mode
1496    remote_rwlock_wr_acquire( lock_xp );
1497
1498    // get extended pointer on target inode
1499    error = vfs_lookup( old_root_xp,
1500                        old_path,
1501                        0,
1502                        &inode_xp,
1503                        NULL );
1504    if( error )
1505    {
1506        remote_rwlock_wr_release( lock_xp );
1507        printk("\n[ERROR] in %s : cannot get target inode for <%s>\n",
1508        __FUNCTION__, old_path );
1509        return -1;
1510    }
1511
1512#if( DEBUG_VFS_LINK & 1 )
1513if( DEBUG_VFS_LINK < cycle )
1514printk("\n[%s] thread[%x,%x] get child inode (%x,%x) for <%s>\n",
1515__FUNCTION__, process->pid, this->trdid,
1516GET_CXY(inode_xp), GET_PTR(inode_xp), old_path, cycle );
1517#endif
1518
1519    // get extended pointer on parent inode in new path
1520    error = vfs_lookup( new_root_xp,
1521                        new_path,
1522                        VFS_LOOKUP_PARENT,
1523                        &new_parent_xp,
1524                        new_name );
1525    if( error )
1526    {
1527        remote_rwlock_wr_release( lock_xp );
1528        printk("\n[ERROR] in %s : cannot get parent inode for <%s>\n",
1529        __FUNCTION__, new_path );
1530        return -1;
1531    }
1532
1533#if( DEBUG_VFS_LINK & 1 )
1534if( DEBUG_VFS_LINK < cycle )
1535printk("\n[%s] thread[%x,%x] get parent inode (%x,%x) for <%s>\n",
1536__FUNCTION__, process->pid, this->trdid,
1537GET_CXY(new_parent_xp), GET_PTR(new_parent_xp), new_path );
1538#endif
1539
1540    // get target inode cluster and local pointer
1541    inode_cxy = GET_CXY( inode_xp );
1542    inode_ptr = GET_PTR( inode_xp );
1543
1544    // get target inode type, context, and FS type
1545    inode_type        = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->type ) );
1546    inode_ctx_ptr     = hal_remote_lpt( XPTR( inode_cxy , &inode_ptr->ctx ) );
1547    inode_fs_type     = hal_remote_l32( XPTR( inode_cxy , &inode_ctx_ptr->type ) );
1548
1549    // get new parent inode cluster an local pointer
1550    new_parent_ptr = GET_PTR( new_parent_xp );
1551    new_parent_cxy = GET_CXY( new_parent_xp );
1552
1553    ///////////////////////////////////////////////////////////////////////
1554    if( (inode_type == INODE_TYPE_FILE) || (inode_type == INODE_TYPE_DIR) )
1555    {
1556        // 1. create one new dentry
1557        if( new_parent_cxy == local_cxy ) 
1558        {
1559            error = vfs_dentry_create( inode_fs_type,
1560                                       new_name,
1561                                       &dentry_xp );
1562        }
1563        else
1564        {
1565            rpc_vfs_dentry_create_client( new_parent_cxy,
1566                                          inode_fs_type,
1567                                          new_name,
1568                                          &dentry_xp,
1569                                          &error );
1570        }
1571
1572        if( error )
1573        {
1574            remote_rwlock_wr_release( lock_xp );
1575            printk("\n[ERROR] in %s : cannot create new dentry for <%s>\n",
1576            __FUNCTION__, new_path );
1577            return -1;
1578        }
1579
1580        // get local pointer on dentry
1581        dentry_ptr = GET_PTR( dentry_xp );
1582
1583        // 2. register dentry in target inode
1584        parents_root_xp  = XPTR( inode_cxy      , &inode_ptr->parents );
1585        parents_entry_xp = XPTR( new_parent_cxy , &dentry_ptr->parents );
1586        xlist_add_first( parents_root_xp , parents_entry_xp );
1587        hal_remote_atomic_add( XPTR( inode_cxy , &inode_ptr->links ) , 1 );
1588
1589        // 3. register dentry in parent inode
1590        children_xhtab_xp = XPTR( new_parent_cxy , &new_parent_ptr->children );
1591        children_entry_xp = XPTR( new_parent_cxy , &dentry_ptr->children );
1592        xhtab_insert( children_xhtab_xp , new_name , children_entry_xp );
1593
1594        // 4. update "parent" and "child_xp" fields in dentry
1595        hal_remote_s64( XPTR( new_parent_cxy , &dentry_ptr->child_xp ) , inode_xp );
1596        hal_remote_spt( XPTR( new_parent_cxy , &dentry_ptr->parent ) , new_parent_ptr );
1597
1598#if(DEBUG_VFS_LINK & 1)
1599if( DEBUG_VFS_LINK < cycle )
1600printk("\n[%s] thread[%x,%x] updated Inode Tree / old <%s> / new <%s>\n",
1601__FUNCTION__, process->pid, this->trdid, old_path, new_path );
1602vfs_display( new_parent_xp ); 
1603#endif
1604
1605        // release the lock protecting Inode Tree
1606        remote_rwlock_wr_release( lock_xp );
1607
1608        // 5. update new parent directory mapper in Inode Tree
1609        //    and synchronize the parent directory on IOC device
1610        if (new_parent_cxy == local_cxy)
1611        {
1612            error = vfs_fs_add_dentry( new_parent_ptr,
1613                                       dentry_ptr );
1614        }
1615        else
1616        {
1617            rpc_vfs_fs_add_dentry_client( new_parent_cxy,
1618                                          new_parent_ptr,
1619                                          dentry_ptr,
1620                                          &error );
1621        }
1622        if( error )
1623        {
1624            printk("\n[ERROR] in %s : cannot update new parent directory for <%s>\n",
1625            __FUNCTION__, new_path );
1626            return -1;
1627        }
1628
1629#if(DEBUG_VFS_LINK & 1)
1630if( DEBUG_VFS_LINK < cycle )
1631printk("\n[%s] thread[%x,%x] updated new parent dir (mapper and IOC) / old <%s> / new <%s>\n",
1632__FUNCTION__, process->pid, this->trdid, old_path, new_path );
1633#endif
1634        return 0;
1635    }
1636    else
1637    {
1638        // release the lock protecting Inode Tree
1639        remote_rwlock_wr_release( lock_xp );
1640
1641        printk("\n[ERROR] in %s : unsupported inode type %s\n",
1642        __FUNCTION__ , vfs_inode_type_str( inode_type ) );
1643        return -1;
1644    }
1645
1646}  // end vfs_link()
1647
1648/////////////////////////////////////
1649error_t vfs_unlink( xptr_t   root_xp,
[23]1650                    char   * path )
[1]1651{
[602]1652    error_t           error;
[610]1653    xptr_t            vfs_root_xp;        // extended pointer on VFS root inode
1654    vfs_inode_t     * vfs_root_ptr;       // local_pointer on VFS root inode
1655    cxy_t             vfs_root_cxy;       // VFS root inode cluster identifier
1656    xptr_t            lock_xp;            // extended pointer on lock protecting Inode Tree
1657    xptr_t            parent_xp;          // extended pointer on target inode
1658    cxy_t             parent_cxy;         // target inode cluster identifier       
1659    vfs_inode_t     * parent_ptr;         // target inode local pointer
[602]1660    xptr_t            inode_xp;           // extended pointer on target inode
1661    cxy_t             inode_cxy;          // target inode cluster identifier       
1662    vfs_inode_t     * inode_ptr;          // target inode local pointer
[610]1663    uint32_t          inode_links;        // target inode links count
1664    vfs_inode_type_t  inode_type;         // target inode type
1665    uint32_t          inode_children;     // target inode number of children
1666    xptr_t            dentry_xp;          // extended pointer on dentry to unlink
1667    vfs_dentry_t    * dentry_ptr;         // local pointer on dentry to unlink
[623]1668    vfs_ctx_t       * ctx_ptr;            // local pointer on FS context
1669    vfs_fs_type_t     fs_type;            // File system type
[1]1670
[610]1671    char              name[CONFIG_VFS_MAX_NAME_LENGTH];  // name of link to remove
1672
1673    thread_t  * this    = CURRENT_THREAD;
1674    process_t * process = this->process;
1675
[602]1676#if DEBUG_VFS_UNLINK
1677uint32_t   cycle = (uint32_t)hal_get_cycles();
[610]1678char root_name[CONFIG_VFS_MAX_NAME_LENGTH];
1679vfs_inode_get_name( root_xp , root_name );
[602]1680if( DEBUG_VFS_UNLINK < cycle )
[623]1681printk("\n[%s] thread[%x,%x] : enter for root <%s> / path <%s> / cycle %d\n",
[610]1682__FUNCTION__, process->pid, this->trdid, root_name, path, cycle );
[602]1683#endif
1684
[610]1685    // build extended pointer on lock protecting Inode Tree (in VFS root inode)
1686    vfs_root_xp  = process->vfs_root_xp;
[633]1687    vfs_root_ptr = GET_PTR( vfs_root_xp );
1688    vfs_root_cxy = GET_CXY( vfs_root_xp );
[610]1689    lock_xp      = XPTR( vfs_root_cxy , &vfs_root_ptr->main_lock );
[602]1690
[610]1691    // take the lock protecting Inode Tree
1692    remote_rwlock_wr_acquire( lock_xp );
[602]1693
[610]1694    // get extended pointer on parent inode
1695    error = vfs_lookup( root_xp,
1696                        path,
1697                        VFS_LOOKUP_PARENT,
1698                        &parent_xp,
1699                        name );
1700    if( error ) 
1701    {
1702        remote_rwlock_wr_release( lock_xp );
1703        printk("\n[ERROR] in %s : cannot get parent inode for <%s> in <%s>\n",
1704        __FUNCTION__, name, path );
1705        return -1;
1706    }
1707
1708    // get parent inode cluster and local pointer
1709    parent_cxy = GET_CXY( parent_xp );
1710    parent_ptr = GET_PTR( parent_xp );
1711 
1712#if( DEBUG_VFS_UNLINK & 1 )
1713char parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
1714vfs_inode_get_name( parent_xp , parent_name );
1715if( DEBUG_VFS_UNLINK < cycle )
[623]1716printk("\n[%s] thread[%x,%x] : parent inode <%s> is (%x,%x)\n",
[610]1717__FUNCTION__, process->pid, this->trdid, parent_name, parent_cxy, parent_ptr );
1718#endif
1719
1720    // build extended pointer on parent inode "children" xhtab
1721    xptr_t children_xp = XPTR( parent_cxy , &parent_ptr->children );
1722
[623]1723    // try to get extended pointer on dentry from Inode Tree
[610]1724    dentry_xp = xhtab_lookup( children_xp , name );
1725   
[623]1726    // when dentry not found in Inode Tree, try to get it from inode tree
1727
1728    if( dentry_xp == XPTR_NULL )           // miss target dentry in Inode Tree
[610]1729    {
1730
1731#if( DEBUG_VFS_UNLINK & 1 )
1732if( DEBUG_VFS_UNLINK < cycle )
[623]1733printk("\n[%s] thread[%x,%x] : inode <%s> not found => scan parent mapper\n",
1734__FUNCTION__, process->pid, this->trdid, name );
[610]1735#endif
[623]1736        // get parent inode FS type
1737        ctx_ptr    = hal_remote_lpt( XPTR( parent_cxy , &parent_ptr->ctx ) );
1738        fs_type    = hal_remote_l32( XPTR( parent_cxy , &ctx_ptr->type ) );
[610]1739
[623]1740        // select a cluster for new inode
1741        inode_cxy = cluster_random_select();
1742
1743        // speculatively insert a new child dentry/inode couple in inode tree
1744        error = vfs_add_child_in_parent( inode_cxy,
1745                                         fs_type, 
1746                                         parent_xp, 
1747                                         name, 
1748                                         &dentry_xp,
1749                                         &inode_xp );
1750        if( error )
1751        {
1752            printk("\n[ERROR] in %s : cannot create inode <%s> in path <%s>\n",
1753            __FUNCTION__ , name, path );
1754
1755            vfs_remove_child_from_parent( dentry_xp );
1756            return -1;
1757        }
1758
1759        // get local pointers on new dentry and new inode descriptors
1760        inode_ptr  = GET_PTR( inode_xp );
1761        dentry_ptr = GET_PTR( dentry_xp );
1762
1763        // scan parent mapper to find the missing dentry, and complete
1764        // initialisation of new dentry and new inode descriptors In Inode Tree
1765        if( parent_cxy == local_cxy )
1766        {
1767            error = vfs_fs_new_dentry( parent_ptr,
1768                                       name,
1769                                       inode_xp );
1770        }
1771        else
1772        {
1773            rpc_vfs_fs_new_dentry_client( parent_cxy,
1774                                          parent_ptr,
1775                                          name,
1776                                          inode_xp,
1777                                          &error );
1778        }
1779
1780        if ( error )   // dentry not found in parent mapper
1781        {
1782            printk("\n[ERROR] in %s : cannot get dentry <%s> in path <%s>\n",
1783            __FUNCTION__ , name, path );
1784            return -1;
1785        }
1786
1787#if (DEBUG_VFS_UNLINK & 1)
1788if( DEBUG_VFS_UNLINK < cycle )
1789printk("\n[%s] thread[%x,%x] : created missing inode & dentry <%s> in cluster %x\n",
1790__FUNCTION__, process->pid, this->trdid, name, inode_cxy );
1791#endif
1792
1793    }
1794    else                                  // found target dentry in Inode Tree
1795    {
1796        dentry_ptr = GET_PTR( dentry_xp );
1797       
1798        // get pointer on target inode from dentry
1799        inode_xp  = hal_remote_l64( XPTR( parent_cxy , &dentry_ptr->child_xp ) );
1800        inode_cxy = GET_CXY( inode_xp );
1801        inode_ptr = GET_PTR( inode_xp );
1802    }
1803
1804    // At this point the Inode Tree contains the target dentry and child inode
1805    // we can safely remove this dentry from both the parent mapper, and the Inode Tree.
1806
[610]1807#if( DEBUG_VFS_UNLINK & 1 )
1808if( DEBUG_VFS_UNLINK < cycle )
[623]1809printk("\n[%s] thread[%x,%x] : dentry (%x,%x) / inode (%x,%x)\n",
1810__FUNCTION__, process->pid, this->trdid, parent_cxy, dentry_ptr, inode_cxy, inode_ptr );
[610]1811#endif
[602]1812
[610]1813    // get target inode "type" and "links"
1814    inode_type   = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->type ) );
1815    inode_links  = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->links ) );
[602]1816
[610]1817    ///////////////////////////////////////////////////////////////////////
1818    if( (inode_type == INODE_TYPE_FILE) || (inode_type == INODE_TYPE_DIR) )
[602]1819    {
[623]1820
1821#if( DEBUG_VFS_UNLINK & 1 )
1822if( DEBUG_VFS_UNLINK < cycle )
1823printk("\n[%s] thread[%x,%x] : unlink inode <%s> / type %s / %d links\n",
1824__FUNCTION__, process->pid, this->trdid, name, vfs_inode_type_str(inode_type), inode_links );
1825#endif
1826
[610]1827        // 1. Release clusters allocated to target inode
1828        //    and synchronize the FAT on IOC device if last link.
1829        if( inode_links == 1 ) 
[602]1830        {
[610]1831            // build extended pointer on target inode "children" number
1832            xptr_t inode_children_xp = XPTR( inode_cxy , &inode_ptr->children.items );
[602]1833
[610]1834            // get target inode number of children
1835            inode_children = hal_remote_l32( inode_children_xp );
1836
1837            // check no children
1838            if( inode_children != 0 )
1839            {
1840                remote_rwlock_wr_release( lock_xp );
1841                printk("\n[ERROR] in %s : cannot remove <%s> inode that has children\n",
1842                __FUNCTION__, path );
1843                return -1;
1844            }
1845
1846            // release clusters on IOC device
1847            error = vfs_fs_release_inode( inode_xp ); 
1848
1849            if( error )
1850            {
1851                remote_rwlock_wr_release( lock_xp );
1852                printk("\n[ERROR] in %s : cannot update FAT mapper to remove <%s> inode\n",
1853                __FUNCTION__ , path );
1854                return -1;
1855            }
1856
[602]1857#if(DEBUG_VFS_UNLINK & 1)
1858if( DEBUG_VFS_UNLINK < cycle )
1859printk("\n[%s] thread[%x,%x] removed <%s> inode from FAT (mapper and IOC device)\n",
[610]1860__FUNCTION__, process->pid, this->trdid, path );
[602]1861#endif
[610]1862        }
[602]1863
[610]1864        // 2. update parent directory mapper
1865        //    and synchronize the parent directory on IOC device
1866        if (parent_cxy == local_cxy)
[602]1867        {
[610]1868            error = vfs_fs_remove_dentry( parent_ptr,
[602]1869                                          dentry_ptr );
1870        }
[610]1871        else           
[602]1872        {
[610]1873            rpc_vfs_fs_remove_dentry_client( parent_cxy,
1874                                             parent_ptr,
[602]1875                                             dentry_ptr,
1876                                             &error );
1877        }
[610]1878
[602]1879        if( error )
1880        {
[610]1881            remote_rwlock_wr_release( lock_xp );
1882            printk("\n[ERROR] in %s : cannot update dentry on device for <%s>\n",
1883            __FUNCTION__ , path );
[602]1884            return -1;
1885        }
1886
1887#if(DEBUG_VFS_UNLINK & 1)
1888if( DEBUG_VFS_UNLINK < cycle )
1889printk("\n[%s] thread[%x,%x] removed <%s> inode from parent dir (mapper and IOC device)\n",
[610]1890__FUNCTION__, process->pid, this->trdid, path );
[602]1891#endif
[610]1892        // 3. remove dentry from Inode Tree (and associated chils inode when last link)
1893        vfs_remove_child_from_parent( dentry_xp );
[602]1894
[610]1895        // release the lock protecting Inode Tree
1896        remote_rwlock_wr_release( lock_xp );
1897
[602]1898#if DEBUG_VFS_UNLINK
1899if( DEBUG_VFS_UNLINK < cycle )
1900printk("\n[%s] thread[%x,%x] exit / removed <%s> inode from Inode Tree / cycle %d\n",
[610]1901__FUNCTION__, process->pid, this->trdid, path, cycle );
[602]1902#endif
1903        return 0;
1904    }
1905    else
1906    {
[610]1907        remote_rwlock_wr_release( lock_xp );
1908        printk("\n[ERROR] in %s : unsupported inode type %s\n",
1909        __FUNCTION__ , vfs_inode_type_str( inode_type ) );
[602]1910        return -1;
1911    }
1912
1913}  // end vfs_unlink()
1914
[611]1915////////////////////////////////////////////////
1916error_t vfs_stat( xptr_t         root_inode_xp,
1917                  char         * path,
1918                  struct stat  * st )
[1]1919{
[610]1920    error_t       error;
1921    xptr_t        inode_xp;           // extended pointer on target inode
1922    vfs_inode_t * inode_ptr;          // local pointer on target inode
1923    cxy_t         inode_cxy;          // target inode cluster identifier
1924    xptr_t        vfs_root_xp;        // extended pointer on VFS root inode
1925    vfs_inode_t * vfs_root_ptr;       // local_pointer on VFS root inode
1926    cxy_t         vfs_root_cxy;       // VFS root inode cluster identifier
1927    xptr_t        lock_xp;            // extended pointer on lock protecting Inode Tree
1928
1929    thread_t  * this    = CURRENT_THREAD;
1930    process_t * process = this->process;
1931
1932    // build extended pointer on lock protecting Inode Tree (in VFS root inode)
1933    vfs_root_xp  = process->vfs_root_xp;
1934    vfs_root_ptr = GET_PTR( vfs_root_xp );
1935    vfs_root_cxy = GET_CXY( vfs_root_xp );
1936    lock_xp      = XPTR( vfs_root_cxy , &vfs_root_ptr->main_lock );
1937
1938    // get the lock protecting Inode Tree in read mode
1939    remote_rwlock_rd_acquire( lock_xp );
1940
1941    // get extended pointer on target inode
1942    error = vfs_lookup( root_inode_xp,
1943                        path,
1944                        0,
1945                        &inode_xp,
1946                        NULL );
1947
1948    // release the lock protecting Inode Tree
1949    remote_rwlock_rd_release( lock_xp );
1950
1951    if( error )
1952    {
1953        printk("\n[ERROR] in %s : cannot found inode <%s>\n",
1954        __FUNCTION__ , path );
1955        return -1;
1956    }
1957
[598]1958    // get cluster and local pointer on inode descriptor
[610]1959    inode_ptr = GET_PTR( inode_xp );
1960    inode_cxy = GET_CXY( inode_xp );
[598]1961
1962    // get relevant infos from inode descriptor
1963    uint32_t inum   = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->inum   ) );
1964    uint32_t size   = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->size   ) );
1965    uint32_t uid    = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->uid    ) );
1966    uint32_t gid    = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->gid    ) );
1967    uint32_t type   = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->type   ) );
1968    uint32_t rights = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->rights ) );
1969
1970    // set stat structure fields
1971    st->st_ino  = inum;
1972    st->st_gid  = gid;
1973    st->st_uid  = uid;
1974    st->st_size = size;
1975    st->st_mode = (type << 16) | rights;
1976
1977#if DEBUG_VFS_STAT
1978uint32_t cycle  = (uint32_t)hal_get_cycles();
1979if( DEBUG_VFS_STAT < cycle )
1980printk("\n[%s] thread[%x,%x] set stat %x for inode %x in cluster %x / cycle %d\n"
1981       " %s / inum %d / size %d\n",
[610]1982__FUNCTION__, process->pid, this->trdid, st, inode_ptr, inode_cxy, cycle,
[598]1983vfs_inode_type_str( type ), inum, size );
1984#endif
1985
[1]1986    return 0;
1987
[602]1988}  // end vfs_stat()
1989
[23]1990////////////////////////////////////
[610]1991error_t vfs_chdir( xptr_t   root_xp,
[23]1992                   char   * path )
[1]1993{
[23]1994    error_t           error;
[610]1995    xptr_t            inode_xp;           // extended pointer on target inode
1996    cxy_t             inode_cxy;          // target inode cluster identifier       
1997    vfs_inode_t     * inode_ptr;          // target inode local pointer
1998    vfs_inode_type_t  inode_type;         // target inode type
1999    xptr_t            vfs_root_xp;        // extended pointer on VFS root inode
2000    vfs_inode_t     * vfs_root_ptr;       // local_pointer on VFS root inode
2001    cxy_t             vfs_root_cxy;       // VFS root inode cluster identifier
2002    xptr_t            main_lock_xp;       // extended pointer on lock protecting Inode Tree
2003    xptr_t            ref_xp;             // extended pointer on reference process
2004    process_t       * ref_ptr;            // local pointer on reference process
2005    cxy_t             ref_cxy;            // reference process cluster
2006    xptr_t            cwd_lock_xp;        // extended pointer on lock protecting CWD change
2007    xptr_t            cwd_xp_xp;          // extended pointer on cwd_xp in reference process
[23]2008
[610]2009    thread_t  * this    = CURRENT_THREAD;
2010    process_t * process = this->process;
[23]2011
[610]2012#if DEBUG_VFS_CHDIR
2013uint32_t cycle = (uint32_t)hal_get_cycles();
2014if( DEBUG_VFS_CHDIR < cycle )
2015printk("\n[%s] thread[%x,%x] enter for path <%s> / cycle %d\n",
2016__FUNCTION__, process->pid, this->trdid, path, cycle );
2017#endif
2018
2019    // build extended pointer on lock protecting Inode Tree (in VFS root inode)
2020    vfs_root_xp  = process->vfs_root_xp;
2021    vfs_root_ptr = GET_PTR( vfs_root_xp );
2022    vfs_root_cxy = GET_CXY( vfs_root_xp );
2023    main_lock_xp = XPTR( vfs_root_cxy , &vfs_root_ptr->main_lock );
2024
2025    // take lock protecting Inode Tree in read mode
2026    remote_rwlock_rd_acquire( main_lock_xp );
2027
[23]2028    // get extended pointer on target inode
[610]2029    error = vfs_lookup( root_xp,
2030                        path,
2031                        VFS_LOOKUP_DIR,
2032                        &inode_xp,
2033                        NULL );
[23]2034
[610]2035    // release lock protecting Inode Tree in read mode
2036    remote_rwlock_rd_release( main_lock_xp );
[23]2037
[610]2038    if( error ) 
2039    {
2040        printk("\n[ERROR] in %s : <%s> not found\n",
2041        __FUNCTION__, path );
2042        return -1;
2043    }
2044
2045    // get inode type from remote file
[23]2046    inode_cxy = GET_CXY( inode_xp );
[473]2047    inode_ptr = GET_PTR( inode_xp );
[568]2048    inode_type = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->type ) );
[23]2049
2050    if( inode_type != INODE_TYPE_DIR )
2051    {
[610]2052        printk("\n[ERROR] in %s : <%s> is not a directory\n",
2053        __FUNCTION__, path );
[23]2054        return -1;
2055    }
2056
[610]2057    // build extended pointer on cwd_lock and cwd_xp
2058    ref_xp       = process->ref_xp;
2059    ref_ptr      = GET_PTR( ref_xp );
2060    ref_cxy      = GET_CXY( ref_xp );
2061    cwd_lock_xp  = XPTR( ref_cxy , &ref_ptr->cwd_lock );
2062    cwd_xp_xp    = XPTR( ref_cxy , &ref_ptr->cwd_xp );
[568]2063
[610]2064    // take lock protecting CWD changes
2065    remote_busylock_acquire( cwd_lock_xp );
[568]2066
[610]2067    // update cwd_xp field in reference process descriptor
2068    hal_remote_s64( cwd_xp_xp , inode_xp );
2069
2070    // release lock protecting CWD changes
2071    remote_busylock_release( cwd_lock_xp );
2072
2073#if DEBUG_VFS_CHDIR
2074cycle = (uint32_t)hal_get_cycles();
2075if( DEBUG_VFS_CHDIR < cycle )
2076printk("\n[%s] thread[%x,%x] exit : inode (%x,%x) / &cwd_xp (%x,%x) / cycle %d\n",
2077__FUNCTION__, process->pid, this->trdid, inode_cxy, inode_ptr, 
2078GET_CXY(cwd_xp_xp), GET_PTR(cwd_xp_xp), cycle );
2079#endif
2080
[1]2081    return 0;
2082
[610]2083}  // end vfs_chdir()
2084
[23]2085///////////////////////////////////
2086error_t vfs_chmod( xptr_t   cwd_xp,
2087                   char   * path,
2088                   uint32_t rights )
[1]2089{
[23]2090    error_t           error;
2091    xptr_t            inode_xp;     // extended pointer on target inode
2092    cxy_t             inode_cxy;    // inode cluster identifier       
2093    vfs_inode_t     * inode_ptr;    // inode local pointer
2094
[625]2095// check lookup working mode
2096assert( (rights == 0), "access rights non implemented yet" );
[23]2097 
2098    // get extended pointer on target inode
[610]2099    error = vfs_lookup( cwd_xp,
2100                        path,
2101                        0,
2102                        &inode_xp,
2103                        NULL );
[23]2104
2105    if( error ) return error;
2106
2107    // get inode cluster and local pointer
2108    inode_cxy = GET_CXY( inode_xp );
[473]2109    inode_ptr = GET_PTR( inode_xp );
[23]2110   
2111    // get inode type from remote inode
[633]2112    // inode_type = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->type ) );
[23]2113
[633]2114    // TODO finalize implementation
[610]2115
[625]2116assert( false , "not implemented" );
[610]2117
[633]2118    // set inode rights in remote inode
2119    hal_remote_s32( XPTR( inode_cxy , &inode_ptr->rights ) , rights );
2120
[1]2121    return 0;
2122}
2123
[23]2124///////////////////////////////////
2125error_t vfs_mkfifo( xptr_t   cwd_xp,
2126                    char   * path,
2127                    uint32_t rights )
2128{
[625]2129    assert( false , "not implemented %l %x %x", cwd_xp, path, rights );
[23]2130    return 0;
2131}
[1]2132
2133
2134
[188]2135//////////////////////////////////////////////////////////////////////////////////////////
[602]2136//       Distributed Inode Tree access related functions
[1]2137//////////////////////////////////////////////////////////////////////////////////////////
2138
[188]2139//////////////////////////////////////////////////////////////////////////
2140// This static function is called by the vfs_display() function.
[337]2141// that is supposed to take the TXT0 lock.
[188]2142//////////////////////////////////////////////////////////////////////////
2143static void vfs_recursive_display( xptr_t   inode_xp,
2144                                   xptr_t   name_xp,
2145                                   uint32_t indent )
2146{
2147    cxy_t              inode_cxy;
2148    vfs_inode_t      * inode_ptr;
2149    vfs_inode_type_t   inode_type;
[598]2150    uint32_t           inode_size;
2151    uint32_t           inode_attr;
2152    uint32_t           inode_dirty;
[625]2153    void             * inode_extd;
2154
[204]2155    xptr_t             children_xp;    // extended pointer on children xhtab
[188]2156
[204]2157    xptr_t             child_dentry_xp;
2158    cxy_t              child_dentry_cxy;
2159    vfs_dentry_t     * child_dentry_ptr;
2160    xptr_t             child_inode_xp;
2161    xptr_t             child_dentry_name_xp;
[598]2162    mapper_t         * mapper_ptr;
[188]2163
2164    char               name[CONFIG_VFS_MAX_NAME_LENGTH];
2165
2166    char *             indent_str[] = { "",                                  // level 0
2167                                        "  ",                                // level 1
2168                                        "    ",                              // level 2
2169                                        "      ",                            // level 3
2170                                        "        ",                          // level 4
2171                                        "          ",                        // level 5
2172                                        "            ",                      // level 6
2173                                        "              ",                    // level 7
2174                                        "                ",                  // level 8
2175                                        "                  ",                // level 9
2176                                        "                    ",              // level 10
2177                                        "                      ",            // level 11
2178                                        "                        ",          // level 12
2179                                        "                          ",        // level 13
2180                                        "                            ",      // level 14
2181                                        "                              " };  // level 15
2182
[625]2183assert( (inode_xp != XPTR_NULL) , "inode_xp cannot be NULL" );
2184assert( (name_xp  != XPTR_NULL) , "name_xp cannot be NULL" );
2185assert( (indent < 16)           , "depth cannot be larger than 15" );
[188]2186   
[610]2187    // get current inode cluster and local pointer
[188]2188    inode_cxy = GET_CXY( inode_xp );
[473]2189    inode_ptr = GET_PTR( inode_xp );
[188]2190
[598]2191    // get inode type, size, attr, mapper, and inum
2192    inode_type = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->type   ) );
2193    inode_size = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->size   ) );
2194    inode_attr = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->attr   ) );
[625]2195    inode_extd = hal_remote_lpt( XPTR( inode_cxy , &inode_ptr->extend ) );
[598]2196    mapper_ptr = hal_remote_lpt( XPTR( inode_cxy , &inode_ptr->mapper ) );
[188]2197
2198    // make a local copy of node name
2199    hal_remote_strcpy( XPTR( local_cxy , name ) , name_xp );
2200
[598]2201    // compute dirty
2202    inode_dirty = ((inode_attr & INODE_ATTR_DIRTY) != 0);
2203
[188]2204    // display inode
[626]2205    nolock_printk("%s<%s> : %s / extd %x / %d bytes / dirty %d / cxy %x / inode %x / mapper %x\n",
[625]2206    indent_str[indent], name, vfs_inode_type_str( inode_type ), (uint32_t)inode_extd,
2207    inode_size, inode_dirty, inode_cxy, inode_ptr, mapper_ptr );
[188]2208
[611]2209    // scan directory entries when current inode is a directory
2210    // don't scan the the "." and ".." directories to break loops
2211    if( (inode_type == INODE_TYPE_DIR) && 
2212        (strcmp( name , "." ) != 0)    &&
2213        (strcmp( name , ".." ) != 0) )
[188]2214    {
2215        // get extended pointer on directory entries xhtab
[204]2216        children_xp =  XPTR( inode_cxy , &inode_ptr->children );
[188]2217
2218        // get xhtab lock
[568]2219        xhtab_lock( children_xp );
[188]2220
2221        // get first dentry from xhtab
[204]2222        child_dentry_xp = xhtab_get_first( children_xp );
[188]2223
[204]2224        while( child_dentry_xp != XPTR_NULL )
[188]2225        {
2226            // get dentry cluster and local pointer
[204]2227            child_dentry_cxy = GET_CXY( child_dentry_xp );
[473]2228            child_dentry_ptr = GET_PTR( child_dentry_xp );
[188]2229
2230            // get extended pointer on child inode
[568]2231            child_inode_xp = hal_remote_l64( XPTR( child_dentry_cxy,
[204]2232                                                   &child_dentry_ptr->child_xp ) );
[188]2233
2234            // get extended pointer on dentry name
[204]2235            child_dentry_name_xp = XPTR( child_dentry_cxy , &child_dentry_ptr->name );
[188]2236
[568]2237            // recursive call on inode display
[204]2238            vfs_recursive_display( child_inode_xp,
2239                                   child_dentry_name_xp,
2240                                   indent+1 );
[188]2241
2242            // get next dentry
[204]2243            child_dentry_xp = xhtab_get_next( children_xp );
[188]2244        }
2245
2246        // release xhtab lock
[568]2247        xhtab_unlock( children_xp );
[188]2248    }
2249}  // end vfs_recursive_display()
2250
2251///////////////////////////////////
2252void vfs_display( xptr_t inode_xp )
2253{
[204]2254    xptr_t         name_xp;
[188]2255    xptr_t         dentry_xp; 
2256    cxy_t          dentry_cxy;
2257    vfs_dentry_t * dentry_ptr;
[610]2258    xptr_t         parents_root_xp;   // root of parent dentries xlist
[188]2259
2260    // get target inode cluster and local pointer
2261    cxy_t         inode_cxy = GET_CXY( inode_xp );
[473]2262    vfs_inode_t * inode_ptr = GET_PTR( inode_xp );
[188]2263
[610]2264    // build extended pointer on parents dentries root
2265    parents_root_xp = XPTR( inode_cxy , &inode_ptr->parents );
[188]2266
[610]2267    // check VFS root     
2268    if( xlist_is_empty( parents_root_xp ) )  // inode is the VFS root
[188]2269    {
2270        // build extended pointer on root name
2271        name_xp = XPTR( local_cxy , "/" );
2272    }
2273    else
2274    {
[610]2275        // get first parent dentry cluster and pointers
2276        dentry_xp  = XLIST_FIRST( parents_root_xp , vfs_dentry_t , parents );
[188]2277        dentry_cxy = GET_CXY( dentry_xp );
[473]2278        dentry_ptr = GET_PTR( dentry_xp );
[188]2279
2280        // get extended pointer on dentry name
2281        name_xp = XPTR( dentry_cxy , &dentry_ptr->name );
2282    }
2283
[337]2284    // get pointers on TXT0 chdev
[407]2285    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
[337]2286    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
2287    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
2288
2289    // get extended pointer on remote TXT0 chdev lock
2290    xptr_t  lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
2291
2292    // get TXT0 lock in busy waiting mode
[568]2293    remote_busylock_acquire( lock_xp );
[337]2294
[188]2295    // print header
[401]2296    nolock_printk("\n***** file system state\n\n");
[188]2297
2298    // call recursive function
[473]2299    vfs_recursive_display( inode_xp , name_xp , 0 );
[188]2300
[337]2301    // release lock
[568]2302    remote_busylock_release( lock_xp );
[337]2303
[204]2304}  // end vfs_display()
[188]2305
[602]2306/*
[1]2307//////////////////////////////////////////////////////////////////////////////////////////
[602]2308// This static function is used by the vfs_lookup() function.
[1]2309// It takes an extended pointer on a remote inode (parent directory inode),
2310// and check access_rights violation for the calling thread.
2311// It can be used by any thread running in any cluster.
2312//////////////////////////////////////////////////////////////////////////////////////////
2313// @ inode_xp    : extended pointer on inode.
2314// @ client_uid  : client thread user ID
2315// @ client_gid  : client thread group ID
2316// @ return true if access rights are violated.
2317//////////////////////////////////////////////////////////////////////////////////////////
[602]2318static bool_t vfs_access_denied( xptr_t   inode_xp,
[1]2319                          uint32_t client_uid,
2320                          uint32_t client_gid )
2321{
2322    // get found inode cluster and local pointer
2323    cxy_t         inode_cxy = GET_CXY( inode_xp );
[473]2324    vfs_inode_t * inode_ptr = GET_PTR( inode_xp );
[1]2325
2326    // get inode access mode, UID, and GID
[568]2327    // TODO uint32_t  mode = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->mode ) );
2328    uid_t     uid  = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->uid  ) );
2329    gid_t     gid  = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->gid  ) );
[1]2330
[634]2331    // TODO : me must use mode
[1]2332    if( (uid == client_uid) || (gid == client_gid) ) return false;
2333    else                                             return true;
2334}
[602]2335*/
[1]2336
2337//////////////////////////////////////////////////////////////////////////////////////////
2338// This static function is used by the vfs_lookup() function.
[204]2339// It takes an extended pointer on a remote parent directory inode, a directory
[626]2340// entry name, and and scan the XHTAB associated to the parent inode to find the
2341// searched dentry. It does NOT modify the inode tree in case of miss.
[1]2342// It can be used by any thread running in any cluster.
2343//////////////////////////////////////////////////////////////////////////////////////////
2344// @ parent_xp   : extended pointer on parent inode in remote cluster.
2345// @ name        : dentry name
2346// @ child_xp    : [out] buffer for extended pointer on child inode.
2347// @ return true if success / return false if not found.
2348//////////////////////////////////////////////////////////////////////////////////////////
2349static bool_t vfs_get_child( xptr_t   parent_xp,
2350                             char   * name,
2351                             xptr_t * child_xp )
2352{
[610]2353    xptr_t         xhtab_xp;    // extended pointer on hash table for children dentries
2354    xptr_t         dentry_xp;   // extended pointer on children dentry
2355    cxy_t          dentry_cxy;
2356    vfs_dentry_t * dentry_ptr;
[1]2357
2358    // get parent inode cluster and local pointer
2359    cxy_t         parent_cxy = GET_CXY( parent_xp );
[473]2360    vfs_inode_t * parent_ptr = GET_PTR( parent_xp );
[1]2361
2362    // get extended pointer on hash table of children directory entries
2363    xhtab_xp = XPTR( parent_cxy , &parent_ptr->children );
2364
[610]2365    // get pointers on matching dentry
2366    dentry_xp  = xhtab_lookup( xhtab_xp , name );
2367    dentry_cxy = GET_CXY( dentry_xp );
2368    dentry_ptr = GET_PTR( dentry_xp );
[1]2369
[610]2370    if( dentry_xp == XPTR_NULL ) 
2371    {
2372        return false;
2373    }
2374    else
2375    {
2376        *child_xp = (xptr_t)hal_remote_l64( XPTR( dentry_cxy , &dentry_ptr->child_xp ) );
2377        return true;
2378    }
[1]2379
[204]2380}  // end vfs_get_child()
2381
[1]2382//////////////////////////////////////////////////////////////////////////////////////////
2383// This static function is used by the vfs_lookup() function.
2384// It takes the <current> pointer on a buffer containing a complete pathname, and return
2385// in the <name> buffer, allocated by the caller, a single name in the path.
2386// It return also in the <next> pointer the next character to analyse in the path.
2387// Finally it returns a <last> boolean, that is true when the returned <name> is the
2388// last name in the path. The names are supposed to be separated by one or several '/'
2389// characters, that are not written in  the <name> buffer.
[610]2390//
2391// WARNING: the leading characters '/' in the path are skiped before analysis.
2392//          The path "/" identifies the VFS root, and is therefore anaysed as an empty
2393//          string. This empty string is dignaled by the (-1) return value. 
[1]2394//////////////////////////////////////////////////////////////////////////////////////////
2395// @ current   : pointer on first character to analyse in buffer containing the path.
2396// @ name      : [out] pointer on buffer allocated by the caller for the returned name.
2397// @ next      : [out] pointer on next character to analyse in buffer containing the path.
2398// @ last      : [out] true if the returned name is the last (NUL character found).
[610]2399// @ return 0 if success / return -1 if string empty (first chracter is NUL).
[1]2400//////////////////////////////////////////////////////////////////////////////////////////
2401static error_t vfs_get_name_from_path( char     * current,
2402                                       char     * name,
2403                                       char    ** next,
2404                                       bool_t   * last )
2405{
2406    char * ptr = current;
2407
2408    // skip leading '/' characters
2409    while( *ptr == '/' ) ptr++;
2410
[610]2411    // signal empty string
2412    if( *ptr == 0 )
2413    {
2414        *last = true;
2415        return -1;
2416    }
[1]2417
2418    // copy all characters in name until NUL or '/'
2419    while( (*ptr != 0) && (*ptr !='/') )  *(name++) = *(ptr++);
2420
[204]2421    // set NUL terminating character in name buffer
2422    *(name++) = 0;
2423
[1]2424    // return last an next
2425    if( *ptr == 0 )             // last found character is NUL => last name in path
2426    {
2427        *last = true;
2428    }
2429    else                        // last found character is '/' => skip it
2430    {
2431        *last = false;
2432        *next = ptr + 1;
2433    }
2434
2435    return 0;
[204]2436
2437}  // end vfs_get name_from_path()
[188]2438   
[610]2439///////////////////////////////////////////////
2440error_t vfs_lookup( xptr_t             root_xp,
[23]2441                    char             * pathname,
[610]2442                    uint32_t           lookup_mode,
2443                                        xptr_t           * inode_xp,
2444                                        char             * last_name )
[1]2445{
[101]2446    char               name[CONFIG_VFS_MAX_NAME_LENGTH];   // one name in path
[1]2447
[23]2448    xptr_t             parent_xp;    // extended pointer on parent inode
2449    cxy_t              parent_cxy;   // cluster for parent inode
2450    vfs_inode_t      * parent_ptr;   // local pointer on parent inode 
[602]2451    xptr_t             dentry_xp;    // extended pointer on dentry       
[23]2452    xptr_t             child_xp;     // extended pointer on child inode
2453    cxy_t              child_cxy;    // cluster for child inode
[602]2454    vfs_inode_t      * child_ptr;    // local pointer on child inode
[23]2455    vfs_fs_type_t      fs_type;      // File system type
2456    vfs_ctx_t        * ctx_ptr;      // local pointer on FS context
2457    char             * current;      // current pointer on path
2458    char             * next;         // next value for current pointer   
2459    bool_t             last;         // true when the name is the last in path
2460    bool_t             found;        // true when a child has been found
[459]2461    bool_t             create;       // searched inode must be created if not found
2462    bool_t             excl;         // searched inode must not exist
[626]2463    bool_t             parent;       // searched inode is the parent
[23]2464    thread_t         * this;         // pointer on calling thread descriptor
2465    process_t        * process;      // pointer on calling process descriptor
2466    error_t            error;
[1]2467
2468    this    = CURRENT_THREAD;
2469    process = this->process;
2470
[610]2471// check pathname / root_xp consistency
2472assert( ((pathname[0] != '/') || (root_xp == process->vfs_root_xp)), 
[625]2473"root inode must be VFS root for path <%s>", pathname );
[610]2474
[438]2475#if DEBUG_VFS_LOOKUP
[433]2476uint32_t cycle = (uint32_t)hal_get_cycles();
[610]2477char     root_name[CONFIG_VFS_MAX_NAME_LENGTH];
2478vfs_inode_get_name( root_xp , root_name );
[438]2479if( DEBUG_VFS_LOOKUP < cycle )
[610]2480printk("\n[%s] thread[%x,%x] enter / root <%s> / path <%s> / mode %x / cycle %d\n",
2481__FUNCTION__, process->pid, this->trdid, root_name, pathname, lookup_mode, cycle );
[433]2482#endif
[380]2483
[459]2484    // compute lookup flags
[610]2485    create = (lookup_mode & VFS_LOOKUP_CREATE) == VFS_LOOKUP_CREATE;
2486    excl   = (lookup_mode & VFS_LOOKUP_EXCL)   == VFS_LOOKUP_EXCL;
[626]2487    parent = (lookup_mode & VFS_LOOKUP_PARENT) == VFS_LOOKUP_PARENT;
[1]2488
[610]2489    // initialise loop variables
2490    parent_xp = root_xp;
2491    current   = pathname;
2492    next      = NULL;
2493    last      = false;
2494    child_xp  = XPTR_NULL;
[1]2495
[610]2496    // loop on nodes in pathname
2497    // load from device if one node in path not found in Inode Tree
[401]2498    // exit loop when last name found (i.e. last == true)
[610]2499    while( 1 )
[1]2500    {
[610]2501        // get parent inode cluster and local pointer
2502        parent_cxy = GET_CXY( parent_xp );
2503        parent_ptr = GET_PTR( parent_xp );
[1]2504
[610]2505        // get one "name" from path, and "last" flag
2506        error = vfs_get_name_from_path( current , name , &next , &last );
2507
[611]2508        // handle VFS root case
[610]2509        if ( error )
2510        {
2511
2512#if DEBUG_VFS_LOOKUP
2513cycle = (uint32_t)hal_get_cycles();
2514if( DEBUG_VFS_LOOKUP < cycle )
2515printk("\n[%s] thread[%x,%x] exit / parent inode(%x,%x) / <%s> / cycle %d\n",
2516__FUNCTION__ , process->pid, this->trdid, parent_cxy, parent_ptr, pathname, cycle );
2517#endif
2518            *inode_xp = process->vfs_root_xp;
2519            break;
2520        }
2521
[438]2522#if (DEBUG_VFS_LOOKUP & 1)
2523if( DEBUG_VFS_LOOKUP < cycle )
[628]2524printk("\n[%s] thread[%x,%x] search <%s> in <%s> / last = %d\n",
[602]2525__FUNCTION__, process->pid, this->trdid, name, pathname, last );
[433]2526#endif
[101]2527
[610]2528        // search the child dentry matching name in parent inode
[1]2529        found = vfs_get_child( parent_xp,
2530                               name,
2531                               &child_xp );
2532
[611]2533        // get child inode local pointer and cluster
2534        child_ptr  = GET_PTR( child_xp );
2535        child_cxy  = GET_CXY( child_xp );
2536
[610]2537        if( found == false )                              // not found in Inode Tree
[1]2538        {
[610]2539            // when a inode is not found in the Inode Tree:
[626]2540            // - if (last and parent) the Inode Tree is not modified
[610]2541            // - else we speculatively introduce a new (dentry/inode) in inode tree,
2542            //        and scan the parent directory mapper to initialise it.
2543            //     . if it is not found in the parent mapper:
2544            //         - if(last and create), a brand new file or directory is created
2545            //         - else, an error is reported
2546            //     . if it is found in parent mapper:
2547            //         - if( last and excl ), an error is reported
2548            //         - else the new child (inode & dentry) is initialised in Inode Tree
2549            //         - if the child is a directory, the child mapper is loaded from device
[101]2550
[626]2551            if( last && parent )   //  does nothing
[610]2552            {
2553
[438]2554#if (DEBUG_VFS_LOOKUP & 1)
2555if( DEBUG_VFS_LOOKUP < cycle )
[610]2556printk("\n[%s] thread[%x,%x] child not found but only parent requested in <%s>\n",
2557__FUNCTION__, process->pid, this->trdid, pathname );
2558#endif
2559            }
2560            else                                    // try to get it from parent mapper
2561            {
2562
2563#if (DEBUG_VFS_LOOKUP & 1)
2564if( DEBUG_VFS_LOOKUP < cycle )
2565printk("\n[%s] thread[%x,%x] miss <%s> inode in Inode Tree => build from parent mapper\n",
[602]2566__FUNCTION__, process->pid, this->trdid, name );
[433]2567#endif
[610]2568                // get parent inode FS type
2569                ctx_ptr    = hal_remote_lpt( XPTR( parent_cxy,&parent_ptr->ctx ) );
2570                fs_type    = hal_remote_l32( XPTR( parent_cxy , &ctx_ptr->type ) );
[407]2571
[610]2572                // select a cluster for new inode
2573                child_cxy = cluster_random_select();
[602]2574
[611]2575                // insert a new child dentry/inode couple in inode tree
[610]2576                error = vfs_add_child_in_parent( child_cxy,
2577                                                 fs_type, 
2578                                                 parent_xp, 
2579                                                 name, 
2580                                                 &dentry_xp,
2581                                                 &child_xp );
2582                if( error )
2583                {
2584                    printk("\n[ERROR] in %s : cannot create inode <%s> in path <%s>\n",
2585                    __FUNCTION__ , name, pathname );
2586                    return -1;
2587                }
[238]2588
[610]2589                // get child inode local pointer
2590                child_ptr = GET_PTR( child_xp );
[459]2591
2592#if (DEBUG_VFS_LOOKUP & 1)
2593if( DEBUG_VFS_LOOKUP < cycle )
[629]2594printk("\n[%s] thread[%x,%x] created missing inode for <%s> in cluster %x\n",
[602]2595__FUNCTION__, process->pid, this->trdid, name, child_cxy );
[459]2596#endif
[610]2597                // scan parent mapper to find the missing dentry, and complete
[611]2598                // the initialisation of dentry and child inode descriptors
[610]2599                if( parent_cxy == local_cxy )
2600                {
[623]2601                    error = vfs_fs_new_dentry( parent_ptr,
[610]2602                                               name,
2603                                               child_xp );
2604                }
2605                else
2606                {
[623]2607                    rpc_vfs_fs_new_dentry_client( parent_cxy,
[610]2608                                                  parent_ptr,
2609                                                  name,
2610                                                  child_xp,
2611                                                  &error );
2612                }
[238]2613
[626]2614                // when the missing dentry is not in the parent mapper,
[629]2615                // a new dentry must be registered in parent directory mapper
[626]2616                if ( error )
[459]2617                {
[625]2618                    if ( last && create )  // add a brand new dentry in parent directory
[602]2619                    {
[612]2620                        error = vfs_new_dentry_init( parent_xp,               
2621                                                     dentry_xp,
2622                                                     child_xp );
[610]2623                        if ( error )
2624                        {
2625                            printk("\n[ERROR] in %s : cannot init inode <%s> in path <%s>\n",
2626                            __FUNCTION__, name, pathname );
2627                            vfs_remove_child_from_parent( dentry_xp );
2628                            return -1;
2629                        }
[1]2630
[459]2631#if (DEBUG_VFS_LOOKUP & 1)
2632if( DEBUG_VFS_LOOKUP < cycle )
[626]2633printk("\n[%s] thread[%x,%x] child <%s> not found in parent mapper => created it\n",
[602]2634__FUNCTION__, process->pid, this->trdid, name );
[626]2635vfs_inode_display( child_xp );
[459]2636#endif
[626]2637
2638
[610]2639                    }
2640                    else                   // not last or not create => error
2641                    {                       
2642                        printk("\n[ERROR] in %s : <%s> node not found in parent for <%s>\n",
2643                        __FUNCTION__ , name , pathname );
2644                        vfs_remove_child_from_parent( dentry_xp );
2645                        return -1;
2646                    }
[238]2647                }
[610]2648                else          // child has been found in parent mapper
[459]2649                {
[610]2650                    // check the excl
2651                    if( last && create && excl )
[459]2652                    {
[610]2653                        printk("\n[ERROR] in %s : node already exist <%s>\n",
2654                        __FUNCTION__, name );
2655                       return -1;
[459]2656                    }
[610]2657
2658#if (DEBUG_VFS_LOOKUP & 1)
2659if( DEBUG_VFS_LOOKUP < cycle )
2660printk("\n[%s] thread[%x,%x] initialised inode <%s> from parent mapper\n",
2661__FUNCTION__, process->pid, this->trdid, name );
2662#endif
2663                    // load child mapper from device if child is a directory (prefetch)
2664                    uint32_t type = hal_remote_l32( XPTR( child_cxy , &child_ptr->type ) );
2665                    if( type == INODE_TYPE_DIR ) 
[459]2666                    {
[610]2667                        if( child_cxy == local_cxy )
2668                        {
2669                            error = vfs_inode_load_all_pages( child_ptr );
2670                        }
2671                        else
2672                        {
2673                            rpc_vfs_inode_load_all_pages_client( child_cxy,
2674                                                                 child_ptr,
2675                                                                 &error );
2676                        }
2677                        if ( error )
2678                        {
2679                            printk("\n[ERROR] in %s : cannot load <%s> from device\n",
2680                            __FUNCTION__ , name );
2681                            vfs_remove_child_from_parent( dentry_xp );
2682                            return -1;
2683                        }
[238]2684
[438]2685#if (DEBUG_VFS_LOOKUP & 1)
2686if( DEBUG_VFS_LOOKUP < cycle )
[610]2687printk("\n[%s] thread[%x,%x] loaded directory mapper for <%s> from IOC\n",
2688__FUNCTION__ , process->pid, this->trdid, name );
[433]2689#endif
[610]2690                    }
[459]2691                }
2692            }
[1]2693        }
[610]2694        else                                    // child directly found in inode tree
[459]2695        {
2696       
[438]2697#if (DEBUG_VFS_LOOKUP & 1)
2698if( DEBUG_VFS_LOOKUP < cycle )
[610]2699printk("\n[%s] thread[%x,%x] found <%s> in Inode Tree / inode (%x,%x)\n",
[611]2700__FUNCTION__, process->pid, this->trdid, name, child_cxy, child_ptr );
[433]2701#endif
[610]2702            // check the excl flag
2703            if( last && create && excl )
[459]2704            {
[610]2705                printk("\n[ERROR] in %s : node <%s> already exist\n",
2706                __FUNCTION__, name );
2707                return -1;
[459]2708            }
2709        }
2710
[380]2711        // TODO check access rights here [AG]
[23]2712        // error = vfs_access_denied( child_xp,
2713        //                            client_uid,
2714        //                            client_gid );
2715        // if( error )
2716        // {
[441]2717        //     printk("\n[ERROR] in %s : thread %x / permission denied for %s\n",
2718        //     __FUNCTION__ , this , name );
[23]2719        //     return EACCES;
2720        // }
[1]2721
[238]2722        // take lock on child inode and release lock on parent
[610]2723        // vfs_inode_lock( child_xp );
2724        // vfs_inode_unlock( parent_xp );
[1]2725
[610]2726        // exit when last
2727        if ( last )           // last inode in path  => return relevant info
2728        {
[626]2729            if ( parent )  // return parent inode and child name
[610]2730            {
[1]2731
[610]2732#if DEBUG_VFS_LOOKUP
2733cycle = (uint32_t)hal_get_cycles();
2734if( DEBUG_VFS_LOOKUP < cycle )
2735printk("\n[%s] thread[%x,%x] exit / parent inode(%x,%x) / <%s> / cycle %d\n",
2736__FUNCTION__ , process->pid, this->trdid, parent_cxy, parent_ptr, pathname, cycle );
2737#endif
2738                *inode_xp = parent_xp;
2739                strcpy( last_name , name );
2740                break; 
2741            }
2742            else        // return child inode name     
2743            {
[1]2744
[438]2745#if DEBUG_VFS_LOOKUP
[433]2746cycle = (uint32_t)hal_get_cycles();
[438]2747if( DEBUG_VFS_LOOKUP < cycle )
[610]2748printk("\n[%s] thread[%x,%x] exit / child inode (%x,%x) / <%s> / cycle %d\n",
2749__FUNCTION__ , process->pid, this->trdid, child_cxy, child_ptr, pathname, cycle );
[433]2750#endif
[610]2751                *inode_xp = child_xp;
2752                break;
2753            }
2754        }
2755        else                     // not the last inode in path => update loop variables
2756        {
2757            parent_xp = child_xp;
2758            current   = next;
2759        }
2760    }
[1]2761
2762    return 0;
2763
2764}  // end vfs_lookup()
2765
[612]2766////////////////////////////////////////////////
2767error_t vfs_new_dentry_init( xptr_t   parent_xp,
2768                             xptr_t   dentry_xp,
2769                             xptr_t   child_xp )
[602]2770{
2771    error_t     error;
2772    uint32_t    cluster;
2773    uint32_t    child_type;
2774    uint32_t    child_size;
2775
[625]2776#if DEBUG_VFS_NEW_DENTRY_INIT
[602]2777char parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
2778char child_name[CONFIG_VFS_MAX_NAME_LENGTH];
2779vfs_inode_get_name( parent_xp , parent_name );
2780vfs_inode_get_name( child_xp  , child_name );
2781uint32_t   cycle = (uint32_t)hal_get_cycles();
2782thread_t * this  = CURRENT_THREAD;
[625]2783if( DEBUG_VFS_NEW_DENTRY_INIT < cycle )
[602]2784printk("\n[%s] thread[%x,%x] enter / parent <%s> / child <%s> / cycle %d\n",
2785__FUNCTION__ , this->process->pid, this->trdid, parent_name, child_name, cycle );
2786#endif
2787
2788    // get parent inode cluster and local pointer
2789    cxy_t          parent_cxy = GET_CXY( parent_xp );
2790    vfs_inode_t  * parent_ptr = GET_PTR( parent_xp );
2791
2792    // get dentry local pointer
2793    vfs_dentry_t * dentry_ptr = GET_PTR( dentry_xp );
2794
2795    // get child inode cluster and local pointer
2796    cxy_t          child_cxy  = GET_CXY( child_xp );
2797    vfs_inode_t  * child_ptr  = GET_PTR( child_xp );
2798
[626]2799    // 1. allocate one free cluster in file system to child inode,
[629]2800    // and update the File Allocation Table in both the FAT mapper and IOC device.
[626]2801    // It depends on the child inode FS type.
[602]2802    vfs_ctx_t * ctx = hal_remote_lpt( XPTR( child_cxy , &child_ptr->ctx ) );
2803
2804    error = vfs_fs_cluster_alloc( ctx->type,
2805                                  &cluster );
2806    if ( error )
2807    {
2808        printk("\n[ERROR] in %s : cannot find a free VFS cluster\n",
2809        __FUNCTION__ );
2810        return -1;
2811    }
2812
[625]2813#if( DEBUG_VFS_NEW_DENTRY_INIT & 1)
2814if( DEBUG_VFS_NEW_DENTRY_INIT < cycle )
[626]2815printk("\n[%s] thread[%x,%x] allocated FS cluster %x to <%s>\n",
[625]2816__FUNCTION__ , this->process->pid, this->trdid, cluster, child_name );
[602]2817#endif
2818
[626]2819    // 2. update the child inode descriptor size and extend
[602]2820    child_type = hal_remote_l32( XPTR( child_cxy , &child_ptr->type ) );
2821    child_size = (child_type == INODE_TYPE_DIR) ? 4096 : 0;
2822   
2823    hal_remote_s32( XPTR( child_cxy , &child_ptr->size )   , child_size );
2824    hal_remote_spt( XPTR( child_cxy , &child_ptr->extend ) , (void*)(intptr_t)cluster );
2825
2826    // 3. update the parent inode mapper, and
2827    // update the dentry extension if required
2828    if( local_cxy == parent_cxy )
2829    {
2830        error = vfs_fs_add_dentry( parent_ptr,
2831                                   dentry_ptr );
2832    }
2833    else
2834    {
2835        rpc_vfs_fs_add_dentry_client( parent_cxy,
2836                                      parent_ptr,
2837                                      dentry_ptr,
2838                                      &error );
2839    }
2840    if ( error )
2841    {
2842        printk("\n[ERROR] in %s : cannot register child in parent directory\n",
2843        __FUNCTION__ );
2844        return -1;
2845    }
2846
[625]2847#if DEBUG_VFS_NEW_DENTRY_INIT
[602]2848cycle = (uint32_t)hal_get_cycles();
[625]2849if( DEBUG_VFS_NEW_DENTRY_INIT < cycle )
[610]2850printk("\n[%s] thread[%x,%x] exit / parent <%s> / child <%s> / cycle %d\n",
[602]2851__FUNCTION__ , this->process->pid, this->trdid, parent_name, child_name, cycle );
2852#endif
2853
2854    return 0;
2855
[612]2856}  // end vfs_new_dentry_init()
[602]2857
[611]2858///////////////////////////////////////////////////
2859error_t vfs_add_special_dentries( xptr_t  child_xp,
2860                                  xptr_t  parent_xp )
2861{
2862    error_t         error;
2863    vfs_inode_t   * child_ptr;         // local pointer on child inode directory
2864    cxy_t           child_cxy;         // child inode directory cluster identifier
2865    vfs_ctx_t     * ctx_ptr;           // local pointer on child inode FS context
2866    vfs_fs_type_t   fs_type;           // FS type of child inode
2867    xptr_t          dentry_xp;         // extended pointer on dentry (used for . and ..)
2868    vfs_dentry_t  * dentry_ptr;        // local pointer on dentry (used for . and ..)
2869
[612]2870    // xptr_t          parents_root_xp;   // extended pointer on inode "parents" field
2871    // xptr_t          parents_entry_xp;  // extended pointer on dentry "parents" field
[611]2872    xptr_t          children_xhtab_xp; // extended pointer on inode "children" field
2873    xptr_t          children_entry_xp; // extended pointer on dentry "children" field
2874
2875#if DEBUG_VFS_ADD_SPECIAL
2876uint32_t   cycle = (uint32_t)hal_get_cycles();
2877thread_t * this  = CURRENT_THREAD;
2878char child_name[CONFIG_VFS_MAX_NAME_LENGTH];
2879char parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
2880vfs_inode_get_name( child_xp  , child_name );
2881vfs_inode_get_name( parent_xp , parent_name );
2882if( DEBUG_VFS_ADD_SPECIAL < cycle )
[612]2883printk("\n[%s] thread[%x,%x] enter for child <%s> in parent <%s> / cycle %d\n",
[611]2884__FUNCTION__, this->process->pid, this->trdid, child_name, parent_name, cycle );
2885#endif
2886
2887    // get new directory cluster and local pointer
2888    child_cxy  = GET_CXY( child_xp );
2889    child_ptr  = GET_PTR( child_xp );
2890
2891    // get child inode FS type
2892    ctx_ptr    = hal_remote_lpt( XPTR( child_cxy , &child_ptr->ctx ) );
2893    fs_type    = hal_remote_l32( XPTR( child_cxy , &ctx_ptr->type ) );
2894
[630]2895    //////////////////////////// create <.> dentry //////////////////////
[611]2896    if( child_cxy == local_cxy )     
2897    {
2898        error = vfs_dentry_create( fs_type,
2899                                   ".",
2900                                   &dentry_xp );
2901    }
2902    else
2903    {
2904        rpc_vfs_dentry_create_client( child_cxy,
2905                                      fs_type,
2906                                      ".",
2907                                      &dentry_xp,
2908                                      &error );
2909    }
2910    if( error )
2911    {
2912        printk("\n[ERROR] in %s : cannot create dentry <.> in cluster %x\n",
2913        __FUNCTION__ , child_cxy );
2914        return -1;
2915    }
2916
2917    // get <.> dentry local pointer
2918    dentry_ptr = GET_PTR( dentry_xp );
2919
2920#if(DEBUG_VFS_ADD_SPECIAL & 1)
[630]2921cycle = (uint32_t)hal_get_cycles();
[611]2922if( DEBUG_VFS_ADD_SPECIAL < cycle )
[630]2923printk("\n[%s] thread[%x,%x] created dentry <.> (%x,%x) / cycle %d\n",
2924__FUNCTION__, this->process->pid, this->trdid, child_cxy, dentry_ptr, cycle );
[611]2925#endif
2926
2927    // register <.> dentry in child inode xhtab of children
2928    children_xhtab_xp = XPTR( child_cxy , &child_ptr->children );
2929    children_entry_xp = XPTR( child_cxy , &dentry_ptr->children );
2930    error = xhtab_insert( children_xhtab_xp , "." , children_entry_xp );
2931    if( error )
2932    {
2933        printk("\n[ERROR] in %s : cannot register dentry <.> in xhtab\n",
2934        __FUNCTION__ );
2935        return -1;
2936    }
2937
[612]2938   
2939    // don't register <.> dentry in child_inode xlist of parents
2940    // parents_root_xp  = XPTR( child_cxy , &child_ptr->parents );
2941    // parents_entry_xp = XPTR( child_cxy , &dentry_ptr->parents );
2942    // xlist_add_first( parents_root_xp , parents_entry_xp );
2943    // hal_remote_atomic_add( XPTR( child_cxy , &child_ptr->links ) , 1 );
[611]2944
2945    // update "parent" and "child_xp" fields in <.> dentry
2946    hal_remote_s64( XPTR( child_cxy , &dentry_ptr->child_xp ) , child_xp );
2947    hal_remote_spt( XPTR( child_cxy , &dentry_ptr->parent ) , child_ptr );
2948
2949#if(DEBUG_VFS_ADD_SPECIAL & 1)
[630]2950cycle = (uint32_t)hal_get_cycles();
[611]2951if( DEBUG_VFS_ADD_SPECIAL < cycle )
[630]2952printk("\n[%s] thread[%x,%x] linked dentry <.> to parent and child inodes / cycle %d\n", 
2953__FUNCTION__, this->process->pid, this->trdid, cycle ); 
[611]2954#endif
2955
2956    // introduce <.> dentry into child directory mapper
[630]2957    // only if the target directory is not the root VFS
2958    if( child_xp != parent_xp )
[611]2959    {
[630]2960        if( child_cxy == local_cxy )
2961        { 
2962            error = vfs_fs_add_dentry( child_ptr,
2963                                       dentry_ptr );
2964        }
2965        else
2966        {
2967            rpc_vfs_fs_add_dentry_client( child_cxy,
2968                                          child_ptr,
2969                                          dentry_ptr,
2970                                          &error );
2971        }
2972        if( error )
2973        {
2974            printk("\n[ERROR] in %s : cannot introduce dentry <..> in mapper %x\n",
2975            __FUNCTION__ );
2976            return -1;
2977        }
[611]2978
2979#if(DEBUG_VFS_ADD_SPECIAL & 1)
[630]2980cycle = (uint32_t)hal_get_cycles();
[611]2981if( DEBUG_VFS_ADD_SPECIAL < cycle )
[630]2982printk("\n[%s] thread[%x,%x] registered dentry <.> in child mapper / cycle %d\n", 
2983__FUNCTION__, this->process->pid, this->trdid, cycle ); 
[611]2984#endif
2985
[630]2986    }
2987
2988    ///////////////////////////// create <..> dentry ///////////////////////
[611]2989    if( child_cxy == local_cxy )     
2990    {
2991        error = vfs_dentry_create( fs_type,
2992                                   "..",
2993                                   &dentry_xp );
2994    }
2995    else
2996    {
2997        rpc_vfs_dentry_create_client( child_cxy,
2998                                      fs_type,
2999                                      "..",
3000                                      &dentry_xp,
3001                                      &error );
3002    }
3003    if( error )
3004    {
3005        printk("\n[ERROR] in %s : cannot create dentry <..> in cluster %x\n",
3006        __FUNCTION__ , child_cxy );
3007        return -1;
3008    }
3009
3010    // get <..> dentry local pointer
3011    dentry_ptr = GET_PTR( dentry_xp );
3012
3013#if(DEBUG_VFS_ADD_SPECIAL & 1)
[630]3014cycle = (uint32_t)hal_get_cycles();
[611]3015if( DEBUG_VFS_ADD_SPECIAL < cycle )
[630]3016printk("\n[%s] thread[%x,%x] created dentry <..> (%x,%x) / cycle %d\n",
3017__FUNCTION__, this->process->pid, this->trdid, child_cxy, dentry_ptr, cycle );
[611]3018#endif
3019
3020    // register <..> dentry in child_inode xhtab of children
3021    children_xhtab_xp = XPTR( child_cxy , &child_ptr->children );
3022    children_entry_xp = XPTR( child_cxy , &dentry_ptr->children );
3023    error = xhtab_insert( children_xhtab_xp , ".." , children_entry_xp );
3024    if( error )
3025    {
3026        printk("\n[ERROR] in %s : cannot register dentry <..> in xhtab\n",
3027        __FUNCTION__ );
3028        return -1;
3029    }
3030
[612]3031    // don't register <..> dentry in parent_inode xlist of parents
[611]3032
3033    // update "parent" and "child_xp" fields in <..> dentry
3034    hal_remote_s64( XPTR( child_cxy , &dentry_ptr->child_xp ) , parent_xp );
3035    hal_remote_spt( XPTR( child_cxy , &dentry_ptr->parent ) , child_ptr );
3036
3037#if(DEBUG_VFS_ADD_SPECIAL & 1)
[630]3038cycle = (uint32_t)hal_get_cycles();
[611]3039if( DEBUG_VFS_ADD_SPECIAL < cycle )
[630]3040printk("\n[%s] thread[%x,%x] linked dentry <..> to parent and child inodes / cycle %d\n", 
3041__FUNCTION__, this->process->pid, this->trdid, cycle ); 
[611]3042#endif
3043
3044    // introduce <..> dentry into child directory mapper
[630]3045    // only if the target directory is not the root VFS
3046    if( child_xp != parent_xp )
[611]3047    {
[630]3048        if( child_cxy == local_cxy )
3049        { 
3050            error = vfs_fs_add_dentry( child_ptr,
3051                                       dentry_ptr );
3052        }
3053        else
3054        {
3055            rpc_vfs_fs_add_dentry_client( child_cxy,
3056                                          child_ptr,
3057                                          dentry_ptr,
3058                                          &error );
3059        }
3060        if( error )
3061        {
3062            printk("\n[ERROR] in %s : cannot introduce dentry <..> in mapper %x\n",
3063            __FUNCTION__ );
3064            return -1;
3065        }
[611]3066
3067#if(DEBUG_VFS_ADD_SPECIAL & 1)
[630]3068cycle = (uint32_t)hal_get_cycles();
[611]3069if( DEBUG_VFS_ADD_SPECIAL < cycle )
[630]3070printk("\n[%s] thread[%x,%x] registered dentry <..> in child mapper / cycle %d\n", 
3071__FUNCTION__, this->process->pid, this->trdid, cycle ); 
[611]3072#endif
3073
[630]3074    }
3075
[611]3076#if DEBUG_VFS_ADD_SPECIAL
3077cycle = (uint32_t)hal_get_cycles();
3078if( DEBUG_VFS_ADD_SPECIAL < cycle )
[612]3079printk("\n[%s] thread[%x,%x] exit for child <%s> in parent <%s> / cycle %d\n",
3080__FUNCTION__, this->process->pid, this->trdid, child_name, parent_name, cycle );
[611]3081#endif
3082
3083    return 0;
3084
3085}  // end vfs_add_special_dentries()
3086
[610]3087//////////////////////////////////////////
3088error_t vfs_get_path( xptr_t     inode_xp,
3089                      char     * buffer,
3090                      char    ** first,
3091                      uint32_t   max_size )
[1]3092{
[610]3093        xptr_t         dentry_xp;        // extended pointer on current dentry
3094    vfs_dentry_t * dentry_ptr;       // local pointer on current dentry
3095    cxy_t          dentry_cxy;       // current dentry cluster identifier
3096    xptr_t         name_xp;          // extended pointer on current dentry name
3097        uint32_t       length;           // length of current dentry name
3098        int32_t        index;            // slot index in buffer
3099    xptr_t         current_xp;       // extended pointer on current inode
3100    vfs_inode_t  * current_ptr;      // local pointer on current inode
3101    cxy_t          current_cxy;      // current inode cluster identifier
3102    xptr_t         vfs_root_xp;      // extended pointer on VFS root inode
3103    vfs_inode_t  * vfs_root_ptr;     // local pointer on VFS root inode
3104    cxy_t          vfs_root_cxy;     // VFS root inode cluster identifier
3105    xptr_t         lock_xp;          // extended pointer on Inode Tree lock
3106    xptr_t         parents_root_xp;  // extended pointer on current inode parents root
3107    bool_t         found;            // condition to exit the while loop
[1]3108
[610]3109    thread_t  * this    = CURRENT_THREAD;
3110    process_t * process = this->process;
[1]3111
[610]3112#if DEBUG_VFS_GET_PATH
3113uint32_t cycle = (uint32_t)hal_get_cycles();
3114if( DEBUG_VFS_GET_PATH < cycle )
3115printk("\n[%s] thread[%x,%x] enter : inode (%x,%x) / cycle %d\n",
3116__FUNCTION__ , process->pid, this->trdid,
3117GET_CXY( inode_xp ), GET_PTR( inode_xp ), cycle );
3118#endif
3119
3120        // set the NUL character in buffer / initialise buffer index
[1]3121        buffer[max_size - 1] = 0;
[610]3122    index    = (int32_t)(max_size - 1);
[1]3123
3124    // initialize current inode
[610]3125    current_xp  = inode_xp;
[1]3126
[610]3127    // build extended pointer on lock protecting Inode Tree
3128    vfs_root_xp  = process->vfs_root_xp;
3129    vfs_root_ptr = GET_PTR( vfs_root_xp );
3130    vfs_root_cxy = GET_CXY( vfs_root_xp );
3131    lock_xp      = XPTR( vfs_root_cxy , &vfs_root_ptr->main_lock );
3132
3133    // take lock protecting Inode Tree in read mode
3134    remote_rwlock_rd_acquire( lock_xp );
3135
3136    // traverse Inode Tree from target inode to VFS root
3137    // selecting always the first parent dentry
3138    // the buffer is written in "reverse order" (from target inode to root)
3139    // exit the while loop when the VFS root has been found
[1]3140        do
3141    {
[610]3142        // get current inode cluster and local pointer
3143        current_cxy = GET_CXY( current_xp );
3144        current_ptr = GET_PTR( current_xp );
[1]3145
[610]3146        // build extended pointer on parents dentries root
3147        parents_root_xp = XPTR( current_cxy , &current_ptr->parents );
[1]3148
[610]3149        // compute exit condition <=> current inode is VFS root   
3150        found = xlist_is_empty( parents_root_xp );
[1]3151
[610]3152        if( found )                              // parent is the VFS root
3153        {
3154            if( index == (int32_t)(max_size - 1) )
3155            {
3156                // update index
3157                index--;
3158                 
3159                // set separator 
3160                        buffer[index] = '/';
[1]3161
[610]3162// check buffer overflow
[625]3163assert( (index >= 0) , "kernel buffer too small" );
[1]3164
[610]3165            }
3166        }
3167        else                                     // not the VFS root
[1]3168        {
[610]3169            // get first parent dentry cluster and pointers
3170            dentry_xp  = XLIST_FIRST( parents_root_xp , vfs_dentry_t , parents );
3171            dentry_cxy = GET_CXY( dentry_xp );
3172            dentry_ptr = GET_PTR( dentry_xp );
[1]3173
[610]3174            // get extended pointer on dentry name and name length
3175            name_xp = XPTR( dentry_cxy , dentry_ptr->name );
3176            length  = hal_remote_l32( XPTR( dentry_cxy , &dentry_ptr->length ) );
[1]3177
[610]3178#if (DEBUG_VFS_GET_PATH & 1)
3179char debug_name[CONFIG_VFS_MAX_NAME_LENGTH];
3180hal_remote_strcpy( XPTR( local_cxy , debug_name ) , name_xp );
3181if( DEBUG_VFS_GET_PATH < cycle )
3182printk("\n[%s] thread(%x,%s) get current dentry <%s> in cluster %x\n",
3183__FUNCTION__ , process->pid, this->trdid, debug_name, current_cxy );
3184#endif
3185            // update index
3186            index -= (length + 1); 
3187
3188// check buffer overflow
[625]3189assert( (index >= 0) , "kernel buffer too small" );
[610]3190
3191            // update pathname
3192            hal_remote_memcpy( XPTR( local_cxy , &buffer[index + 1] ) ,
3193                               name_xp , length );
3194
3195            // set separator 
3196                    buffer[index] = '/';
3197
3198            // get extended pointer on parent inode
3199            current_xp = XPTR( dentry_cxy , 
3200                               hal_remote_lpt( XPTR( dentry_cxy , &dentry_ptr->parent ) ) );
3201        }
[1]3202    }
[610]3203    while( found == false );
[1]3204
[610]3205    // release lock protecting Inode Tree in read mode
3206    remote_rwlock_rd_release( lock_xp );
3207
3208#if DEBUG_VFS_GET_PATH
3209cycle = (uint32_t)hal_get_cycles();
3210if( DEBUG_VFS_GET_PATH < cycle )
3211printk("\n[%s] thread[%x,%x] exit : path <%s> / cycle %d\n",
3212__FUNCTION__ , process->pid, this->trdid, &buffer[index], cycle );
3213#endif
3214
3215    // return pointer on first character in buffer
3216    *first = &buffer[index];
[1]3217        return 0;
3218
3219}  // end vfs_get_path()
3220
[188]3221     
[602]3222////////////////////////////////////////////////////////////////////
[610]3223error_t vfs_add_child_in_parent( cxy_t              child_cxy,
[23]3224                                 vfs_fs_type_t      fs_type,
[602]3225                                 xptr_t             parent_inode_xp,
[23]3226                                 char             * name,
[610]3227                                 xptr_t           * child_dentry_xp,
[602]3228                                 xptr_t           * child_inode_xp )
[1]3229{
[610]3230    error_t        error;
3231    cxy_t          parent_cxy;          // parent inode cluster identifier
3232    vfs_inode_t  * parent_inode_ptr;    // parent inode local pointer
3233    xptr_t         new_dentry_xp;       // extended pointer on created dentry
3234    vfs_dentry_t * new_dentry_ptr;      // created dentry local pointer
3235    xptr_t         new_inode_xp;        // extended pointer on created child inode
3236    vfs_inode_t  * new_inode_ptr;       // local pointer on created child inode
[1]3237
[610]3238    xptr_t         parents_root_xp;     // extended pointer on child inode  "parents" field
3239    xptr_t         parents_entry_xp;    // extended pointer on child dentry "parents" field
3240    xptr_t         children_xhtab_xp;   // extended pointer on parent inode "children" field
3241    xptr_t         children_entry_xp;   // extended pointer on child dentry "children" field
3242   
3243    // get parent inode cluster and pointer
3244    parent_cxy       = GET_CXY( parent_inode_xp );
[602]3245    parent_inode_ptr = GET_PTR( parent_inode_xp );
[1]3246
[438]3247#if DEBUG_VFS_ADD_CHILD
[602]3248char parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
3249vfs_inode_get_name( parent_inode_xp , parent_name );
[433]3250uint32_t cycle = (uint32_t)hal_get_cycles();
[568]3251thread_t * this = CURRENT_THREAD; 
[438]3252if( DEBUG_VFS_ADD_CHILD < cycle )
[610]3253printk("\n[%s] thread[%x,%x] enter / child <%s> / parent <%s> / cycle %d\n",
3254__FUNCTION__, this->process->pid, this->trdid, name,
3255parent_name, (uint32_t)hal_get_cycles() );
[433]3256#endif
[279]3257
[610]3258    // 1. create dentry in parent cluster
3259    if( parent_cxy == local_cxy )           // parent cluster is local
[1]3260    {
[23]3261        error = vfs_dentry_create( fs_type,
[1]3262                                   name,
[602]3263                                   &new_dentry_xp );
[1]3264    }
[610]3265    else                                    // parent cluster is remote
[1]3266    {
[610]3267        rpc_vfs_dentry_create_client( parent_cxy,
[23]3268                                      fs_type,
[1]3269                                      name,
[602]3270                                      &new_dentry_xp,
[1]3271                                      &error );
3272    }
3273                                     
3274    if( error )
3275    {
[437]3276        printk("\n[ERROR] in %s : cannot create dentry <%s> in cluster %x\n",
[610]3277        __FUNCTION__ , name , parent_cxy );
[602]3278        return -1;
[1]3279    }
3280
[602]3281    // get dentry local pointer
3282    new_dentry_ptr = GET_PTR( new_dentry_xp );
3283
[568]3284#if(DEBUG_VFS_ADD_CHILD & 1)
3285if( DEBUG_VFS_ADD_CHILD < cycle )
[610]3286printk("\n[%s] thread[%x,%x] / dentry <%s> created (%x,%x)\n",
3287__FUNCTION__, this->process->pid, this->trdid, name, parent_cxy, new_dentry_ptr );
[568]3288#endif
3289
[610]3290    // 2. create child inode in child cluster
3291    // TODO : define attr / mode / uid / gid
[1]3292    uint32_t attr = 0;
3293    uint32_t mode = 0;
3294    uint32_t uid  = 0;
3295    uint32_t gid  = 0;
3296   
[610]3297    if( child_cxy == local_cxy )      // child cluster is local
[1]3298    {
[610]3299        error = vfs_inode_create( fs_type,
[1]3300                                  attr,
3301                                  mode,
3302                                  uid,
3303                                  gid,
[602]3304                                  &new_inode_xp );
[1]3305    }
3306    else                              // child cluster is remote
3307    {
[610]3308        rpc_vfs_inode_create_client( child_cxy,
[23]3309                                     fs_type,
[1]3310                                     attr,
3311                                     mode,
3312                                     uid,
3313                                     gid,
[602]3314                                     &new_inode_xp,
[1]3315                                     &error );
3316    }
3317                                     
3318    if( error )
3319    {
3320        printk("\n[ERROR] in %s : cannot create inode in cluster %x\n",
[610]3321               __FUNCTION__ , child_cxy );
[1]3322 
[610]3323        if( parent_cxy == local_cxy ) vfs_dentry_destroy( new_dentry_ptr );
3324        else rpc_vfs_dentry_destroy_client( parent_cxy , new_dentry_ptr );
[602]3325        return -1;
[1]3326    }
3327
[610]3328    // get new inode local pointer
3329    new_inode_ptr = GET_PTR( new_inode_xp );
3330   
[568]3331#if(DEBUG_VFS_ADD_CHILD & 1)
3332if( DEBUG_VFS_ADD_CHILD < cycle )
[610]3333printk("\n[%s] thread[%x,%x] / inode <%s> created (%x,%x)\n",
3334__FUNCTION__ , this->process->pid, this->trdid, name , child_cxy, new_inode_ptr );
[568]3335#endif
3336
[635]3337
[610]3338    // 3. register new_dentry in new_inode xlist of parents
3339    parents_root_xp  = XPTR( child_cxy , &new_inode_ptr->parents );
3340    parents_entry_xp = XPTR( parent_cxy, &new_dentry_ptr->parents );
3341    xlist_add_first( parents_root_xp , parents_entry_xp );
3342    hal_remote_atomic_add( XPTR( child_cxy , &new_inode_ptr->links ) , 1 );
[204]3343
[610]3344#if(DEBUG_VFS_ADD_CHILD & 1)
[611]3345if( DEBUG_VFS_ADD_CHILD < cycle )
[633]3346printk("\n[%s] thread[%x,%x] link dentry(%x,%x) to child inode(%x,%x)\n",
[610]3347__FUNCTION__, this->process->pid, this->trdid, 
3348parent_cxy, new_dentry_ptr, child_cxy, new_inode_ptr );
3349#endif
3350
[626]3351    // 4. register new_dentry in parent_inode xhtab of children
[610]3352    children_xhtab_xp = XPTR( parent_cxy , &parent_inode_ptr->children );
3353    children_entry_xp = XPTR( parent_cxy , &new_dentry_ptr->children );
3354    xhtab_insert( children_xhtab_xp , name , children_entry_xp );
3355
3356#if(DEBUG_VFS_ADD_CHILD & 1)
3357if( DEBUG_VFS_ADD_CHILD < cycle )
[633]3358printk("\n[%s] thread[%x,%x] link dentry(%x,%x) to parent inode(%x,%x)\n",
[610]3359__FUNCTION__, this->process->pid, this->trdid, 
3360parent_cxy, new_dentry_ptr, parent_cxy, parent_inode_ptr );
3361#endif
3362
[626]3363    // 5. update "parent" and "child_xp" fields in new_dentry
[610]3364    hal_remote_s64( XPTR( parent_cxy , &new_dentry_ptr->child_xp ) , new_inode_xp );
3365    hal_remote_spt( XPTR( parent_cxy , &new_dentry_ptr->parent ) , parent_inode_ptr );
3366
[438]3367#if DEBUG_VFS_ADD_CHILD
[433]3368cycle = (uint32_t)hal_get_cycles();
[438]3369if( DEBUG_VFS_ADD_CHILD < cycle )
[598]3370printk("\n[%s] thread[%x,%x] exit for <%s> / cycle %d\n",
[633]3371__FUNCTION__, this->process->pid, this->trdid, name, cycle );
[433]3372#endif
[296]3373
[602]3374    // return extended pointer on dentry & child inode
[610]3375    *child_dentry_xp = new_dentry_xp;
3376    *child_inode_xp  = new_inode_xp;
[1]3377    return 0;
3378
3379}  // end vfs_add_child_in_parent()
3380
[610]3381/////////////////////////////////////////////////////
3382void vfs_remove_child_from_parent( xptr_t dentry_xp )
[459]3383{
[610]3384    cxy_t          parent_cxy;         // parent inode cluster identifier
3385    cxy_t          child_cxy;          // child inode cluster identifier
3386    vfs_dentry_t * dentry_ptr;         // local pointer on dentry
3387    xptr_t         child_inode_xp;     // extended pointer on child inode
3388    vfs_inode_t  * child_inode_ptr;    // local pointer on child inode
3389    vfs_inode_t  * parent_inode_ptr;   // local pointer on parent inode
3390    uint32_t       links;              // number of child inode parents
3391
3392    char dentry_name[CONFIG_VFS_MAX_NAME_LENGTH];
[459]3393   
[610]3394    // get parent cluster and dentry local pointer
3395    parent_cxy = GET_CXY( dentry_xp );
[459]3396    dentry_ptr = GET_PTR( dentry_xp );
3397
[610]3398    // get a local copy of dentry name
3399    hal_remote_strcpy( XPTR( local_cxy  , dentry_name ),
3400                       XPTR( parent_cxy , &dentry_ptr->name ) );
[459]3401
[610]3402    // get parent_inode local pointer
3403    parent_inode_ptr = hal_remote_lpt( XPTR( parent_cxy , &dentry_ptr->parent ) );
3404 
3405    // get child cluster and child_inode pointers
3406    child_inode_xp   = hal_remote_l64( XPTR( parent_cxy , &dentry_ptr->child_xp ) );
3407    child_cxy        = GET_CXY( child_inode_xp ); 
3408    child_inode_ptr  = GET_PTR( child_inode_xp );
[602]3409
[610]3410    // remove dentry from parent_inode
3411    xhtab_remove( XPTR( parent_cxy , &parent_inode_ptr->children ),
3412                  dentry_name,
3413                  XPTR( parent_cxy , &dentry_ptr->children ) );
[602]3414
[610]3415    // remove dentry from child_inode
3416    xlist_unlink( XPTR( parent_cxy , &dentry_ptr->parents ) );
3417    links = hal_remote_atomic_add( XPTR( child_cxy , &child_inode_ptr->links ) , -1 );
3418
3419    // delete dentry descriptor
3420    if( parent_cxy == local_cxy )
[459]3421    {
[602]3422         vfs_dentry_destroy( dentry_ptr );
[459]3423    }
3424    else
3425    {
[610]3426         rpc_vfs_dentry_destroy_client( parent_cxy,
[602]3427                                        dentry_ptr );
[459]3428    }
3429
[610]3430    // delete child_inode descriptor if last link
3431    if( links == 1 )
[459]3432    {
[610]3433        if( child_cxy == local_cxy )
3434        {
3435            vfs_inode_destroy( child_inode_ptr );
3436        }
3437        else
3438        {
3439            rpc_vfs_inode_destroy_client( child_cxy , child_inode_ptr );
3440        }
[459]3441    }
3442
3443}  // end vfs_remove_child_from_parent()
3444
[612]3445
3446
3447
[23]3448//////////////////////////////////////////////////////////////////////////////////////////
[602]3449//    API used by VFS to access a specific FS 
[23]3450//////////////////////////////////////////////////////////////////////////////////////////
3451
[614]3452//////////////////////////////////////////////
3453error_t vfs_fs_move_page( xptr_t      page_xp,
3454                          cmd_type_t  cmd_type )
[23]3455{
[204]3456    error_t error = 0;
[23]3457
[625]3458assert( (page_xp != XPTR_NULL) , "page pointer is NULL" );
[23]3459
[602]3460    page_t * page_ptr = GET_PTR( page_xp );
3461    cxy_t    page_cxy = GET_CXY( page_xp );
[23]3462
[602]3463    // get local pointer on page mapper
3464    mapper_t * mapper = hal_remote_lpt( XPTR( page_cxy , &page_ptr->mapper ) );
[23]3465
[625]3466assert( (mapper != NULL) , "no mapper for page" );
[246]3467
[23]3468    // get FS type
[602]3469    vfs_fs_type_t fs_type = hal_remote_l32( XPTR( page_cxy , &mapper->type ) );
[23]3470
[238]3471    // call relevant FS function
[23]3472    if( fs_type == FS_TYPE_FATFS )
3473    {
[614]3474        error = fatfs_move_page( page_xp , cmd_type ); 
[602]3475    }
3476    else if( fs_type == FS_TYPE_RAMFS )
3477    {
3478        assert( false , "should not be called for RAMFS\n" );
3479    }
3480    else if( fs_type == FS_TYPE_DEVFS )
3481    {
3482        assert( false , "should not be called for DEVFS\n" );
3483    }
3484    else
3485    {
[625]3486        assert( false , "undefined file system type" );
[602]3487    }
[568]3488
[602]3489    return error;
[568]3490
[602]3491}  // end vfs_fs_move_page()
3492
3493////////////////////////////////////////////////
3494error_t vfs_fs_add_dentry( vfs_inode_t  * inode,
3495                           vfs_dentry_t * dentry )
3496{
3497    error_t error = 0;
3498
[625]3499assert( (inode  != NULL) , "inode  pointer is NULL" );
3500assert( (dentry != NULL) , "dentry pointer is NULL" );
[602]3501
3502    mapper_t * mapper = inode->mapper;
3503
[625]3504assert( (mapper != NULL) , "mapper pointer is NULL" );
[602]3505
3506    // get FS type
3507    vfs_fs_type_t fs_type = mapper->type;
3508
3509    // call relevant FS function
3510    if( fs_type == FS_TYPE_FATFS )
3511    {
3512        error = fatfs_add_dentry( inode , dentry ); 
[23]3513    }
3514    else if( fs_type == FS_TYPE_RAMFS )
3515    {
[612]3516        error = 0;     // does nothing for RAMFS
[23]3517    }
3518    else if( fs_type == FS_TYPE_DEVFS )
3519    {
[612]3520        error = 0;     // does nothing for DEVFS
[23]3521    }
3522    else
3523    {
[625]3524        assert( false , "undefined file system type" );
[23]3525    }
3526
3527    return error;
3528
[602]3529}  // end vfs_fs_add_dentry()
[23]3530
[602]3531///////////////////////////////////////////////////
3532error_t vfs_fs_remove_dentry( vfs_inode_t  * inode,
3533                              vfs_dentry_t * dentry )
[23]3534{
[602]3535    error_t error = 0;
[23]3536
[625]3537assert( (inode  != NULL) , "inode  pointer is NULL" );
3538assert( (dentry != NULL) , "dentry pointer is NULL" );
[23]3539
[238]3540    mapper_t * mapper = inode->mapper;
[23]3541
[625]3542assert( (mapper != NULL) , "mapper pointer is NULL" );
[23]3543
[602]3544    // get FS type
3545    vfs_fs_type_t fs_type = mapper->type;
[401]3546
[602]3547    // call relevant FS function
3548    if( fs_type == FS_TYPE_FATFS )
3549    {
3550        error = fatfs_remove_dentry( inode , dentry ); 
3551    }
3552    else if( fs_type == FS_TYPE_RAMFS )
3553    {
[612]3554        error = 0;     // does nothing for RAMFS
[602]3555    }
3556    else if( fs_type == FS_TYPE_DEVFS )
3557    {
[612]3558        error = 0;     // does nothing for DEVFS
[602]3559    }
3560    else
3561    {
[625]3562        assert( false , "undefined file system type" );
[602]3563    }
[238]3564
[602]3565    return error;
3566
3567}  // end vfs_fs_remove_dentry()
3568
3569////////////////////////////////////////////////
[623]3570error_t vfs_fs_new_dentry( vfs_inode_t * parent,
[602]3571                           char        * name,
3572                           xptr_t        child_xp )
3573{
3574    error_t error = 0;
3575
3576// check arguments
[625]3577assert( (parent != NULL) , "parent pointer is NULL");
3578assert( (child_xp != XPTR_NULL) , "child pointer is NULL");
[602]3579
3580    // get parent inode FS type
3581    vfs_fs_type_t fs_type = parent->ctx->type;
3582
3583    // call relevant FS function
3584    if( fs_type == FS_TYPE_FATFS )
[23]3585    {
[623]3586        error = fatfs_new_dentry( parent , name , child_xp );
[602]3587    }
3588    else if( fs_type == FS_TYPE_RAMFS )
3589    {
[625]3590        assert( false , "should not be called for RAMFS" );
[602]3591    }
3592    else if( fs_type == FS_TYPE_DEVFS )
3593    {
[625]3594        assert( false , "should not be called for DEVFS" );
[602]3595    }
3596    else
3597    {
[625]3598        assert( false , "undefined file system type" );
[602]3599    }
[23]3600
[602]3601    return error;
3602
[623]3603} // end vfs_fs_new_dentry()
[602]3604
[612]3605///////////////////////////////////////////////////
[623]3606error_t vfs_fs_update_dentry( vfs_inode_t  * inode,
3607                              vfs_dentry_t * dentry,
3608                              uint32_t       size )
3609{
3610    error_t error = 0;
3611
3612// check arguments
[625]3613assert( (inode  != NULL) , "inode  pointer is NULL");
3614assert( (dentry != NULL) , "dentry pointer is NULL");
[623]3615
3616    // get parent inode FS type
3617    vfs_fs_type_t fs_type = inode->ctx->type;
3618
3619    // call relevant FS function
3620    if( fs_type == FS_TYPE_FATFS )
3621    {
3622        error = fatfs_update_dentry( inode , dentry , size );
3623    }
3624    else if( fs_type == FS_TYPE_RAMFS )
3625    {
[625]3626        assert( false , "should not be called for RAMFS" );
[623]3627    }
3628    else if( fs_type == FS_TYPE_DEVFS )
3629    {
[625]3630        assert( false , "should not be called for DEVFS" );
[623]3631    }
3632    else
3633    {
[625]3634        assert( false , "undefined file system type" );
[623]3635    }
3636
3637    return error;
3638
3639} // end vfs_fs_update_dentry()
3640
3641///////////////////////////////////////////////////
[612]3642error_t vfs_fs_get_user_dir( vfs_inode_t   * inode,
3643                             struct dirent * array,
3644                             uint32_t        max_dirent,
3645                             uint32_t        min_dentry,
3646                             bool_t          detailed,
3647                             uint32_t      * entries,
3648                             bool_t        * done )
3649{
3650    error_t error = 0;
3651
3652// check arguments
[625]3653assert( (inode != NULL) , "parent pointer is NULL");
3654assert( (array != NULL) , "child pointer is NULL");
[612]3655assert( (detailed == false) , "detailed argument not supported\n");
3656
3657    // check inode type
3658    if( inode->type != INODE_TYPE_DIR )
3659    {
3660        printk("\n[ERROR] in %s : target inode is not a directory\n",
3661        __FUNCTION__ );
3662        return -1;
3663    }
3664
3665    // get parent inode FS type
3666    vfs_fs_type_t fs_type = inode->ctx->type;
3667
3668    // call relevant FS function
3669    if( fs_type == FS_TYPE_FATFS )
3670    {
3671        error = fatfs_get_user_dir( inode, 
3672                                    array,
3673                                    max_dirent,
3674                                    min_dentry,
3675                                    detailed,
3676                                    entries,
3677                                    done );
3678    }
3679    else if( fs_type == FS_TYPE_RAMFS )
3680    {
[625]3681        assert( false , "should not be called for RAMFS" );
[612]3682    }
3683    else if( fs_type == FS_TYPE_DEVFS )
3684    {
3685        error = devfs_get_user_dir( inode,
3686                                    array,
3687                                    max_dirent,
3688                                    min_dentry,
3689                                    detailed,
3690                                    entries,
3691                                    done );
3692    }
3693    else
3694    {
[625]3695        assert( false , "undefined file system type" );
[612]3696    }
3697
3698    return error;
3699
3700}  // end vfs_fs_get_user_dir()
3701 
[610]3702////////////////////////////////////////////////
3703error_t vfs_fs_sync_inode( vfs_inode_t * inode )
3704{
3705    error_t error = 0;
3706
3707// check arguments
[625]3708assert( (inode != NULL) , "inode pointer is NULL");
[610]3709
3710    // get inode FS type
3711    vfs_fs_type_t fs_type = inode->ctx->type;
3712
3713    // call relevant FS function
3714    if( fs_type == FS_TYPE_FATFS )
3715    {
3716        error = fatfs_sync_inode( inode );
3717    }
3718    else if( fs_type == FS_TYPE_RAMFS )
3719    {
[625]3720        assert( false , "should not be called for RAMFS" );
[610]3721    }
3722    else if( fs_type == FS_TYPE_DEVFS )
3723    {
[625]3724        assert( false , "should not be called for DEVFS" );
[610]3725    }
3726    else
3727    {
[625]3728        assert( false , "undefined file system type" );
[610]3729    }
3730
3731    return error;
3732
3733}  // end vfs_fs_sync_inode()
3734
3735////////////////////////////////////////////////
3736error_t vfs_fs_sync_fat( vfs_fs_type_t fs_type )
3737{
3738    error_t error = 0;
3739
3740    // call relevant FS function
3741    if( fs_type == FS_TYPE_FATFS )
3742    {
3743        error = fatfs_sync_fat();
3744    }
3745    else if( fs_type == FS_TYPE_RAMFS )
3746    {
[625]3747        assert( false , "should not be called for RAMFS" );
[610]3748    }
3749    else if( fs_type == FS_TYPE_DEVFS )
3750    {
[625]3751        assert( false , "should not be called for DEVFS" );
[610]3752    }
3753    else
3754    {
[625]3755        assert( false , "undefined file system type" );
[610]3756    }
3757
3758    return error;
3759
3760}  // end vfs_fs_sync_fat()
3761
3762//////////////////////////////////////////////////////
3763error_t vfs_fs_sync_free_info( vfs_fs_type_t fs_type )
3764{
3765    error_t error = 0;
3766
3767    // call relevant FS function
3768    if( fs_type == FS_TYPE_FATFS )
3769    {
3770        error = fatfs_sync_free_info();
3771    }
3772    else if( fs_type == FS_TYPE_RAMFS )
3773    {
[625]3774        assert( false , "should not be called for RAMFS" );
[610]3775    }
3776    else if( fs_type == FS_TYPE_DEVFS )
3777    {
[625]3778        assert( false , "should not be called for DEVFS" );
[610]3779    }
3780    else
3781    {
[625]3782        assert( false , "undefined file system type" );
[610]3783    }
3784
3785    return error;
3786
3787}  // end vfs_fs_sync_fat()
3788
[602]3789/////////////////////////////////////////////////
3790error_t vfs_fs_cluster_alloc( uint32_t   fs_type,
3791                              uint32_t * cluster )
3792{
3793    error_t error = 0;
3794
3795    // call relevant FS function
3796    if( fs_type == FS_TYPE_FATFS )
3797    {
3798        error = fatfs_cluster_alloc( cluster );
[23]3799    }
[602]3800    else if( fs_type == FS_TYPE_RAMFS )
3801    {
[625]3802        assert( false , "should not be called for RAMFS" );
[602]3803    }
3804    else if( fs_type == FS_TYPE_DEVFS )
3805    {
[625]3806        assert( false , "should not be called for DEVFS" );
[602]3807    }
3808    else
3809    {
[625]3810        assert( false , "undefined file system type" );
[602]3811    }
[23]3812
[602]3813    return error;
[401]3814
[602]3815} // end vfs_fs_alloc_cluster()
[23]3816
[602]3817////////////////////////////////////////////////
3818error_t vfs_fs_release_inode( xptr_t  inode_xp )
3819{
3820    error_t error = 0;
[23]3821
[625]3822assert( (inode_xp  != XPTR_NULL) , "inode pointer is NULL")       
[602]3823
3824    vfs_inode_t * inode_ptr = GET_PTR( inode_xp );
3825    cxy_t         inode_cxy = GET_CXY( inode_xp );
3826
3827    // get local pointer on page mapper
3828    mapper_t * mapper = hal_remote_lpt( XPTR( inode_cxy , &inode_ptr->mapper ) );
3829
[625]3830assert( (mapper != NULL) , "mapper pointer is NULL")       
[602]3831
3832    // get FS type from mapper
3833    vfs_fs_type_t fs_type = hal_remote_l32( XPTR( inode_cxy , &mapper->type ) );
3834
3835    // call relevant FS function
3836    if( fs_type == FS_TYPE_FATFS )
3837    {
3838        error = fatfs_release_inode( inode_xp ); 
3839    }
3840    else if( fs_type == FS_TYPE_RAMFS )
3841    {
[625]3842        assert( false , "should not be called for RAMFS" );
[602]3843    }
3844    else if( fs_type == FS_TYPE_DEVFS )
3845    {
[625]3846        assert( false , "should not be called for DEVFS" );
[602]3847    }
3848    else
3849    {
[625]3850        assert( false , "undefined file system type" );
[602]3851    }
3852
3853    return error;
3854   
3855}  // end vfs_fs_release_inode()
3856
3857
Note: See TracBrowser for help on using the repository browser.