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

Last change on this file since 411 was 409, checked in by alain, 6 years ago

Fix bugs in exec

File size: 60.6 KB
RevLine 
[1]1/*
2 * vfs.c - Virtual File System implementation.
3 *
4 * Author  Mohamed Lamine Karaoui (2015)
[408]5 *         Alain Greiner (2016,2017)
[1]6 *
7 * Copyright (c) UPMC Sorbonne Universites
8 *
9 * This file is part of ALMOS-MKH.
10 *
11 * ALMOS-MKH is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2.0 of the License.
14 *
15 * ALMOS-MKH is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25
[14]26#include <kernel_config.h>
[1]27#include <hal_types.h>
28#include <hal_atomic.h>
29#include <hal_special.h>
30#include <readlock.h>
31#include <spinlock.h>
32#include <printk.h>
33#include <list.h>
34#include <xlist.h>
35#include <slist.h>
36#include <xhtab.h>
[23]37#include <rpc.h>
[1]38#include <errno.h>
39#include <kmem.h>
40#include <mapper.h>
41#include <thread.h>
[337]42#include <chdev.h>
[1]43#include <process.h>
[23]44#include <vfs.h>
[1]45#include <fatfs.h>
46#include <ramfs.h>
[23]47#include <devfs.h>
48#include <syscalls.h>
[1]49
50
51//////////////////////////////////////////////////////////////////////////////////////////
[50]52//           Extern variables         
[1]53//////////////////////////////////////////////////////////////////////////////////////////
54
[337]55extern vfs_ctx_t          fs_context[FS_TYPES_NR];    // allocated in kernel_init.c
[188]56
[337]57extern chdev_directory_t  chdev_dir;                  // allocated in kernel_init.c 
[50]58 
[1]59//////////////////////////////////////////////////////////////////////////////////////////
60//           Context related functions
61//////////////////////////////////////////////////////////////////////////////////////////
62
[188]63////////////////////////////////////////
64void vfs_ctx_init( vfs_fs_type_t   type,
65                   uint32_t        attr,
66                       uint32_t        total_clusters,
67                       uint32_t        cluster_size,
68                       xptr_t          vfs_root_xp,
69                   void          * extend )
70{
71    vfs_ctx_t * vfs_ctx = &fs_context[type];
72
73    vfs_ctx->type           = type;
74    vfs_ctx->attr           = attr;
75    vfs_ctx->total_clusters = total_clusters;
76    vfs_ctx->cluster_size   = cluster_size;
77    vfs_ctx->vfs_root_xp    = vfs_root_xp;
78    vfs_ctx->extend         = extend;
79
80    spinlock_init( &vfs_ctx->lock );
81
82    bitmap_init( vfs_ctx->bitmap , BITMAP_SIZE(CONFIG_VFS_MAX_INODES) ); 
83}
84
[23]85////////////////////////////////////////////
[1]86error_t vfs_ctx_inum_alloc( vfs_ctx_t * ctx,
87                            uint32_t  * inum )
88{
89    // get lock on inum allocator
90    spinlock_lock( &ctx->lock );
91
92    // get lid from local inum allocator
[23]93    uint32_t lid = bitmap_ffc( ctx->bitmap , CONFIG_VFS_MAX_INODES );
[1]94
95    if( lid == -1 )   // no more free slot => error
96    {
97        // release lock
98        spinlock_unlock( &ctx->lock );
99
100        // return error
101        return 1;
102    }
103    else              // found => return inum
104    {
105        // set slot allocated
[23]106        bitmap_set( ctx->bitmap , lid );
[1]107
108        // release lock
109        spinlock_unlock( &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{
[23]121    bitmap_clear( ctx->bitmap , inum & 0xFFFF ); 
[1]122}
123
124//////////////////////////////////////////////////////////////////////////////////////////
125//           Inode related functions
126//////////////////////////////////////////////////////////////////////////////////////////
127
[188]128char * vfs_inode_type_str( uint32_t type )
129{
130    if     ( type == INODE_TYPE_FILE ) return "FILE";
131    else if( type == INODE_TYPE_DIR  ) return "DIR ";
132    else if( type == INODE_TYPE_FIFO ) return "FIFO";
133    else if( type == INODE_TYPE_PIPE ) return "PIPE";
134    else if( type == INODE_TYPE_SOCK ) return "SOCK";
135    else if( type == INODE_TYPE_DEV  ) return "DEV ";
136    else if( type == INODE_TYPE_SYML ) return "SYML";
137    else                               return "undefined";
138}
139
[23]140//////////////////////////////////////////////////////
141error_t vfs_inode_create( xptr_t            dentry_xp,
142                          vfs_fs_type_t     fs_type,
143                          vfs_inode_type_t  inode_type,
[188]144                          void            * extend,
[23]145                          uint32_t          attr,
146                          uint32_t          rights,
147                          uid_t             uid,
148                          gid_t             gid,
149                          xptr_t          * inode_xp )
[1]150{
151    mapper_t         * mapper;     // associated mapper( to be allocated)
152    vfs_inode_t      * inode;      // inode descriptor (to be allocated)
153    uint32_t           inum;       // inode identifier (to be allocated)
154    vfs_ctx_t        * ctx;        // file system context
155        kmem_req_t         req;        // request to kernel memory allocator
156    error_t            error;
157
[407]158vfs_dmsg("\n[DBG] %s : core[%x,%d] enter / dentry = %x in cluster %x\n",
159__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, GET_PTR(dentry_xp), GET_CXY(dentry_xp) );
[279]160 
[23]161    // check fs type and get pointer on context
162    if     ( fs_type == FS_TYPE_FATFS ) ctx = &fs_context[FS_TYPE_FATFS];
163    else if( fs_type == FS_TYPE_RAMFS ) ctx = &fs_context[FS_TYPE_RAMFS];
164    else if( fs_type == FS_TYPE_DEVFS ) ctx = &fs_context[FS_TYPE_DEVFS];
[1]165    else
166    {
167        ctx = NULL;
[395]168                panic("illegal file system type = %d" , fs_type );
[1]169    }
170
171    // allocate inum
172    error = vfs_ctx_inum_alloc( ctx , &inum );
173
174    if( error )
175    {
176        printk("\n[ERROR] in %s : cannot allocate inum\n", __FUNCTION__ );
177        return ENOMEM;
178    }
179
180    // allocate memory for mapper
[246]181    mapper = mapper_create( fs_type );
[1]182
183    if( mapper == NULL )
184    {
185        printk("\n[ERROR] in %s : cannot allocate mapper\n", __FUNCTION__ );
186        vfs_ctx_inum_release( ctx , inum );
187        return ENOMEM;
188    }
189
[23]190    // allocate memory for VFS inode descriptor
[1]191        req.type  = KMEM_VFS_INODE;
192        req.size  = sizeof(vfs_inode_t);
193    req.flags = AF_KERNEL | AF_ZERO;
194        inode     = (vfs_inode_t *)kmem_alloc( &req );
195
196    if( inode == NULL )
197    {
198        printk("\n[ERROR] in %s : cannot allocate inode descriptor\n", __FUNCTION__ );
199        vfs_ctx_inum_release( ctx , inum );
200        mapper_destroy( mapper );
201        return ENOMEM;
202    }
203
204    // initialize inode descriptor
205    inode->gc         = 0;
[23]206    inode->type       = inode_type;
[1]207    inode->inum       = inum;
208    inode->attr       = attr;
[23]209    inode->rights     = rights;
[1]210    inode->uid        = uid;
211    inode->gid        = gid;
212    inode->refcount   = 0;
213    inode->parent_xp  = dentry_xp;
214    inode->ctx        = ctx;
[246]215    inode->mapper     = mapper;
[188]216    inode->extend     = extend;
[1]217
[246]218    // initialise inode field in mapper
219    mapper->inode     = inode;
220 
[1]221    // initialise threads waiting queue
222    xlist_root_init( XPTR( local_cxy , &inode->wait_root ) );
223
[204]224    // initialize dentries hash table
225    xhtab_init( &inode->children , XHTAB_DENTRY_TYPE );
[1]226
227    // initialize inode locks
[10]228    remote_rwlock_init( XPTR( local_cxy , &inode->data_lock ) );
[1]229    remote_spinlock_init( XPTR( local_cxy , &inode->main_lock ) );
230
[407]231vfs_dmsg("\n[DBG] %s : core[%x,%d] exit / inode = %x in cluster %x\n",
232__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, inode , local_cxy );
[401]233 
[1]234    // return extended pointer on inode
235    *inode_xp = XPTR( local_cxy , inode );
236    return 0;
237
238}  // end vfs_inode_create() 
239
240/////////////////////////////////////////////
241void vfs_inode_destroy( vfs_inode_t * inode )
242{
243    if( inode->refcount )
244    {
[395]245        panic("inode refcount non zero");
[1]246    }       
247
248    // release memory allocated for mapper
249    mapper_destroy( inode->mapper );
250
251    // release memory allocate for inode descriptor
252        kmem_req_t req;
253        req.ptr   = inode;
254        req.type  = KMEM_VFS_INODE;
255        kmem_free( &req );
256
257}  // end vfs_inode_destroy()
258
[238]259/////////////////////////////////////////////
260error_t vfs_inode_load( vfs_inode_t * parent,
261                        char        * name,
262                        xptr_t        child_xp )
263{
[407]264vfs_dmsg("\n[DBG] %s : core[%x,%d] enter for <%s> / cycle %d\n",
265__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , name , hal_time_stamp() );
[246]266
[238]267    error_t error = 0;
268
269    assert( (parent != NULL) , __FUNCTION__ , "parent pointer is NULL\n");
270
271    assert( (child_xp != XPTR_NULL) , __FUNCTION__ , "child pointer is NULL\n");
272
273    // get parent inode FS type
274    vfs_fs_type_t fs_type = parent->ctx->type;
275
276    // call relevant FS function
277    if( fs_type == FS_TYPE_FATFS )
278    {
279        error = fatfs_inode_load( parent , name , child_xp );
280    }
281    else if( fs_type == FS_TYPE_RAMFS )
282    {
283        assert( false , __FUNCTION__ , "should not be called for RAMFS\n" );
284    }
285    else if( fs_type == FS_TYPE_DEVFS )
286    {
287        assert( false , __FUNCTION__ , "should not be called for DEVFS\n" );
288    }
289    else
290    {
291        assert( false , __FUNCTION__ , "undefined file system type\n" );
292    }
293
[407]294vfs_dmsg("\n[DBG] %s : core[%x,%d] exit for <%s> / cycle %d\n",
295__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , name , hal_time_stamp() );
[246]296
[238]297    return error;
298
299} // end vfs_load_inode()
300
[1]301////////////////////////////////////////////
302void vfs_inode_remote_up( xptr_t  inode_xp )
303{
304    // get inode cluster and local pointer
305    cxy_t         inode_cxy = GET_CXY( inode_xp );
306    vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
307
308    hal_remote_atomic_add( XPTR( inode_cxy , &inode_ptr->refcount ) , 1 );   
309}
310
311//////////////////////////////////////////////
312void vfs_inode_remote_down( xptr_t  inode_xp )
313{
314    // get inode cluster and local pointer
315    cxy_t         inode_cxy = GET_CXY( inode_xp );
316    vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
317
318    hal_remote_atomic_add( XPTR( inode_cxy , &inode_ptr->refcount ) , -1 );   
319}
320
321//////////////////////////////////////////////
322uint32_t vfs_inode_get_size( xptr_t inode_xp )
323{
324    // get inode cluster and local pointer
325    cxy_t         cxy = GET_CXY( inode_xp );
326    vfs_inode_t * ptr = (vfs_inode_t *)GET_PTR( inode_xp );
327
328    // get size
[10]329    remote_rwlock_rd_lock( XPTR( cxy , &ptr->data_lock ) );
[1]330    uint32_t size = hal_remote_lw( XPTR( cxy , &ptr->size ) );
[10]331    remote_rwlock_rd_unlock( XPTR( cxy , &ptr->data_lock ) );
[1]332    return size;
333}
334
[101]335////////////////////////////////////////////
336void vfs_inode_set_size( xptr_t    inode_xp,
[409]337                         uint32_t  size )
[1]338{
339    // get inode cluster and local pointer
340    cxy_t         cxy = GET_CXY( inode_xp );
341    vfs_inode_t * ptr = (vfs_inode_t *)GET_PTR( inode_xp );
342
343    // set size
[10]344    remote_rwlock_wr_unlock( XPTR( cxy , &ptr->data_lock ) );
[1]345    hal_remote_sw( XPTR( cxy , &ptr->size ) , size );
[10]346    remote_rwlock_wr_unlock( XPTR( cxy , &ptr->data_lock ) );
[1]347}
348
[101]349////////////////////////////////////////
350void vfs_inode_unlock( xptr_t inode_xp )
[1]351{
352    // get inode cluster and local pointer
353    cxy_t         cxy = GET_CXY( inode_xp );
354    vfs_inode_t * ptr = (vfs_inode_t *)GET_PTR( inode_xp );
355
356    // release the main lock
357    remote_spinlock_unlock( XPTR( cxy , &ptr->main_lock ) );
358}
359
[101]360//////////////////////////////////////
361void vfs_inode_lock( xptr_t inode_xp )
[1]362{
363    // get inode cluster and local pointer
364    cxy_t         cxy = GET_CXY( inode_xp );
365    vfs_inode_t * ptr = (vfs_inode_t *)GET_PTR( inode_xp );
366
367    // get the main lock
368    remote_spinlock_lock( XPTR( cxy , &ptr->main_lock ) );
369}
370
[101]371/////////////////////////////////////////
[409]372void vfs_inode_get_name( xptr_t inode_xp,
373                         char * name )
[101]374{
[204]375    cxy_t          inode_cxy;
376    vfs_inode_t  * inode_ptr;
377    xptr_t         dentry_xp;
378    cxy_t          dentry_cxy;
379    vfs_dentry_t * dentry_ptr;
380   
381    // get inode cluster and local pointer
382    inode_cxy = GET_CXY( inode_xp );
383    inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
384
385    // get parent dentry
386    dentry_xp  = hal_remote_lwd( XPTR( inode_cxy , &inode_ptr->parent_xp ) );
387
388    // get local copy of name
389    if( dentry_xp == XPTR_NULL )  // it is the VFS root
390    {
391        strcpy( name , "/" );
392    }
393    else                          // not the VFS root
394    {
395        dentry_cxy = GET_CXY( dentry_xp );
396        dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
397
398        hal_remote_strcpy( XPTR( local_cxy  , name ) , 
399                           XPTR( dentry_cxy , &dentry_ptr->name ) );
400    }
[409]401}  // end vfs_inode_get_name()
[204]402
403////////////////////////////////////////////////////////////////////////////////////////////
[1]404//           Dentry related functions
405//////////////////////////////////////////////////////////////////////////////////////////
406
[23]407///////////////////////////////////////////////////
408error_t vfs_dentry_create( vfs_fs_type_t   fs_type,
409                           char          * name,
410                           vfs_inode_t   * parent,
411                           xptr_t        * dentry_xp )
[1]412{
413    vfs_ctx_t      * ctx;        // context descriptor
414    vfs_dentry_t   * dentry;     // dentry descriptor (to be allocated)
415        kmem_req_t       req;        // request to kernel memory allocator
416
[407]417vfs_dmsg("\n[DBG] %s : core[%x,%d] enter for <%s> / parent inode = %x / cycle %d\n",
418__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, name, parent, hal_time_stamp() );
[296]419
[188]420    // get pointer on context
[23]421    if     ( fs_type == FS_TYPE_FATFS ) ctx = &fs_context[FS_TYPE_FATFS];
422    else if( fs_type == FS_TYPE_RAMFS ) ctx = &fs_context[FS_TYPE_RAMFS];
423    else if( fs_type == FS_TYPE_DEVFS ) ctx = &fs_context[FS_TYPE_DEVFS];
[1]424    else
425    {
426        ctx = NULL;
[395]427        panic("undefined file system type");
[1]428    }
429
430    // get name length
431    uint32_t length = strlen( name );
432
[23]433    if( length >= CONFIG_VFS_MAX_NAME_LENGTH )
[1]434    {
435        printk("\n[ERROR] in %s : name too long\n", __FUNCTION__ );
436        return EINVAL;
437    }
438
439    // allocate memory for dentry descriptor
440        req.type  = KMEM_VFS_DENTRY;
441        req.size  = sizeof(vfs_dentry_t);
442    req.flags = AF_KERNEL | AF_ZERO;
443        dentry     = (vfs_dentry_t *)kmem_alloc( &req );
444
445    if( dentry == NULL )
446    {
447        printk("\n[ERROR] in %s : cannot allocate dentry descriptor\n", __FUNCTION__ );
448        return ENOMEM;
449    }
450
451    // initialize dentry descriptor
[23]452
[1]453    dentry->ctx     = ctx;
454    dentry->length  = length;
455    dentry->parent  = parent;
456    strcpy( dentry->name , name );
457
[23]458    // register dentry in hash table rooted in parent inode
459    xhtab_insert( XPTR( local_cxy , &parent->children ),
460                  name, 
[188]461                  XPTR( local_cxy , &dentry->list ) );
[23]462
463    // return extended pointer on dentry
[1]464    *dentry_xp = XPTR( local_cxy , dentry );
465
[407]466vfs_dmsg("\n[DBG] %s : core[%x,%d] exit for <%s> / dentry = %x in cluster %x / cycle %d\n",
467__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, name, dentry, local_cxy , hal_time_stamp() );
[296]468
[1]469    return 0;
470
471}  // end vfs_dentry_create()
472
473////////////////////////////////////////////////
474void vfs_dentry_destroy( vfs_dentry_t * dentry )
475{
476    if( dentry->refcount )
477    {
[395]478        panic("dentry refcount non zero");
[1]479    }       
480
481        kmem_req_t req;
482        req.ptr   = dentry;
483        req.type  = KMEM_VFS_DENTRY;
484        kmem_free( &req );
485}
486
487
[188]488
[1]489//////////////////////////////////////////////////////////////////////////////////////////
490//           File descriptor related functions
491//////////////////////////////////////////////////////////////////////////////////////////
492
[23]493/////////////////////////////////////////////
494error_t vfs_file_create( vfs_inode_t * inode,
495                         uint32_t      attr,
496                         xptr_t      * file_xp )
497{
498    vfs_file_t  * file;
499        kmem_req_t    req;
500
501    // allocate memory for new file descriptor
502        req.type  = KMEM_VFS_FILE;
503        req.size  = sizeof(vfs_file_t);
504    req.flags = AF_KERNEL | AF_ZERO;
505        file      = (vfs_file_t *)kmem_alloc( &req );
506
507    if( file == NULL ) return ENOMEM;
508
509    // initializes new file descriptor
510    file->gc       = 0;
511    file->type     = inode->type;
512    file->attr     = attr;
513    file->offset   = 0;
[337]514    file->refcount = 1;
[23]515    file->inode    = inode;
516    file->ctx      = inode->ctx;
517    file->mapper   = inode->mapper;
518
519    remote_rwlock_init( XPTR( local_cxy , &file->lock ) );
520
521    *file_xp = XPTR( local_cxy , file );
522    return 0;
523
524}  // end vfs_file_create()
525
526///////////////////////////////////////////
527void vfs_file_destroy( vfs_file_t *  file )
528{
529    if( file->refcount )
530    {
[395]531        panic("file refcount non zero");
[23]532    }       
533
534        kmem_req_t req;
535        req.ptr   = file;
536        req.type  = KMEM_VFS_FILE;
537        kmem_free( &req );
538
539}  // end vfs_file_destroy()
540
541
[1]542////////////////////////////////////////
543void vfs_file_count_up( xptr_t file_xp )
544{
545    // get file cluster and local pointer
546    cxy_t        file_cxy = GET_CXY( file_xp );
547    vfs_file_t * file_ptr = (vfs_file_t *)GET_PTR( file_xp ); 
548
549    // atomically increment count
550    hal_remote_atomic_add( XPTR( file_cxy , &file_ptr->refcount ) , 1 ); 
551}
552
553//////////////////////////////////////////
554void vfs_file_count_down( xptr_t file_xp )
555{
556    // get file cluster and local pointer
557    cxy_t        file_cxy = GET_CXY( file_xp );
558    vfs_file_t * file_ptr = (vfs_file_t *)GET_PTR( file_xp ); 
559
560    // atomically decrement count
561    hal_remote_atomic_add( XPTR( file_cxy , &file_ptr->refcount ) , -1 ); 
562}
563
[23]564//////////////////////////////////////////////////////////////////////////////////////////
565//           File access related functions
566//////////////////////////////////////////////////////////////////////////////////////////
567
[407]568//////////////////////////////////////
569error_t vfs_open( process_t * process,
570                          char      * path,
571                          uint32_t    flags,
572                  uint32_t    mode, 
573                          xptr_t    * new_file_xp,
574                  uint32_t  * new_file_id )
[1]575{
[23]576    error_t       error;
577    xptr_t        inode_xp;     // extended pointer on target inode
578    cxy_t         inode_cxy;    // inode cluster identifier       
579    vfs_inode_t * inode_ptr;    // inode local pointer
580    uint32_t      file_attr;    // file descriptor attributes
581    uint32_t      lookup_mode;  // lookup working mode       
582    xptr_t        file_xp;      // extended pointer on created file descriptor
583    uint32_t      file_id;      // created file descriptor index in reference fd_array
[1]584
[407]585vfs_dmsg("\n[DBG] %s : core[%x,%d] enter for <%s> / cycle %d\n",
586__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, path, (uint32_t)hal_time_stamp() );
[101]587
[23]588    // compute lookup working mode
589    lookup_mode = VFS_LOOKUP_OPEN;
590    if( (flags & O_DIR    )      )  lookup_mode |= VFS_LOOKUP_DIR;
591    if( (flags & O_CREAT  )      )  lookup_mode |= VFS_LOOKUP_CREATE;
592    if( (flags & O_EXCL   )      )  lookup_mode |= VFS_LOOKUP_EXCL;
593 
594    // compute attributes for the created file
595    file_attr = 0;
[407]596    if( (flags & O_RDONLY ) == 0 )  file_attr |= FD_ATTR_WRITE_ENABLE;
597    if( (flags & O_WRONLY ) == 0 )  file_attr |= FD_ATTR_READ_ENABLE;
[23]598    if( (flags & O_SYNC   )      )  file_attr |= FD_ATTR_SYNC;
599    if( (flags & O_APPEND )      )  file_attr |= FD_ATTR_APPEND;
600    if( (flags & O_CLOEXEC)      )  file_attr |= FD_ATTR_CLOSE_EXEC;
[1]601
[23]602    // get extended pointer on target inode
[407]603    error = vfs_lookup( process->vfs_cwd_xp , path , lookup_mode , &inode_xp );
[23]604
605    if( error ) return error;
606
607    // get target inode cluster and local pointer
608    inode_cxy = GET_CXY( inode_xp );
609    inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
610   
[407]611vfs_dmsg("\n[DBG] %s : core[%x,%d] found inode for <%s> in cluster %x / cycle %d\n",
612__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, path, inode_cxy , (uint32_t)hal_time_stamp() );
613
[23]614    // create a new file descriptor in cluster containing inode
615    if( inode_cxy == local_cxy )      // target cluster is local
[1]616    {
[23]617        error = vfs_file_create( inode_ptr , file_attr , &file_xp );
[1]618    }
[23]619    else                              // target cluster is remote
620    {
621        rpc_vfs_file_create_client( inode_cxy , inode_ptr , file_attr , &file_xp , &error );
622    }
[1]623
[23]624    if( error )  return error;
[1]625
[407]626    // allocate and register a new file descriptor index in reference process
627    error = process_fd_register( process , file_xp , &file_id );
[1]628
[23]629    if( error ) return error;
[1]630
[407]631vfs_dmsg("\n[DBG] %s : core[%x,%d] exit for <%s> / file = %x in cluster %x / cycle %d\n",
632__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, path,
633GET_PTR(file_xp), GET_CXY(file_xp), hal_time_stamp() );
[238]634
[23]635    // success
636    *new_file_xp = file_xp;
637    *new_file_id = file_id;
638    return 0;
[1]639
[23]640}  // end vfs_open()
641
[407]642//////////////////////////////////////
643int vfs_user_move( bool_t   to_buffer,
644                   xptr_t   file_xp,
645                   void   * buffer,
646                   uint32_t size )
[23]647{
[407]648    assert( ( file_xp != XPTR_NULL ) , __FUNCTION__ , 
649    "file_xp == XPTR_NULL" );
[23]650
651    cxy_t              file_cxy;     // remote file descriptor cluster
652    vfs_file_t       * file_ptr;     // remote file descriptor local pointer
653    vfs_inode_type_t   inode_type;
654    uint32_t           file_offset;  // current offset in file
655    mapper_t         * mapper;
656    error_t            error;
657
658    // get cluster and local pointer on remote file descriptor
659    file_cxy  = GET_CXY( file_xp );
660    file_ptr  = (vfs_file_t *)GET_PTR( file_xp );
661
662    // get inode type from remote file descriptor
663    inode_type = hal_remote_lw( XPTR( file_cxy , &file_ptr->type   ) );
664   
[407]665    assert( (inode_type == INODE_TYPE_FILE) , __FUNCTION__ ,
666    "inode type is not INODE_TYPE_FILE" );
[23]667
[407]668    // get mapper pointer and file offset from file descriptor
669    file_offset = hal_remote_lw( XPTR( file_cxy , &file_ptr->offset ) );
670    mapper = (mapper_t *)hal_remote_lpt( XPTR( file_cxy , &file_ptr->mapper ) );
[23]671
[407]672    // move data between mapper and buffer
673    if( file_cxy == local_cxy )
674    {
675        error = mapper_move_user( mapper,
676                                  to_buffer,
677                                  file_offset,
678                                  buffer,
679                                  size );
[23]680    }
[407]681    else
[23]682    {
[407]683        rpc_mapper_move_buffer_client( file_cxy,
684                                       mapper,
685                                       to_buffer,
686                                       true,          // user buffer
687                                       file_offset,
688                                       (uint64_t)(intptr_t)buffer,
689                                       size,
690                                       &error );
691    } 
692
693    if( error ) return -1;
694    else        return size;
695
[313]696}  // end vfs_user_move()
[23]697
[317]698////////////////////////////////////////////
699error_t vfs_kernel_move( bool_t   to_buffer,
700                         xptr_t   file_xp,
701                         xptr_t   buffer_xp,
702                         uint32_t size )
703{
704    assert( ( file_xp != XPTR_NULL ) , __FUNCTION__ , "file_xp == XPTR_NULL" );
705
706    cxy_t              file_cxy;     // remote file descriptor cluster
707    vfs_file_t       * file_ptr;     // remote file descriptor local pointer
708    vfs_inode_type_t   inode_type;
709    uint32_t           file_offset;  // current offset in file
710    mapper_t         * mapper;
711    error_t            error;
712
713    // get cluster and local pointer on remote file descriptor
714    file_cxy  = GET_CXY( file_xp );
715    file_ptr  = (vfs_file_t *)GET_PTR( file_xp );
716
717    // get inode type from remote file descriptor
718    inode_type = hal_remote_lw( XPTR( file_cxy , &file_ptr->type   ) );
719   
720    // action depends on inode type
721    if( inode_type == INODE_TYPE_FILE )
722    {
723        // get mapper pointer and file offset from file descriptor
724        file_offset = hal_remote_lw( XPTR( file_cxy , &file_ptr->offset ) );
725        mapper = (mapper_t *)hal_remote_lpt( XPTR( file_cxy , &file_ptr->mapper ) );
726
727        // move data between mapper and buffer
728        if( file_cxy == local_cxy )
729        {
730            error = mapper_move_kernel( mapper,
731                                        to_buffer,
732                                        file_offset,
733                                        buffer_xp,
734                                        size );
735        }
736        else
737        {
738            rpc_mapper_move_buffer_client( file_cxy,
739                                           mapper,
740                                           to_buffer,
741                                           false,          // kernel buffer
742                                           file_offset,
743                                           buffer_xp,
744                                           size,
745                                           &error );
746        } 
747
748        if( error ) return -1;
749        else        return 0;
750    }
751    else 
752    {
753        printk("\n[ERROR] in %s : inode is not a file", __FUNCTION__ );
754        return -1;
755    }
756}  // end vfs_kernel_move()
757
[23]758//////////////////////////////////////
759error_t vfs_lseek( xptr_t     file_xp,
760                   uint32_t   offset,
761                   uint32_t   whence, 
762                   uint32_t * new_offset )
763{
[266]764    xptr_t         offset_xp;
765    xptr_t         lock_xp;
766    cxy_t          file_cxy;
767    vfs_file_t  *  file_ptr;
768    vfs_inode_t *  inode_ptr;
769    uint32_t       new;
770
771    assert( (file_xp != XPTR_NULL) , __FUNCTION__ , "file_xp == XPTR_NULL" );
772
773    // get cluster and local pointer on remote file descriptor
774    file_cxy = GET_CXY( file_xp );
775    file_ptr = (vfs_file_t *)GET_PTR( file_xp );
776
777    // build extended pointers on lock and offset
778    offset_xp = XPTR( file_cxy , &file_ptr->offset );
779    lock_xp   = XPTR( file_cxy , &file_ptr->lock );
780
781    // take file descriptor lock
782    remote_rwlock_wr_lock( lock_xp );
783
784    if      ( whence == SEEK_CUR )   // new = current + offset
785    {
786        new = hal_remote_lw( offset_xp ) + offset;
787    }
788    else if ( whence == SEEK_SET )   // new = offset
789    {
790        new = offset;
791    }
792    else if ( whence == SEEK_END )   // new = size + offset
793    { 
794        // get local pointer on remote inode
795        inode_ptr = (vfs_inode_t *)hal_remote_lpt( XPTR( file_cxy , &file_ptr->inode ) );
796
797        new = hal_remote_lw( XPTR( file_cxy , &inode_ptr->size ) ) + offset;
798    }
799    else
800    {
801        printk("\n[ERROR] in %s : illegal whence value\n", __FUNCTION__ );
802        remote_rwlock_wr_unlock( lock_xp );
803        return -1;
804    }
805
806    // set new offset
807    hal_remote_sw( offset_xp , new );
808
809    // release file descriptor lock
810    remote_rwlock_wr_unlock( lock_xp );
811
812    // success
[271]813    if ( new_offset != NULL )
814        *new_offset = new;
[1]815    return 0;
816
[23]817}  // vfs_lseek()
818
819///////////////////////////////////
820error_t vfs_close( xptr_t   file_xp,
821                   uint32_t file_id )
[1]822{
[23]823    assert( (file_xp != XPTR_NULL) , __FUNCTION__ , "file_xp == XPTR_NULL" );
824
825    assert( (file_id < CONFIG_PROCESS_FILE_MAX_NR) , __FUNCTION__ , "illegal file_id" );
826
827    thread_t  * this    = CURRENT_THREAD;
828    process_t * process = this->process;
829
830    // get cluster and local pointer on remote file descriptor
[1]831    cxy_t        file_cxy = GET_CXY( file_xp );
832    vfs_file_t * file_ptr = (vfs_file_t *)GET_PTR( file_xp );
833
[23]834    // get local pointer on local cluster manager
835    cluster_t * cluster = LOCAL_CLUSTER;
836
837    // get owner process cluster and lpid
838    cxy_t   owner_cxy  = CXY_FROM_PID( process->pid );
839    lpid_t  lpid       = LPID_FROM_PID( process->pid );
840
841    // get extended pointers on copies root and lock
842    xptr_t root_xp = XPTR( owner_cxy , &cluster->pmgr.copies_root[lpid] );
843    xptr_t lock_xp = XPTR( owner_cxy , &cluster->pmgr.copies_lock[lpid] );
844
845    // take the lock protecting the copies
846    remote_spinlock_lock( lock_xp );
847
848    // 1) loop on the process descriptor copies to cancel all fd_array[file_id] entries
849    xptr_t  iter_xp;
850    XLIST_FOREACH( root_xp , iter_xp )
[1]851    {
[23]852        xptr_t      process_xp  = XLIST_ELEMENT( iter_xp , process_t , copies_list );
853        cxy_t       process_cxy = GET_CXY( process_xp );
854        process_t * process_ptr = (process_t *)GET_PTR( process_xp );
[1]855
[23]856        xptr_t lock_xp  = XPTR( process_cxy , &process_ptr->fd_array.lock );
857        xptr_t entry_xp = XPTR( process_cxy , &process_ptr->fd_array.array[file_id] );
858
859        // lock is required for atomic write of a 64 bits word
860        remote_rwlock_wr_lock( lock_xp );
861        hal_remote_swd( entry_xp , XPTR_NULL );
862        remote_rwlock_wr_unlock( lock_xp );
863
[124]864        hal_fence();
[23]865    }   
866
867    // 2) release memory allocated to file descriptor in remote cluster
868    if( file_cxy == local_cxy )             // file cluster is local
[1]869    {
[23]870        vfs_file_destroy( file_ptr );
871    }
872    else                                    // file cluster is local
873    {
874        rpc_vfs_file_destroy_client( file_cxy , file_ptr );
875    }
[1]876
[23]877    return 0;
[1]878
[23]879}  // end vfs_close()
[1]880
881////////////////////////////////////
[23]882error_t vfs_unlink( xptr_t   cwd_xp,
883                    char   * path )
[1]884{
[395]885    panic("not implemented");
[1]886    return 0;
[407]887} 
[1]888
[407]889////////////////////////////////////////
890error_t vfs_stat( xptr_t        file_xp,
891                  struct stat * k_stat )
[1]892{
[395]893    panic("not implemented");
[1]894    return 0;
895}
896
[407]897/////////////////////////////////////////////
898error_t vfs_readdir( xptr_t          file_xp,
899                     struct dirent * k_dirent )
[1]900{
[395]901    panic("not implemented");
[1]902    return 0;
903}
904
905//////////////////////////////////////
[23]906error_t vfs_mkdir( xptr_t     file_xp,
907                   char     * path,
908                   uint32_t   mode )
[1]909{
[395]910    panic("not implemented");
[1]911    return 0;
912}
913
[23]914////////////////////////////////////
915error_t vfs_rmdir( xptr_t   file_xp,
916                   char   * path )
[1]917{
[395]918    panic("not implemented");
[1]919    return 0;
920}
921
[23]922///////////////////////////////////
923error_t vfs_chdir( xptr_t   cwd_xp,
924                   char   * path )
[1]925{
[23]926    error_t           error;
927    xptr_t            inode_xp;     // extended pointer on target inode
928    cxy_t             inode_cxy;    // target inode cluster identifier       
929    vfs_inode_t     * inode_ptr;    // target inode local pointer
930    uint32_t          mode;         // lookup working mode       
931    vfs_inode_type_t  inode_type;   // target inode type
932
933    // set lookup working mode
934    mode = 0;
935
936    // get extended pointer on target inode
937    error = vfs_lookup( cwd_xp , path , mode , &inode_xp );
938
939    if( error ) return error;
940
941    // get inode cluster and local pointer
942    inode_cxy = GET_CXY( inode_xp );
943    inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
944
945    // get inode type from remote file
946    inode_type = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->type ) );
947
948    if( inode_type != INODE_TYPE_DIR )
949    {
950        CURRENT_THREAD->errno = ENOTDIR;
951        return -1;
952    }
953
[395]954    panic("not fully implemented");
[1]955    return 0;
956}
957
[23]958///////////////////////////////////
959error_t vfs_chmod( xptr_t   cwd_xp,
960                   char   * path,
961                   uint32_t rights )
[1]962{
[23]963    error_t           error;
964    xptr_t            inode_xp;     // extended pointer on target inode
965    cxy_t             inode_cxy;    // inode cluster identifier       
966    vfs_inode_t     * inode_ptr;    // inode local pointer
967    uint32_t          mode;         // lookup working mode
968    vfs_inode_type_t  inode_type;   // target inode type
969
970    // set lookup working mode
971    mode = 0;
972 
973    // get extended pointer on target inode
974    error = vfs_lookup( cwd_xp , path , mode , &inode_xp );
975
976    if( error ) return error;
977
978    // get inode cluster and local pointer
979    inode_cxy = GET_CXY( inode_xp );
980    inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
981   
982    // get inode type from remote inode
983    inode_type = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->type ) );
984
985   
[395]986    panic("not fully implemented");
[1]987    return 0;
988}
989
[23]990///////////////////////////////////
991error_t vfs_mkfifo( xptr_t   cwd_xp,
992                    char   * path,
993                    uint32_t rights )
994{
[395]995    panic("not implemented");
[23]996    return 0;
997}
[1]998
999
1000
[188]1001//////////////////////////////////////////////////////////////////////////////////////////
[1]1002//            Inode Tree functions
1003//////////////////////////////////////////////////////////////////////////////////////////
1004
[188]1005/////////////////////////////////
1006cxy_t vfs_cluster_random_select()
1007{
1008    uint32_t  x_size    = LOCAL_CLUSTER->x_size;
1009    uint32_t  y_size    = LOCAL_CLUSTER->y_size;
1010    uint32_t  y_width   = LOCAL_CLUSTER->y_width;
1011    uint32_t  index     = ( hal_get_cycles() + hal_get_gid() ) % (x_size * y_size);
1012    uint32_t  x         = index / y_size;   
1013    uint32_t  y         = index % y_size;
1014
1015    return (x<<y_width) + y;
1016}
1017
1018
1019//////////////////////////////////////////////////////////////////////////
1020// This static function is called by the vfs_display() function.
[337]1021// that is supposed to take the TXT0 lock.
[188]1022//////////////////////////////////////////////////////////////////////////
1023static void vfs_recursive_display( xptr_t   inode_xp,
1024                                   xptr_t   name_xp,
[204]1025                                   xptr_t   dentry_xp,
[188]1026                                   uint32_t indent )
1027{
1028    cxy_t              inode_cxy;
1029    vfs_inode_t      * inode_ptr;
1030    vfs_inode_type_t   inode_type;
[204]1031    xptr_t             children_xp;    // extended pointer on children xhtab
[188]1032
[204]1033    xptr_t             child_dentry_xp;
1034    cxy_t              child_dentry_cxy;
1035    vfs_dentry_t     * child_dentry_ptr;
1036    xptr_t             child_inode_xp;
1037    xptr_t             child_dentry_name_xp;
[188]1038
1039    char               name[CONFIG_VFS_MAX_NAME_LENGTH];
1040
1041    char *             indent_str[] = { "",                                  // level 0
1042                                        "  ",                                // level 1
1043                                        "    ",                              // level 2
1044                                        "      ",                            // level 3
1045                                        "        ",                          // level 4
1046                                        "          ",                        // level 5
1047                                        "            ",                      // level 6
1048                                        "              ",                    // level 7
1049                                        "                ",                  // level 8
1050                                        "                  ",                // level 9
1051                                        "                    ",              // level 10
1052                                        "                      ",            // level 11
1053                                        "                        ",          // level 12
1054                                        "                          ",        // level 13
1055                                        "                            ",      // level 14
1056                                        "                              " };  // level 15
1057
1058    assert( (inode_xp != XPTR_NULL) , __FUNCTION__ , "inode_xp cannot be NULL\n" );
1059    assert( (name_xp  != XPTR_NULL) , __FUNCTION__ , "name_xp cannot be NULL\n" );
1060    assert( (indent < 16)           , __FUNCTION__ , "depth cannot be larger than 15\n" );
1061   
1062    // get inode cluster and local pointer
1063    inode_cxy = GET_CXY( inode_xp );
1064    inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
1065
1066    // get inode type
1067    inode_type = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->type ) );
1068
[367]1069    // get local pointer on associated mapper
1070    mapper_t * mapper_ptr = hal_remote_lpt( XPTR( inode_cxy , &inode_ptr->mapper ) );
1071
[188]1072    // make a local copy of node name
1073    hal_remote_strcpy( XPTR( local_cxy , name ) , name_xp );
1074
1075    // display inode
[407]1076    nolock_printk("%s%s <%s> : inode = %x / mapper = %x / cluster %x\n",
[367]1077                  indent_str[indent], vfs_inode_type_str( inode_type ), name,
[407]1078                  inode_ptr , mapper_ptr , inode_cxy );
[188]1079
1080    // scan directory entries 
1081    if( inode_type == INODE_TYPE_DIR )
1082    {
1083        // get extended pointer on directory entries xhtab
[204]1084        children_xp =  XPTR( inode_cxy , &inode_ptr->children );
[188]1085
1086        // get xhtab lock
[204]1087        xhtab_read_lock( children_xp );
[188]1088
1089        // get first dentry from xhtab
[204]1090        child_dentry_xp = xhtab_get_first( children_xp );
[188]1091
[204]1092        while( child_dentry_xp != XPTR_NULL )
[188]1093        {
1094            // get dentry cluster and local pointer
[204]1095            child_dentry_cxy = GET_CXY( child_dentry_xp );
1096            child_dentry_ptr = (vfs_dentry_t *)GET_PTR( child_dentry_xp );
[188]1097
1098            // get extended pointer on child inode
[204]1099            child_inode_xp = hal_remote_lwd( XPTR( child_dentry_cxy,
1100                                                   &child_dentry_ptr->child_xp ) );
[188]1101
1102            // get extended pointer on dentry name
[204]1103            child_dentry_name_xp = XPTR( child_dentry_cxy , &child_dentry_ptr->name );
[188]1104
1105            // recursive call on child inode
[204]1106            vfs_recursive_display( child_inode_xp,
1107                                   child_dentry_name_xp,
1108                                   child_dentry_xp,
1109                                   indent+1 );
[188]1110
1111            // get next dentry
[204]1112            child_dentry_xp = xhtab_get_next( children_xp );
[188]1113        }
1114
1115        // release xhtab lock
[204]1116        xhtab_read_unlock( children_xp );
[188]1117    }
1118}  // end vfs_recursive_display()
1119
1120///////////////////////////////////
1121void vfs_display( xptr_t inode_xp )
1122{
[204]1123    xptr_t         name_xp;
[188]1124    xptr_t         dentry_xp; 
1125    cxy_t          dentry_cxy;
1126    vfs_dentry_t * dentry_ptr;
[337]1127    uint32_t       save_sr;
[188]1128
1129    // get target inode cluster and local pointer
1130    cxy_t         inode_cxy = GET_CXY( inode_xp );
1131    vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
1132
1133    // get extended pointer on associated dentry
[367]1134    dentry_xp   = hal_remote_lwd( XPTR( inode_cxy , &inode_ptr->parent_xp ) );
[188]1135
1136    // check if target inode is the File System root
1137    if( dentry_xp == XPTR_NULL )
1138    {
1139        // build extended pointer on root name
1140        name_xp = XPTR( local_cxy , "/" );
1141    }
1142    else
1143    {
1144        // get dentry cluster and local pointer
1145        dentry_cxy = GET_CXY( dentry_xp );
1146        dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
1147
1148        // get extended pointer on dentry name
1149        name_xp = XPTR( dentry_cxy , &dentry_ptr->name );
1150    }
1151
[337]1152    // get pointers on TXT0 chdev
[407]1153    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
[337]1154    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
1155    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
1156
1157    // get extended pointer on remote TXT0 chdev lock
1158    xptr_t  lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
1159
1160    // get TXT0 lock in busy waiting mode
1161    remote_spinlock_lock_busy( lock_xp , &save_sr );
1162
[188]1163    // print header
[401]1164    nolock_printk("\n***** file system state\n\n");
[188]1165
1166    // call recursive function
[204]1167    vfs_recursive_display( inode_xp , name_xp , dentry_xp , 0 );
[188]1168
[337]1169    // release lock
1170    remote_spinlock_unlock_busy( lock_xp , save_sr );
1171
[204]1172}  // end vfs_display()
[188]1173
[1]1174//////////////////////////////////////////////////////////////////////////////////////////
[23]1175// This function is used by the vfs_lookup() function.
[1]1176// It takes an extended pointer on a remote inode (parent directory inode),
1177// and check access_rights violation for the calling thread.
1178// It can be used by any thread running in any cluster.
1179//////////////////////////////////////////////////////////////////////////////////////////
1180// @ inode_xp    : extended pointer on inode.
1181// @ client_uid  : client thread user ID
1182// @ client_gid  : client thread group ID
1183// @ return true if access rights are violated.
1184//////////////////////////////////////////////////////////////////////////////////////////
1185bool_t vfs_access_denied( xptr_t   inode_xp,
1186                          uint32_t client_uid,
1187                          uint32_t client_gid )
1188{
1189    // get found inode cluster and local pointer
1190    cxy_t         inode_cxy = GET_CXY( inode_xp );
1191    vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
1192
1193    // get inode access mode, UID, and GID
1194    // TODO uint32_t  mode = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->mode ) );
1195    uid_t     uid  = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->uid  ) );
1196    gid_t     gid  = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->gid  ) );
1197
1198    // FIXME : me must use mode
1199    if( (uid == client_uid) || (gid == client_gid) ) return false;
1200    else                                             return true;
1201}
1202
1203//////////////////////////////////////////////////////////////////////////////////////////
1204// This static function is used by the vfs_lookup() function.
[204]1205// It takes an extended pointer on a remote parent directory inode, a directory
[1]1206// entry name, and returns an extended pointer on the child inode.
1207// It can be used by any thread running in any cluster.
1208//////////////////////////////////////////////////////////////////////////////////////////
1209// @ parent_xp   : extended pointer on parent inode in remote cluster.
1210// @ name        : dentry name
1211// @ child_xp    : [out] buffer for extended pointer on child inode.
1212// @ return true if success / return false if not found.
1213//////////////////////////////////////////////////////////////////////////////////////////
1214static bool_t vfs_get_child( xptr_t   parent_xp,
1215                             char   * name,
1216                             xptr_t * child_xp )
1217{
1218    xptr_t  xhtab_xp;    // extended pointer on hash table containing children dentries
1219    xptr_t  dentry_xp;   // extended pointer on children dentry
1220
1221    // get parent inode cluster and local pointer
1222    cxy_t         parent_cxy = GET_CXY( parent_xp );
1223    vfs_inode_t * parent_ptr = (vfs_inode_t *)GET_PTR( parent_xp );
1224
1225    // get extended pointer on hash table of children directory entries
1226    xhtab_xp = XPTR( parent_cxy , &parent_ptr->children );
1227
1228    // search extended pointer on matching dentry
1229    dentry_xp = xhtab_lookup( xhtab_xp , name );
1230
1231    if( dentry_xp == XPTR_NULL ) return false;
1232
1233    // get dentry cluster and local pointer
1234    cxy_t          dentry_cxy = GET_CXY( dentry_xp );
1235    vfs_dentry_t * dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
1236
1237    // return child inode
[101]1238    *child_xp = (xptr_t)hal_remote_lwd( XPTR( dentry_cxy , &dentry_ptr->child_xp ) );
[1]1239    return true;
1240
[204]1241}  // end vfs_get_child()
1242
[1]1243//////////////////////////////////////////////////////////////////////////////////////////
1244// This static function is used by the vfs_lookup() function.
1245// It takes the <current> pointer on a buffer containing a complete pathname, and return
1246// in the <name> buffer, allocated by the caller, a single name in the path.
1247// It return also in the <next> pointer the next character to analyse in the path.
1248// Finally it returns a <last> boolean, that is true when the returned <name> is the
1249// last name in the path. The names are supposed to be separated by one or several '/'
1250// characters, that are not written in  the <name> buffer.
1251//////////////////////////////////////////////////////////////////////////////////////////
1252// @ current   : pointer on first character to analyse in buffer containing the path.
1253// @ name      : [out] pointer on buffer allocated by the caller for the returned name.
1254// @ next      : [out] pointer on next character to analyse in buffer containing the path.
1255// @ last      : [out] true if the returned name is the last (NUL character found).
1256// @ return 0 if success / return EINVAL if string empty (first chracter is NUL).
1257//////////////////////////////////////////////////////////////////////////////////////////
1258static error_t vfs_get_name_from_path( char     * current,
1259                                       char     * name,
1260                                       char    ** next,
1261                                       bool_t   * last )
1262{
1263    char * ptr = current;
1264
1265    // skip leading '/' characters
1266    while( *ptr == '/' ) ptr++;
1267
1268    // return EINVAL if string empty
1269    if( *ptr == 0 ) return EINVAL;
1270
1271    // copy all characters in name until NUL or '/'
1272    while( (*ptr != 0) && (*ptr !='/') )  *(name++) = *(ptr++);
1273
[204]1274    // set NUL terminating character in name buffer
1275    *(name++) = 0;
1276
[1]1277    // return last an next
1278    if( *ptr == 0 )             // last found character is NUL => last name in path
1279    {
1280        *last = true;
1281    }
1282    else                        // last found character is '/' => skip it
1283    {
1284        *last = false;
1285        *next = ptr + 1;
1286    }
1287
1288    return 0;
[204]1289
1290}  // end vfs_get name_from_path()
[188]1291   
[23]1292//////////////////////////////////////////////
1293error_t vfs_lookup( xptr_t             cwd_xp,
1294                    char             * pathname,
1295                    uint32_t           mode,
1296                                        xptr_t           * inode_xp )
[1]1297{
[101]1298    char               name[CONFIG_VFS_MAX_NAME_LENGTH];   // one name in path
[1]1299
[23]1300    xptr_t             parent_xp;    // extended pointer on parent inode
1301    cxy_t              parent_cxy;   // cluster for parent inode
1302    vfs_inode_t      * parent_ptr;   // local pointer on parent inode 
1303    xptr_t             child_xp;     // extended pointer on child inode
1304    cxy_t              child_cxy;    // cluster for child inode
1305    vfs_inode_t      * child_ptr;    // local pointer on child inode 
[238]1306    vfs_inode_type_t   child_type;   // child inode type
[23]1307    vfs_fs_type_t      fs_type;      // File system type
1308    vfs_ctx_t        * ctx_ptr;      // local pointer on FS context
1309    char             * current;      // current pointer on path
1310    char             * next;         // next value for current pointer   
1311    bool_t             last;         // true when the name is the last in path
1312    bool_t             found;        // true when a child has been found
1313    thread_t         * this;         // pointer on calling thread descriptor
1314    process_t        * process;      // pointer on calling process descriptor
1315    error_t            error;
[1]1316
1317    this    = CURRENT_THREAD;
1318    process = this->process;
1319
[407]1320vfs_dmsg("\n[DBG] %s : core[%x,%d] enter for <%s> / cycle %d\n",
1321__FUNCTION__ , local_cxy , this->core->lid , pathname , hal_time_stamp() );
[380]1322
[1]1323    // get extended pointer on first inode to search
1324    if( pathname[0] == '/' ) parent_xp = process->vfs_root_xp;
1325    else                     parent_xp = cwd_xp;
1326
[101]1327    // initialise other loop variables
[1]1328    current  = pathname;
1329    next     = NULL;
1330    last     = false;
1331    child_xp = XPTR_NULL;
1332
1333    // take lock on parent inode
[101]1334    vfs_inode_lock( parent_xp );
[1]1335
[401]1336    // sequencially loop on nodes in pathname
1337    // load from device if one node not found in inode tree
1338    // exit loop when last name found (i.e. last == true)
[1]1339    do
1340    {
[401]1341        // get one name from path, and "last" flag
[1]1342        vfs_get_name_from_path( current , name , &next , &last );
1343
[407]1344vfs_dmsg("\n[DBG] %s : core[%x,%d] look for <%s> / last = %d\n",
1345__FUNCTION__ , local_cxy , this->core->lid , name , last );
[101]1346
[204]1347        // search a child dentry matching name in parent inode
[1]1348        found = vfs_get_child( parent_xp,
1349                               name,
1350                               &child_xp );
1351
[238]1352        // if a child inode is not found in the inode tree:
1353        // - we create the missing inode/dentry couple in the inode tree,
1354        // - we scan the parent mapper to complete the child inode (type and extension),
1355        // - we return an error if child not found on device.
1356        // - if the missing child is a directory, we load the child mapper from device
1357
1358        // for the last name, the behaviour depends on the "mode" argument:
1359
[246]1360        if (found == false ) // child node not found in inode tree
[1]1361        {
[101]1362
[407]1363vfs_dmsg("\n[DBG] %s : core[%x,%d] miss <%s> => load it\n",
1364__FUNCTION__ , local_cxy , this->core->lid , name );
1365
[1]1366            // release lock on parent inode
[101]1367            vfs_inode_unlock( parent_xp );
[1]1368
[238]1369            // get parent inode FS type
[23]1370            parent_cxy = GET_CXY( parent_xp );
1371            parent_ptr = (vfs_inode_t *)GET_PTR( parent_xp );
[401]1372            ctx_ptr    = (vfs_ctx_t *)hal_remote_lpt( XPTR( parent_cxy , &parent_ptr->ctx ) );
[238]1373            fs_type    = hal_remote_lw( XPTR( parent_cxy , &ctx_ptr->type ) );
[23]1374
[238]1375            // select a cluster for missing inode
1376            child_cxy = vfs_cluster_random_select();
[401]1377 
[188]1378            // insert a new child dentry/inode in parent inode
1379            error = vfs_add_child_in_parent( child_cxy,
[238]1380                                             INODE_TYPE_DIR,
[23]1381                                             fs_type, 
1382                                             parent_xp, 
[222]1383                                             name, 
[238]1384                                             NULL,     // fs_type_specific inode extend
[23]1385                                             &child_xp );
[1]1386            if( error )
1387            {
[407]1388                printk("\n[ERROR] in %s : no memory for inode <%s> in path <%s>\n",
[380]1389                __FUNCTION__ , name , pathname );
[238]1390                return ENOMEM;
1391            }
1392
1393            // scan parent mapper to complete the missing inode
1394            if( parent_cxy == local_cxy )
1395            {
1396                error = vfs_inode_load( parent_ptr,
1397                                        name,
1398                                        child_xp );
1399            }
1400            else
1401            {
1402                rpc_vfs_inode_load_client( parent_cxy,
1403                                           parent_ptr,
1404                                           name,
1405                                           child_xp,
1406                                           &error );
1407            }
1408
1409            if ( error )
1410            {
[407]1411                printk("\n[ERROR] in %s : core[%x,%d] / <%s> node not found in <%s>\n",
1412                __FUNCTION__ , local_cxy , this->core->lid , name , pathname );
[1]1413                return ENOENT;
1414            }
1415
[238]1416            // get child inode type
1417            child_ptr  = (vfs_inode_t *)GET_PTR( child_xp );
1418            child_type = hal_remote_lw( XPTR( child_cxy , &child_ptr->type ) );
1419
1420            // load child mapper from device if it is a directory
1421            if( child_type == INODE_TYPE_DIR )
1422            {
1423                if( child_cxy == local_cxy )
1424                {
1425                    error = vfs_mapper_load_all( child_ptr );
1426                }
1427                else
1428                {
1429                    rpc_vfs_mapper_load_all_client( child_cxy,
1430                                                    child_ptr,
1431                                                    &error );
1432                }
1433
1434                if ( error )
1435                {
[380]1436                    printk("\n[ERROR] in %s : core[%x,%d] cannot access device for <%s>\n",
1437                    __FUNCTION__ , local_cxy , this->core->lid , name );
[238]1438                    return EIO;
1439                }
1440            }
1441
1442            // TODO handle lookup mode here [AG]
1443
[1]1444            // take lock on parent inode
[101]1445            vfs_inode_lock( parent_xp );
[401]1446
[407]1447vfs_dmsg("\n[DBG] %s : core[%x,%d] created node <%s>\n",
1448__FUNCTION__ , local_cxy , this->core->lid , name );
1449
[1]1450        }
1451
[407]1452vfs_dmsg("\n[DBG] %s : core[%x,%d] found <%s> / inode = %x in cluster %x\n",
1453__FUNCTION__ , local_cxy , this->core->lid , name , GET_PTR(child_xp) , GET_CXY(child_xp) );
[101]1454
[380]1455        // TODO check access rights here [AG]
[23]1456        // error = vfs_access_denied( child_xp,
1457        //                            client_uid,
1458        //                            client_gid );
1459        // if( error )
1460        // {
1461        //     printk("\n[ERROR] in %s : permission denied for %s\n", __FUNCTION__ , name );
1462        //     return EACCES;
1463        // }
[1]1464
[238]1465        // take lock on child inode and release lock on parent
1466        vfs_inode_lock( child_xp );
[101]1467        vfs_inode_unlock( parent_xp );
[1]1468
1469        // update loop variables
1470        parent_xp = child_xp;
1471        current   = next;
1472    }
1473    while( last == false );
1474
[238]1475    // release lock
1476    vfs_inode_unlock( parent_xp );
[1]1477
[407]1478vfs_dmsg("\n[DBG] %s : core[%x,%d] exit for <%s> / inode = %x in cluster %x\n",
1479__FUNCTION__,local_cxy,this->core->lid,pathname,GET_PTR(child_xp),GET_CXY(child_xp) );
[1]1480
[238]1481    // return searched pointer
[1]1482    *inode_xp = child_xp;
1483
1484    return 0;
1485
1486}  // end vfs_lookup()
1487
1488////////////////////////////////////////////
1489error_t vfs_get_path( xptr_t    searched_xp,
1490                      char    * buffer,
1491                      uint32_t  max_size )
1492{
1493        xptr_t       dentry_xp;   // extended pointer on current dentry
1494    char       * name;        // local pointer on current dentry name
1495        uint32_t     length;      // length of current dentry name
1496        uint32_t     count;       // number of characters written in buffer
1497        uint32_t     index;       // slot index in buffer
[23]1498    xptr_t       inode_xp;    // extended pointer on   
[1]1499
1500    // implementation note:
1501    // we use two variables "index" and "count" because the buffer
[401]1502    // is written in decreasing index order (from leaf to root)
1503    // TODO : handle conflict with a concurrent rename [AG]
1504    // TODO : handle synchro in the loop  [AG]
[1]1505
1506        // set the NUL character in buffer / initialise buffer index and count
1507        buffer[max_size - 1] = 0;
1508        count    = 1;
1509    index    = max_size - 2;
1510
1511    // initialize current inode
1512    inode_xp  = searched_xp;
1513
1514    // exit when root inode found (i.e. dentry_xp == XPTR_NULL)
1515        do
1516    {
1517        // get inode cluster and local pointer
1518        cxy_t         inode_cxy = GET_CXY( inode_xp );
1519        vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
1520
1521        // get extended pointer on parent dentry               
1522        dentry_xp = (xptr_t)hal_remote_lwd( XPTR( inode_cxy , inode_ptr->parent_xp ) );
1523
1524        // get dentry cluster and local pointer
1525        cxy_t          dentry_cxy = GET_CXY( dentry_xp );
1526        vfs_dentry_t * dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
1527
1528        // get dentry name length and pointer
1529        length =  hal_remote_lw( XPTR( dentry_cxy , &dentry_ptr->length ) );
1530        name   = (char *)hal_remote_lpt( XPTR( dentry_cxy , &dentry_ptr->name ) );
1531
1532        // update index and count
1533        index -= (length + 1); 
1534        count += (length + 1);
1535
1536        // check buffer overflow
1537        if( count >= max_size )
1538        {
1539            printk("\n[ERROR] in %s : kernel buffer too small\n", __FUNCTION__ );
1540            return EINVAL;
1541        }
1542
1543        // update pathname
1544        hal_remote_memcpy( XPTR( local_cxy , &buffer[index + 1] ) ,
1545                           XPTR( dentry_cxy , name ) , length );
1546                buffer[index] = '/';
1547
1548                // get extended pointer on next inode
1549        inode_xp = (xptr_t)hal_remote_lwd( XPTR( dentry_cxy , dentry_ptr->parent ) );
1550    }
1551    while( (dentry_xp != XPTR_NULL) );
1552
1553        return 0;
1554
1555}  // end vfs_get_path()
1556
[188]1557     
1558//////////////////////////////////////////////////////////////
1559error_t vfs_add_child_in_parent( cxy_t              child_cxy,
1560                                 vfs_inode_type_t   inode_type,
[23]1561                                 vfs_fs_type_t      fs_type,
1562                                 xptr_t             parent_xp,
1563                                 char             * name,
[188]1564                                 void             * extend,
[23]1565                                 xptr_t           * child_xp )
[1]1566{
[23]1567    error_t         error;
1568    xptr_t          dentry_xp;   // extended pointer on created dentry
1569    xptr_t          inode_xp;    // extended pointer on created inode
1570    cxy_t           parent_cxy;  // parent inode cluster identifier
1571    vfs_inode_t   * parent_ptr;  // parent inode local pointer
[1]1572
1573    // get parent inode cluster and local pointer
[23]1574    parent_cxy = GET_CXY( parent_xp );
1575    parent_ptr = (vfs_inode_t *)GET_PTR( parent_xp );
[1]1576
[407]1577vfs_dmsg("\n[DBG] %s : core[%x,%d] enter for <%s> / child_cxy = %x / parent_cxy = %x\n",
1578__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , name , child_cxy , parent_cxy );
[279]1579
[204]1580    // 1. create dentry
[1]1581    if( parent_cxy == local_cxy )      // parent cluster is the local cluster
1582    {
[23]1583        error = vfs_dentry_create( fs_type,
[1]1584                                   name,
1585                                   parent_ptr,
1586                                   &dentry_xp );
[279]1587
[407]1588vfs_dmsg("\n[DBG] %s : dentry <%s> created in local cluster %x\n",
1589__FUNCTION__ , name , local_cxy );
1590
[1]1591    }
1592    else                               // parent cluster is remote
1593    {
1594        rpc_vfs_dentry_create_client( parent_cxy,
[23]1595                                      fs_type,
[1]1596                                      name,
1597                                      parent_ptr,
1598                                      &dentry_xp,
1599                                      &error );
[279]1600
[407]1601vfs_dmsg("\n[DBG] %s : dentry <%s> created in remote cluster %x\n",
1602__FUNCTION__ , name , parent_cxy );
1603
[1]1604    }
1605                                     
1606    if( error )
1607    {
1608        printk("\n[ERROR] in %s : cannot create dentry in cluster %x\n",
[407]1609        __FUNCTION__ , parent_cxy );
[204]1610        return ENOMEM;
[1]1611    }
1612
[204]1613    // 2. create child inode TODO : define attr / mode / uid / gid
[1]1614    uint32_t attr = 0;
1615    uint32_t mode = 0;
1616    uint32_t uid  = 0;
1617    uint32_t gid  = 0;
1618   
1619    if( child_cxy == local_cxy )      // child cluster is the local cluster
1620    {
1621        error = vfs_inode_create( dentry_xp,
[23]1622                                  fs_type,
1623                                  inode_type,
[188]1624                                  extend,
[1]1625                                  attr,
1626                                  mode,
1627                                  uid,
1628                                  gid,
1629                                  &inode_xp );
[279]1630
[407]1631vfs_dmsg("\n[DBG] %s : inode %x created in local cluster %x\n",
1632__FUNCTION__ , GET_PTR(inode_xp) , local_cxy );
1633
[1]1634    }
1635    else                              // child cluster is remote
1636    {
1637        rpc_vfs_inode_create_client( child_cxy,
1638                                     dentry_xp,
[23]1639                                     fs_type,
1640                                     inode_type,
[188]1641                                     extend,
[1]1642                                     attr,
1643                                     mode,
1644                                     uid,
1645                                     gid,
1646                                     &inode_xp,
1647                                     &error );
[279]1648
[407]1649vfs_dmsg("\n[DBG] %s : inode %x created in remote cluster %x\n",
1650__FUNCTION__ , GET_PTR(inode_xp) , child_cxy );
1651
[1]1652    }
1653                                     
1654    if( error )
1655    {
1656        printk("\n[ERROR] in %s : cannot create inode in cluster %x\n",
1657               __FUNCTION__ , child_cxy );
1658 
1659        vfs_dentry_t * dentry = (vfs_dentry_t *)GET_PTR( dentry_xp );
1660        if( parent_cxy == local_cxy ) vfs_dentry_destroy( dentry );
1661        else rpc_vfs_dentry_destroy_client( parent_cxy , dentry );
[204]1662        return ENOMEM;
[1]1663    }
1664
[204]1665    // 3. update extended pointer on inode in dentry
1666    cxy_t          dentry_cxy = GET_CXY( dentry_xp );
1667    vfs_dentry_t * dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
1668    hal_remote_swd( XPTR( dentry_cxy , &dentry_ptr->child_xp ) , inode_xp );
1669
[407]1670vfs_dmsg("\n[DBG] %s : exit in cluster %x for <%s>\n",
1671__FUNCTION__ , local_cxy , name );
[296]1672
[1]1673    // success : return extended pointer on child inode
1674    *child_xp = inode_xp;
1675    return 0;
1676
1677}  // end vfs_add_child_in_parent()
1678
[23]1679//////////////////////////////////////////////////////////////////////////////////////////
1680//            Mapper related functions
1681//////////////////////////////////////////////////////////////////////////////////////////
1682
[238]1683////////////////////////////////////////////
1684error_t vfs_mapper_move_page( page_t * page,
1685                              bool_t   to_mapper )
[23]1686{
[204]1687    error_t error = 0;
[23]1688
1689    assert( (page != NULL) , __FUNCTION__ , "page pointer is NULL\n" );
1690
[246]1691    mapper_t    * mapper = page->mapper;
[23]1692
1693    assert( (mapper != NULL) , __FUNCTION__ , "no mapper for page\n" );
1694
[407]1695vfs_dmsg("\n[DBG] %s : core[%x,%d] enters for page %d / mapper = %x / inode = %x\n",
1696__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid , page->index , mapper, mapper->inode );
[246]1697
[23]1698    // get FS type
[246]1699    vfs_fs_type_t fs_type = mapper->type;
[23]1700
[238]1701    // call relevant FS function
[23]1702    if( fs_type == FS_TYPE_FATFS )
1703    {
1704        rwlock_wr_lock( &mapper->lock );
[246]1705        error = fatfs_mapper_move_page( page , to_mapper ); 
[23]1706        rwlock_wr_unlock( &mapper->lock );
1707    }
1708    else if( fs_type == FS_TYPE_RAMFS )
1709    {
1710        assert( false , __FUNCTION__ , "should not be called for RAMFS\n" );
1711    }
1712    else if( fs_type == FS_TYPE_DEVFS )
1713    {
1714        assert( false , __FUNCTION__ , "should not be called for DEVFS\n" );
1715    }
1716    else
1717    {
1718        assert( false , __FUNCTION__ , "undefined file system type\n" );
1719    }
1720
[407]1721vfs_dmsg("\n[DBG] %s : core[%x,%d] exit for page %d / mapper = %x / inode = %x\n",
1722__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, page->index, mapper, mapper->inode );
[246]1723
[23]1724    return error;
1725
[238]1726}  // end vfs_move_page()
[23]1727
1728//////////////////////////////////////////////////
[238]1729error_t vfs_mapper_load_all( vfs_inode_t * inode )
[23]1730{
[265]1731    assert( (inode != NULL) , __FUNCTION__ , "inode pointer is NULL\n" );
[23]1732
[238]1733    uint32_t   index;
1734    page_t   * page;
[23]1735
[238]1736    mapper_t * mapper = inode->mapper;
1737    uint32_t   size   = inode->size;
[23]1738
[265]1739    assert( (mapper != NULL) , __FUNCTION__ , "mapper pointer is NULL\n" );
[23]1740
[407]1741vfs_dmsg("\n[DBG] %s : core[%x,%d] enter for inode %x in cluster %x/ cycle %d\n",
1742__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, inode , local_cxy , hal_time_stamp() );
[401]1743
1744    // compute number of pages
[238]1745    uint32_t npages = size >> CONFIG_PPM_PAGE_SHIFT;
[265]1746    if( (size & CONFIG_PPM_PAGE_MASK) || (size == 0) ) npages++;
[238]1747
[265]1748    // loop on pages
[238]1749    for( index = 0 ; index < npages ; index ++ )
[23]1750    {
[238]1751        // this function allocates the missing page in mapper,
1752        // and call the vfs_mapper_move_page() to load the page from device
1753        page = mapper_get_page( mapper , index );
[23]1754
[238]1755        if( page == NULL ) return EIO;
[23]1756    }
1757
[407]1758vfs_dmsg("\n[DBG] %s : core[%x,%d] exit for inode %x in cluster %x / cycle %d\n",
1759__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, inode , local_cxy , hal_time_stamp() );
[401]1760
[238]1761    return 0;
[23]1762
[238]1763}  // end vfs_mapper_load_all()
[23]1764
Note: See TracBrowser for help on using the repository browser.