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

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

All modifications required to support the <tcp_chat> application
including error recovery in case of packet loss.A

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