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

Last change on this file since 609 was 602, checked in by alain, 6 years ago

Improve the FAT32 file system to support cat, rm, cp commands.

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