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

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

1) Fix a bug in the vfs_add_special_dentries() function:
The <.> and <..> dentries must not be created on IOC and on the mapper
for the VFS root directory.
2) Fix a bug in the hal_gpt_allocate_pt2 function, related to the
use of the TSAR_LOCKED attribute to avoid concurrent mapping of the PTD1.

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