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

Last change on this file since 12 was 10, checked in by alain, 8 years ago

Merge all FS related files in one single directory.

File size: 30.9 KB
Line 
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
26#include <almos_config.h>
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>
37#include <errno.h>
38#include <kmem.h>
39#include <mapper.h>
40#include <thread.h>
41#include <process.h>
42#include <fatfs.h>
43#include <ramfs.h>
44#include <vfs.h>
45
46
47//////////////////////////////////////////////////////////////////////////////////////////
48//           Global variables         
49//////////////////////////////////////////////////////////////////////////////////////////
50
51// array of supported FS contexts (indexed by the FS type)
52vfs_ctx_t   fs_context[FS_TYPES_NR];
53
54//////////////////////////////////////////////////////////////////////////////////////////
55//           Context related functions
56//////////////////////////////////////////////////////////////////////////////////////////
57
58/////////////////////////////////////////////////
59error_t vfs_ctx_inum_alloc( vfs_ctx_t * ctx,
60                            uint32_t  * inum )
61{
62    // get lock on inum allocator
63    spinlock_lock( &ctx->lock );
64
65    // get lid from local inum allocator
66    uint32_t lid = bitmap_ffc( ctx->inum , CONFIG_VFS_MAX_INODES );
67
68    if( lid == -1 )   // no more free slot => error
69    {
70        // release lock
71        spinlock_unlock( &ctx->lock );
72
73        // return error
74        return 1;
75    }
76    else              // found => return inum
77    {
78        // set slot allocated
79        bitmap_set( ctx->inum , lid );
80
81        // release lock
82        spinlock_unlock( &ctx->lock );
83
84        // return inum
85        *inum = (((uint32_t)local_cxy) << 16) | (lid & 0xFFFF);
86        return 0;
87    }
88}
89
90////////////////////////////////////////////
91void vfs_ctx_inum_release( vfs_ctx_t * ctx,
92                           uint32_t    inum )
93{
94    bitmap_clear( ctx->inum , inum & 0xFFFF ); 
95}
96
97//////////////////////////////////////////////////////////////////////////////////////////
98//           Inode related functions
99//////////////////////////////////////////////////////////////////////////////////////////
100
101////////////////////////////////////////////////
102error_t vfs_inode_create( xptr_t      dentry_xp,
103                          uint32_t    type,
104                          uint32_t    attr,
105                          uint32_t    mode,
106                          uid_t       uid,
107                          gid_t       gid,
108                          xptr_t    * inode_xp )
109{
110    mapper_t         * mapper;     // associated mapper( to be allocated)
111    vfs_inode_t      * inode;      // inode descriptor (to be allocated)
112    uint32_t           inum;       // inode identifier (to be allocated)
113    vfs_ctx_t        * ctx;        // file system context
114        kmem_req_t         req;        // request to kernel memory allocator
115    error_t            error;
116
117    // check type and get pointer on context
118    if     ( type == FS_TYPE_FATFS ) ctx = &fs_context[FS_TYPE_FATFS];
119    else if( type == FS_TYPE_RAMFS ) ctx = &fs_context[FS_TYPE_RAMFS];
120    else
121    {
122        ctx = NULL;
123        printk("\n[PANIC] in %s : undefined file system type\n", __FUNCTION__ );
124        hal_core_sleep();
125    }
126
127    // allocate inum
128    error = vfs_ctx_inum_alloc( ctx , &inum );
129
130    if( error )
131    {
132        printk("\n[ERROR] in %s : cannot allocate inum\n", __FUNCTION__ );
133        return ENOMEM;
134    }
135
136    // allocate memory for mapper
137    mapper = mapper_create();
138
139    if( mapper == NULL )
140    {
141        printk("\n[ERROR] in %s : cannot allocate mapper\n", __FUNCTION__ );
142        vfs_ctx_inum_release( ctx , inum );
143        return ENOMEM;
144    }
145
146    // allocate memory for inode descriptor
147        req.type  = KMEM_VFS_INODE;
148        req.size  = sizeof(vfs_inode_t);
149    req.flags = AF_KERNEL | AF_ZERO;
150        inode     = (vfs_inode_t *)kmem_alloc( &req );
151
152    if( inode == NULL )
153    {
154        printk("\n[ERROR] in %s : cannot allocate inode descriptor\n", __FUNCTION__ );
155        vfs_ctx_inum_release( ctx , inum );
156        mapper_destroy( mapper );
157        return ENOMEM;
158    }
159
160    // initialize inode descriptor
161    inode->gc         = 0;
162    inode->inum       = inum;
163    inode->attr       = attr;
164    inode->mode       = mode;
165    inode->uid        = uid;
166    inode->gid        = gid;
167    inode->refcount   = 0;
168    inode->parent_xp  = dentry_xp;
169    inode->ctx        = ctx;
170    inode->mapper     = NULL; 
171
172    // initialise threads waiting queue
173    xlist_root_init( XPTR( local_cxy , &inode->wait_root ) );
174
175    // initialize dentries hash table, if new inode is a directory
176    if( attr & INODE_ATTR_DIR )  xhtab_init( &inode->children , XHTAB_DENTRY_TYPE );
177
178    // initialize inode locks
179    remote_rwlock_init( XPTR( local_cxy , &inode->data_lock ) );
180    remote_spinlock_init( XPTR( local_cxy , &inode->main_lock ) );
181
182    // create FS specific inode
183    if     ( ctx->type == FS_TYPE_FATFS )  fatfs_inode_create( inode );
184    else if( ctx->type == FS_TYPE_RAMFS )  ramfs_inode_create( inode );
185
186    // return extended pointer on inode
187    *inode_xp = XPTR( local_cxy , inode );
188    return 0;
189
190}  // end vfs_inode_create() 
191
192/////////////////////////////////////////////
193void vfs_inode_destroy( vfs_inode_t * inode )
194{
195    if( inode->refcount )
196    {
197        printk("\n[PANIC] in %s : inode refcount non zero\n", __FUNCTION__ );
198        hal_core_sleep(); 
199    }       
200
201    // release memory allocated for mapper
202    mapper_destroy( inode->mapper );
203
204    // release memory allocate for inode descriptor
205        kmem_req_t req;
206        req.ptr   = inode;
207        req.type  = KMEM_VFS_INODE;
208        kmem_free( &req );
209
210}  // end vfs_inode_destroy()
211
212////////////////////////////////////////////
213void vfs_inode_remote_up( xptr_t  inode_xp )
214{
215    // get inode cluster and local pointer
216    cxy_t         inode_cxy = GET_CXY( inode_xp );
217    vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
218
219    hal_remote_atomic_add( XPTR( inode_cxy , &inode_ptr->refcount ) , 1 );   
220}
221
222//////////////////////////////////////////////
223void vfs_inode_remote_down( xptr_t  inode_xp )
224{
225    // get inode cluster and local pointer
226    cxy_t         inode_cxy = GET_CXY( inode_xp );
227    vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
228
229    hal_remote_atomic_add( XPTR( inode_cxy , &inode_ptr->refcount ) , -1 );   
230}
231
232//////////////////////////////////////////////
233uint32_t vfs_inode_get_size( xptr_t inode_xp )
234{
235    // get inode cluster and local pointer
236    cxy_t         cxy = GET_CXY( inode_xp );
237    vfs_inode_t * ptr = (vfs_inode_t *)GET_PTR( inode_xp );
238
239    // get size
240    remote_rwlock_rd_lock( XPTR( cxy , &ptr->data_lock ) );
241    uint32_t size = hal_remote_lw( XPTR( cxy , &ptr->size ) );
242    remote_rwlock_rd_unlock( XPTR( cxy , &ptr->data_lock ) );
243    return size;
244}
245
246/////////////////////////////////////////////////
247void vfs_inode_size_set_size( xptr_t    inode_xp,
248                              uint32_t  size )
249{
250    // get inode cluster and local pointer
251    cxy_t         cxy = GET_CXY( inode_xp );
252    vfs_inode_t * ptr = (vfs_inode_t *)GET_PTR( inode_xp );
253
254    // set size
255    remote_rwlock_wr_unlock( XPTR( cxy , &ptr->data_lock ) );
256    hal_remote_sw( XPTR( cxy , &ptr->size ) , size );
257    remote_rwlock_wr_unlock( XPTR( cxy , &ptr->data_lock ) );
258}
259
260///////////////////////////////////////////////
261void vfs_inode_remote_unlock( xptr_t inode_xp )
262{
263    // get inode cluster and local pointer
264    cxy_t         cxy = GET_CXY( inode_xp );
265    vfs_inode_t * ptr = (vfs_inode_t *)GET_PTR( inode_xp );
266
267    // release the main lock
268    remote_spinlock_unlock( XPTR( cxy , &ptr->main_lock ) );
269}
270
271/////////////////////////////////////////////
272void vfs_inode_remote_lock( xptr_t inode_xp )
273{
274    // get inode cluster and local pointer
275    cxy_t         cxy = GET_CXY( inode_xp );
276    vfs_inode_t * ptr = (vfs_inode_t *)GET_PTR( inode_xp );
277
278    // get the main lock
279    remote_spinlock_lock( XPTR( cxy , &ptr->main_lock ) );
280}
281
282//////////////////////////////////////////////////////////////////////////////////////////
283//           Dentry related functions
284//////////////////////////////////////////////////////////////////////////////////////////
285
286//////////////////////////////////////////////
287error_t vfs_dentry_create( uint32_t      type,
288                           char        * name,
289                           vfs_inode_t * parent,
290                           xptr_t      * dentry_xp )
291{
292    vfs_ctx_t      * ctx;        // context descriptor
293    vfs_dentry_t   * dentry;     // dentry descriptor (to be allocated)
294        kmem_req_t       req;        // request to kernel memory allocator
295    xptr_t           xhtab_xp;   // extended pointer on xhtab_t embedded in inode
296    xptr_t           xlist_xp;   // extended pointer on xlist_entry_t in dentry
297
298    // check type and get pointer on context
299    if     ( type == FS_TYPE_FATFS ) ctx = &fs_context[FS_TYPE_FATFS];
300    else if( type == FS_TYPE_RAMFS ) ctx = &fs_context[FS_TYPE_RAMFS];
301    else
302    {
303        ctx = NULL;
304        printk("\n[PANIC] in %s : undefined file system type\n", __FUNCTION__ );
305        hal_core_sleep();
306    }
307
308    // get name length
309    uint32_t length = strlen( name );
310
311    if( length > (CONFIG_VFS_MAX_NAME_LENGTH - 1) )
312    {
313        printk("\n[ERROR] in %s : name too long\n", __FUNCTION__ );
314        return EINVAL;
315    }
316
317    // allocate memory for dentry descriptor
318        req.type  = KMEM_VFS_DENTRY;
319        req.size  = sizeof(vfs_dentry_t);
320    req.flags = AF_KERNEL | AF_ZERO;
321        dentry     = (vfs_dentry_t *)kmem_alloc( &req );
322
323    if( dentry == NULL )
324    {
325        printk("\n[ERROR] in %s : cannot allocate dentry descriptor\n", __FUNCTION__ );
326        return ENOMEM;
327    }
328
329    // initialize dentry descriptor
330    dentry->ctx     = ctx;
331    dentry->length  = length;
332    dentry->parent  = parent;
333    strcpy( dentry->name , name );
334
335    // return extended pointer on dentry to caller
336    *dentry_xp = XPTR( local_cxy , dentry );
337
338    // register dentry in hash table rooted in parent inode
339    xhtab_xp    = XPTR( local_cxy , &parent->children );
340    xlist_xp    = XPTR( local_cxy , &dentry->xlist );
341    xhtab_register( xhtab_xp  , name , xlist_xp );
342   
343    return 0;
344
345}  // end vfs_dentry_create()
346
347////////////////////////////////////////////////
348void vfs_dentry_destroy( vfs_dentry_t * dentry )
349{
350    if( dentry->refcount )
351    {
352        printk("\n[PANIC] in %s : dentry refcount non zero\n", __FUNCTION__ );
353        hal_core_sleep(); 
354    }       
355
356        kmem_req_t req;
357        req.ptr   = dentry;
358        req.type  = KMEM_VFS_DENTRY;
359        kmem_free( &req );
360}
361
362
363//////////////////////////////////////////////////////////////////////////////////////////
364//           File descriptor related functions
365//////////////////////////////////////////////////////////////////////////////////////////
366
367////////////////////////////////////////
368void vfs_file_count_up( xptr_t file_xp )
369{
370    // get file cluster and local pointer
371    cxy_t        file_cxy = GET_CXY( file_xp );
372    vfs_file_t * file_ptr = (vfs_file_t *)GET_PTR( file_xp ); 
373
374    // atomically increment count
375    hal_remote_atomic_add( XPTR( file_cxy , &file_ptr->refcount ) , 1 ); 
376}
377
378//////////////////////////////////////////
379void vfs_file_count_down( xptr_t file_xp )
380{
381    // get file cluster and local pointer
382    cxy_t        file_cxy = GET_CXY( file_xp );
383    vfs_file_t * file_ptr = (vfs_file_t *)GET_PTR( file_xp ); 
384
385    // atomically decrement count
386    hal_remote_atomic_add( XPTR( file_cxy , &file_ptr->refcount ) , -1 ); 
387}
388
389////////////////////////////////////////////////
390error_t vfs_file_create( xptr_t        inode_xp,
391                         uint32_t      type,
392                         uint32_t      attr,
393                         xptr_t      * file_xp ) 
394{
395    vfs_file_t  * file_ptr;
396        kmem_req_t    req;
397
398    // get inode cluster and local pointer
399    cxy_t         inode_cxy = GET_CXY( inode_xp );
400    vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
401
402    // check cluster identifier
403    if( inode_cxy != local_cxy )
404    {
405        printk("\n[PANIC] in %s : local cluster is not the inode owner\n", __FUNCTION__ );
406        hal_core_sleep();
407    }
408
409    // allocate memory for new file descriptor
410        req.type  = KMEM_VFS_FILE;
411        req.size  = sizeof(vfs_file_t);
412    req.flags = AF_KERNEL | AF_ZERO;
413        file_ptr  = (vfs_file_t *)kmem_alloc( &req );
414
415    if( file_ptr == NULL ) return ENOMEM;
416
417    // get inode local pointer
418    // initializes new file descriptor
419    file_ptr->gc       = 0;
420    file_ptr->type     = type;
421    file_ptr->attr     = attr;
422    file_ptr->offset   = 0;
423    file_ptr->refcount = 0;
424    file_ptr->inode    = inode_ptr;
425    file_ptr->ctx      = inode_ptr->ctx;
426    file_ptr->mapper   = inode_ptr->mapper;
427
428    remote_rwlock_init( XPTR( local_cxy , &file_ptr->lock ) );
429
430    *file_xp = XPTR( local_cxy , file_ptr );
431    return 0;
432}
433
434////////////////////////////////////////
435void vfs_file_destroy( xptr_t  file_xp )
436{
437    // get file cluster and local pointer
438    cxy_t        file_cxy = GET_CXY( file_xp );
439    vfs_file_t * file_ptr = (vfs_file_t *)GET_PTR( file_xp );
440
441    if( file_cxy != local_cxy )
442    {
443        printk("\n[PANIC] in %s : file descriptor not in local cluster\n", __FUNCTION__ );
444        hal_core_sleep(); 
445    }
446
447    if( file_ptr->refcount )
448    {
449        printk("\n[PANIC] in %s : file refcount non zero\n", __FUNCTION__ );
450        hal_core_sleep(); 
451    }       
452
453        kmem_req_t req;
454        req.ptr   = file_ptr;
455        req.type  = KMEM_VFS_FILE;
456        kmem_free( &req );
457}
458
459//////////////////////////////////////////////////////////////////////////////////////////
460//           File related functions
461//////////////////////////////////////////////////////////////////////////////////////////
462
463////////////////////////////////////
464error_t vfs_open( xptr_t     cwd_xp,
465                          char     * path,
466                          uint32_t   flags,
467                          xptr_t   * file_xp )
468{
469    return 0;
470}
471
472///////////////////////////////////
473uint32_t vfs_read( xptr_t   file_xp, 
474                   void   * buffer,
475                   uint32_t size )
476{
477    return 0;
478}
479
480////////////////////////////////////
481uint32_t vfs_write( xptr_t   file_xp,
482                    void   * buffer,
483                    uint32_t size )
484{
485    return 0;
486}
487
488//////////////////////////////////////
489error_t vfs_lseek( xptr_t     file_xp,
490                   uint32_t   offset,
491                   uint32_t   whence, 
492                   uint32_t * new_offset )
493{
494    return 0;
495}
496
497//////////////////////////////////////
498error_t vfs_close( xptr_t     file_xp, 
499                   uint32_t * refcount )
500{
501    return 0;
502}
503
504////////////////////////////////////
505error_t vfs_unlink( xptr_t   cwd_xp,
506                    char   * path )
507{
508    return 0;
509}
510
511//////////////////////////////////////
512error_t vfs_stat( xptr_t       file_xp,
513                  vfs_stat_t * stat )
514{
515    return 0;
516}
517
518//////////////////////////////////////////////////////////////////////////////////////////
519//           Directory related functions
520//////////////////////////////////////////////////////////////////////////////////////////
521
522
523
524
525
526//////////////////////////////////////////////////////////////////////////////////////////
527//            Inode Tree functions
528//////////////////////////////////////////////////////////////////////////////////////////
529
530//////////////////////////////////////////////////////////////////////////////////////////
531// This static function is used by the vfs_lookup() function.
532// It takes an extended pointer on a remote inode (parent directory inode),
533// and check access_rights violation for the calling thread.
534// It can be used by any thread running in any cluster.
535//////////////////////////////////////////////////////////////////////////////////////////
536// @ inode_xp    : extended pointer on inode.
537// @ client_uid  : client thread user ID
538// @ client_gid  : client thread group ID
539// @ return true if access rights are violated.
540//////////////////////////////////////////////////////////////////////////////////////////
541bool_t vfs_access_denied( xptr_t   inode_xp,
542                          uint32_t client_uid,
543                          uint32_t client_gid )
544{
545    // get found inode cluster and local pointer
546    cxy_t         inode_cxy = GET_CXY( inode_xp );
547    vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
548
549    // get inode access mode, UID, and GID
550    // TODO uint32_t  mode = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->mode ) );
551    uid_t     uid  = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->uid  ) );
552    gid_t     gid  = hal_remote_lw( XPTR( inode_cxy , &inode_ptr->gid  ) );
553
554    // FIXME : me must use mode
555    if( (uid == client_uid) || (gid == client_gid) ) return false;
556    else                                             return true;
557}
558
559//////////////////////////////////////////////////////////////////////////////////////////
560// This static function is used by the vfs_lookup() function.
561// It takes an extended pointer on a remote inode (parent directory inode), a directory
562// entry name, and returns an extended pointer on the child inode.
563// It can be used by any thread running in any cluster.
564//////////////////////////////////////////////////////////////////////////////////////////
565// @ parent_xp   : extended pointer on parent inode in remote cluster.
566// @ name        : dentry name
567// @ child_xp    : [out] buffer for extended pointer on child inode.
568// @ return true if success / return false if not found.
569//////////////////////////////////////////////////////////////////////////////////////////
570static bool_t vfs_get_child( xptr_t   parent_xp,
571                             char   * name,
572                             xptr_t * child_xp )
573{
574    xptr_t  xhtab_xp;    // extended pointer on hash table containing children dentries
575    xptr_t  dentry_xp;   // extended pointer on children dentry
576
577    // get parent inode cluster and local pointer
578    cxy_t         parent_cxy = GET_CXY( parent_xp );
579    vfs_inode_t * parent_ptr = (vfs_inode_t *)GET_PTR( parent_xp );
580
581    // get extended pointer on hash table of children directory entries
582    xhtab_xp = XPTR( parent_cxy , &parent_ptr->children );
583
584    // search extended pointer on matching dentry
585    dentry_xp = xhtab_lookup( xhtab_xp , name );
586
587    if( dentry_xp == XPTR_NULL ) return false;
588
589    // get dentry cluster and local pointer
590    cxy_t          dentry_cxy = GET_CXY( dentry_xp );
591    vfs_dentry_t * dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
592
593    // return child inode
594    *child_xp = (xptr_t)hal_remote_lwd( XPTR( dentry_cxy , &dentry_ptr->parent ) );
595    return true;
596}
597
598//////////////////////////////////////////////////////////////////////////////////////////
599// This static function is used by the vfs_lookup() function.
600// It takes the <current> pointer on a buffer containing a complete pathname, and return
601// in the <name> buffer, allocated by the caller, a single name in the path.
602// It return also in the <next> pointer the next character to analyse in the path.
603// Finally it returns a <last> boolean, that is true when the returned <name> is the
604// last name in the path. The names are supposed to be separated by one or several '/'
605// characters, that are not written in  the <name> buffer.
606//////////////////////////////////////////////////////////////////////////////////////////
607// @ current   : pointer on first character to analyse in buffer containing the path.
608// @ name      : [out] pointer on buffer allocated by the caller for the returned name.
609// @ next      : [out] pointer on next character to analyse in buffer containing the path.
610// @ last      : [out] true if the returned name is the last (NUL character found).
611// @ return 0 if success / return EINVAL if string empty (first chracter is NUL).
612//////////////////////////////////////////////////////////////////////////////////////////
613static error_t vfs_get_name_from_path( char     * current,
614                                       char     * name,
615                                       char    ** next,
616                                       bool_t   * last )
617{
618    char * ptr = current;
619
620    // skip leading '/' characters
621    while( *ptr == '/' ) ptr++;
622
623    // return EINVAL if string empty
624    if( *ptr == 0 ) return EINVAL;
625
626    // copy all characters in name until NUL or '/'
627    while( (*ptr != 0) && (*ptr !='/') )  *(name++) = *(ptr++);
628
629    // return last an next
630    if( *ptr == 0 )             // last found character is NUL => last name in path
631    {
632        *last = true;
633    }
634    else                        // last found character is '/' => skip it
635    {
636        *last = false;
637        *next = ptr + 1;
638    }
639
640    return 0;
641}
642
643////////////////////////////////////////
644error_t vfs_lookup( xptr_t       cwd_xp,
645                    char       * pathname,
646                    uint32_t     client_uid,
647                    uint32_t     client_gid,
648                                        xptr_t     * inode_xp,
649                    xptr_t     * ctx_xp )
650{
651    char          name[CONFIG_VFS_MAX_NAME_LENGTH];   // one name in path
652
653    xptr_t        parent_xp;    // extended pointer on parent inode
654    cxy_t         parent_cxy;   // cluster for parentc inode
655    vfs_inode_t * parent_ptr;   // local pointer on parent inode 
656    xptr_t        child_xp;     // extended pointer on child inode
657    cxy_t         child_cxy;    // cluster for child inode
658    vfs_inode_t * child_ptr;    // local pointer on child inode 
659    char        * current;      // current pointer on path
660    char        * next;         // next value for current pointer   
661    bool_t        last;         // true when the name is the last in path
662    bool_t        found;        // true when a child has been found
663    thread_t    * this;         // pointer on calling thread descriptor
664    process_t   * process;      // pointer on calling process descriptor
665    vfs_ctx_t   * ctx;          // parent inode context
666    uint32_t      type;         // file system type of parent inode
667    error_t       error;
668
669    this    = CURRENT_THREAD;
670    process = this->process;
671
672    // get extended pointer on first inode to search
673    if( pathname[0] == '/' ) parent_xp = process->vfs_root_xp;
674    else                     parent_xp = cwd_xp;
675
676    // initialise loop variables
677    current  = pathname;
678    next     = NULL;
679    last     = false;
680    child_xp = XPTR_NULL;
681
682    // take lock on parent inode
683    vfs_inode_remote_lock( parent_xp );
684
685    // break : if one intermediate name not found
686    // exit  : when last name found (i.e. last == true)
687    do
688    {
689        // get cluster and local pointer for parent inode
690        parent_cxy = GET_CXY( parent_xp );
691        parent_ptr = (vfs_inode_t *)GET_PTR( parent_xp );
692       
693        // get parent inode FS type
694        ctx = (vfs_ctx_t *)(intptr_t)hal_remote_lpt( XPTR( parent_cxy , &parent_ptr->ctx ) );
695        type = ctx->type;
696
697        // get one name from path
698        vfs_get_name_from_path( current , name , &next , &last );
699
700        // search a child dentry matching name for parent inode
701        found = vfs_get_child( parent_xp,
702                               name,
703                               &child_xp );
704
705        if( found == false ) // child inode not found in inode tree => try to load it
706        {
707            // release lock on parent inode
708            vfs_inode_remote_unlock( parent_xp );
709
710            // insert a new dentry/inode in parent inode
711            error = vfs_add_child_in_parent( type , parent_xp , name , &child_xp );
712
713            if( error )
714            {
715                printk("\n[ERROR] in %s : inode %s not found in path %s\n",
716                       __FUNCTION__ , name , pathname );
717                return ENOENT;
718            }
719
720            // take lock on parent inode
721            vfs_inode_remote_lock( parent_xp );
722        }
723
724        // check access rights
725        error = vfs_access_denied( child_xp,
726                                   client_uid,
727                                   client_gid );
728        if( error ) 
729        {
730            printk("\n[ERROR] in %s : permission denied for %s\n", __FUNCTION__ , name );
731            return EACCES;
732        }
733
734        // take lock on child inode if not last
735        if( last == false ) vfs_inode_remote_lock( child_xp );
736
737        // release lock on parent inode
738        vfs_inode_remote_unlock( parent_xp );
739
740        // update loop variables
741        parent_xp = child_xp;
742        current   = next;
743    }
744    while( last == false );
745
746    vfs_dmsg("\n[INFO] in %s : searched inode found for %s\n",
747                 __FUNCTION__ , pathname );
748
749    // get cluster and local pointer on child inode
750    child_cxy = GET_CXY( child_xp );
751    child_ptr = (vfs_inode_t *)GET_PTR( child_xp );
752
753    // return searched pointers
754    *inode_xp = child_xp;
755    *ctx_xp   = (xptr_t)hal_remote_lwd( XPTR( child_cxy , &child_ptr->ctx ) );
756
757    return 0;
758
759}  // end vfs_lookup()
760
761
762////////////////////////////////////////////
763error_t vfs_get_path( xptr_t    searched_xp,
764                      char    * buffer,
765                      uint32_t  max_size )
766{
767        xptr_t       dentry_xp;   // extended pointer on current dentry
768    char       * name;        // local pointer on current dentry name
769        uint32_t     length;      // length of current dentry name
770        uint32_t     count;       // number of characters written in buffer
771        uint32_t     index;       // slot index in buffer
772    xptr_t       inode_xp;  // extended pointer on   
773
774    // implementation note:
775    // we use two variables "index" and "count" because the buffer
776    // is actually written in decreasing index order (from leaf to root)
777    // TODO : handle conflict with a concurrent rename
778    // FIXME : handle synchro in the loop ... [AG]
779
780        // set the NUL character in buffer / initialise buffer index and count
781        buffer[max_size - 1] = 0;
782        count    = 1;
783    index    = max_size - 2;
784
785    // initialize current inode
786    inode_xp  = searched_xp;
787
788    // exit when root inode found (i.e. dentry_xp == XPTR_NULL)
789        do
790    {
791        // get inode cluster and local pointer
792        cxy_t         inode_cxy = GET_CXY( inode_xp );
793        vfs_inode_t * inode_ptr = (vfs_inode_t *)GET_PTR( inode_xp );
794
795        // get extended pointer on parent dentry               
796        dentry_xp = (xptr_t)hal_remote_lwd( XPTR( inode_cxy , inode_ptr->parent_xp ) );
797
798        // get dentry cluster and local pointer
799        cxy_t          dentry_cxy = GET_CXY( dentry_xp );
800        vfs_dentry_t * dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp );
801
802        // get dentry name length and pointer
803        length =  hal_remote_lw( XPTR( dentry_cxy , &dentry_ptr->length ) );
804        name   = (char *)hal_remote_lpt( XPTR( dentry_cxy , &dentry_ptr->name ) );
805
806        // update index and count
807        index -= (length + 1); 
808        count += (length + 1);
809
810        // check buffer overflow
811        if( count >= max_size )
812        {
813            printk("\n[ERROR] in %s : kernel buffer too small\n", __FUNCTION__ );
814            return EINVAL;
815        }
816
817        // update pathname
818        hal_remote_memcpy( XPTR( local_cxy , &buffer[index + 1] ) ,
819                           XPTR( dentry_cxy , name ) , length );
820                buffer[index] = '/';
821
822                // get extended pointer on next inode
823        inode_xp = (xptr_t)hal_remote_lwd( XPTR( dentry_cxy , dentry_ptr->parent ) );
824    }
825    while( (dentry_xp != XPTR_NULL) );
826
827        return 0;
828
829}  // end vfs_get_path()
830
831///////////////////////////////////////////////
832error_t vfs_add_child_in_parent( uint32_t type,
833                                 xptr_t   parent_xp,
834                                 char   * name,   
835                                 xptr_t * child_xp )
836{
837    xptr_t     dentry_xp;  // extended pointer on created dentry
838    xptr_t     inode_xp;   // extended pointer on created inode
839    error_t    error;
840
841    // get parent inode cluster and local pointer
842    cxy_t         parent_cxy = GET_CXY( parent_xp );
843    vfs_inode_t * parent_ptr = (vfs_inode_t *)GET_PTR( parent_xp );
844
845    // create dentry
846    if( parent_cxy == local_cxy )      // parent cluster is the local cluster
847    {
848        error = vfs_dentry_create( type,
849                                   name,
850                                   parent_ptr,
851                                   &dentry_xp );
852    }
853    else                               // parent cluster is remote
854    {
855        rpc_vfs_dentry_create_client( parent_cxy,
856                                      type,
857                                      name,
858                                      parent_ptr,
859                                      &dentry_xp,
860                                      &error );
861    }
862                                     
863    if( error )
864    {
865        printk("\n[ERROR] in %s : cannot create dentry in cluster %x\n",
866               __FUNCTION__ , parent_cxy );
867
868        return error;
869    }
870
871    // select a target cluster for child inode
872    uint32_t  x_size    = LOCAL_CLUSTER->x_size;
873    uint32_t  y_size    = LOCAL_CLUSTER->y_size;
874    uint32_t  y_width   = LOCAL_CLUSTER->y_width;
875    uint32_t  index     = ( hal_time_stamp() + hal_get_gid() ) % (x_size * y_size);
876    uint32_t  x         = index / y_size;   
877    uint32_t  y         = index % y_size;
878    cxy_t     child_cxy = (x<<y_width) + y;
879                                     
880    // create child inode TODO : define attr / mode / uid / gid
881    uint32_t attr = 0;
882    uint32_t mode = 0;
883    uint32_t uid  = 0;
884    uint32_t gid  = 0;
885   
886    if( child_cxy == local_cxy )      // child cluster is the local cluster
887    {
888        error = vfs_inode_create( dentry_xp,
889                                  type,
890                                  attr,
891                                  mode,
892                                  uid,
893                                  gid,
894                                  &inode_xp );
895    }
896    else                              // child cluster is remote
897    {
898        rpc_vfs_inode_create_client( child_cxy,
899                                     dentry_xp,
900                                     type,
901                                     attr,
902                                     mode,
903                                     uid,
904                                     gid,
905                                     &inode_xp,
906                                     &error );
907    }
908                                     
909    if( error )
910    {
911        printk("\n[ERROR] in %s : cannot create inode in cluster %x\n",
912               __FUNCTION__ , child_cxy );
913 
914        vfs_dentry_t * dentry = (vfs_dentry_t *)GET_PTR( dentry_xp );
915        if( parent_cxy == local_cxy ) vfs_dentry_destroy( dentry );
916        else rpc_vfs_dentry_destroy_client( parent_cxy , dentry );
917        return error;
918    }
919
920    // success : return extended pointer on child inode
921    *child_xp = inode_xp;
922    return 0;
923
924}  // end vfs_add_child_in_parent()
925
926
Note: See TracBrowser for help on using the repository browser.