source: trunk/kernel/vfs/vfs.c @ 271

Last change on this file since 271 was 271, checked in by max@…, 7 years ago

new_offset can be NULL

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