source: trunk/kernel/fs/fatfs.c @ 632

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

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

File size: 106.3 KB
RevLine 
[1]1/*
2 * fatfs.c - FATFS file system API implementation.
3 *
[625]4 * Author    Alain Greiner (2016,2017,2018,2019)
[1]5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24
[457]25#include <hal_kernel_types.h>
[1]26#include <hal_special.h>
27#include <printk.h>
[401]28#include <thread.h>
[1]29#include <kmem.h>
30#include <ppm.h>
31#include <vfs.h>
[238]32#include <string.h>
[1]33#include <rpc.h>
34#include <mapper.h>
[23]35#include <cluster.h>
[1]36#include <dev_ioc.h>
37#include <fatfs.h>
38
[626]39#define LITTLE_ENDIAN  1
[50]40
[23]41//////////////////////////////////////////////////////////////////////////////////////////
42//          Extern  variables         
43//////////////////////////////////////////////////////////////////////////////////////////
[1]44
[602]45extern vfs_ctx_t     fs_context[FS_TYPES_NR];   // allocated in kernel_init.c file
[23]46
[1]47//////////////////////////////////////////////////////////////////////////////////////////
[602]48//              FATFS specific static functions
[1]49//////////////////////////////////////////////////////////////////////////////////////////
50
[188]51//////////////////////////////////////////////////////////////////////////////////////////
[238]52// These functions return the "offset" and "length" values of an
53// [offset,length] constant defined in the fatfs.h file.
54//////////////////////////////////////////////////////////////////////////////////////////
55
[568]56static inline int get_length( int offset __attribute__((unused)), int length ) { return length; }
[238]57
[568]58static inline int get_offset( int offset, int length __attribute__((unused)) ) { return offset; }
[238]59
60//////////////////////////////////////////////////////////////////////////////////////////
[440]61// This static function returns the LBA of the first sector of a FAT cluster.
[188]62// This function can be called by any thread running in any cluster.
63//////////////////////////////////////////////////////////////////////////////////////////
64// @ ctx          :     pointer on FATFS context.
65// @ cluster  : cluster index in FATFS.
66// @ return the lba value.
67//////////////////////////////////////////////////////////////////////////////////////////
68static inline uint32_t fatfs_lba_from_cluster( fatfs_ctx_t * ctx,
69                                               uint32_t      cluster )
[1]70{
[23]71    return (ctx->cluster_begin_lba + ((cluster - 2) << 3));
[1]72}
73
[246]74//////////////////////////////////////////////////////////////////////////////////////////
[626]75// This function return an integer record value (one, two, or four bytes) from a local
76// array of bytes, taking into account the global LITTLE_ENDIAN parameter:
77// if LITTLE_ENDIAN is true, the most significant byte has the highest address.
[238]78//////////////////////////////////////////////////////////////////////////////////////////
[626]79// @ offset        : first byte in array.
80// @ nbytes        : record length in bytes (1/2/4).
81// @ buffer        : local pointer on byte array.
[23]82// @ return the integer value in a 32 bits word.
[238]83//////////////////////////////////////////////////////////////////////////////////////////
84static uint32_t fatfs_get_record( uint32_t    offset,
[626]85                                  uint32_t    nbytes,
86                                  uint8_t   * buffer )
[23]87{
[626]88    uint32_t i;
89    uint32_t res = 0;
[1]90
[626]91    if ( LITTLE_ENDIAN )
[23]92    {
[626]93        for( i = nbytes ; i > 0 ; i-- ) res = (res<<8) | buffer[offset+i-1];
[23]94    }
[626]95    else 
[23]96    {
[626]97        for( i = 0 ; i < nbytes ; i++ ) res = (res<<8) | buffer[offset+i];
[23]98    }
99    return res;
100
[238]101}  // end fatfs_get_record()
[23]102
[238]103//////////////////////////////////////////////////////////////////////////////////////////
[626]104// This function return an integer record value (one, two, or four bytes) from a remote
105// array of bytes, taking into account the global LITTLE_ENDIAN parameter:
106// if LITTLE_ENDIAN is true, the most significant byte has the highest address.
[602]107//////////////////////////////////////////////////////////////////////////////////////////
[626]108// @ offset        : first byte in array.
109// @ nbytes        : record length in bytes (1/2/4).
110// @ buffer_xp     : extended pointer on byte array.
[602]111// @ return the integer value in a 32 bits word.
112//////////////////////////////////////////////////////////////////////////////////////////
[626]113static uint32_t fatfs_get_remote_record( uint32_t   offset,
114                                         uint32_t   nbytes,
115                                         xptr_t     buffer_xp )
116{
117    uint32_t i;
118    uint32_t res = 0;
119
120    if ( LITTLE_ENDIAN )
121    {
122        for( i = nbytes ; i > 0 ; i-- )
123        {
124            res = (res<<8) | hal_remote_lb( buffer_xp+offset+i-1 );
125        }
126    }
127    else 
128    {
129        for( i = 0 ; i < nbytes ; i++ )
130        {
131            res = (res<<8) | hal_remote_lb( buffer_xp+offset+i );
132        }
133    }
134    return res;
135
136}  // end fatfs_get_remote_record()
137
138//////////////////////////////////////////////////////////////////////////////////////////
139// This function writes one, two, or four bytes from a 32 bits integer to a local
140// array of bytes, taking into account the global LITTLE_ENDIAN parameter:
141// if LITTLE_ENDIAN is true, the most significant byte has the highest address.
142//////////////////////////////////////////////////////////////////////////////////////////
143// @ offset        : first byte in array.
144// @ nbytes        : record length in bytes (1/2/4).
145// @ buffer        : local pointer on byte array.
146// @ value         : 32 bits integer value.
147//////////////////////////////////////////////////////////////////////////////////////////
[602]148static void fatfs_set_record( uint32_t    offset,
[626]149                              uint32_t    nbytes,
[602]150                              uint8_t   * buffer,
151                              uint32_t    value )
152{
[626]153    uint32_t i;
[602]154
[626]155    if ( LITTLE_ENDIAN )
[602]156    {
[626]157        for( i = nbytes ; i > 0 ; i-- ) buffer[offset+i-1] = (uint8_t)(value>>((i-1)<<3));
[602]158    }
[626]159    else
[602]160    {
[626]161        for( i = 0 ; i < nbytes ; i++ ) buffer[offset+i] = (uint8_t)(value>>((nbytes-1-i)<<3));
[602]162    }
163
164}  // end fatfs_set_record()
165
166//////////////////////////////////////////////////////////////////////////////////////////
[626]167// This function writes one, two, or four bytes from a 32 bits integer to a remote
168// array of bytes, taking into account the global LITTLE_ENDIAN parameter:
169// if LITTLE_ENDIAN is true, the most significant byte has the highest address.
170//////////////////////////////////////////////////////////////////////////////////////////
171// @ offset        : first byte in array.
172// @ nbytes        : record length in bytes (1/2/4).
173// @ buffer_xp     : extended pointer on byte array.
174// @ value         : 32 bits integer value.
175//////////////////////////////////////////////////////////////////////////////////////////
176static void fatfs_set_remote_record( uint32_t    offset,
177                                     uint32_t    nbytes,
178                                     xptr_t      buffer_xp,
179                                     uint32_t    value )
180{
181    uint32_t i;
182
183    if ( LITTLE_ENDIAN )
184    {
185        for( i = nbytes ; i > 0 ; i-- )
186        {
187            hal_remote_sb( (buffer_xp+offset+i-1) , (uint8_t)(value>>((i-1)<<3)) );
188        }
189    }
190    else
191    {
192        for( i = 0 ; i < nbytes ; i++ )
193        {
194            hal_remote_sb( (buffer_xp+offset+i) , (uint8_t)(value>>((nbytes-1-i)<<3)) );
195        }
196    }
197
198}  // end fatfs_set_record()
199
200//////////////////////////////////////////////////////////////////////////////////////////
[238]201// This static function retun in the <name> buffer a short name stored in
202// a SFN FATFS directory entry.
203/////////////////////////i////////////////////////////////////////////////////////////////
204// @ buffer   : pointer on buffer containing the directory entry.
205// @ name     : [out] buffer allocated by the caller.
206//////////////////////////////////////////////////////////////////////////////////////////
207static void fatfs_get_name_from_short( uint8_t * buffer,
208                                       char    * name )
209{
210    uint32_t i;
211    uint32_t j = 0;
[23]212
[238]213    // get name
214    for ( i = 0; i < 8 && buffer[i] != ' '; i++ )
215    {
216        name[j] = to_lower( buffer[i] );
217        j++;
218    }
[23]219
[238]220    // get extension
221    for ( i = 8; i < 8 + 3 && buffer[i] != ' '; i++ )
222    {
223        // we entered the loop so there is an extension. add the dot
224        if ( i == 8 )
225        {
226            name[j] = '.';
227            j++;
228        }
229
230        name[j] = to_lower( buffer[i] );
231        j++;
232    }
233
234    name[j] = '\0';
235
[602]236}  // fatfs_get_name_from_short()
237
[238]238//////////////////////////////////////////////////////////////////////////////////////////
239// This static function retun in the <name> buffer a partial name stored in
240// a LFN FATFS directory entry.
241/////////////////////////i////////////////////////////////////////////////////////////////
242// @ buffer   : pointer on buffer containing the directory entry.
243// @ name     : [out] buffer allocated by the caller.
244//////////////////////////////////////////////////////////////////////////////////////////
245static void fatfs_get_name_from_long( uint8_t * buffer,
246                                      char    * name )
247{
248    uint32_t   name_offset   = 0;
249    uint32_t   buffer_offset = get_length(LDIR_ORD);
250    uint32_t   l_name_1      = get_length(LDIR_NAME_1);
251    uint32_t   l_name_2      = get_length(LDIR_NAME_2);
252    uint32_t   l_name_3      = get_length(LDIR_NAME_3);
253    uint32_t   l_attr        = get_length(LDIR_ATTR);
254    uint32_t   l_type        = get_length(LDIR_TYPE);
255    uint32_t   l_chksum      = get_length(LDIR_CHKSUM);
256    uint32_t   l_rsvd        = get_length(LDIR_RSVD);
257
258    uint32_t   j             = 0;
259    uint32_t   eof           = 0;
260
261    while ( (buffer_offset != DIR_ENTRY_SIZE)  && (!eof) )
262    {
263        while (j != l_name_1 && !eof )
264        {
265            if ( (buffer[buffer_offset] == 0x00) || 
266                 (buffer[buffer_offset] == 0xFF) )
267            {
268                eof = 1;
269                continue;
270            }
271            name[name_offset] = buffer[buffer_offset];
272            buffer_offset += 2;
273            j += 2;
274            name_offset++;
275        }
276
277        buffer_offset += (l_attr + l_type + l_chksum);
278        j = 0;
279
280        while (j != l_name_2 && !eof )
281        {
282            if ( (buffer[buffer_offset] == 0x00) || 
283                 (buffer[buffer_offset] == 0xFF) )
284            {
285                eof = 1;
286                continue;
287            }
288            name[name_offset] = buffer[buffer_offset];
289            buffer_offset += 2;
290            j += 2;
291            name_offset++;
292        }
293
294        buffer_offset += l_rsvd;
295        j = 0;
296
297        while (j != l_name_3 && !eof )
298        {
299            if ( (buffer[buffer_offset] == 0x00) || 
300                 (buffer[buffer_offset] == 0xFF) )
301            {
302                eof = 1;
303                continue;
304            }
305            name[name_offset] = buffer[buffer_offset];
306            buffer_offset += 2;
307            j += 2;
308            name_offset++;
309        }
310    }
311    name[name_offset] = 0;
312
[602]313} // end fatfs_get_name_from_long()
[238]314
[602]315//////////////////////////////////////////////////////////////////////////////////////////
316// This static function analyse the <name> input argument, and returns in other
317// output arguments various informations required to store the name in FATFS directory.
318// The <name> length cannot be larger than 31 characters :
319// - Short name (less than 13 characters) require 1 LFN entry.
320// - Medium names (from 14 to 26 characters require 2 LFN entries.
321// - Large names (up to 31 characters) require 3 LFN entries.
322//////////////////////////////////////////////////////////////////////////////////////////
323// @ name     : [in]  complete directory entry name.
324// @ length   : [out] total number of characters in name.
325// @ nb_lfn   : [out] number of LFN entries required to store the name.
326// @ sfn      : [out] a legal SFN name extracted from name / upper case and 8-3 format.
327// @ checksum : [out] checksum to be stored in SFN.
328// @ returns 0 on success / returns 1 if the name length is larger than 31 characters.
329//////////////////////////////////////////////////////////////////////////////////////////
330static error_t fatfs_name_format( const char  * name,
331                                  uint32_t    * length,
332                                  uint32_t    * nb_lfn,
333                                  char        * sfn,
334                                  uint8_t     * checksum )
335{
336    // compute name length
337    uint32_t name_length = strlen( name );
338    *length = name_length;
[1]339
[602]340    uint32_t suffix_length = 0;
341    uint32_t prefix_length = 0;
342    uint32_t dot_found     = 0;
343    uint32_t i;
344
345    // compute prefix and suffix length
346    // only the last '.' is taken into account
347    for ( i=0 ; i<name_length ; i++ )
348    {
349        if (name[i] == '.' )
350        {
351            if ( dot_found ) 
352            {
353                prefix_length += suffix_length + 1;
354                suffix_length =  0;
355            }
356            else
357            {
358                dot_found = 1;
359            }
360        }
361        else
362        { 
363            if ( dot_found)  suffix_length++;
364            else             prefix_length++;
365        }
366    } 
367
368    // build SFN prefix (8bits)
369    if (prefix_length <= 8)
370    {
371        for( i=0 ; i<8 ; i++)
372        {
373            if ( i<prefix_length ) sfn[i] = to_upper( name[i] );
374            else                   sfn[i] = 0x20;
375        }
376    }
377    else
378    {
379        for( i=0 ; i<6 ; i++)
380        {
381            sfn[i] = to_upper( name[i] );
382        }
383        sfn[6] = 0x7E;
384        sfn[7] = 0x31;
385    }
386
387    // build SFN suffix (3 bits)
388    if ( suffix_length == 0 )
389    {
390        sfn[8]  = 0x20;
391        sfn[9]  = 0x20;
392        sfn[10] = 0x20;
393    }
394    else if ( suffix_length == 1 )
395    {
396        sfn[8]  = to_upper( name[name_length-1] );
397        sfn[9]  = 0x20;
398        sfn[10] = 0x20;
399    }
400    else if ( suffix_length == 2 )
401    {
402        sfn[8]  = to_upper( name[name_length-2] );
403        sfn[9]  = to_upper( name[name_length-1] );
404        sfn[10] = 0x20;
405    }
406    else
407    {
408        sfn[8]  = to_upper( name[name_length-suffix_length] );
409        sfn[9]  = to_upper( name[name_length-suffix_length+1] );
410        sfn[10] = to_upper( name[name_length-suffix_length+2] );
411    }
412
413    // compute 8 bits checksum
414    uint8_t sum = 0;
415    for ( i=0 ; i<11 ; i++ )
416    {
417        sum = (((sum & 0x01)<<7) | ((sum & 0xFE)>>1)) + sfn[i];
418    }
419    *checksum = sum;
420
421    // set nb_lfn and length values
422    if      ( name_length <= 13 )
423    {
424        *nb_lfn  = 1;
425        return 0;
426    }
427    else if ( name_length <= 26 )
428    {
429        *nb_lfn  = 2;
430        return 0;
431    }
432    else if ( name_length <= 31 )
433    {
434        *nb_lfn  = 3;
435        return 0;
436    }
437    else
438    {
439        return 1;
440    }
441}   // end fatfs_name_format() 
442
[238]443//////////////////////////////////////////////////////////////////////////////////////////
[628]444// This static function synchronously updates the FAT on IOC device.
445// It scan the FAT mapper to copy on IOC device all dirty pages in the interval
446// defined by the <page_min> & <page_max> arguments.
447// It can be called by a thread running in any cluster.
448// WARNING : We don't take the lock protecting the FAT mapper, because the FAT lock
449// (in FATFS context) must be taken by the calling function.
[626]450//////////////////////////////////////////////////////////////////////////////////////////
[628]451// @ fatfs_ctx_xp  : extended pointer on FATFS context in FAT cluster.
452// @ page_min      : first page to be checked.
453// @ page_max      : last page to be checked
[626]454// @ return 0 if success, return -1 if the FS_INFO sector cannot be updated.
455//////////////////////////////////////////////////////////////////////////////////////////
[628]456static error_t fatfs_update_ioc_fat( xptr_t   fatfs_ctx_xp,
457                                     uint32_t page_min,
458                                     uint32_t page_max )
[626]459{
[628]460
461#if DEBUG_FATFS_UPDATE_IOC
462uint32_t   cycle = (uint32_t)hal_get_cycles();
463thread_t * this  = CURRENT_THREAD;
464if( DEBUG_FATFS_UPDATE_IOC < cycle )
465printk("\n[%s] thread[%x,%x] enter / page_min %d / page_max %d / cycle %d\n",
466__FUNCTION__ , this->process->pid, this->trdid, page_min, page_max, cycle );
467#endif
468
469    error_t       error;
470    cxy_t         fat_cxy;         // FAT cluster identifier
471    fatfs_ctx_t * fatfs_ctx;       // local pointer on FATFS context in FAT cluster
472    xptr_t        fat_mapper_xp;   // extended pointer on FAT mapper
473    mapper_t    * fat_mapper_ptr;  // local pointer on FAT mapper
474    uint32_t      page_id;         // current page index in FAT mapper
475    xptr_t        rt_xp;           // extended pointer on FAT mapper radix tree
476    xptr_t        page_xp;         // extended pointer on current page in FAT mapper
477    page_t      * page_ptr;        // local pointer on current page
478    uint32_t      flags;           // current page flags
479
480    // get pointer and cluster on FATFS context in FAT cluster
481    fat_cxy   = GET_CXY( fatfs_ctx_xp );
482    fatfs_ctx = GET_PTR( fatfs_ctx_xp );
483 
484    // get FAT mapper pointers from FATFS context
485    fat_mapper_xp  = hal_remote_l64( XPTR( fat_cxy , &fatfs_ctx->fat_mapper_xp ) );
486    fat_mapper_ptr = GET_PTR( fat_mapper_xp );
487
488// check FAT cluster
489assert( (fat_cxy == GET_CXY( fat_mapper_xp )) , "unconsistent FAT cluster" );
490
491    // build extended pointer on FAT mapper radix tree
492    rt_xp   = XPTR( fat_cxy , &fat_mapper_ptr->rt );
493
494    // scan all pages in [min,max] interval
495    for( page_id = page_min ; page_id <= page_max ; page_id++ )
496    {
497        // get extended pointer on page descriptor from FAT mapper
498        page_xp = grdxt_remote_lookup( rt_xp , page_id );
499
500        // check only existing pages
501        if ( page_xp != XPTR_NULL )
502        {
503            page_ptr = GET_PTR( page_xp );
504            flags    = hal_remote_l32( XPTR( fat_cxy , &page_ptr->flags ) );
505
506            // copy only dirty pages
507            if ( flags & PG_DIRTY )
508            {
509
510#if (DEBUG_FATFS_UPDATE_IOC & 1)
511if( DEBUG_FATFS_UPDATE_IOC < cycle )
512printk("\n[%s] thread[%x,%x] copy page %d from FAT mapper to IOC device\n",
513__FUNCTION__, page_id );
514#endif
515                // move page from mapper to device
516                error = fatfs_move_page( page_xp , IOC_SYNC_WRITE );
517
518                if ( error )  return -1;
519
520                // reset page dirty flag
521                ppm_page_undo_dirty( page_xp );
522            }
523        }
524    }  // end loop on pages
525
526#if DEBUG_FATFS_UPDATE_IOC
527cycle = (uint32_t)hal_get_cycles();
528if( DEBUG_FATFS_UPDATE_IOC < cycle )
529printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
530__FUNCTION__ , this->process->pid, this->trdid, cycle );
531#endif
532
533    return 0;
534
535}  // end fatfs_update_ioc_fat()
536
537//////////////////////////////////////////////////////////////////////////////////////////
538// This static function synchronously updates the FS_INFO sector on IOC device,
539// from values contained in the FATFS context in FAT cluster.
540// It uses and updates the FS_INFO buffer allocated in the FAT cluster.
541// It can be called by a thread running in any cluster.
542//////////////////////////////////////////////////////////////////////////////////////////
543// @ fatfs_ctx_xp  : extended pointer on FATFS context in FAT cluster.
544// @ return 0 if success, return -1 if the FS_INFO sector cannot be updated.
545//////////////////////////////////////////////////////////////////////////////////////////
546static error_t fatfs_update_ioc_fsinfo( xptr_t fatfs_ctx_xp )
547{
[626]548    cxy_t         fat_cxy;             // FAT cluster identifier
549    fatfs_ctx_t * fatfs_ctx_ptr;       // local pointer on fatfs context in FAT cluster
[628]550    uint32_t      free_clusters;       // current vale of "free_clusters" in fatfs context
551    uint32_t      free_cluster_hint;   // current vale of "free_cluster_hint" in fatfs context
[626]552    uint8_t     * fs_info_buffer_ptr;  // local pointer on FS_INFO buffer in FAT cluster
553    xptr_t        fs_info_buffer_xp;   // extended pointer on FS_INFO buffer in FAT cluster
554    uint32_t      fs_info_lba;         // FS_INFO sector lba on IOC device
555
556    // get cluster and local pointer on FAT cluster context
557    fat_cxy       = GET_CXY( fatfs_ctx_xp ); 
558    fatfs_ctx_ptr = GET_PTR( fatfs_ctx_xp ); 
559
[628]560    // force FATFS context update
561    hal_fence();
562
563    // get relevant info from fatfs context in FAT cluster
564    fs_info_lba        = hal_remote_l32( XPTR( fat_cxy , &fatfs_ctx_ptr->fs_info_lba ) );
565    free_clusters      = hal_remote_l32( XPTR( fat_cxy , &fatfs_ctx_ptr->free_clusters ) );
566    free_cluster_hint  = hal_remote_l32( XPTR( fat_cxy , &fatfs_ctx_ptr->free_cluster_hint ) );
[626]567    fs_info_buffer_ptr = hal_remote_lpt( XPTR( fat_cxy , &fatfs_ctx_ptr->fs_info_buffer ) );
[628]568
569    // build extended pointer on FS_INFO buffer in FAT cluster
[626]570    fs_info_buffer_xp  = XPTR( fat_cxy , fs_info_buffer_ptr );
[628]571   
[626]572    // update the FS_INFO buffer in FAT cluster
573    fatfs_set_remote_record( FS_FREE_CLUSTERS     , fs_info_buffer_xp , free_clusters );
574    fatfs_set_remote_record( FS_FREE_CLUSTER_HINT , fs_info_buffer_xp , free_cluster_hint );
575   
576    // update the FS_INFO sector on IOC device
577    return dev_ioc_sync_write( fs_info_buffer_xp , fs_info_lba , 1 );
578 
[628]579}  // end fatfs_update_ioc_fsinfo()
[626]580
581//////////////////////////////////////////////////////////////////////////////////////////
[625]582// This static function decrements the  "free_clusters" variable, and updates the
[626]583// "free_cluster_hint" variable in the FATFS context in FAT cluster, identified
584// by the <fat_ctx_xp> argument, when a new <cluster> has been allocated from FAT.
[625]585// It scan all slots in the FAT mapper seen as an array of 32 bits words, looking for the
586// first free slot larger than the <cluster> argument, to update "free_cluster_hint".
[628]587// It synchronously updates the FS_INFO sector on the IOC device.
588// It can be called by a thead running in any cluster.
589// The lock protecting exclusive access to the FAT must be taken by the calling function.
[602]590//////////////////////////////////////////////////////////////////////////////////////////
[626]591// @ fatfs_ctx_xp  : extended pointer on FATFS context in FAT cluster.
592// @ cluster       : recently allocated cluster index in FAT.
593// @ return 0 if success, return -1 if the FS_INFO sector cannot be updated.
[602]594//////////////////////////////////////////////////////////////////////////////////////////
[626]595static error_t fatfs_free_clusters_decrement( xptr_t    fatfs_ctx_xp,
596                                              uint32_t  cluster )
[602]597{
[626]598    error_t       error;
[628]599    cxy_t         fat_cxy;        // FAT cluster identifier
600    fatfs_ctx_t * fat_ctx_ptr;    // local pointer on fatfs context in FAT cluster
601    xptr_t        fat_mapper_xp;  // extended pointer on FAT mapper
602    xptr_t        hint_xp;        // extended pointer on "free_cluster_hint" shared variable
603    xptr_t        numb_xp;        // extended pointer on "free_clusters" shared variable
604    uint32_t      numb;           // "free_clusters" variable current value
605    uint32_t      hint;           // "free_cluster_hint" variable current value
606    uint32_t      page_id;        // page index in FAT mapper
607    uint32_t      slot_id;        // slot index in one page of FAT (1024 slots per page)
608    uint32_t      page_max;       // max number of pages in FAT mapper
609    xptr_t        page_xp;        // extended pointer on current page in FAT mapper
610    xptr_t        base_xp;        // extended pointer on current page base
611    xptr_t        slot_xp;        // extended pointer on current slot in FAT mapper
[602]612
613#if DEBUG_FATFS_FREE_CLUSTERS
614uint32_t   cycle = (uint32_t)hal_get_cycles();
615thread_t * this  = CURRENT_THREAD;
[626]616if( DEBUG_FATFS_FREE_CLUSTERS < cycle )
[602]617printk("\n[%s] thread[%x,%x] enter for allocated cluster %x / cycle %d\n",
618__FUNCTION__, this->process->pid, this->trdid, cluster , cycle );
619#endif
620
[626]621    // get FAT cluster an local pointer on fatfs context in FAT cluster
622    fat_cxy      = GET_CXY( fatfs_ctx_xp );
623    fat_ctx_ptr  = GET_PTR( fatfs_ctx_xp );
624   
625    // build extended pointers on free_clusters, and free_cluster_hint in fatfs context
626    hint_xp = XPTR( fat_cxy , &fat_ctx_ptr->free_cluster_hint );
627    numb_xp = XPTR( fat_cxy , &fat_ctx_ptr->free_clusters );
[602]628
[626]629    // update "free_clusters" value
630    numb = hal_remote_l32( numb_xp ) - 1;
631    hal_remote_s32( numb_xp , numb );
[602]632
[625]633    // get extended pointer on FAT mapper
[628]634    fat_mapper_xp = hal_remote_l64( XPTR( fat_cxy , &fat_ctx_ptr->fat_mapper_xp ) );
[625]635
636    // initialise variables to scan the FAT mapper
637    // and find the first free slot > cluster
[602]638    page_id  = (cluster + 1) >> 10;
639    slot_id  = (cluster + 1) & 0x3FF;
[626]640    page_max = hal_remote_l32( XPTR( fat_cxy, &fat_ctx_ptr->fat_sectors_count ) ) >> 3;
[602]641
642    // scan FAT mapper / loop on pages
643    while ( page_id < page_max )           
644    {
645        // get current page from mapper
[628]646        page_xp = mapper_remote_get_page( fat_mapper_xp , page_id );
[602]647
648        if( page_xp == XPTR_NULL )
649        {
650            printk("\n[ERROR] in %s : cannot access FAT mapper\n", __FUNCTION__ );
651            return -1;
652        }
653
[625]654        // get extended pointer on page
655        base_xp = ppm_page2base( page_xp );
656
[602]657        // scan FAT mapper / loop on slots
658        while ( slot_id < 1024 )
659        {
660            // get extended pointer on current slot
[625]661            slot_xp = base_xp + (slot_id << 2);
[602]662
[625]663            // test slot value
[602]664            if ( hal_remote_l32( slot_xp ) == FREE_CLUSTER )
665            {
[626]666                // update "free_cluster_hint" value
667                hint = (page_id << 10) + slot_id - 1;
668                hal_remote_s32( hint_xp , hint );
[602]669
[626]670                // update FS_INFO sector on IOC device
[628]671                error = fatfs_update_ioc_fat( fatfs_ctx_xp,
672                                              page_id,
673                                              page_id );
[626]674
675                if( error ) 
676                {
677                    printk("\n[ERROR] in %s : cannot update FS_INFO on IOC\n", __FUNCTION__ );
678                    return -1;
679                }
680
[602]681#if DEBUG_FATFS_FREE_CLUSTERS
682cycle = (uint32_t)hal_get_cycles();
683if( DEBUG_FATFS_FREE_CLUSTERS < (uint32_t)hal_get_cycles() )
[628]684printk("\n[%s] thread[%x,%x] exit / hint %x / free %x / cycle %d\n",
[626]685__FUNCTION__, this->process->pid, this->trdid, 
[628]686hal_remote_l32(hint_xp), hal_remote_l32(numb_xp), cycle );
[602]687#endif
688                return 0;
689            }
690
[625]691            // update slot_id
692            slot_id = 0;
[602]693
694        }  // end loop on slots
695
[626]696        // update page_id & slot_id variables
[602]697        page_id++;
698        slot_id = 0;
699
700    }  // end loop on pages
701
702    // return error if no free cluster found
703    printk("\n[ERROR] in %s : No free cluster found\n", __FUNCTION__ );
704    return -1;
705   
706}  // end fatfs_free_clusters_decrement()
707
708//////////////////////////////////////////////////////////////////////////////////////////
[625]709// This static function increments the "free_clusters" variable, and updates the
[626]710// "free_cluster_hint" variables in the FATFS context in FAT cluster, identified
[628]711// by the <fat_ctx_xp> argument, when a FATFS cluster is released.
[625]712// If the released cluster index is smaller than the current (hint) value,
713// it set "free_cluster_hint" <= cluster.
[628]714// It does NOT update the  FS_INFO sector on the IOC device.
715// It can be called by a thead running in any cluster.
716// The lock protecting exclusive access to the FAT must be taken by the calling function.
[602]717//////////////////////////////////////////////////////////////////////////////////////////
[626]718// @ fatfs_ctx_xp  : extended pointer on FATFS context in FAT cluster.
719// @ cluster       : recently released cluster index in FAT.
720// @ return 0 if success, return -1 if the FS_INFO sector cannot be updated.
[602]721//////////////////////////////////////////////////////////////////////////////////////////
[626]722static error_t fatfs_free_clusters_increment( xptr_t   fatfs_ctx_xp,
723                                              uint32_t cluster )
[602]724{
[626]725    error_t       error;
726    cxy_t         fat_cxy;      // FAT cluster identifier
727    fatfs_ctx_t * fat_ctx_ptr;  // local pointer on fatfs context in FAT cluster
[602]728    xptr_t        hint_xp;      // extended pointer on "free_cluster_hint" shared variable
729    xptr_t        numb_xp;      // extended pointer on "free_clusters" shared variable
730    uint32_t      hint;         // "free_cluster_hint" variable current value
731    uint32_t      numb;         // "free_clusters" variable current value
732
[626]733#if DEBUG_FATFS_FREE_CLUSTERS
734uint32_t   cycle = (uint32_t)hal_get_cycles();
735thread_t * this  = CURRENT_THREAD;
736if( DEBUG_FATFS_FREE_CLUSTERS < cycle )
737printk("\n[%s] thread[%x,%x] enter for released cluster %x / cycle %d\n",
738__FUNCTION__, this->process->pid, this->trdid, cluster , cycle );
739#endif
740
741    // get FAT cluster an local pointer on fatfs context in FAT cluster
742    fat_cxy      = GET_CXY( fatfs_ctx_xp );
743    fat_ctx_ptr  = GET_PTR( fatfs_ctx_xp );
744   
[625]745    // build extended pointers on free_clusters, and free_cluster_hint
[626]746    hint_xp = XPTR( fat_cxy , &fat_ctx_ptr->free_cluster_hint );
747    numb_xp = XPTR( fat_cxy , &fat_ctx_ptr->free_clusters );
[602]748
749    // get current value of free_cluster_hint and free_clusters
750    hint = hal_remote_l32( hint_xp );
751    numb = hal_remote_l32( numb_xp );
752
[626]753    // update "numb" and "hint" variables as required
754    numb++;
755    if ( (cluster - 1) < hint ) hint = cluster - 1;
[602]756
757    // update free_clusters
[626]758    hal_remote_s32( numb_xp , numb );
759    hal_remote_s32( hint_xp , hint );
[602]760
[626]761    // update FS_INFO sector on IOC device
[628]762    error = fatfs_update_ioc_fsinfo( fatfs_ctx_xp );
[626]763
764    if( error ) 
765    {
766        printk("\n[ERROR] in %s : cannot update FS_INFO on IOC\n", __FUNCTION__ );
767        return -1;
768    }
769
[602]770#if DEBUG_FATFS_FREE_CLUSTERS
[628]771cycle = (uint32_t)hal_get_cycles();
[602]772if( DEBUG_FATFS_FREE_CLUSTERS < (uint32_t)hal_get_cycles() )
[628]773printk("\n[%s] thread[%x,%x] exit / hint %x / free %x / cycle %d\n",
[602]774__FUNCTION__, this->process->pid, this->trdid,
[628]775hal_remote_l32( hint_xp ), hal_remote_l32( numb_xp ), cycle );
[602]776#endif
777
[626]778    return 0;
779
[602]780}  // end fatfs_free_clusters_increment()
781
782//////////////////////////////////////////////////////////////////////////////////////////
[628]783// This recursive function is called by the generic function fatfs_release_inode().
784// It release all FATFS clusters allocated to a given inode to the FAT mapper.
785// It can be called by a thread running in any cluster, as it use remote pointers
786// to access both the FAT mapper and the FATFS context in the FAT cluster, defined
787// by the <fat_mapper_xp> and <fatfs_ctx_xp> arguments.
788// The removal is done in reverse order of the linked list (from last cluster to first).
789// It returns in the <dirty_page_min> and <dirty_page_max> buffers the indexes of the
790// modified pages in the FAT mapper.
791// It updates the FAT mapper and the free_cluster info in the FATFS context, but does NOT
792// update the FAT and the FS_INFO on IOC device.
[602]793//////////////////////////////////////////////////////////////////////////////////////////
[628]794// @ fat_mapper_xp  : [in]  extended pointer on FAT mapper.
795// @ fatfs_ctx_xp   : [in]  extended pointer on FATFS context in FAT cluster.
796// @ cluster        : [in]  index of cluster to be released from FAT mapper.
797// @ dirty_page_min : [out] pointer on buffer for min dirty page index.
798// @ dirty_page_max : [out] pointer on buffer for max dirty page index.
799// @ return 0 if success / return -1 if error.
[602]800//////////////////////////////////////////////////////////////////////////////////////////
[628]801static error_t fatfs_recursive_release( xptr_t      fat_mapper_xp,
802                                        xptr_t      fatfs_ctx_xp,
803                                        uint32_t    cluster,
804                                        uint32_t  * dirty_page_min,
805                                        uint32_t  * dirty_page_max )
[602]806{
[628]807    uint32_t next;       // next cluster index
808    uint32_t page_id;    // page index in FAT mapper
809    uint32_t word_id;    // word index in page
[602]810
[628]811    // get page index and word index from cluster
812    page_id = cluster >> 10;
813    word_id = cluster & 0x3FF;
[602]814
[625]815    // get next cluster index from FAT mapper
[628]816    if ( mapper_remote_get_32( fat_mapper_xp,
817                               page_id,
818                               word_id,
[625]819                               &next ) ) return -1;
820
[602]821#if (DEBUG_FATFS_RELEASE_INODE & 1)
822thread_t * this = CURRENT_THREAD;
823if ( DEBUG_FATFS_RELEASE_INODE < (uint32_t)hal_get_cycles() )
824printk("\n[%s] thread[%x,%x] access FAT for cluster %x / next %x\n",
825__FUNCTION__, this->process->pid, this->trdid, cluster, next );
826#endif
827
828    if ( next < END_OF_CHAIN_CLUSTER_MIN )  // non terminal case
829    {
830        // call fatfs_recursive_release() on next cluster
[628]831        if ( fatfs_recursive_release( fat_mapper_xp,
832                                      fatfs_ctx_xp,
833                                      next,
834                                      dirty_page_min,
835                                      dirty_page_max ) ) return -1;
[602]836    }       
837
[628]838    // update FAT mapper
839    if ( mapper_remote_set_32( fat_mapper_xp,
840                               page_id, 
841                               word_id,
[625]842                               FREE_CLUSTER ) ) return -1;
[602]843
[628]844    // update dirty_page_min / dirty_page_max buffers
845    if( page_id < *dirty_page_min ) *dirty_page_min = page_id;
846    if( page_id > *dirty_page_max ) *dirty_page_max = page_id;
[602]847
[628]848    // Update free_cluster info in FATFS context
849    return fatfs_free_clusters_increment( fatfs_ctx_xp , cluster );
850
[602]851}  // end fatfs_recursive_release()
852
853
854//////////////////////////////////////////////////////////////////////////////////////////
[568]855//              FATFS specific extern functions
[238]856//////////////////////////////////////////////////////////////////////////////////////////
[1]857
[626]858///////////////////////////////////
859void fatfs_display_ctx( cxy_t cxy )
[265]860{
[626]861    // get pointer on local FATFS context
862    vfs_ctx_t   * vfs_ctx = &fs_context[FS_TYPE_FATFS];
863        fatfs_ctx_t * ctx     = hal_remote_lpt( XPTR( cxy , &vfs_ctx->extend ) );
864
865    uint32_t fat_sectors       = hal_remote_l32( XPTR( cxy , &ctx->fat_sectors_count ) );
866    uint32_t sector_size       = hal_remote_l32( XPTR( cxy , &ctx->bytes_per_sector ) );
867    uint32_t sec_per_clus      = hal_remote_l32( XPTR( cxy , &ctx->sectors_per_cluster ) );
868    uint32_t fat_lba           = hal_remote_l32( XPTR( cxy , &ctx->fat_begin_lba ) );
869    uint32_t data_lba          = hal_remote_l32( XPTR( cxy , &ctx->cluster_begin_lba ) );
870    uint32_t fsinfo_lba        = hal_remote_l32( XPTR( cxy , &ctx->fs_info_lba ) );
871    uint32_t root_dir_clus     = hal_remote_l32( XPTR( cxy , &ctx->root_dir_cluster ) );
872    uint32_t free_clusters     = hal_remote_l32( XPTR( cxy , &ctx->free_clusters ) );
873    uint32_t free_cluster_hint = hal_remote_l32( XPTR( cxy , &ctx->free_cluster_hint ) );
874    xptr_t   mapper_xp         = hal_remote_l64( XPTR( cxy , &ctx->fat_mapper_xp ) );
875    void   * fs_info_buffer    = hal_remote_lpt( XPTR( cxy , &ctx->fs_info_buffer ) );
876
877    printk("\n*** FAT context in cluster %x\n" 
[602]878           "- fat_sectors       = %d\n"
879           "- sector size       = %d\n"
880           "- cluster size      = %d\n"
[626]881           "- fat_lba           = %x\n"
882           "- data_lba          = %x\n"
883           "- fsinfo_lba        = %x\n"
884           "- root_dir_cluster  = %x\n"
885           "- free_clusters     = %x\n"
886           "- free_cluster_hint = %x\n"
887           "- fat_mapper_ptr    = %x\n"
888           "- fs_info_buffer    = %x\n",
889           cxy,
890           fat_sectors,
891           sector_size,
892           sector_size * sec_per_clus,
893           fat_lba,
894           data_lba,
895           fsinfo_lba,
896           root_dir_clus,
897           free_clusters,
898           free_cluster_hint,
899           GET_PTR( mapper_xp ),
900           fs_info_buffer );
[265]901
[626]902}  // end fatfs_ctx_display()
[602]903
904//////////////////////////////////////////
905void fatfs_display_fat( uint32_t  page_id,
906                        uint32_t  nentries )
907{
908    uint32_t line;
909    uint32_t maxline;
910
[626]911    // compute number of lines to display
[602]912    maxline = nentries >> 3;
913    if( nentries & 0x7 ) maxline++;
914
915    // get pointer on local FATFS context
[626]916    vfs_ctx_t   * vfs_ctx       = &fs_context[FS_TYPE_FATFS];
917    fatfs_ctx_t * loc_fatfs_ctx = (fatfs_ctx_t *)vfs_ctx->extend;
[602]918
919    // get extended pointer on FAT mapper
[626]920    xptr_t fat_mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
[602]921
[626]922    // get FAT cluster identifier
923    cxy_t  fat_cxy = GET_CXY( fat_mapper_xp );
924
925    // get pointer on FATFS context in FAT cluster
926    fatfs_ctx_t * fat_fatfs_ctx = hal_remote_lpt( XPTR( fat_cxy , &vfs_ctx->extend ) );
927 
928    // get current value of hint and free_clusters
929    uint32_t hint = hal_remote_l32( XPTR( fat_cxy , &fat_fatfs_ctx->free_cluster_hint ) );
930    uint32_t free = hal_remote_l32( XPTR( fat_cxy , &fat_fatfs_ctx->free_clusters ) );
931 
932    // get extended pointer on requested page in FAT mapper
[602]933    xptr_t     page_xp  = mapper_remote_get_page( fat_mapper_xp , page_id );
934
935    // get extended pointer on requested page base
936    xptr_t     base_xp  = ppm_page2base( page_xp );
[626]937    void     * base     = GET_PTR( base_xp );
[602]938
[626]939    printk("\n***** FAT mapper / cxy %x / page_id %d / base %x / free_clusters %x / hint %x\n",
940    fat_cxy, page_id, base, free, hint );
941
[602]942    for( line = 0 ; line < maxline ; line++ )
943    {
944        printk("%x : %X | %X | %X | %X | %X | %X | %X | %X\n", (line<<3),
945        hal_remote_l32( base_xp + ((line<<5)      ) ),
946        hal_remote_l32( base_xp + ((line<<5) + 4  ) ),
947        hal_remote_l32( base_xp + ((line<<5) + 8  ) ),
948        hal_remote_l32( base_xp + ((line<<5) + 12 ) ),
949        hal_remote_l32( base_xp + ((line<<5) + 16 ) ),
950        hal_remote_l32( base_xp + ((line<<5) + 20 ) ),
951        hal_remote_l32( base_xp + ((line<<5) + 24 ) ),
952        hal_remote_l32( base_xp + ((line<<5) + 28 ) ) );
953    }
954
955}  // end fatfs_display_fat()
956
957///////////////////////////////////////////////////////
958error_t fatfs_get_cluster( uint32_t   first_cluster_id,
[406]959                           uint32_t   searched_page_index,
[265]960                           uint32_t * searched_cluster_id )
[238]961{
[602]962    xptr_t     current_page_xp;        // pointer on current page descriptor
963    uint32_t * buffer;                 // pointer on current page (array of uint32_t)
[406]964    uint32_t   current_page_index;     // index of current page in FAT
[625]965    uint32_t   current_slot_index;     // index of slot in current page
[238]966    uint32_t   page_count_in_file;     // index of page in file (index in linked list)
[406]967    uint32_t   next_cluster_id;        // content of current FAT slot
[627]968    xptr_t     lock_xp;                // extended pointer on FAT lock
[1]969
[602]970assert( (searched_page_index > 0) ,
971"no FAT access required for first page\n");
[246]972
[438]973#if DEBUG_FATFS_GET_CLUSTER
[602]974uint32_t   cycle = (uint32_t)hal_get_cycles();
975thread_t * this  = CURRENT_THREAD;
[438]976if( DEBUG_FATFS_GET_CLUSTER < cycle )
[625]977printk("\n[%s] thread[%x,%x] enter / first_cluster_id %d / searched_index %d / cycle %d\n",
[602]978__FUNCTION__, this->process->pid, this->trdid, first_cluster_id, searched_page_index, cycle );
[435]979#endif
[265]980
[627]981    // get local pointer on VFS context (same in all clusters)
982    vfs_ctx_t * vfs_ctx = &fs_context[FS_TYPE_FATFS];
983
[602]984    // get local pointer on local FATFS context
[627]985    fatfs_ctx_t * loc_fatfs_ctx = vfs_ctx->extend;
[1]986
[602]987    // get extended pointer and cluster on FAT mapper
[627]988    xptr_t fat_mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
989    cxy_t  fat_cxy        = GET_CXY( fat_mapper_xp );
[602]990
[627]991    // get local pointer on FATFS context in FAT cluster
992    fatfs_ctx_t * fat_fatfs_ctx = hal_remote_lpt( XPTR( fat_cxy , &vfs_ctx->extend ) );
993
994    // build extended pointer on FAT lock in FAT cluster
995    lock_xp = XPTR( fat_cxy , &fat_fatfs_ctx->lock );
996
997    // take FAT lock in read mode
998    remote_rwlock_rd_acquire( lock_xp );
999
[602]1000    // initialize loop variable (1024 slots per page)
1001    current_page_index  = first_cluster_id >> 10;
[625]1002    current_slot_index  = first_cluster_id & 0x3FF;
[238]1003    page_count_in_file  = 0;
[406]1004    next_cluster_id     = 0xFFFFFFFF;
[238]1005
[625]1006    // scan FAT mapper (i.e. traverse FAT linked list)
[406]1007    while( page_count_in_file < searched_page_index )
[238]1008    {
[625]1009        // get pointer on current page descriptor in FAT mapper
1010        current_page_xp = mapper_remote_get_page( fat_mapper_xp , current_page_index );
[238]1011
[602]1012        if( current_page_xp == XPTR_NULL )
1013        {
[625]1014            printk("\n[ERROR] in %s : cannot get next page from FAT mapper\n", __FUNCTION__);
[627]1015            remote_rwlock_rd_release( lock_xp );
[602]1016            return -1;
1017        }
[238]1018
1019        // get pointer on buffer for current page
[602]1020        xptr_t base_xp = ppm_page2base( current_page_xp );
1021        buffer = (uint32_t *)GET_PTR( base_xp );
[238]1022
1023        // get FAT slot content
[627]1024        next_cluster_id = hal_remote_l32( XPTR( fat_cxy, &buffer[current_slot_index] ) );
[238]1025
[438]1026#if (DEBUG_FATFS_GET_CLUSTER & 1)
1027if( DEBUG_FATFS_GET_CLUSTER < cycle )
[602]1028printk("\n[%s] traverse FAT / current_page_index = %d\n"
[625]1029"current_slot_index = %d / next_cluster_id = %d\n",
1030__FUNCTION__, current_page_index, current_slot_index , next_cluster_id );
[435]1031#endif
[238]1032        // update loop variables
[625]1033        current_page_index = next_cluster_id >> 10;
1034        current_slot_index = next_cluster_id & 0x3FF;
[238]1035        page_count_in_file++;
1036    }
[246]1037
[625]1038    if( next_cluster_id == 0xFFFFFFFF )
1039    {
1040        printk("\n[ERROR] in %s : searched_cluster_id not found in FAT\n", __FUNCTION__ );
[627]1041        remote_rwlock_rd_release( lock_xp );
[625]1042        return -1;
1043    }
[406]1044   
[627]1045    // release FAT lock
1046    remote_rwlock_rd_release( lock_xp );
1047
[438]1048#if DEBUG_FATFS_GET_CLUSTER
[435]1049cycle = (uint32_t)hal_get_cycles();
[438]1050if( DEBUG_FATFS_GET_CLUSTER < cycle )
[602]1051printk("\n[%s] thread[%x,%x] exit / searched_cluster_id = %d / cycle %d\n",
1052__FUNCTION__, this->process->pid, this->trdid, next_cluster_id / cycle );
[435]1053#endif
[406]1054
1055    *searched_cluster_id = next_cluster_id;
[238]1056    return 0;
1057
1058}  // end fatfs_get_cluster()
1059
1060
1061
[1]1062///////////////////////////////////////////////////////////////////////////////////////
[602]1063// Generic API : the following functions are called by the kernel VFS
[188]1064//               and must be defined by all supported file systems.
[1]1065///////////////////////////////////////////////////////////////////////////////////////
1066
[568]1067/////////////////////////////////////
[484]1068fatfs_ctx_t * fatfs_ctx_alloc( void )
[1]1069{
[23]1070    kmem_req_t    req;
[188]1071        req.type    = KMEM_FATFS_CTX;
1072        req.size    = sizeof(fatfs_ctx_t);
1073    req.flags   = AF_KERNEL | AF_ZERO;
[1]1074
[188]1075        return (fatfs_ctx_t *)kmem_alloc( &req );
1076}
[23]1077
[188]1078//////////////////////////////////////////////
1079void fatfs_ctx_init( fatfs_ctx_t * fatfs_ctx )
1080{
1081    error_t       error;
1082    kmem_req_t    req;
1083    uint8_t     * buffer;
[626]1084    xptr_t        buffer_xp;
[23]1085
[602]1086#if DEBUG_FATFS_CTX_INIT
[625]1087uint32_t   cycle = (uint32_t)hal_get_cycles();
1088thread_t * this  = CURRENT_THREAD;
[602]1089if( DEBUG_FATFS_CTX_INIT < cycle )
1090printk("\n[%s] thread[%x,%x] enter for fatfs_ctx = %x / cycle %d\n",
1091__FUNCTION__ , this->process->pid, this->trdid, fatfs_ctx , cycle );
[435]1092#endif
[23]1093
[602]1094// check argument
[625]1095assert( (fatfs_ctx != NULL) , "pointer on FATFS context is NULL" );
[23]1096
[626]1097// check only cluster 0 does FATFS initialization
[625]1098assert( (local_cxy == 0) , "only cluster 0 can initialize FATFS");
[602]1099
[626]1100    // allocate a permanent 512 bytes buffer to store
1101    // - temporarily the BOOT sector
1102    // - permanently the FS_INFO sector
[50]1103        req.type    = KMEM_512_BYTES;
1104    req.flags   = AF_KERNEL | AF_ZERO;
1105        buffer      = (uint8_t *)kmem_alloc( &req );
[626]1106    buffer_xp   = XPTR( local_cxy , buffer );
[188]1107
[602]1108    if( buffer == NULL ) 
1109    {
1110        printk("\n[PANIC] in %s : cannot allocate buffer\n", __FUNCTION__ );
1111        hal_core_sleep();
1112    }
[50]1113     
[602]1114    // load the BOOT record from device
[626]1115    error = dev_ioc_sync_read( buffer_xp , 0 , 1 );
[23]1116
[602]1117    if ( error )
1118    {
1119        printk("\n[PANIC] in %s : cannot access boot record\n", __FUNCTION__ );
1120        hal_core_sleep();
1121    }
[279]1122
[602]1123#if (DEBUG_FATFS_CTX_INIT & 0x1)
1124if( DEBUG_FATFS_CTX_INIT < cycle )
[623]1125putb( "boot record", buffer , 256 );
[50]1126#endif
1127
[602]1128    // get sector size from boot record
[626]1129    uint32_t sector_size = fatfs_get_record( BPB_BYTSPERSEC , buffer );
[602]1130    if ( sector_size != 512 )
1131    {
1132        printk("\n[PANIC] in %s : sector size must be 512 bytes\n", __FUNCTION__ );
1133        hal_core_sleep();
1134    }
[50]1135
[602]1136    // get cluster size from boot record
[626]1137    uint32_t nb_sectors = fatfs_get_record( BPB_SECPERCLUS , buffer );
[602]1138    if ( nb_sectors != 8 )
1139    {
1140        printk("\n[PANIC] in %s : cluster size must be 8 sectors\n", __FUNCTION__ );
1141        hal_core_sleep();
1142    }
[50]1143
[602]1144    // get number of FAT copies from boot record
[626]1145    uint32_t nb_fats = fatfs_get_record( BPB_NUMFATS , buffer );
[602]1146    if ( nb_fats != 1 )
1147    {
1148        printk("\n[PANIC] in %s : number of FAT copies must be 1\n", __FUNCTION__ );
1149        hal_core_sleep();
1150    }
[50]1151
[602]1152    // get number of sectors in FAT from boot record
[626]1153    uint32_t fat_sectors = fatfs_get_record( BPB_FAT32_FATSZ32 , buffer );
[602]1154    if ( (fat_sectors & 0xF) != 0 )
1155    {
1156        printk("\n[PANIC] in %s : FAT size not multiple of 16 sectors\n", __FUNCTION__ );
1157        hal_core_sleep();
1158    }
[50]1159
[602]1160    // get root cluster from boot record
[626]1161    uint32_t root_cluster = fatfs_get_record( BPB_FAT32_ROOTCLUS , buffer );
[602]1162    if ( root_cluster != 2 ) 
1163    {
1164        printk("\n[PANIC] in %s : root cluster index must be 2\n", __FUNCTION__ );
1165        hal_core_sleep();
1166    }
[50]1167
[23]1168    // get FAT lba from boot record
[626]1169    uint32_t fat_lba = fatfs_get_record( BPB_RSVDSECCNT , buffer );
[50]1170
[602]1171    // get FS_INFO sector lba from boot record
[626]1172    uint32_t fs_info_lba = fatfs_get_record( BPB_FAT32_FSINFO , buffer );
[602]1173
1174    // load the FS_INFO record from device
[626]1175    error = dev_ioc_sync_read( buffer_xp , fs_info_lba , 1 );
[602]1176
1177    if ( error )
1178    {
1179        printk("\n[PANIC] in %s : cannot access FS_INFO record\n", __FUNCTION__ );
1180        hal_core_sleep();
1181    }
1182
[626]1183    // get free_clusters number from FS_INFO record
1184    uint32_t free_clusters = fatfs_get_record( FS_FREE_CLUSTERS , buffer );
[602]1185    if ( free_clusters >= fat_sectors << 7 )
1186    {
1187        printk("\n[PANIC] in %s : unconsistent free_clusters\n", __FUNCTION__ );
1188        hal_core_sleep();
1189    }
1190
[626]1191    // get free_cluster_hint from FS_INFO record
1192    uint32_t free_cluster_hint = fatfs_get_record( FS_FREE_CLUSTER_HINT , buffer );
1193
[602]1194    if ( free_cluster_hint >= fat_sectors << 7 )
1195    {
1196        printk("\n[PANIC] in %s : unconsistent free_cluster_hint\n", __FUNCTION__ );
1197        hal_core_sleep();
1198    }
1199
[23]1200    // allocate a mapper for the FAT itself
[246]1201    mapper_t * fat_mapper = mapper_create( FS_TYPE_FATFS );
[602]1202    if ( fat_mapper == NULL )
1203    {
1204        printk("\n[PANIC] in %s : no memory for FAT mapper\n", __FUNCTION__ );
1205        hal_core_sleep();
1206    }
[50]1207
[626]1208    // the inode field is NULL for the FAT mapper
[246]1209    fat_mapper->inode = NULL;
1210
[23]1211    // initialize the FATFS context
1212    fatfs_ctx->fat_begin_lba         = fat_lba;
1213    fatfs_ctx->fat_sectors_count     = fat_sectors; 
1214    fatfs_ctx->bytes_per_sector      = sector_size;
[188]1215    fatfs_ctx->sectors_per_cluster   = nb_sectors;
[23]1216    fatfs_ctx->cluster_begin_lba     = fat_lba + fat_sectors;
1217    fatfs_ctx->root_dir_cluster      = 2;
1218    fatfs_ctx->fat_mapper_xp         = XPTR( local_cxy , fat_mapper );
[626]1219    fatfs_ctx->fs_info_lba           = fs_info_lba;
[602]1220    fatfs_ctx->free_clusters         = free_clusters;
1221    fatfs_ctx->free_cluster_hint     = free_cluster_hint;
[626]1222    fatfs_ctx->fs_info_buffer        = buffer;
[23]1223
[628]1224    remote_rwlock_init( XPTR( local_cxy , &fatfs_ctx->lock ) , LOCK_FATFS_FAT );
[602]1225
[625]1226#if (DEBUG_FATFS_CTX_INIT & 0x1)
1227if( DEBUG_FATFS_CTX_INIT < cycle )
1228fatfs_ctx_display( fatfs_ctx );
1229#endif
1230
[602]1231#if DEBUG_FATFS_CTX_INIT
[435]1232cycle = (uint32_t)hal_get_cycles();
[602]1233if( DEBUG_FATFS_CTX_INIT < cycle )
1234printk("\n[%s]  thread[%x,%x] exit for fatfs_ctx = %x / cycle %d\n",
1235__FUNCTION__, this->process->pid, this->trdid, fatfs_ctx, cycle );
[435]1236#endif
[279]1237
[23]1238}  // end fatfs_ctx_init()
1239
[188]1240/////////////////////////////////////////////////
1241void fatfs_ctx_destroy( fatfs_ctx_t * fatfs_ctx )
[23]1242{
1243    kmem_req_t    req;
[188]1244    req.type = KMEM_FATFS_CTX;
[23]1245    req.ptr  = fatfs_ctx;
1246    kmem_free( &req );
1247}
1248
[602]1249///////////////////////////////////////////////
1250error_t fatfs_add_dentry( vfs_inode_t  * inode,
1251                          vfs_dentry_t * dentry )
[1]1252{
[401]1253    error_t       error;
[602]1254    uint32_t      length;        // dentry name length
1255    uint32_t      nb_lfn;        // number or required LFN
1256    char          sfn[11];       // buffer for SFN name
1257    uint8_t       checksum;      // name checksum
1258    mapper_t    * mapper;        // loal pointer on parent inode mapper
1259    xptr_t        mapper_xp;     // extended pointer on parent inode mapper
1260    xptr_t        child_xp;      // extended pointer on child inode
1261    cxy_t         child_cxy;     // child inode cluster
1262    vfs_inode_t * child_ptr;     // child inode local pointer
1263    uint32_t      size;          // child inode size
1264    uint32_t      type;          // child inode type
1265    uint32_t      cluster;       // child inode cluster index
[246]1266
[602]1267#if DEBUG_FATFS_ADD_DENTRY
1268char       dir_name[CONFIG_VFS_MAX_NAME_LENGTH];
1269uint32_t   cycle = (uint32_t)hal_get_cycles();
1270thread_t * this  = CURRENT_THREAD;
1271vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
1272if( DEBUG_FATFS_ADD_DENTRY < cycle )
1273printk("\n[%s]  thread[%x,%x] enter / parent <%s> / child <%s> / cycle %d\n",
1274__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1275#endif
[1]1276
[602]1277// check arguments
1278assert( (inode != NULL) , "inode pointer is NULL\n" );
1279assert( (dentry != NULL) , "dentry pointer is NULL\n" );
1280assert( (inode->mapper != NULL ) , "mapper pointer is NULL\n" );
1281 
1282    // get pointers on directory mapper
1283    mapper    = inode->mapper;
1284    mapper_xp = XPTR( local_cxy , mapper );
[1]1285
[602]1286    // get extended pointers on remote child inode
1287    child_xp  = dentry->child_xp;
1288    child_cxy = GET_CXY( child_xp );
1289    child_ptr = GET_PTR( child_xp );
[1]1290
[602]1291    // get relevant infos from child inode
1292    type    =                     hal_remote_l32( XPTR( child_cxy , &child_ptr->type ) );
1293    size    =                     hal_remote_l32( XPTR( child_cxy , &child_ptr->size ) );
1294    cluster = (uint32_t)(intptr_t)hal_remote_lpt( XPTR( child_cxy , &child_ptr->extend ) );
[1]1295
[602]1296    // analyse dentry name
1297    error = fatfs_name_format( dentry->name,
1298                               &length,
1299                               &nb_lfn,
1300                               sfn,
1301                               &checksum );
1302    if ( error )
[246]1303    {
[602]1304        printk("\n[ERROR] in %s : dentry name > 31 bytes\n", __FUNCTION__ );
1305        return -1;
1306    }
1307                               
1308    // Search end of directory with two embedded loops:
1309    // - scan the pages in the mapper
1310    // - scan the entries in each page to find NO_MORE_ENTRY
[1]1311
[602]1312    xptr_t     page_xp;                 // extended pointer on page descriptor
1313    xptr_t     base_xp;                 // extended pointer on page base
1314    uint8_t  * base;                    // local pointer on page base (array of bytes)
1315    uint32_t   page_id = 0;             // page index in mapper
1316    uint32_t   offset  = 0;             // position in page
1317    uint32_t   found   = 0;             // NO_MORE_ENTRY found
[1]1318
[602]1319    // loop on pages in mapper
1320    while ( found == 0 )
[1]1321    {
[602]1322        // get extended pointer on page descriptor in mapper
1323        page_xp  = mapper_remote_get_page( mapper_xp , page_id );
[1]1324
[602]1325        if ( page_xp == XPTR_NULL )
1326        {
1327            printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ );
1328            return -1;
1329        }
1330       
1331        // get pointer on page base
1332        base_xp = ppm_page2base( page_xp );
1333        base = GET_PTR( base_xp );
[246]1334
[602]1335        // loop on directory entries in this page
1336        while ( (offset < 4096) && (found == 0) )
[265]1337        {
[626]1338            if ( fatfs_get_record( LDIR_ORD, (base + offset) ) == NO_MORE_ENTRY )
[602]1339            {
1340                found = 1;
1341            } 
1342            else
1343            {
1344                offset = offset + 32;
1345            }
1346        }  // end loop on entries
1347
1348        if ( found == 0 )
1349        {
1350            page_id++;
1351            offset = 0;
[265]1352        }
[602]1353    }  // end loop on pages
1354
1355    // Modify the directory mapper: depending on the name length,
1356    // the new child requires to write (3, 4, or 5) directory entries.
1357    // To actually register the new child, we use a 5 steps FSM
1358    // (one state per entry to be written), that is traversed as:
1359    // LFN3 -> LFN2 -> LFN1 -> NORMAL -> NOMORE
1360    // At most two pages are modified:
1361    // - the page containing the NO_MORE_ENTRY is always modified
1362    // - the following page can be modified if the name spread on to pages.
1363
1364    char * name = dentry->name;
1365
1366    uint32_t step;          // FSM state
1367
1368    if      ( nb_lfn == 1 ) step = 3;
1369    else if ( nb_lfn == 2 ) step = 4;
1370    else if ( nb_lfn == 3 ) step = 5;
1371   
1372    uint8_t  * entry;       // pointer on directory entry to be written
1373    uint32_t   i;           // byte index in one 32 bytes directory
1374    uint32_t   c;           // character index in name
1375
1376    while ( step )   
1377    {
1378        // when the new child is split on two pages,
1379        // we need to access a new page in mapper
1380        if ( offset >= 4096 )
[265]1381        {
[602]1382            // copy the modified page to IOC device
[614]1383            fatfs_move_page( page_xp , IOC_SYNC_WRITE );   
[265]1384
[602]1385            // get the next page in FAT mapper
1386            page_xp  = mapper_remote_get_page( mapper_xp , page_id + 1 );
1387
1388            if ( page_xp == XPTR_NULL )
[265]1389            {
[602]1390                printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ );
1391                return -1;
1392            }
1393       
1394            // get pointer on page base
1395            base_xp = ppm_page2base( page_xp );
1396            base = GET_PTR( base_xp );
1397           
1398            // update offset
1399            offset = 0;
1400        }
[407]1401
[602]1402        // compute directory entry address
1403        entry = base + offset;
1404
1405#if (DEBUG_FATFS_ADD_DENTRY & 1)
[630]1406cycle = (uint32_t)hal_get_cycles();
[602]1407if( DEBUG_FATFS_ADD_DENTRY < cycle )
[630]1408printk("\n[%s] FSM step = %d / offset = %x / nb_lfn = %d / cycle %d\n",
1409__FUNCTION__, step, offset, nb_lfn, cycle );
[435]1410#endif
[602]1411
1412        // write 32 bytes (one directory entry) per iteration
1413        switch ( step )
1414        {
1415            case 5:   // write LFN3 entry
1416            {
1417                c = 26;
1418                // scan the 32 bytes in dir_entry
1419                for ( i = 0 ; i < 32 ; i++ )
1420                {
1421                    if (i == 0)
1422                    {
1423                        if ( nb_lfn == 3) entry[i] = 0x43;
1424                        else              entry[i] = 0x03;
1425                    }
1426                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1427                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1428                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1429                              ( c < length ) )
1430                    {
1431                                          entry[i] = name[c];
1432                                          c++;
1433                    }
1434                    else if (i == 11)     entry[i] = 0x0F;
1435                    else if (i == 13)     entry[i] = checksum;
1436                    else                  entry[i] = 0x00;
1437                }
1438                step--;
1439                break;
[265]1440            }
[602]1441            case 4:   // write LFN2 entry 
[265]1442            {
[602]1443                c = 13;
1444                // scan the 32 bytes in dir_entry
1445                for ( i = 0 ; i < 32 ; i++ )
1446                {
1447                    if (i == 0)
1448                    {
1449                        if ( nb_lfn == 2) entry[i] = 0x42;
1450                        else              entry[i] = 0x02;
1451                    }
1452                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1453                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1454                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1455                              ( c < length ) )
1456                    {
1457                                          entry[i] = name[c];
1458                                          c++;
1459                    }
1460                    else if (i == 11)     entry[i] = 0x0F;
1461                    else if (i == 13)     entry[i] = checksum;
1462                    else                  entry[i] = 0x00;
1463                }
1464                step--;
1465                break;
1466            }
1467            case 3:   // Write LFN1 entry   
1468            {
1469                c = 0;
1470                // scan the 32 bytes in dir_entry
1471                for ( i = 0 ; i < 32 ; i++ )
1472                {
1473                    if (i == 0)
1474                    {
1475                        if ( nb_lfn == 1) entry[i] = 0x41;
1476                        else              entry[i] = 0x01;
1477                    }
1478                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1479                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1480                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1481                              ( c < length ) )
1482                    {
1483                                          entry[i] = name[c];
1484                                          c++;
1485                    }
1486                    else if (i == 11)     entry[i] = 0x0F;
1487                    else if (i == 13)     entry[i] = checksum;
1488                    else                  entry[i] = 0x00;
1489                }
1490                step--;
1491                break;
1492            }
1493            case 2:   // write NORMAL entry     
1494            {
1495                // scan the 32 bytes in dir_entry
1496                for ( i = 0 ; i < 32 ; i++ )
1497                {
1498                    if      ( i < 11 )                              // 8.3 SFN
1499                    {
1500                                          entry[i] = sfn[i];
1501                    }
1502                    else if (i == 11)                               // ATTR
1503                    {
1504                        if (type == INODE_TYPE_DIR)  entry[i] = 0x10;
1505                        else                         entry[i] = 0x20;
1506                    }
1507                    else if (i == 20)     entry[i] = cluster>>16;   // cluster.B2
1508                    else if (i == 21)     entry[i] = cluster>>24;   // cluster.B3
1509                    else if (i == 26)     entry[i] = cluster>>0;    // cluster.B0
1510                    else if (i == 27)     entry[i] = cluster>>8;    // cluster.B1
1511                    else if (i == 28)     entry[i] = size>>0;       // size.B0
1512                    else if (i == 29)     entry[i] = size>>8;       // size.B1
1513                    else if (i == 30)     entry[i] = size>>16;      // size.B2
1514                    else if (i == 31)     entry[i] = size>>24;      // size.B3
1515                    else                  entry[i] = 0x00;
1516                }
[407]1517
[602]1518                // update the "extend" field in dentry descriptor
1519                dentry->extend = (void*)(intptr_t)(((page_id<<12) + offset)>>5);
1520
1521                step--;
1522                break;
[265]1523            }
[602]1524            case 1:   // write NOMORE entry 
1525            {
1526                entry [0] = 0x00;
1527                step--;
1528                break;
1529            }
1530        } // end switch step
[265]1531
[602]1532        offset += 32;
[265]1533
[602]1534    } // exit while     
1535
[630]1536#if (DEBUG_FATFS_ADD_DENTRY & 1)
1537cycle = (uint32_t)hal_get_cycles();
1538if( DEBUG_FATFS_ADD_DENTRY < cycle )
1539printk("\n[%s]  thread[%x,%x] before IOC access / cycle %d\n",
1540__FUNCTION__, this->process->pid, this->trdid, cycle );
1541#endif
1542
[602]1543    // copy the modified page to the IOC device
[614]1544    fatfs_move_page( page_xp , IOC_SYNC_WRITE );   
[602]1545
1546#if DEBUG_FATFS_ADD_DENTRY
1547cycle = (uint32_t)hal_get_cycles();
1548if( DEBUG_FATFS_ADD_DENTRY < cycle )
[614]1549printk("\n[%s]  thread[%x,%x] exit / parent <%s> / child <%s> / cycle %d\n",
[602]1550__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
[435]1551#endif
[406]1552
[602]1553    return 0;
[265]1554
[602]1555}  // end fatfs_add_dentry()
[246]1556
[602]1557//////////////////////////////////////////////////
1558error_t fatfs_remove_dentry( vfs_inode_t  * inode,
1559                             vfs_dentry_t * dentry )
1560{
1561    xptr_t     mapper_xp;  // extended pointer on mapper
1562    mapper_t * mapper;     // local pointer on mapper
1563    xptr_t     page_xp;    // extended pointer on mapper page descriptor
1564    xptr_t     base_xp;    // extended pointer on mapper page base
1565    uint8_t  * base;       // local pointer on mapper page base
[246]1566
[602]1567#if DEBUG_FATFS_REMOVE_DENTRY
1568char       dir_name[CONFIG_VFS_MAX_NAME_LENGTH];
1569uint32_t   cycle = (uint32_t)hal_get_cycles();
1570thread_t * this  = CURRENT_THREAD;
1571vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
1572if( DEBUG_FATFS_REMOVE_DENTRY < cycle )
[610]1573printk("\n[%s] thread[%x,%x] enter / parent <%s> / child <%s> / cycle %d\n",
[602]1574__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
[435]1575#endif
[401]1576
[602]1577// check arguments
1578assert( (inode != NULL) , "inode pointer is NULL\n" );
1579assert( (dentry != NULL) , "dentry pointer is NULL\n" );
1580assert( (inode->type == INODE_TYPE_DIR) , "inode is not a directory\n" );
1581assert( (inode->mapper != NULL ) , "mapper pointer is NULL\n" );
1582
1583    // get pointers on directory mapper
1584    mapper    = inode->mapper;
1585    mapper_xp = XPTR( local_cxy , mapper );
1586
1587    // compute number of LFN entries
1588    uint32_t nb_lfn;
1589    uint32_t name_length = strlen( dentry->name );
1590
1591    if      ( name_length <= 13 ) nb_lfn  = 1;
1592    else if ( name_length <= 26 ) nb_lfn  = 2;
1593    else                          nb_lfn  = 3;
1594
1595    // we must invalidate (2, 3 or 4) 32 bytes entries:
1596    // the NORMAL entry (registered in dentry->extend) and all preceding LFN entries
1597    // At most two pages are modified:
1598    // - the page containing the NORMAL entry is always modified.
1599    // - the preceding page is modified when the name spread on two pages.
1600
1601    // get 32 bytes directory entry index from dentry->extend
1602    uint32_t  dentry_id  = (uint32_t)(intptr_t)dentry->extend; 
1603
1604    // get page index and offset in parent directory mapper
1605    uint32_t  page_id    = dentry_id >> 7;
1606    uint32_t  offset     = (dentry_id & 0x7F)<<5;
1607
[610]1608#if DEBUG_FATFS_REMOVE_DENTRY & 1
1609if( DEBUG_FATFS_REMOVE_DENTRY < cycle )
1610printk("\n[%s] dentry_id %x / page_id %x / offset %x\n",
1611__FUNCTION__, dentry_id, page_id, offset );
1612#endif
1613
[602]1614    // get extended pointer on page descriptor from parent directory mapper
1615    page_xp  = mapper_remote_get_page( mapper_xp , page_id );
1616
1617    if ( page_xp == XPTR_NULL )
[406]1618    {
[602]1619        printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ );
1620        return -1;
[406]1621    }
[602]1622       
1623    // get pointers on page base
1624    base_xp = ppm_page2base( page_xp );
1625    base    = GET_PTR( base_xp );
1626
1627    // invalidate NORMAL entry in directory cache
1628    base[offset] = 0xE5;
1629
1630    // invalidate LFN entries
1631    while ( nb_lfn )
1632    {
1633        if (offset == 0)  // we must load page (page_id - 1)
1634        {
1635
1636// check page_id
1637assert( (page_id > 0), "page_id and offset cannot be both 0\n" );
1638
1639            // copy the modified page to the IOC device
[614]1640            fatfs_move_page( page_xp , IOC_SYNC_WRITE );   
[602]1641
1642            // get extended pointer on page descriptor from parent directory mapper
1643            page_xp  = mapper_remote_get_page( mapper_xp , page_id );
1644
1645            if ( page_xp == XPTR_NULL )
1646            {
1647                printk("\n[ERROR] in %s : cannot access directory mapper\n", __FUNCTION__ );
1648                return -1;
1649            }
1650       
1651            // get pointers on page base
1652            base_xp = ppm_page2base( page_xp );
1653            base    = GET_PTR( base_xp );
1654
1655            // update offset
1656            offset = 4096;
1657        }
1658
1659        offset = offset - 32;
1660
1661// check for LFN entry
[626]1662assert( (fatfs_get_record( DIR_ATTR, base + offset ) == ATTR_LONG_NAME_MASK ),
[602]1663"this directory entry must be a LFN\n");
1664
1665        // invalidate LFN entry
1666        base[offset] = 0xE5;
1667
1668        nb_lfn--;
1669    }     
1670
1671    // copy the modified page to the IOC device
[614]1672    fatfs_move_page( page_xp , IOC_SYNC_WRITE );   
[602]1673   
1674
1675#if DEBUG_FATFS_REMOVE_DENTRY
1676cycle = (uint32_t)hal_get_cycles();
1677if( DEBUG_FATFS_REMOVE_DENTRY < cycle )
[610]1678printk("\n[%s] thread[%x,%x] exit / parent %s / child %s / cycle %d\n",
[602]1679__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
[406]1680#endif
1681
[1]1682    return 0;
1683
[602]1684}  // end fatfs_remove_dentry
[246]1685
[623]1686
1687//////////////////////////////////////////////////////////////////////////////////////////////
1688// This static function scan the pages of a mapper containing a FAT32 directory, identified
1689// by the <mapper> argument, to find the directory entry identified by the <name> argument,
1690// and return a pointer on the directory entry, described as and array of 32 bytes, and the
1691// incex of this entry in the FAT32 mapper, seen as an array of 32 bytes entries.
1692// It is called by the fatfs_new_dentry() and fatfs_update_dentry() functions.
1693// It must be called by a thread running in the cluster containing the mapper.
1694//////////////////////////////////////////////////////////////////////////////////////////////
1695// @ mapper    : [in]  local pointer on directory mapper.
1696// @ name      : [in]  searched directory entry name.
1697// @ entry     : [out] buffer for the pointer on the 32 bytes directory entry (when found).
1698// @ index     : [out] buffer for the directory entry index in mapper.
1699// @ return 0 if found / return 1 if not found / return -1 if mapper access error.
1700//////////////////////////////////////////////////////////////////////////////////////////////
1701error_t fatfs_scan_directory( mapper_t *  mapper,
1702                              char     *  name,
1703                              uint8_t  ** entry,
1704                              uint32_t *  index )
[1]1705{
[610]1706    // Two embedded loops to scan the directory mapper:
[602]1707    // - scan the parent directory mapper pages
[238]1708    // - scan the directory entries in each 4 Kbytes page
[1]1709
[623]1710// check parent_inode and child_inode
1711assert( (mapper != NULL) , "mapper pointer is NULL\n" );
1712assert( (name   != NULL ), "child name is undefined\n" );
1713assert( (entry  != NULL ), "entry buffer undefined\n" );
1714
1715#if DEBUG_FATFS_SCAN_DIRECTORY
[602]1716char       parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
1717uint32_t   cycle = (uint32_t)hal_get_cycles();
1718thread_t * this  = CURRENT_THREAD;
[623]1719vfs_inode_get_name( XPTR( local_cxy , mapper->inode ) , parent_name );
1720if( DEBUG_FATFS_SCAN_DIRECTORY < cycle )
1721printk("\n[%s]  thread[%x,%x] enter to search child <%s> in parent <%s> / cycle %d\n",
[602]1722__FUNCTION__, this->process->pid, this->trdid, name , parent_name , cycle );
[435]1723#endif
[1]1724
[623]1725    char       cname[CONFIG_VFS_MAX_NAME_LENGTH];  // name extracted from each directory entry
[238]1726
1727    char       lfn1[16];         // buffer for one partial cname
1728    char       lfn2[16];         // buffer for one partial cname
1729    char       lfn3[16];         // buffer for one partial cname
[623]1730    xptr_t     mapper_xp;        // extended pointer on mapper descriptor
[602]1731    xptr_t     page_xp;          // extended pointer on page descriptor
1732    xptr_t     base_xp;          // extended pointer on page base
1733    uint8_t  * base;             // local pointer on page base
[614]1734    uint8_t    attr;             // directory entry ATTR field
1735    uint8_t    ord;              // directory entry ORD field
[238]1736    uint32_t   seq;              // sequence index
[602]1737    uint32_t   lfn       = 0;    // LFN entries number
[623]1738    int32_t    found     = 0;    // not yet = 0 / success = 1 / not found = 2 / error = -1
[602]1739    uint32_t   page_id   = 0;    // page index in mapper
1740    uint32_t   offset    = 0;    // byte offset in page
[238]1741
[623]1742    mapper_xp = XPTR( local_cxy , mapper );
1743
1744    // scan the mapper pages
[238]1745    while ( found == 0 )
1746    {
1747        // get one page
[602]1748        page_xp = mapper_remote_get_page( mapper_xp , page_id );
[238]1749
[623]1750        if( page_xp == XPTR_NULL)
1751        {
1752            found = -1;
1753        }
[238]1754
1755        // get page base
[602]1756        base_xp = ppm_page2base( page_xp );
1757        base    = (uint8_t *)GET_PTR( base_xp );
[238]1758
[623]1759#if (DEBUG_FATFS_SCAN_DIRECTORY & 0x1)
1760if( DEBUG_FATFS_SCAN_DIRECTORY < cycle )
[614]1761mapper_display_page( mapper_xp , page_id , 256 );
[265]1762#endif
[238]1763        // scan this page until end of directory, end of page, or name found
1764        while( (offset < 4096) && (found == 0) )
1765        {
[626]1766            attr = fatfs_get_record( DIR_ATTR , base + offset );   
1767            ord  = fatfs_get_record( LDIR_ORD , base + offset );   
[238]1768
1769            if (ord == NO_MORE_ENTRY)                 // no more entry => break
1770            {
[623]1771                found = 2;
[238]1772            }
1773            else if ( ord == FREE_ENTRY )             // free entry => skip
1774            {
1775                offset = offset + 32;
1776            }
[614]1777            else if ( attr == 0x28 )                  // volune_id => skip
1778            {
1779                offset = offset + 32;
1780            }
[238]1781            else if ( attr == ATTR_LONG_NAME_MASK )   // LFN entry => get partial cname
1782            {
1783                seq = ord & 0x3;
1784                lfn = (seq > lfn) ? seq : lfn;   
1785                if      ( seq == 1 ) fatfs_get_name_from_long( base + offset, lfn1 );
1786                else if ( seq == 2 ) fatfs_get_name_from_long( base + offset, lfn2 );
1787                else if ( seq == 3 ) fatfs_get_name_from_long( base + offset, lfn3 );
1788                offset = offset + 32;
1789            }
1790            else                                 // NORMAL entry
1791            {
1792                // build the extracted name
1793                if      ( lfn == 0 )
1794                {
1795                    fatfs_get_name_from_short( base + offset , cname );
1796                }
1797                else if ( lfn == 1 )
1798                {
1799                    strcpy( cname      , lfn1 );
1800                }   
1801                else if ( lfn == 2 ) 
1802                {
1803                    strcpy( cname      , lfn1 );
1804                    strcpy( cname + 13 , lfn2 );
1805                }
1806                else if ( lfn == 3 ) 
1807                {
1808                    strcpy( cname      , lfn1 );
1809                    strcpy( cname + 13 , lfn2 );
1810                    strcpy( cname + 26 , lfn3 );
1811                }
1812
1813                // get dentry arguments if extracted cname == searched name
1814                if ( strcmp( name , cname ) == 0 )
1815                {
[623]1816                    *entry = base + offset;
1817                    *index = ((page_id<<12) + offset)>>5; 
[602]1818                    found     = 1;
[238]1819                }
1820                offset = offset + 32;
1821                lfn    = 0;
1822            }
[602]1823        }  // end loop on directory entries in page
1824
1825        page_id++;
[238]1826        offset = 0;
[602]1827
[238]1828    }  // end loop on pages
1829
[623]1830    if( found == 1 )
1831    {
[238]1832
[623]1833#if DEBUG_FATFS_SCAN_DIRECTORY
1834cycle = (uint32_t)hal_get_cycles();
1835if( DEBUG_FATFS_SCAN_DIRECTORY < cycle )
1836printk("\n[%s]  thread[%x,%x] exit / found child <%s> in <%s>\n",
1837__FUNCTION__, this->process->pid, this->trdid, name, parent_name );
1838#endif
1839        return 0;
1840    }
1841    else if( found == 2 )
[238]1842    {
1843
[623]1844#if DEBUG_FATFS_SCAN_DIRECTORY
[435]1845cycle = (uint32_t)hal_get_cycles();
[623]1846if( DEBUG_FATFS_SCAN_DIRECTORY < cycle )
1847printk("\n[%s]  thread[%x,%x] exit / child <%s> in <%s> not found\n",
1848__FUNCTION__, this->process->pid, this->trdid, name, parent_name );
[435]1849#endif
[623]1850        return 1;
1851    }
1852    else
1853    {
1854        printk("\n[ERROR] in %s : cannot get page %d from mapper\n",
1855        __FUNCTION__, page_id );
[407]1856
[602]1857        return -1;
[238]1858    }
[623]1859}  // end fatfs_scan_directory()
[602]1860
1861
[610]1862
[623]1863/////////////////////////////////////////////////////
1864error_t fatfs_new_dentry( vfs_inode_t * parent_inode,
1865                          char        * name,
1866                          xptr_t        child_inode_xp )
1867{
[625]1868    uint8_t      * entry;            // pointer on FAT32 directory entry (array of 32 bytes)
1869    uint32_t       index;            // index of FAT32 directory entry in mapper
1870    mapper_t     * mapper;           // pointer on directory mapper
1871    uint32_t       cluster;          // directory entry cluster
1872    uint32_t       size;             // directory entry size
1873    bool_t         is_dir;           // directory entry type (file/dir)
1874    xptr_t         root_xp;          // extended pointer on root of parent dentries
1875    xptr_t         iter_xp;          // iterator for this list
1876    cxy_t          child_inode_cxy;  // child inode cluster 
1877    vfs_inode_t  * child_inode_ptr;  // child inode local pointer
1878    xptr_t         dentry_xp;        // extended pointer on searched dentry descriptor
1879    cxy_t          dentry_cxy;       // cluster identifier of dentry (must be local_cxy)
1880    vfs_dentry_t * dentry_ptr;       // local pointer
1881    error_t        error;
[623]1882
[628]1883    char           dir_name[CONFIG_VFS_MAX_NAME_LENGTH];
[625]1884
[623]1885// check arguments
[626]1886assert( (parent_inode   != NULL)       , "parent_inode is NULL\n" );
1887assert( (name           != NULL)       , "name is NULL\n" );
1888assert( (child_inode_xp != XPTR_NULL ) , "child_inode is NULL\n" );
[623]1889
[626]1890    // get child inode cluster and local pointer
1891    child_inode_cxy = GET_CXY( child_inode_xp );
1892    child_inode_ptr = GET_PTR( child_inode_xp );
1893
1894    // build extended pointer on root of list of parent dentries
1895    root_xp = XPTR( child_inode_cxy , &child_inode_ptr->parents );
1896
1897// check child inode has at least one parent
1898assert( (xlist_is_empty( root_xp ) == false ), "child inode must have one parent\n");
1899
[623]1900#if DEBUG_FATFS_GET_DENTRY
1901uint32_t   cycle = (uint32_t)hal_get_cycles();
1902thread_t * this  = CURRENT_THREAD;
[625]1903vfs_inode_get_name( XPTR( local_cxy , parent_inode ) , dir_name );
[623]1904if( DEBUG_FATFS_GET_DENTRY < cycle )
1905printk("\n[%s]  thread[%x,%x] enter for child <%s> in parent <%s> / cycle %d\n",
[625]1906__FUNCTION__, this->process->pid, this->trdid, name , dir_name , cycle );
[623]1907#endif
1908
[625]1909    // get local pointer on parent mapper
[623]1910    mapper = parent_inode->mapper;
[625]1911
1912    // get pointer and index in mapper for searched directory entry
[623]1913    error  = fatfs_scan_directory( mapper, name , &entry , &index );
1914
[626]1915    // return non fatal error if not found
1916    if( error ) return -1;
[623]1917
[625]1918    // get relevant infos from FAT32 directory entry
[626]1919    cluster = (fatfs_get_record( DIR_FST_CLUS_HI , entry ) << 16) |
1920              (fatfs_get_record( DIR_FST_CLUS_LO , entry )      ) ;
1921    is_dir  = (fatfs_get_record( DIR_ATTR        , entry ) & ATTR_DIRECTORY);
1922    size    =  fatfs_get_record( DIR_FILE_SIZE   , entry );
[623]1923
[625]1924    // scan list of parent dentries to search the parent_inode
1925    bool_t found = false;
1926    XLIST_FOREACH( root_xp , iter_xp )
1927    {
1928        // get pointers on dentry
1929        dentry_xp  = XLIST_ELEMENT( iter_xp , vfs_dentry_t , parents );
1930        dentry_cxy = GET_CXY( dentry_xp );
1931        dentry_ptr = GET_PTR( dentry_xp );
[602]1932
[625]1933        // get local pointer on current parent directory inode
1934        vfs_inode_t * current = hal_remote_lpt( XPTR( dentry_cxy , &dentry_ptr->parent ) );
[602]1935
[625]1936        // check if current parent is the searched parent
1937        if( XPTR( dentry_cxy , current ) == XPTR( local_cxy , parent_inode ) )
1938        {
1939            found = true;
1940            break;
1941        }
1942    }
[602]1943
[625]1944    if( found == false )
1945    { 
1946        vfs_inode_get_name( XPTR( local_cxy , parent_inode ) , dir_name );
1947        printk("\n[ERROR] in %s : cannot find <%s> directory in list of parents for <%s>\n",
1948        __FUNCTION__, dir_name, name );
[623]1949        return -1;
1950    }
1951
[625]1952    // update the child inode "type", "size", and "extend" fields
1953    vfs_inode_type_t type = (is_dir) ? INODE_TYPE_DIR : INODE_TYPE_FILE;
1954
1955    hal_remote_s32( XPTR( child_inode_cxy , &child_inode_ptr->type   ) , type );
1956    hal_remote_s32( XPTR( child_inode_cxy , &child_inode_ptr->size   ) , size );
1957    hal_remote_s32( XPTR( child_inode_cxy , &child_inode_ptr->extend ) , cluster );
1958
1959    // update the dentry "extend" field
1960    dentry_ptr->extend = (void *)(intptr_t)index;
1961
1962#if DEBUG_FATFS_GET_DENTRY
1963cycle = (uint32_t)hal_get_cycles();
1964if( DEBUG_FATFS_GET_DENTRY < cycle )
1965printk("\n[%s]  thread[%x,%x] exit / intialised inode & dentry for <%s> in <%s> / cycle %d\n",
1966__FUNCTION__, this->process->pid, this->trdid, name, dir_name, cycle );
1967#endif
1968
1969    return 0;
1970
[623]1971}  // end fatfs_new_dentry()
1972
1973//////////////////////////////////////////////////
1974error_t fatfs_update_dentry( vfs_inode_t  * inode,
1975                             vfs_dentry_t * dentry,
1976                             uint32_t       size )
1977{
1978    uint8_t  * entry;    // pointer on FAT32 directory entry (array of 32 bytes)
1979    uint32_t   index;    // index of FAT32 directory entry in mapper
1980    mapper_t * mapper;   // pointer on directory mapper
1981    error_t    error;
1982
[625]1983    char       dir_name[CONFIG_VFS_MAX_NAME_LENGTH];
1984
[623]1985// check arguments
1986assert( (inode  != NULL) , "inode is NULL\n" );
1987assert( (dentry != NULL) , "dentry is NULL\n" );
1988assert( (size   != 0   ) , "size is 0\n" );
1989
1990#if DEBUG_FATFS_UPDATE_DENTRY
1991uint32_t   cycle = (uint32_t)hal_get_cycles();
1992thread_t * this  = CURRENT_THREAD;
1993vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
1994if( DEBUG_FATFS_UPDATE_DENTRY < cycle )
[625]1995printk("\n[%s]  thread[%x,%x] enter for <%s/%s> / size %d / cycle %d\n",
1996__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, size, cycle );
[623]1997#endif
1998
[625]1999    // get local pointer on mapper
[623]2000    mapper = inode->mapper;
[625]2001
2002    // get pointer and index in mapper for searched directory entry
[623]2003    error  = fatfs_scan_directory( mapper, dentry->name , &entry , &index );
2004
[625]2005    if( error )
[623]2006    { 
[625]2007        vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
2008        printk("\n[ERROR] in %s : cannot find <%s> in parent mapper <%s>\n",
2009        __FUNCTION__, dentry->name, dir_name );
2010        return -1;
2011    }
[623]2012
[625]2013    // set size in FAT32 directory entry
[626]2014    fatfs_set_record( DIR_FILE_SIZE , entry , size );
[602]2015
[625]2016    // get local pointer on modified page base
2017    void * base = (void *)((intptr_t)entry & (~CONFIG_PPM_PAGE_MASK)); 
[602]2018
[625]2019    // get extended pointer on modified page descriptor
2020    xptr_t page_xp = ppm_base2page( XPTR( local_cxy , base ) );
[602]2021
[625]2022    // synchronously update the modified page on device
2023    error = fatfs_move_page( page_xp , IOC_SYNC_WRITE );
[623]2024
[625]2025    if( error )
2026    { 
2027        vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
2028        printk("\n[ERROR] in %s : cannot update parent directory <%s> on device\n",
2029        __FUNCTION__, dir_name );
[623]2030        return -1;
2031    }
2032
[625]2033#if DEBUG_FATFS_UPDATE_DENTRY
2034cycle = (uint32_t)hal_get_cycles();
2035if( DEBUG_FATFS_UPDATE_DENTRY < cycle )
2036printk("\n[%s]  thread[%x,%x] exit / updated size for <%s/%s> / cycle %d\n",
2037__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
2038#endif
2039
2040    return 0;
2041
[623]2042}  // end fatfs_update_dentry()
2043
[612]2044///////////////////////////////////////////////////////
2045error_t fatfs_get_user_dir( struct vfs_inode_s * inode,
2046                            struct dirent      * array, 
2047                            uint32_t             max_dirent,
2048                            uint32_t             min_dentry,
2049                            bool_t               detailed,
2050                            uint32_t           * entries,
2051                            bool_t             * done )
2052{
2053    // Two embedded loops to scan the directory mapper:
2054    // - scan the parent directory mapper pages starting always from page 0
2055    // - scan the 32 bytes NORMAL/LFN directory entries in each page
2056    // Only valid dentries are copied : dentry_id >= min_dentry && dirent_id < dirent_max
2057
2058#if DEBUG_FATFS_GET_USER_DIR
2059char       inode_name[CONFIG_VFS_MAX_NAME_LENGTH];
2060uint32_t   cycle = (uint32_t)hal_get_cycles();
2061thread_t * this  = CURRENT_THREAD;
2062vfs_inode_get_name( XPTR( local_cxy , inode ) , inode_name );
2063if( DEBUG_FATFS_GET_USER_DIR < cycle )
2064printk("\n[%s]  thread[%x,%x] enter for inode <%s> / cycle %d\n",
2065__FUNCTION__, this->process->pid, this->trdid, inode_name , cycle );
2066#endif
2067
2068    mapper_t * mapper    = inode->mapper;
2069    xptr_t     mapper_xp = XPTR( local_cxy , mapper );
2070
2071// check mapper pointer
2072assert( (mapper != NULL) , "mapper is NULL\n");
2073   
2074// TODO handle the detailed flag
2075assert( (detailed == false), "detailed argument not supported/n");
2076
[614]2077    char       cname[CONFIG_VFS_MAX_NAME_LENGTH];  // name extracted from each dentry
[612]2078
2079    char       lfn1[16];           // buffer for one partial cname
2080    char       lfn2[16];           // buffer for one partial cname
2081    char       lfn3[16];           // buffer for one partial cname
2082    xptr_t     page_xp;            // extended pointer on page descriptor
2083    xptr_t     base_xp;            // extended pointer on page base
2084    uint8_t  * base;               // local pointer on page base
[614]2085    uint8_t    attr;               // directory entry ATTR field
2086    uint8_t    ord;                // directory entry ORD field
[612]2087    uint32_t   seq;                // sequence index
2088    uint32_t   lfn       = 0;      // LFN entries number
2089    uint32_t   offset    = 0;      // byte offset in page
2090    uint32_t   page_id   = 0;      // page index in mapper
2091    uint32_t   dentry_id = 0;      // valid (i.e. copied) dentry index in mapper
2092    uint32_t   dirent_id = 0;      // slot index in dirent array to initialize
2093    bool_t     end       = false;  // true if end of directory found
2094
2095    // loop on mapper pages
2096    while ( (end == false) && (dirent_id < max_dirent) )
2097    {
2098        // get one page from mapper
2099        page_xp = mapper_remote_get_page( mapper_xp , page_id );
2100
2101        if( page_xp == XPTR_NULL) return -1;
2102
2103        // get page base
2104        base_xp = ppm_page2base( page_xp );
2105        base    = (uint8_t *)GET_PTR( base_xp );
2106
2107#if (DEBUG_FATFS_GET_USER_DIR & 0x1)
2108if( DEBUG_FATFS_GET_USER_DIR < cycle )
[614]2109mapper_display_page( mapper_xp , page_id , 256 );
[612]2110#endif
2111        // loop on NORMAL/LFN (32 bytes) directory entries in this page
2112        while( (end == false) && (offset < 4096) )
2113        {
2114            // compute condition to copy one dentry to dirent array
2115            bool_t valid = (dentry_id >= min_dentry) && (dirent_id <  max_dirent );
2116
[626]2117            attr = fatfs_get_record( DIR_ATTR , base + offset );   
2118            ord  = fatfs_get_record( LDIR_ORD , base + offset );   
[612]2119
2120            if (ord == NO_MORE_ENTRY)                 // no more entry => break
2121            {
2122                end = true;
2123            }
2124            else if ( ord == FREE_ENTRY )             // free entry => skip
2125            {
2126                offset = offset + 32;
2127            }
[614]2128            else if ( attr == 0x28 )                  // volune_id => skip
2129            {
2130                offset = offset + 32;
2131            }
[612]2132            else if ( attr == ATTR_LONG_NAME_MASK )   // LFN entry
2133            {
2134                if( valid )
2135                {
2136                    // get partial cname
2137                    seq = ord & 0x3;
2138                    lfn = (seq > lfn) ? seq : lfn;   
2139                    if      ( seq == 1 ) fatfs_get_name_from_long( base + offset, lfn1 );
2140                    else if ( seq == 2 ) fatfs_get_name_from_long( base + offset, lfn2 );
2141                    else if ( seq == 3 ) fatfs_get_name_from_long( base + offset, lfn3 );
2142                }
2143                offset = offset + 32;
2144            }
2145            else                                     // NORMAL entry
2146            {
2147                // increment dentry_id
2148                dentry_id++;
2149
2150                if( valid )
2151                {
2152                    // build the complete cname
2153                    if      ( lfn == 0 )
2154                    {
2155                        fatfs_get_name_from_short( base + offset , cname );
2156                    }
2157                    else if ( lfn == 1 )
2158                    {
2159                        strcpy( cname      , lfn1 );
2160                    }   
2161                    else if ( lfn == 2 ) 
2162                    {
2163                        strcpy( cname      , lfn1 );
2164                        strcpy( cname + 13 , lfn2 );
2165                    }
2166                    else if ( lfn == 3 ) 
2167                    {
2168                        strcpy( cname      , lfn1 );
2169                        strcpy( cname + 13 , lfn2 );
2170                        strcpy( cname + 26 , lfn3 );
2171                    }
2172                   
2173                    // copy cname into dirent array
2174                    strcpy( array[dirent_id].d_name , cname ); 
2175
2176                    // increment dirent_id
2177                    dirent_id++;
2178                }
2179                offset = offset + 32;
2180                lfn    = 0;
2181            }
2182        }  // end loop on directory entries in page
2183
2184        page_id++;
2185        offset = 0;
2186
2187    }  // end loop on pages
2188
2189    // return result of scan
2190    *done    = end;
2191    *entries = dirent_id;
2192
2193#if DEBUG_FATFS_GET_USER_DIR
2194cycle = (uint32_t)hal_get_cycles();
2195if( DEBUG_FATFS_GET_USER_DIR < cycle )
2196printk("\n[%s]  thread[%x,%x] exit for inode <%s> / %d entries / cycle %d\n",
[614]2197__FUNCTION__, this->process->pid, this->trdid, inode_name, dirent_id, cycle );
[612]2198#endif
2199
2200    return 0;
2201
2202}  // end fatfs_get_user_dir()
2203
[602]2204///////////////////////////////////////////////
2205error_t fatfs_sync_inode( vfs_inode_t * inode )
2206{
2207
2208// check inode pointer and cluster index
2209assert( (inode != NULL)                  , "inode pointer undefined\n" );
2210assert( (inode->mapper != NULL )         , "mapper pointer undefined\n" );
2211assert( (inode->type == INODE_TYPE_FILE) , "inode must be a file\n" );     
2212
2213#if DEBUG_FATFS_SYNC_INODE
2214char       name[CONFIG_VFS_MAX_NAME_LENGTH];
2215uint32_t   cycle = (uint32_t)hal_get_cycles();
2216thread_t * this  = CURRENT_THREAD;
2217vfs_inode_get_name( XPTR( local_cxy , inode ) , name );
2218if( DEBUG_FATFS_SYNC_INODE < cycle )
2219printk("\n[%s] thread[%x,%x] enter for <%s> / cycle %d\n",
2220__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
2221#endif
2222
2223    error_t    error;
2224    mapper_t * mapper;
2225    page_t   * page;
2226    uint32_t   page_id;
2227
2228    // get mapper from inode
2229    mapper = inode->mapper;
2230
2231    // compute max number of pages in mapper from file size
2232    uint32_t size  = inode->size;
2233    uint32_t pages = size >> CONFIG_PPM_PAGE_SHIFT;
2234    if( size & CONFIG_PPM_PAGE_MASK ) pages++; 
2235         
2236    // get pointer on mapper radix tree
2237    grdxt_t * rt = &mapper->rt;
2238
2239    // scan all pages
2240    for( page_id = 0 ; page_id < pages ; page_id++ )
[238]2241    {
[602]2242        // get page descriptor from mapper
2243        page = grdxt_lookup( rt , page_id );
[238]2244
[602]2245        // check all existing pages
2246        if ( page != NULL )
2247        {
2248            if ( page->flags & PG_DIRTY )
2249            {
[238]2250
[602]2251#if (DEBUG_FATFS_SYNC_INODE & 1)
2252if( DEBUG_FATFS_SYNC_INODE < cycle )
2253printk("\n[%s] thread[%x,%x] synchronizes page %d from <%s> mapper to IOC device\n",
2254__FUNCTION__, page_id, name );
2255#endif
2256                // build extended pointer on page descriptor
2257                xptr_t page_xp = XPTR( local_cxy , page );
[238]2258
[602]2259                // move page from mapper to device
[614]2260                error = fatfs_move_page( page_xp , IOC_WRITE );
[602]2261
2262                if ( error )  return -1;
2263
2264                // reset page dirty flag
2265                ppm_page_undo_dirty( page_xp );
2266            }
2267        }
2268    }  // end loop on pages
2269
2270#if DEBUG_FATFS_SYNC_INODE
[435]2271cycle = (uint32_t)hal_get_cycles();
[602]2272if( DEBUG_FATFS_SYNC_INODE < cycle )
2273printk("\n[%s] thread[%x,%x] exit for <%s> / cycle %d\n",
2274__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
[435]2275#endif
[246]2276
[602]2277    return 0;
2278
2279}  // end fatfs_sync_inode()
2280
[628]2281
2282
2283
2284
2285
[602]2286//////////////////////////////
2287error_t fatfs_sync_fat( void )
2288{
2289
2290#if DEBUG_FATFS_SYNC_FAT
2291uint32_t   cycle = (uint32_t)hal_get_cycles();
2292thread_t * this  = CURRENT_THREAD;
2293if( DEBUG_FATFS_SYNC_FAT < cycle )
2294printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
2295__FUNCTION__ , this->process->pid, this->trdid, cycle );
2296#endif
2297
2298    uint32_t   page_id;
2299    error_t    error;
2300
2301    // get FAT mapper pointers an cluster
2302    fatfs_ctx_t * fatfs_ctx  = fs_context[FS_TYPE_FATFS].extend;
2303    xptr_t        mapper_xp  = fatfs_ctx->fat_mapper_xp;
2304    cxy_t         mapper_cxy = GET_CXY( mapper_xp );
2305    mapper_t    * mapper_ptr = GET_PTR( mapper_xp );
2306
2307    // compute max number of 4 Kbytes pages in FAT mapper
2308    // TODO : this could be improved (see fatfs.h) [AG]
2309    uint32_t   pages = fatfs_ctx->fat_sectors_count >> 3;
2310         
2311    // get pointers on remote FAT mapper radix tree
2312    grdxt_t  * rt_ptr = &mapper_ptr->rt;
2313    xptr_t     rt_xp  = XPTR( mapper_cxy , rt_ptr );
2314
2315    // scan all pages
2316    for( page_id = 0 ; page_id < pages ; page_id++ )
2317    {
2318        // get extended pointer on page descriptor from FAT mapper
2319        xptr_t page_xp = grdxt_remote_lookup( rt_xp , page_id );
2320
2321        // check all existing pages
2322        if ( page_xp != XPTR_NULL )
2323        {
2324            page_t * page_ptr = GET_PTR( page_xp );
2325            uint32_t flags    = hal_remote_l32( XPTR( mapper_cxy , &page_ptr->flags ) );
2326
2327            if ( flags & PG_DIRTY )
2328            {
2329
2330#if (DEBUG_FATFS_SYNC_FAT & 1)
2331if( DEBUG_FATFS_SYNC_FAT < cycle )
2332printk("\n[%s] thread[%x,%x] synchronizes page %d from FAT mapper to IOC device\n",
2333__FUNCTION__, page_id );
2334#endif
2335                // move page from mapper to device
[614]2336                error = fatfs_move_page( page_xp , IOC_SYNC_WRITE );
[602]2337
2338                if ( error )  return -1;
2339
2340                // reset page dirty flag
2341                ppm_page_undo_dirty( page_xp );
2342            }
2343        }
2344    }  // end loop on pages
2345
2346#if DEBUG_FATFS_SYNC_FAT
2347cycle = (uint32_t)hal_get_cycles();
2348if( DEBUG_FATFS_SYNC_FAT < cycle )
2349printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
2350__FUNCTION__ , this->process->pid, this->trdid, cycle );
2351#endif
2352
2353    return 0;
2354
2355}  // end fatfs_sync_fat()
2356
2357////////////////////////////////////
2358error_t fatfs_sync_free_info( void )
2359{
[626]2360    error_t       error;
2361    fatfs_ctx_t * fatfs_ctx_ptr;              // local pointer on fatfs context in cluster 0
2362    uint32_t      ctx_free_clusters;          // number of free clusters from fatfs context
2363    uint32_t      ctx_free_cluster_hint;      // free cluster hint from fatfs context
2364    uint32_t      ioc_free_clusters;          // number of free clusters from fatfs context
2365    uint32_t      ioc_free_cluster_hint;      // free cluster hint from fatfs context
2366    uint32_t      fs_info_lba;                // lba of FS_INFO sector on IOC device
2367    uint8_t     * fs_info_buffer;             // local pointer on FS_INFO buffer in cluster 0
2368    xptr_t        fs_info_buffer_xp;          // extended pointer on FS_INFO buffer in cluster 0
2369    uint8_t       tmp_buf[512];               // 512 bytes temporary buffer
2370    xptr_t        tmp_buf_xp;                 // extended pointer on temporary buffer
[602]2371
2372#if DEBUG_FATFS_SYNC_FSINFO
2373uint32_t   cycle = (uint32_t)hal_get_cycles();
2374thread_t * this  = CURRENT_THREAD;
2375if( DEBUG_FATFS_SYNC_FSINFO < cycle )
2376printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
2377__FUNCTION__ , this->process->pid, this->trdid, cycle );
2378#endif
2379
[626]2380    // get pointer on fatfs context in cluster 0
2381    fatfs_ctx_ptr = hal_remote_lpt( XPTR( 0 , &fs_context[FS_TYPE_FATFS].extend ) );
[602]2382
[626]2383    // get "free_clusters" and "free_cluster_hint" from fatfs context in cluster 0
2384    ctx_free_clusters     = hal_remote_l32( XPTR( 0 , &fatfs_ctx_ptr->free_clusters ) );
2385    ctx_free_cluster_hint = hal_remote_l32( XPTR( 0 , &fatfs_ctx_ptr->free_cluster_hint ) );
[602]2386
[626]2387    // get fs_info_lba
2388    fs_info_lba = hal_remote_l32( XPTR( 0 , &fatfs_ctx_ptr->fs_info_lba ) );
2389
2390    // build extended pointer on temporary buffer
2391    tmp_buf_xp = XPTR( local_cxy , tmp_buf );
2392
2393    // copy FS_INFO sector from IOC to local buffer
2394    error = dev_ioc_sync_read( tmp_buf_xp , fs_info_lba , 1 );
2395
[602]2396    if ( error )
2397    {
[626]2398        printk("\n[ERROR] in %s : cannot access FS_INFO on IOC device\n", __FUNCTION__ );
2399        return -1;
[602]2400    }
2401
[626]2402    // get current values of "free_clusters" and "free_cluster_hint" from FS_INFO on IOC
2403    ioc_free_clusters     = fatfs_get_remote_record( FS_FREE_CLUSTERS     , tmp_buf_xp );
2404    ioc_free_cluster_hint = fatfs_get_remote_record( FS_FREE_CLUSTER_HINT , tmp_buf_xp );
[602]2405
[628]2406#if DEBUG_FATFS_SYNC_FSINFO
2407if( DEBUG_FATFS_SYNC_FSINFO < cycle )
2408printk("\n[%s] thread[%x,%x] / ctx_free %x / ioc_free %x / ctx_hint %x / ioc_hint %x\n",
2409__FUNCTION__ , this->process->pid, this->trdid, 
2410ctx_free_clusters, ioc_free_clusters, ctx_free_cluster_hint, ioc_free_cluster_hint );
2411#endif
2412
[626]2413    // check values
2414    if( (ioc_free_clusters     != ctx_free_clusters) || 
2415        (ioc_free_cluster_hint != ctx_free_cluster_hint) )
[602]2416    {
[626]2417        printk("\n[WARNING] in %s : unconsistent free clusters info\n"
2418        " ioc_free %x / ctx_free %x / ioc_hint %x / ctx_hint %x\n",
2419        __FUNCTION__, ioc_free_clusters, ctx_free_clusters,
2420        ioc_free_cluster_hint, ctx_free_cluster_hint );
2421
2422        // get pointers on FS_INFO buffer in cluster 0
2423        fs_info_buffer    = hal_remote_lpt( XPTR( 0 , &fatfs_ctx_ptr->fs_info_buffer ) );
2424        fs_info_buffer_xp = XPTR( 0 , fs_info_buffer );
2425
2426        // update FS_INFO buffer in cluster 0
2427        fatfs_set_remote_record(FS_FREE_CLUSTERS    ,fs_info_buffer_xp,ctx_free_clusters );
2428        fatfs_set_remote_record(FS_FREE_CLUSTER_HINT,fs_info_buffer_xp,ctx_free_cluster_hint);
2429
2430        // update the FS_INFO sector on IOC device
2431        error = dev_ioc_sync_write( fs_info_buffer_xp , fs_info_lba , 1 );
2432
2433        if ( error )
2434        {
2435            printk("\n[ERROR] in %s : cannot update FS_INFO on IOC device\n", __FUNCTION__ );
2436            return -1;
2437        }
[602]2438    }
2439
2440#if DEBUG_FATFS_SYNC_FSINFO
2441cycle = (uint32_t)hal_get_cycles();
2442if( DEBUG_FATFS_SYNC_FSINFO < cycle )
2443printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
2444__FUNCTION__ , this->process->pid, this->trdid, cycle );
2445#endif
2446
2447    return 0;
2448
[626]2449}  // end fatfs_sync_free_info()
[602]2450
2451//////////////////////////////////////////////////////////
2452error_t fatfs_cluster_alloc( uint32_t * searched_cluster )
2453{
[626]2454    error_t       error;
[625]2455    uint32_t      page_id;        // page index in FAT mapper
[602]2456    uint32_t      slot_id;        // slot index in page (1024 slots per page)
[625]2457    uint32_t      cluster;        // first free cluster index in FAT
[602]2458    uint32_t      free_clusters;  // total number of free clusters
2459    vfs_ctx_t   * vfs_ctx;        // local pointer on VFS context (same in all clusters)
2460    fatfs_ctx_t * loc_fatfs_ctx;  // local pointer on local FATFS context
2461    fatfs_ctx_t * fat_fatfs_ctx;  // local pointer on FATFS context in FAT cluster
[628]2462    xptr_t        fat_mapper_xp;  // extended pointer on FAT mapper
[626]2463    cxy_t         fat_cxy;        // Fat mapper cluster identifier
[602]2464    xptr_t        page_xp;        // extended pointer on current page descriptor in mapper
2465    xptr_t        slot_xp;        // extended pointer on FAT slot defined by hint
2466    xptr_t        lock_xp;        // extended pointer on lock protecting free clusters info
2467    xptr_t        hint_xp;        // extended pointer on free_cluster_hint in FAT cluster
[626]2468    xptr_t        free_xp;        // extended pointer on free_clusters_number in FAT cluster
[602]2469
2470#if DEBUG_FATFS_CLUSTER_ALLOC
2471uint32_t   cycle = (uint32_t)hal_get_cycles();
2472thread_t * this  = CURRENT_THREAD;
2473if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
2474printk("\n[%s] thread[%x,%x] enter / cycle = %d\n",
2475__FUNCTION__, this->process->pid, this->trdid, cycle );
2476#endif
2477
2478    // get local pointer on VFS context (same in all clusters)
2479    vfs_ctx = &fs_context[FS_TYPE_FATFS];
2480
2481    // get local pointer on local FATFS context
2482    loc_fatfs_ctx = vfs_ctx->extend;
2483
[626]2484    // get extended pointer on FAT mapper
[628]2485    fat_mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
[626]2486
2487    // get FAT cluster
[628]2488    fat_cxy = GET_CXY( fat_mapper_xp );
[602]2489   
2490    // get local pointer on FATFS context in FAT cluster
[626]2491    fat_fatfs_ctx = hal_remote_lpt( XPTR( fat_cxy , &vfs_ctx->extend ) );
[602]2492
[625]2493    // build relevant extended pointers on free clusters info in mapper cluster
[627]2494    lock_xp = XPTR( fat_cxy , &fat_fatfs_ctx->lock );
[626]2495    hint_xp = XPTR( fat_cxy , &fat_fatfs_ctx->free_cluster_hint );
2496    free_xp = XPTR( fat_cxy , &fat_fatfs_ctx->free_clusters );
[602]2497
[627]2498    // take the FAT lock in write mode
2499    remote_rwlock_wr_acquire( lock_xp );
[602]2500
[626]2501    // get hint and free_clusters values from FATFS context in FAT cluster
[625]2502    cluster       = hal_remote_l32( hint_xp ) + 1;
[626]2503    free_clusters = hal_remote_l32( free_xp );
[602]2504       
2505#if (DEBUG_FATFS_CLUSTER_ALLOC & 1)
2506if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
[625]2507printk("\n[%s] thread[%x,%x] get free info : hint %x / free_clusters %x\n",
2508__FUNCTION__, this->process->pid, this->trdid, (cluster - 1), free_clusters );
[602]2509#endif
2510
2511    // check "free_clusters"
2512    if ( free_clusters == 0 )
2513    {
2514        printk("\n[ERROR] in %s : no more free FATFS clusters\n", __FUNCTION__ );
[627]2515        remote_rwlock_wr_release( lock_xp );
[602]2516        return -1;
2517    }
2518    else if ( free_clusters < CONFIG_VFS_FREE_CLUSTERS_MIN )
2519    {
2520        printk("\n[WARNING] in %s : only %n free FATFS clusters\n", 
2521        __FUNCTION__, CONFIG_VFS_FREE_CLUSTERS_MIN );
2522    }
2523
[625]2524    // get page index & slot index for selected cluster
2525    page_id  = cluster >> 10;
2526    slot_id  = cluster & 0x3FF;
2527
[626]2528    // get relevant page descriptor from FAT mapper
[628]2529    page_xp = mapper_remote_get_page( fat_mapper_xp , page_id );
[625]2530
2531    if( page_xp == XPTR_NULL )
2532    {
2533        printk("\n[ERROR] in %s : cannot acces FAT mapper\n", __FUNCTION__ );
[627]2534        remote_rwlock_wr_release( lock_xp );
[625]2535        return -1;
2536    }
2537
2538    // build extended pointer on selected cluster slot in FAT mapper
2539    slot_xp = ppm_page2base( page_xp ) + (slot_id << 2);
2540         
2541    // check selected cluster actually free
[602]2542    if( hal_remote_l32( slot_xp ) != FREE_CLUSTER )
2543    { 
[625]2544        printk("\n[ERROR] in %s : selected cluster %x not free\n", __FUNCTION__, cluster );
[627]2545        remote_rwlock_wr_release( lock_xp );
[602]2546        return -1;
2547    }
2548
[626]2549    // update free cluster info in FATFS context and in FS_INFO sector
2550    error = fatfs_free_clusters_decrement( XPTR( fat_cxy , fat_fatfs_ctx ) , cluster );
[602]2551
[626]2552    if( error )
2553    { 
2554        printk("\n[ERROR] in %s : cannot update free cluster info\n", __FUNCTION__ );
[627]2555        remote_rwlock_wr_release( lock_xp );
[626]2556        return -1;
2557    }
[602]2558
[625]2559    // update FAT mapper
2560    hal_remote_s32( slot_xp , END_OF_CHAIN_CLUSTER_MAX );
2561
[628]2562    // we don't mark the FAT mapper page as dirty,
2563    // because we synchronously update FAT on IOC device
[626]2564    error = fatfs_move_page( page_xp , IOC_SYNC_WRITE );
[625]2565
[626]2566    if( error )
2567    { 
2568        printk("\n[ERROR] in %s : cannot update FAT on IOC device\n", __FUNCTION__ );
[627]2569        remote_rwlock_wr_release( lock_xp );
[626]2570        return -1;
2571    }
2572
[627]2573    // release FAT lock
2574    remote_rwlock_wr_release( lock_xp );
[626]2575
[602]2576#if DEBUG_FATFS_CLUSTER_ALLOC
2577cycle = (uint32_t)hal_get_cycles();
2578if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
[626]2579printk("\n[%s] thread[%x,%x] exit / allocated cluster %x in FAT / cycle %d\n",
[625]2580__FUNCTION__, this->process->pid, this->trdid, cluster, cycle );
[602]2581#endif
2582
[625]2583    *searched_cluster = cluster;
[602]2584    return 0;
2585
2586}  // end fat_cluster_alloc()
2587
2588//////////////////////////////////////////////
2589error_t fatfs_release_inode( xptr_t inode_xp )
2590{
2591    vfs_ctx_t   * vfs_ctx;        // local pointer on VFS context (same in all clusters).
2592    fatfs_ctx_t * loc_fatfs_ctx;  // local pointer on local FATFS context
[628]2593    cxy_t         fat_cxy;        // FAT cluster identifier
2594    xptr_t        fatfs_ctx_xp;   // extended pointer on FATFS context in FAT cluster
2595    fatfs_ctx_t * fatfs_ctx_ptr;  // local pointer on FATFS context in FAT cluster
2596    xptr_t        fat_mapper_xp;  // extended pointer on FAT mapper
2597    mapper_t    * fat_mapper_ptr; // local pointer on FAT mapper
2598    xptr_t        lock_xp;        // extended pointer on lock protecting FAT.
[602]2599    xptr_t        first_xp;       // extended pointer on inode extension
2600    uint32_t      first_cluster;  // first cluster index for released inode
[626]2601    vfs_inode_t * inode_ptr;      // local pointer on target inode
2602    cxy_t         inode_cxy;      // target inode cluster identifier
[628]2603    error_t       error;
[602]2604
2605// check inode pointer
2606assert( (inode_xp != XPTR_NULL) , "inode pointer is NULL\n" );
2607
[623]2608    // get inode cluster and local pointer
[602]2609    inode_ptr     = GET_PTR( inode_xp );
2610    inode_cxy     = GET_CXY( inode_xp );
[623]2611
2612    // get first_cluster from inode extension
[602]2613    first_xp      = XPTR( inode_cxy , &inode_ptr->extend );
2614    first_cluster = (uint32_t)(intptr_t)hal_remote_lpt( first_xp );
2615
2616// check first cluster index
2617assert( (first_cluster != 0) , "inode extend is NULL\n" );
2618
2619#if DEBUG_FATFS_RELEASE_INODE
2620char       name[CONFIG_VFS_MAX_NAME_LENGTH];
2621uint32_t   cycle = (uint32_t)hal_get_cycles();
2622thread_t * this  = CURRENT_THREAD;
2623vfs_inode_get_name( inode_xp , name );
2624if( DEBUG_FATFS_RELEASE_INODE < cycle )
2625printk("\n[%s] thread[%x,%x] enter for <%s> / first_cluster %x / cycle %d\n",
2626__FUNCTION__ , this->process->pid, this->trdid, name, first_cluster, cycle );
2627#endif
2628
2629    // get local pointer on VFS context (same in all clusters)
2630    vfs_ctx = &fs_context[FS_TYPE_FATFS];
2631
2632    // get local pointer on local FATFS context
2633    loc_fatfs_ctx = vfs_ctx->extend;
2634
[628]2635    // get pointers on FAT mapper
2636    fat_mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
2637    fat_cxy        = GET_CXY( fat_mapper_xp );
2638    fat_mapper_ptr = GET_PTR( fat_mapper_xp );
[602]2639   
[628]2640    // get pointers on FATFS context in FAT cluster
2641    fatfs_ctx_ptr  = hal_remote_lpt( XPTR( fat_cxy , &vfs_ctx->extend ) );
2642    fatfs_ctx_xp   = XPTR( fat_cxy , fatfs_ctx_ptr );
[602]2643
[627]2644    // get extended pointer on FAT lock in FAT cluster
[628]2645    lock_xp = XPTR( fat_cxy , &fatfs_ctx_ptr->lock );
[602]2646
[627]2647    // take FAT lock in write mode
2648    remote_rwlock_wr_acquire( lock_xp );
[602]2649
[628]2650#if (DEBUG_FATFS_RELEASE_INODE & 0x11 == 0x11)
2651mapper_display_page( fat_mapper_xp , 0 , 4096 );
2652#endif
2653
[602]2654    // call the recursive function to release all clusters from FAT mapper
[628]2655    uint32_t dirty_page_min = 0xFFFFFFFF;
2656    uint32_t dirty_page_max = 0;
2657
2658    if ( fatfs_recursive_release( fat_mapper_xp,
2659                                  fatfs_ctx_xp,
2660                                  first_cluster,
2661                                  &dirty_page_min,
2662                                  &dirty_page_max ) )
[602]2663    {
2664        printk("\n[ERROR] in %s : cannot update FAT mapper\n", __FUNCTION__ );
[627]2665        remote_rwlock_wr_release( lock_xp );
[602]2666        return -1;
2667    }
2668
2669#if (DEBUG_FATFS_RELEASE_INODE & 1)
2670if( DEBUG_FATFS_RELEASE_INODE < cycle )
2671printk("\n[%s] inode <%s> removed from FAT mapper\n", __FUNCTION__, name );
2672#endif
2673
[628]2674#if (DEBUG_FATFS_RELEASE_INODE & 0x11 == 0x11)
2675mapper_display_page( fat_mapper_xp , 0 , 4096 );
2676#endif
2677
[602]2678    // update FAT on IOC device (from FAT mapper)
[628]2679    error = fatfs_update_ioc_fat( fatfs_ctx_xp,
2680                                  dirty_page_min,
2681                                  dirty_page_max );
2682
2683    if( error )
[602]2684    {
[628]2685        printk("\n[ERROR] in %s : cannot update FAT on IOC device\n", __FUNCTION__ );
[627]2686        remote_rwlock_wr_release( lock_xp );
[602]2687        return -1;
2688    }
2689
2690#if (DEBUG_FATFS_RELEASE_INODE & 1)
2691if( DEBUG_FATFS_RELEASE_INODE < cycle )
2692printk("\n[%s] inode <%s> removed from FAT on IOC device\n", __FUNCTION__, name );
2693#endif
2694
[628]2695    // update FS-INFO on IOC device (from FATFS context)
2696    error = fatfs_update_ioc_fsinfo( fatfs_ctx_xp );
2697
2698    if( error )
[602]2699    {
[628]2700        printk("\n[ERROR] in %s: cannot update FSINFO on IOC device\n", __FUNCTION__ );
[627]2701        remote_rwlock_wr_release( lock_xp );
[602]2702        return -1;
2703    }
2704
[628]2705#if (DEBUG_FATFS_RELEASE_INODE & 1)
2706if( DEBUG_FATFS_RELEASE_INODE < cycle )
2707printk("\n[%s] updated FS_INFO on IOC device for >%s>\n", __FUNCTION__, name );
2708#endif
2709
[627]2710    // release FAT lock
2711    remote_rwlock_wr_release( lock_xp );
2712
[602]2713#if DEBUG_FATFS_RELEASE_INODE
2714cycle = (uint32_t)hal_get_cycles();
2715if( DEBUG_FATFS_RELEASE_INODE < cycle )
2716printk("\n[%s] thread[%x,%x] removed <%s> inode from FATFS / cycle %d\n",
2717__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
2718#endif
2719
2720    return 0;
2721
2722}  // end fatfs_release_inode()
2723
[614]2724////////////////////////////////////////////
2725error_t fatfs_move_page( xptr_t     page_xp,
2726                         cmd_type_t cmd_type )
[602]2727{
2728    error_t       error;
2729    vfs_inode_t * inode_ptr;
2730    mapper_t    * mapper_ptr;     
2731    uint32_t      page_id;     // page index in mapper
2732
2733#if DEBUG_FATFS_MOVE_PAGE
2734uint32_t   cycle = (uint32_t)hal_get_cycles();
2735thread_t * this  = CURRENT_THREAD;
2736char       name[CONFIG_VFS_MAX_NAME_LENGTH];
2737#endif
2738
2739    // get page cluster an local pointer
2740    cxy_t    page_cxy = GET_CXY( page_xp );
2741    page_t * page_ptr = GET_PTR( page_xp );
2742
2743    // get mapper pointer and page index from page descriptor
2744    mapper_ptr = hal_remote_lpt( XPTR( page_cxy , &page_ptr->mapper ) );
2745    page_id    = hal_remote_l32( XPTR( page_cxy , &page_ptr->index ) );
2746
2747    // get pointer on local FATFS context
[611]2748    fatfs_ctx_t * fatfs_ctx = fs_context[FS_TYPE_FATFS].extend;
[602]2749
2750    // get page base address
[626]2751    xptr_t    buffer_xp  = ppm_page2base( page_xp );
2752    uint8_t * buffer_ptr = (uint8_t *)GET_PTR( buffer_xp );
[602]2753 
2754    // get inode pointer from mapper
2755    inode_ptr  = hal_remote_lpt( XPTR( page_cxy , &mapper_ptr->inode ) );
2756
[626]2757#if DEBUG_FATFS_MOVE_PAGE
2758if( DEBUG_FATFS_MOVE_PAGE < cycle )
2759printk("\n[%s] thread[%x,%x] enters : %s / cxy %x / mapper %x / inode %x / page %x\n",
2760__FUNCTION__, this->process->pid, this->trdid,
2761dev_ioc_cmd_str( cmd_type ), page_cxy, mapper_ptr, inode_ptr, buffer_ptr );
2762#endif
2763
2764    //////////////////////////////  FAT mapper
[602]2765    if( inode_ptr == NULL )
2766    {
2767        // get lba from FATFS context and page_id
[625]2768        uint32_t      lba = fatfs_ctx->fat_begin_lba + (page_id << 3);
[602]2769 
2770        // access device
[626]2771        if     (cmd_type == IOC_SYNC_READ ) error = dev_ioc_sync_read ( buffer_xp  , lba , 8 );
2772        else if(cmd_type == IOC_SYNC_WRITE) error = dev_ioc_sync_write( buffer_xp  , lba , 8 );
2773        else if(cmd_type == IOC_READ      ) error = dev_ioc_read      ( buffer_ptr , lba , 8 );
2774        else if(cmd_type == IOC_WRITE     ) error = dev_ioc_write     ( buffer_ptr , lba , 8 );
2775        else                                error = -1;
[602]2776
[626]2777        if( error )
2778        {
2779            printk("\n[ERROR] in %s : cannot access device\n", __FUNCTION__ );
2780            return -1;
2781        }
[602]2782
2783#if DEBUG_FATFS_MOVE_PAGE
2784if( DEBUG_FATFS_MOVE_PAGE < cycle )
2785{
[614]2786    if ( (cmd_type == IOC_READ) || (cmd_type == IOC_SYNC_READ) )
[626]2787        printk("\n[%s] thread[%x,%x] load FAT mapper page %d from IOC / cycle %d\n",
2788        __FUNCTION__, this->process->pid, this->trdid, page_id, cycle );
[602]2789    else
[626]2790        printk("\n[%s] thread[%x,%x] sync FAT mapper page %d to IOC / cycle %d\n",
[602]2791        __FUNCTION__, this->process->pid, this->trdid, page_id, cycle );
2792}
2793#endif
2794
2795    }
[626]2796    /////////////////////////  inode mapper
[602]2797    else                       
2798    {
2799
2800#if DEBUG_FATFS_MOVE_PAGE
2801vfs_inode_get_name( XPTR( page_cxy , inode_ptr ) , name );
2802#endif
2803
2804        uint32_t  searched_cluster;
2805        uint32_t  first_cluster;
2806
2807        // get first_cluster from inode extension
2808        void * extend = hal_remote_lpt( XPTR( page_cxy , &inode_ptr->extend ) );
2809        first_cluster = (uint32_t)(intptr_t)extend;
2810
2811        // compute searched_cluster
2812        if( page_id == 0 )            // no need to access FAT mapper
2813        {
2814            // searched cluster is first cluster
2815            searched_cluster = first_cluster;
2816        }
2817        else                        // FAT mapper access required
2818        {
2819            // access FAT mapper to get searched cluster
2820            error = fatfs_get_cluster( first_cluster,
2821                                       page_id,
2822                                       &searched_cluster );
[625]2823            if( error )
2824            {
2825                printk("\n[ERROR] in %s : cannot access FAT mapper\n", __FUNCTION__ );
2826                return -1;
2827            }
[602]2828        }
2829
[626]2830        // get lba for searched_cluster
[602]2831        uint32_t lba = fatfs_lba_from_cluster( fatfs_ctx , searched_cluster );
2832
[626]2833        // access device
2834        if     (cmd_type == IOC_SYNC_READ ) error = dev_ioc_sync_read ( buffer_xp  , lba , 8 );
2835        else if(cmd_type == IOC_SYNC_WRITE) error = dev_ioc_sync_write( buffer_xp  , lba , 8 );
2836        else if(cmd_type == IOC_READ      ) error = dev_ioc_read      ( buffer_ptr , lba , 8 );
2837        else if(cmd_type == IOC_WRITE     ) error = dev_ioc_write     ( buffer_ptr , lba , 8 );
2838        else                                error = -1;
2839
2840        if( error )
2841        {
2842            printk("\n[ERROR] in %s : cannot access device\n", __FUNCTION__ );
2843            return -1;
2844        }
2845
[625]2846#if DEBUG_FATFS_MOVE_PAGE
2847if( DEBUG_FATFS_MOVE_PAGE < cycle )
2848{
2849    if ( (cmd_type == IOC_READ) || (cmd_type == IOC_SYNC_READ) )
2850    printk("\n[%s] thread[%x,%x] load page %d of <%s> / cluster_id %x / cycle %d\n",
2851    __FUNCTION__, this->process->pid, this->trdid, page_id, name, searched_cluster, cycle );
2852    else
2853    printk("\n[%s] thread[%x,%x] sync page %d of <%s> / cluster_id %x / cycle %d\n",
2854    __FUNCTION__, this->process->pid, this->trdid, page_id, name, searched_cluster, cycle );
2855}
2856#endif
2857
[602]2858    }
2859
2860    return 0;
2861
2862}  // end fatfs_move_page()
2863
2864
Note: See TracBrowser for help on using the repository browser.