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

Last change on this file since 656 was 656, checked in by alain, 4 years ago

Fix several bugs in the FATFS and in the VFS,
related to the creation of big files requiring
more than 4 Kbytes (one cluster) on device.

File size: 108.8 KB
Line 
1/*
2 * fatfs.c - FATFS file system API implementation.
3 *
4 * Author    Alain Greiner (2016,2017,2018,2019)
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
25#include <hal_kernel_types.h>
26#include <hal_special.h>
27#include <printk.h>
28#include <thread.h>
29#include <kmem.h>
30#include <ppm.h>
31#include <vfs.h>
32#include <string.h>
33#include <rpc.h>
34#include <mapper.h>
35#include <cluster.h>
36#include <dev_ioc.h>
37#include <fatfs.h>
38
39#define LITTLE_ENDIAN  1
40
41//////////////////////////////////////////////////////////////////////////////////////////
42//          Extern  variables         
43//////////////////////////////////////////////////////////////////////////////////////////
44
45extern vfs_ctx_t     fs_context[FS_TYPES_NR];   // allocated in kernel_init.c file
46
47//////////////////////////////////////////////////////////////////////////////////////////
48//              FATFS specific static functions
49//////////////////////////////////////////////////////////////////////////////////////////
50
51//////////////////////////////////////////////////////////////////////////////////////////
52// These functions return the "offset" and "length" values of an
53// [offset,length] constant defined in the fatfs.h file.
54//////////////////////////////////////////////////////////////////////////////////////////
55
56static inline int get_length( int offset __attribute__((unused)), int length ) { return length; }
57
58static inline int get_offset( int offset, int length __attribute__((unused)) ) { return offset; }
59
60//////////////////////////////////////////////////////////////////////////////////////////
61// This static function returns the LBA of the first sector of a FAT cluster.
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 )
70{
71    return (ctx->cluster_begin_lba + ((cluster - 2) << 3));
72}
73
74//////////////////////////////////////////////////////////////////////////////////////////
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.
78//////////////////////////////////////////////////////////////////////////////////////////
79// @ offset        : first byte in array.
80// @ nbytes        : record length in bytes (1/2/4).
81// @ buffer        : local pointer on byte array.
82// @ return the integer value in a 32 bits word.
83//////////////////////////////////////////////////////////////////////////////////////////
84static uint32_t fatfs_get_record( uint32_t    offset,
85                                  uint32_t    nbytes,
86                                  uint8_t   * buffer )
87{
88    uint32_t i;
89    uint32_t res = 0;
90
91    if ( LITTLE_ENDIAN )
92    {
93        for( i = nbytes ; i > 0 ; i-- ) res = (res<<8) | buffer[offset+i-1];
94    }
95    else 
96    {
97        for( i = 0 ; i < nbytes ; i++ ) res = (res<<8) | buffer[offset+i];
98    }
99    return res;
100
101}  // end fatfs_get_record()
102
103//////////////////////////////////////////////////////////////////////////////////////////
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.
107//////////////////////////////////////////////////////////////////////////////////////////
108// @ offset        : first byte in array.
109// @ nbytes        : record length in bytes (1/2/4).
110// @ buffer_xp     : extended pointer on byte array.
111// @ return the integer value in a 32 bits word.
112//////////////////////////////////////////////////////////////////////////////////////////
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//////////////////////////////////////////////////////////////////////////////////////////
148static void fatfs_set_record( uint32_t    offset,
149                              uint32_t    nbytes,
150                              uint8_t   * buffer,
151                              uint32_t    value )
152{
153    uint32_t i;
154
155    if ( LITTLE_ENDIAN )
156    {
157        for( i = nbytes ; i > 0 ; i-- ) buffer[offset+i-1] = (uint8_t)(value>>((i-1)<<3));
158    }
159    else
160    {
161        for( i = 0 ; i < nbytes ; i++ ) buffer[offset+i] = (uint8_t)(value>>((nbytes-1-i)<<3));
162    }
163
164}  // end fatfs_set_record()
165
166//////////////////////////////////////////////////////////////////////////////////////////
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//////////////////////////////////////////////////////////////////////////////////////////
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;
212
213    // get name
214    for ( i = 0; i < 8 && buffer[i] != ' '; i++ )
215    {
216        name[j] = to_lower( buffer[i] );
217        j++;
218    }
219
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
236}  // fatfs_get_name_from_short()
237
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
313} // end fatfs_get_name_from_long()
314
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;
339
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
443//////////////////////////////////////////////////////////////////////////////////////////
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.
450//////////////////////////////////////////////////////////////////////////////////////////
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
454// @ return 0 if success, return -1 if the FS_INFO sector cannot be updated.
455//////////////////////////////////////////////////////////////////////////////////////////
456static error_t fatfs_update_ioc_fat( xptr_t   fatfs_ctx_xp,
457                                     uint32_t page_min,
458                                     uint32_t page_max )
459{
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{
548    cxy_t         fat_cxy;             // FAT cluster identifier
549    fatfs_ctx_t * fatfs_ctx_ptr;       // local pointer on fatfs context in FAT cluster
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
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
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 ) );
567    fs_info_buffer_ptr = hal_remote_lpt( XPTR( fat_cxy , &fatfs_ctx_ptr->fs_info_buffer ) );
568
569    // build extended pointer on FS_INFO buffer in FAT cluster
570    fs_info_buffer_xp  = XPTR( fat_cxy , fs_info_buffer_ptr );
571   
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_move_data( IOC_SYNC_WRITE , fs_info_buffer_xp , fs_info_lba , 1 );
578 
579}  // end fatfs_update_ioc_fsinfo()
580
581//////////////////////////////////////////////////////////////////////////////////////////
582// This static function decrements the  "free_clusters" variable, and updates the
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.
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".
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.
590//////////////////////////////////////////////////////////////////////////////////////////
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.
594//////////////////////////////////////////////////////////////////////////////////////////
595static error_t fatfs_free_clusters_decrement( xptr_t    fatfs_ctx_xp,
596                                              uint32_t  cluster )
597{
598    error_t       error;
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
612
613#if DEBUG_FATFS_FREE_CLUSTERS
614uint32_t   cycle = (uint32_t)hal_get_cycles();
615thread_t * this  = CURRENT_THREAD;
616if( DEBUG_FATFS_FREE_CLUSTERS < cycle )
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
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 );
628
629    // update "free_clusters" value
630    numb = hal_remote_l32( numb_xp ) - 1;
631    hal_remote_s32( numb_xp , numb );
632
633    // get extended pointer on FAT mapper
634    fat_mapper_xp = hal_remote_l64( XPTR( fat_cxy , &fat_ctx_ptr->fat_mapper_xp ) );
635
636    // initialise variables to scan the FAT mapper
637    // and find the first free slot > cluster
638    page_id  = (cluster + 1) >> 10;
639    slot_id  = (cluster + 1) & 0x3FF;
640    page_max = hal_remote_l32( XPTR( fat_cxy, &fat_ctx_ptr->fat_sectors_count ) ) >> 3;
641
642    // scan FAT mapper / loop on pages
643    while ( page_id < page_max )           
644    {
645        // get current page from mapper
646        page_xp = mapper_remote_get_page( fat_mapper_xp , page_id );
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
654        // get extended pointer on page
655        base_xp = ppm_page2base( page_xp );
656
657        // scan FAT mapper / loop on slots
658        while ( slot_id < 1024 )
659        {
660            // get extended pointer on current slot
661            slot_xp = base_xp + (slot_id << 2);
662
663            // test slot value
664            if ( hal_remote_l32( slot_xp ) == FREE_CLUSTER )
665            {
666                // update "free_cluster_hint" value
667                hint = (page_id << 10) + slot_id - 1;
668                hal_remote_s32( hint_xp , hint );
669
670                // update FS_INFO sector on IOC device
671                error = fatfs_update_ioc_fat( fatfs_ctx_xp,
672                                              page_id,
673                                              page_id );
674
675                if( error ) 
676                {
677                    printk("\n[ERROR] in %s : cannot update FS_INFO on IOC\n", __FUNCTION__ );
678                    return -1;
679                }
680
681#if DEBUG_FATFS_FREE_CLUSTERS
682cycle = (uint32_t)hal_get_cycles();
683if( DEBUG_FATFS_FREE_CLUSTERS < (uint32_t)hal_get_cycles() )
684printk("\n[%s] thread[%x,%x] exit / hint %x / free %x / cycle %d\n",
685__FUNCTION__, this->process->pid, this->trdid, 
686hal_remote_l32(hint_xp), hal_remote_l32(numb_xp), cycle );
687#endif
688                return 0;
689            }
690
691            // update slot_id
692            slot_id = 0;
693
694        }  // end loop on slots
695
696        // update page_id & slot_id variables
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//////////////////////////////////////////////////////////////////////////////////////////
709// This static function increments the "free_clusters" variable, and updates the
710// "free_cluster_hint" variables in the FATFS context in FAT cluster, identified
711// by the <fat_ctx_xp> argument, when a FATFS cluster is released.
712// If the released cluster index is smaller than the current (hint) value,
713// it set "free_cluster_hint" <= cluster.
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.
717//////////////////////////////////////////////////////////////////////////////////////////
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.
721//////////////////////////////////////////////////////////////////////////////////////////
722static error_t fatfs_free_clusters_increment( xptr_t   fatfs_ctx_xp,
723                                              uint32_t cluster )
724{
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
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
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   
745    // build extended pointers on free_clusters, and free_cluster_hint
746    hint_xp = XPTR( fat_cxy , &fat_ctx_ptr->free_cluster_hint );
747    numb_xp = XPTR( fat_cxy , &fat_ctx_ptr->free_clusters );
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
753    // update "numb" and "hint" variables as required
754    numb++;
755    if ( (cluster - 1) < hint ) hint = cluster - 1;
756
757    // update free_clusters
758    hal_remote_s32( numb_xp , numb );
759    hal_remote_s32( hint_xp , hint );
760
761    // update FS_INFO sector on IOC device
762    error = fatfs_update_ioc_fsinfo( fatfs_ctx_xp );
763
764    if( error ) 
765    {
766        printk("\n[ERROR] in %s : cannot update FS_INFO on IOC\n", __FUNCTION__ );
767        return -1;
768    }
769
770#if DEBUG_FATFS_FREE_CLUSTERS
771cycle = (uint32_t)hal_get_cycles();
772if( DEBUG_FATFS_FREE_CLUSTERS < (uint32_t)hal_get_cycles() )
773printk("\n[%s] thread[%x,%x] exit / hint %x / free %x / cycle %d\n",
774__FUNCTION__, this->process->pid, this->trdid,
775hal_remote_l32( hint_xp ), hal_remote_l32( numb_xp ), cycle );
776#endif
777
778    return 0;
779
780}  // end fatfs_free_clusters_increment()
781
782//////////////////////////////////////////////////////////////////////////////////////////
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.
793//////////////////////////////////////////////////////////////////////////////////////////
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.
800//////////////////////////////////////////////////////////////////////////////////////////
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 )
806{
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
810
811    // get page index and word index from cluster
812    page_id = cluster >> 10;
813    word_id = cluster & 0x3FF;
814
815    // get next cluster index from FAT mapper
816    if ( mapper_remote_get_32( fat_mapper_xp,
817                               page_id,
818                               word_id,
819                               &next ) ) return -1;
820
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
831        if ( fatfs_recursive_release( fat_mapper_xp,
832                                      fatfs_ctx_xp,
833                                      next,
834                                      dirty_page_min,
835                                      dirty_page_max ) ) return -1;
836    }       
837
838    // update FAT mapper
839    if ( mapper_remote_set_32( fat_mapper_xp,
840                               page_id, 
841                               word_id,
842                               FREE_CLUSTER ) ) return -1;
843
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;
847
848    // Update free_cluster info in FATFS context
849    return fatfs_free_clusters_increment( fatfs_ctx_xp , cluster );
850
851}  // end fatfs_recursive_release()
852
853
854//////////////////////////////////////////////////////////////////////////////////////////
855// This static function access the FAT (File Allocation Table), stored in the FAT mapper,
856// and returns in <searched_cluster_id> the FATFS cluster_id for a given page of a given
857// inode, identified by the <searched_page_id> argument, that is the page index in file
858// (i.e. the page index in file mapper). The entry point in the FAT is defined by the
859// <first_cluster_id> argument, that is the cluster_id of an already allocated cluster.
860// It can be the cluster_id of the first page of the file (always registered in the
861// fatfs_inode extension), or any page of the file whose <first_page_id> argument
862// is smaller than the searched <first_page_id> argument.
863// This function can be called by a thread running in any cluster, as it uses remote
864// access primitives when the FAT mapper is remote.
865// The FAT mapper being a WRITE-THROUGH cache, this function updates the FAT mapper
866// from informations stored on IOC device in case of miss when scanning the FAT mapper.
867// The searched inode mapper being a WRITE-BACK cache, this function allocates a new
868// cluster_id when the searched page exist in the inode mapper, and there is no FATFS
869// cluster allocated yet for this page. It updates the FAT, but it does NOT copy the
870// mapper page content to the File System.
871//////////////////////////////////////////////////////////////////////////////////////////
872// @ first_page_id       : [in]  index in file mapper for an existing page.
873// @ first_cluster_id    : [in]  cluster_id for this existing page.
874// @ searched_page_id    : [in]  index in file mapper for the searched page.
875// @ searched_cluster_id : [out] cluster_id for the searched page.
876// @ return 0 if success / return -1 if a FAT mapper miss cannot be solved,
877//                         or if a missing cluster_id cannot be allocated.
878//////////////////////////////////////////////////////////////////////////////////////////
879static error_t fatfs_get_cluster( uint32_t   first_page_id,
880                                  uint32_t   first_cluster_id,
881                                  uint32_t   searched_page_id,
882                                  uint32_t * searched_cluster_id )
883{
884    uint32_t   current_page_id;        // index of page in file mapper
885    uint32_t   current_cluster_id;     // index of cluster in FATFS
886    xptr_t     lock_xp;                // extended pointer on FAT lock
887
888assert( (searched_page_id > first_page_id) ,
889"searched_page_id must be larger than first_page_id\n");
890
891#if DEBUG_FATFS_GET_CLUSTER
892uint32_t   cycle = (uint32_t)hal_get_cycles();
893thread_t * this  = CURRENT_THREAD;
894if( DEBUG_FATFS_GET_CLUSTER < cycle )
895printk("\n[%s] thread[%x,%x] enter / first_cluster_id %x / searched_page_id %d / cycle %d\n",
896__FUNCTION__, this->process->pid, this->trdid, first_cluster_id, searched_page_id, cycle );
897#endif
898
899    // get local pointer on VFS context (same in all clusters)
900    vfs_ctx_t * vfs_ctx = &fs_context[FS_TYPE_FATFS];
901
902    // get local pointer on local FATFS context
903    fatfs_ctx_t * loc_fatfs_ctx = vfs_ctx->extend;
904
905    // get extended pointer and cluster on FAT mapper
906    xptr_t fat_mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
907    cxy_t  fat_cxy        = GET_CXY( fat_mapper_xp );
908
909    // get local pointer on FATFS context in FAT cluster
910    fatfs_ctx_t * fat_fatfs_ctx = hal_remote_lpt( XPTR( fat_cxy , &vfs_ctx->extend ) );
911
912    // build extended pointer on FAT lock in FAT cluster
913    lock_xp = XPTR( fat_cxy , &fat_fatfs_ctx->lock );
914
915    // take FAT lock in read mode
916    remote_rwlock_rd_acquire( lock_xp );
917
918    // initialize loop variables
919    current_page_id    = first_page_id;
920    current_cluster_id = first_cluster_id;
921
922    // scan FAT mapper (i.e. traverse FAT linked list)
923    // starting from first_page_id until searched_page_id
924    // each iteration in this loop can change both
925    // the FAT page index and the slot index in FAT
926    while( current_page_id < searched_page_id )
927    {
928        // FAT mapper page and slot indexes (1024 slots per FAT page)
929        uint32_t fat_page_index   = current_cluster_id >> 10;
930        uint32_t fat_slot_index   = current_cluster_id & 0x3FF;
931
932        // get pointer on current page descriptor in FAT mapper
933        xptr_t current_page_xp = mapper_remote_get_page( fat_mapper_xp , fat_page_index );
934
935        if( current_page_xp == XPTR_NULL )
936        {
937            printk("\n[ERROR] in %s : cannot get page %d from FAT mapper\n",
938            __FUNCTION__ , fat_page_index );
939            remote_rwlock_rd_release( lock_xp );
940            return -1;
941        }
942
943        // get pointer on buffer containing the FAT mapper page
944        xptr_t base_xp = ppm_page2base( current_page_xp );
945        uint32_t * buffer = (uint32_t *)GET_PTR( base_xp );
946
947        // get next_cluster_id from FAT slot 
948        uint32_t next_cluster_id = hal_remote_l32( XPTR( fat_cxy, &buffer[fat_slot_index] ) );
949
950        // allocate a new FAT cluster when there is no cluster
951        // allocated on device for the current page
952        if( next_cluster_id >= END_OF_CHAIN_CLUSTER_MIN ) 
953        {
954            // release the FAT lock in read mode,
955            remote_rwlock_rd_release( lock_xp );
956
957            // allocate a new cluster_id (and update both FAT mapper and FAT on device).
958            error_t error = fatfs_cluster_alloc( &next_cluster_id );
959
960            if( error )
961            {
962                printk("\n[ERROR] in %s : cannot allocate cluster on FAT32 for page %d\n",
963                __FUNCTION__ , current_page_id );
964                remote_rwlock_wr_release( lock_xp );
965                return -1;
966            }
967
968#if (DEBUG_FATFS_GET_CLUSTER & 1)
969if( DEBUG_FATFS_GET_CLUSTER < cycle )
970printk("\n[%s] allocated a new cluster_id %d in FATFS\n",
971__FUNCTION__, next_cluster_id );
972#endif
973            // take the FAT lock in read mode,
974            remote_rwlock_rd_acquire( lock_xp );
975        }
976
977#if (DEBUG_FATFS_GET_CLUSTER & 1)
978if( DEBUG_FATFS_GET_CLUSTER < cycle )
979printk("\n[%s] traverse FAT / fat_page_index %d / fat_slot_index %d / next_cluster_id %x\n",
980__FUNCTION__, fat_page_index, fat_slot_index , next_cluster_id );
981#endif
982
983        // update loop variables
984        current_cluster_id = next_cluster_id;
985        current_page_id++;
986    }
987   
988    // release FAT lock
989    remote_rwlock_rd_release( lock_xp );
990
991#if DEBUG_FATFS_GET_CLUSTER
992if( DEBUG_FATFS_GET_CLUSTER < cycle )
993printk("\n[%s] thread[%x,%x] exit / searched_cluster_id = %d\n",
994__FUNCTION__, this->process->pid, this->trdid, current_cluster_id );
995#endif
996
997    *searched_cluster_id = current_cluster_id;
998    return 0;
999
1000}  // end fatfs_get_cluster()
1001
1002
1003
1004
1005
1006//////////////////////////////////////////////////////////////////////////////////////////
1007//              FATFS specific extern functions
1008//////////////////////////////////////////////////////////////////////////////////////////
1009
1010///////////////////////////////////
1011void fatfs_display_ctx( cxy_t cxy )
1012{
1013    // get pointer on local FATFS context
1014    vfs_ctx_t   * vfs_ctx = &fs_context[FS_TYPE_FATFS];
1015        fatfs_ctx_t * ctx     = hal_remote_lpt( XPTR( cxy , &vfs_ctx->extend ) );
1016
1017    uint32_t fat_sectors       = hal_remote_l32( XPTR( cxy , &ctx->fat_sectors_count ) );
1018    uint32_t sector_size       = hal_remote_l32( XPTR( cxy , &ctx->bytes_per_sector ) );
1019    uint32_t sec_per_clus      = hal_remote_l32( XPTR( cxy , &ctx->sectors_per_cluster ) );
1020    uint32_t fat_lba           = hal_remote_l32( XPTR( cxy , &ctx->fat_begin_lba ) );
1021    uint32_t data_lba          = hal_remote_l32( XPTR( cxy , &ctx->cluster_begin_lba ) );
1022    uint32_t fsinfo_lba        = hal_remote_l32( XPTR( cxy , &ctx->fs_info_lba ) );
1023    uint32_t root_dir_clus     = hal_remote_l32( XPTR( cxy , &ctx->root_dir_cluster ) );
1024    uint32_t free_clusters     = hal_remote_l32( XPTR( cxy , &ctx->free_clusters ) );
1025    uint32_t free_cluster_hint = hal_remote_l32( XPTR( cxy , &ctx->free_cluster_hint ) );
1026    xptr_t   mapper_xp         = hal_remote_l64( XPTR( cxy , &ctx->fat_mapper_xp ) );
1027    void   * fs_info_buffer    = hal_remote_lpt( XPTR( cxy , &ctx->fs_info_buffer ) );
1028
1029    printk("\n*** FAT context in cluster %x\n" 
1030           "- fat_sectors       = %d\n"
1031           "- sector size       = %d\n"
1032           "- cluster size      = %d\n"
1033           "- fat_lba           = %x\n"
1034           "- data_lba          = %x\n"
1035           "- fsinfo_lba        = %x\n"
1036           "- root_dir_cluster  = %x\n"
1037           "- free_clusters     = %x\n"
1038           "- free_cluster_hint = %x\n"
1039           "- fat_mapper_ptr    = %x\n"
1040           "- fs_info_buffer    = %x\n",
1041           cxy,
1042           fat_sectors,
1043           sector_size,
1044           sector_size * sec_per_clus,
1045           fat_lba,
1046           data_lba,
1047           fsinfo_lba,
1048           root_dir_clus,
1049           free_clusters,
1050           free_cluster_hint,
1051           GET_PTR( mapper_xp ),
1052           fs_info_buffer );
1053
1054}  // end fatfs_ctx_display()
1055
1056//////////////////////////////////////////
1057void fatfs_display_fat( uint32_t  page_id,
1058                        uint32_t  min_slot,
1059                        uint32_t  nb_slots )
1060{
1061    uint32_t line;
1062
1063    // compute number of lines to display
1064    uint32_t min_line = min_slot >> 3;
1065    uint32_t max_line = (min_slot + nb_slots - 1) >> 3;
1066
1067    // get pointer on local FATFS context
1068    vfs_ctx_t   * vfs_ctx       = &fs_context[FS_TYPE_FATFS];
1069    fatfs_ctx_t * loc_fatfs_ctx = (fatfs_ctx_t *)vfs_ctx->extend;
1070
1071    // get pointers on FAT mapper (in FAT cluster)
1072    xptr_t     mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
1073    cxy_t      mapper_cxy = GET_CXY( mapper_xp );
1074
1075    // get pointer on FATFS context in FAT cluster
1076    fatfs_ctx_t * fat_fatfs_ctx = hal_remote_lpt( XPTR( mapper_cxy , &vfs_ctx->extend ) );
1077 
1078    // get current value of hint and free_clusters
1079    uint32_t hint = hal_remote_l32( XPTR( mapper_cxy , &fat_fatfs_ctx->free_cluster_hint ) );
1080    uint32_t free = hal_remote_l32( XPTR( mapper_cxy , &fat_fatfs_ctx->free_clusters ) );
1081
1082    // get extended pointer on requested page descriptor in FAT mapper
1083    xptr_t page_xp = mapper_remote_get_page( mapper_xp , page_id );
1084
1085    // get pointers on requested page base
1086    xptr_t     base_xp  = ppm_page2base( page_xp );
1087    void     * base     = GET_PTR( base_xp );
1088
1089    printk("\n***** FAT mapper / cxy %x / page_id %d / base %x / free_clusters %x / hint %x\n",
1090    mapper_cxy, page_id, base, free, hint );
1091
1092    for( line = min_line ; line <= max_line ; line++ )
1093    {
1094        printk("%d : %X | %X | %X | %X | %X | %X | %X | %X\n", (line<<3),
1095        hal_remote_l32( base_xp + ((line<<5)      ) ),
1096        hal_remote_l32( base_xp + ((line<<5) + 4  ) ),
1097        hal_remote_l32( base_xp + ((line<<5) + 8  ) ),
1098        hal_remote_l32( base_xp + ((line<<5) + 12 ) ),
1099        hal_remote_l32( base_xp + ((line<<5) + 16 ) ),
1100        hal_remote_l32( base_xp + ((line<<5) + 20 ) ),
1101        hal_remote_l32( base_xp + ((line<<5) + 24 ) ),
1102        hal_remote_l32( base_xp + ((line<<5) + 28 ) ) );
1103    }
1104
1105}  // end fatfs_display_fat()
1106
1107
1108
1109///////////////////////////////////////////////////////////////////////////////////////
1110// Generic API : the following functions are called by the kernel VFS
1111//               and must be defined by all supported file systems.
1112///////////////////////////////////////////////////////////////////////////////////////
1113
1114/////////////////////////////////////
1115fatfs_ctx_t * fatfs_ctx_alloc( void )
1116{
1117    kmem_req_t    req;
1118        req.type    = KMEM_KCM;
1119        req.order   = bits_log2( sizeof(fatfs_ctx_t) );
1120    req.flags   = AF_KERNEL | AF_ZERO;
1121
1122        return kmem_alloc( &req );
1123}
1124
1125//////////////////////////////////////////////
1126void fatfs_ctx_init( fatfs_ctx_t * fatfs_ctx )
1127{
1128    error_t       error;
1129    kmem_req_t    req;
1130    uint8_t     * buffer;
1131    xptr_t        buffer_xp;
1132
1133#if DEBUG_FATFS_CTX_INIT
1134uint32_t   cycle = (uint32_t)hal_get_cycles();
1135thread_t * this  = CURRENT_THREAD;
1136if( DEBUG_FATFS_CTX_INIT < cycle )
1137printk("\n[%s] thread[%x,%x] enter for fatfs_ctx = %x / cycle %d\n",
1138__FUNCTION__ , this->process->pid, this->trdid, fatfs_ctx , cycle );
1139#endif
1140
1141// check argument
1142assert( (fatfs_ctx != NULL) , "pointer on FATFS context is NULL" );
1143
1144// check only cluster 0 does FATFS initialization
1145assert( (local_cxy == 0) , "only cluster 0 can initialize FATFS");
1146
1147    // allocate a permanent 512 bytes buffer to store
1148    // - temporarily the BOOT sector
1149    // - permanently the FS_INFO sector
1150        req.type    = KMEM_KCM;
1151    req.order   = 9;                    // 512 bytes
1152    req.flags   = AF_KERNEL | AF_ZERO;
1153        buffer      = kmem_alloc( &req );
1154
1155    if( buffer == NULL ) 
1156    {
1157        printk("\n[PANIC] in %s : cannot allocate buffer\n", __FUNCTION__ );
1158        hal_core_sleep();
1159    }
1160     
1161    buffer_xp   = XPTR( local_cxy , buffer );
1162
1163    // load the BOOT record from device
1164    error = dev_ioc_move_data( IOC_SYNC_READ , buffer_xp , 0 , 1 );
1165
1166    if ( error )
1167    {
1168        printk("\n[PANIC] in %s : cannot access boot record\n", __FUNCTION__ );
1169        hal_core_sleep();
1170    }
1171
1172#if (DEBUG_FATFS_CTX_INIT & 0x1)
1173if( DEBUG_FATFS_CTX_INIT < cycle )
1174putb( "boot record", buffer , 256 );
1175#endif
1176
1177    // get sector size from boot record
1178    uint32_t sector_size = fatfs_get_record( BPB_BYTSPERSEC , buffer );
1179    if ( sector_size != 512 )
1180    {
1181        printk("\n[PANIC] in %s : sector size must be 512 bytes\n", __FUNCTION__ );
1182        hal_core_sleep();
1183    }
1184
1185    // get cluster size from boot record
1186    uint32_t nb_sectors = fatfs_get_record( BPB_SECPERCLUS , buffer );
1187    if ( nb_sectors != 8 )
1188    {
1189        printk("\n[PANIC] in %s : cluster size must be 8 sectors\n", __FUNCTION__ );
1190        hal_core_sleep();
1191    }
1192
1193    // get number of FAT copies from boot record
1194    uint32_t nb_fats = fatfs_get_record( BPB_NUMFATS , buffer );
1195    if ( nb_fats != 1 )
1196    {
1197        printk("\n[PANIC] in %s : number of FAT copies must be 1\n", __FUNCTION__ );
1198        hal_core_sleep();
1199    }
1200
1201    // get number of sectors in FAT from boot record
1202    uint32_t fat_sectors = fatfs_get_record( BPB_FAT32_FATSZ32 , buffer );
1203    if ( (fat_sectors & 0xF) != 0 )
1204    {
1205        printk("\n[PANIC] in %s : FAT size not multiple of 16 sectors\n", __FUNCTION__ );
1206        hal_core_sleep();
1207    }
1208
1209    // get root cluster from boot record
1210    uint32_t root_cluster = fatfs_get_record( BPB_FAT32_ROOTCLUS , buffer );
1211    if ( root_cluster != 2 ) 
1212    {
1213        printk("\n[PANIC] in %s : root cluster index must be 2\n", __FUNCTION__ );
1214        hal_core_sleep();
1215    }
1216
1217    // get FAT lba from boot record
1218    uint32_t fat_lba = fatfs_get_record( BPB_RSVDSECCNT , buffer );
1219
1220    // get FS_INFO sector lba from boot record
1221    uint32_t fs_info_lba = fatfs_get_record( BPB_FAT32_FSINFO , buffer );
1222
1223    // load the FS_INFO record from device
1224    error = dev_ioc_move_data( IOC_SYNC_READ , buffer_xp , fs_info_lba , 1 );
1225
1226    if ( error )
1227    {
1228        printk("\n[PANIC] in %s : cannot access FS_INFO record\n", __FUNCTION__ );
1229        hal_core_sleep();
1230    }
1231
1232    // get free_clusters number from FS_INFO record
1233    uint32_t free_clusters = fatfs_get_record( FS_FREE_CLUSTERS , buffer );
1234    if ( free_clusters >= fat_sectors << 7 )
1235    {
1236        printk("\n[PANIC] in %s : unconsistent free_clusters\n", __FUNCTION__ );
1237        hal_core_sleep();
1238    }
1239
1240    // get free_cluster_hint from FS_INFO record
1241    uint32_t free_cluster_hint = fatfs_get_record( FS_FREE_CLUSTER_HINT , buffer );
1242
1243    if ( free_cluster_hint >= fat_sectors << 7 )
1244    {
1245        printk("\n[PANIC] in %s : unconsistent free_cluster_hint\n", __FUNCTION__ );
1246        hal_core_sleep();
1247    }
1248
1249    // allocate a mapper for the FAT itself
1250    mapper_t * fat_mapper = mapper_create( FS_TYPE_FATFS );
1251    if ( fat_mapper == NULL )
1252    {
1253        printk("\n[PANIC] in %s : no memory for FAT mapper\n", __FUNCTION__ );
1254        hal_core_sleep();
1255    }
1256
1257    // the inode field is NULL for the FAT mapper
1258    fat_mapper->inode = NULL;
1259
1260    // initialize the FATFS context
1261    fatfs_ctx->fat_begin_lba         = fat_lba;
1262    fatfs_ctx->fat_sectors_count     = fat_sectors; 
1263    fatfs_ctx->bytes_per_sector      = sector_size;
1264    fatfs_ctx->sectors_per_cluster   = nb_sectors;
1265    fatfs_ctx->cluster_begin_lba     = fat_lba + fat_sectors;
1266    fatfs_ctx->root_dir_cluster      = 2;
1267    fatfs_ctx->fat_mapper_xp         = XPTR( local_cxy , fat_mapper );
1268    fatfs_ctx->fs_info_lba           = fs_info_lba;
1269    fatfs_ctx->free_clusters         = free_clusters;
1270    fatfs_ctx->free_cluster_hint     = free_cluster_hint;
1271    fatfs_ctx->fs_info_buffer        = buffer;
1272
1273    remote_rwlock_init( XPTR( local_cxy , &fatfs_ctx->lock ) , LOCK_FATFS_FAT );
1274
1275#if (DEBUG_FATFS_CTX_INIT & 0x1)
1276if( DEBUG_FATFS_CTX_INIT < cycle )
1277fatfs_ctx_display( fatfs_ctx );
1278#endif
1279
1280#if DEBUG_FATFS_CTX_INIT
1281cycle = (uint32_t)hal_get_cycles();
1282if( DEBUG_FATFS_CTX_INIT < cycle )
1283printk("\n[%s]  thread[%x,%x] exit for fatfs_ctx = %x / cycle %d\n",
1284__FUNCTION__, this->process->pid, this->trdid, fatfs_ctx, cycle );
1285#endif
1286
1287}  // end fatfs_ctx_init()
1288
1289/////////////////////////////////////////////////
1290void fatfs_ctx_destroy( fatfs_ctx_t * fatfs_ctx )
1291{
1292    kmem_req_t    req;
1293    req.type = KMEM_KCM;
1294    req.ptr  = fatfs_ctx;
1295    kmem_free( &req );
1296}
1297
1298///////////////////////////////////////////////
1299error_t fatfs_add_dentry( vfs_inode_t  * inode,
1300                          vfs_dentry_t * dentry )
1301{
1302    error_t       error;
1303    uint32_t      length;        // dentry name length
1304    uint32_t      nb_lfn;        // number or required LFN
1305    char          sfn[11];       // buffer for SFN name
1306    uint8_t       checksum;      // name checksum
1307    mapper_t    * mapper;        // loal pointer on parent inode mapper
1308    xptr_t        mapper_xp;     // extended pointer on parent inode mapper
1309    xptr_t        child_xp;      // extended pointer on child inode
1310    cxy_t         child_cxy;     // child inode cluster
1311    vfs_inode_t * child_ptr;     // child inode local pointer
1312    uint32_t      size;          // child inode size
1313    uint32_t      type;          // child inode type
1314    uint32_t      cluster;       // child inode cluster index
1315
1316#if DEBUG_FATFS_ADD_DENTRY
1317char       dir_name[CONFIG_VFS_MAX_NAME_LENGTH];
1318uint32_t   cycle = (uint32_t)hal_get_cycles();
1319thread_t * this  = CURRENT_THREAD;
1320vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
1321if( DEBUG_FATFS_ADD_DENTRY < cycle )
1322printk("\n[%s]  thread[%x,%x] enter / parent <%s> / child <%s> / cycle %d\n",
1323__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1324#endif
1325
1326// check arguments
1327assert( (inode != NULL) , "inode pointer is NULL\n" );
1328assert( (dentry != NULL) , "dentry pointer is NULL\n" );
1329assert( (inode->mapper != NULL ) , "mapper pointer is NULL\n" );
1330 
1331    // get pointers on directory mapper
1332    mapper    = inode->mapper;
1333    mapper_xp = XPTR( local_cxy , mapper );
1334
1335    // get extended pointers on remote child inode
1336    child_xp  = dentry->child_xp;
1337    child_cxy = GET_CXY( child_xp );
1338    child_ptr = GET_PTR( child_xp );
1339
1340    // get relevant infos from child inode
1341    type    =                     hal_remote_l32( XPTR( child_cxy , &child_ptr->type ) );
1342    size    =                     hal_remote_l32( XPTR( child_cxy , &child_ptr->size ) );
1343    cluster = (uint32_t)(intptr_t)hal_remote_lpt( XPTR( child_cxy , &child_ptr->extend ) );
1344
1345    // analyse dentry name
1346    error = fatfs_name_format( dentry->name,
1347                               &length,
1348                               &nb_lfn,
1349                               sfn,
1350                               &checksum );
1351    if ( error )
1352    {
1353        printk("\n[ERROR] in %s : dentry name > 31 bytes\n", __FUNCTION__ );
1354        return -1;
1355    }
1356                               
1357    // Search end of directory with two embedded loops:
1358    // - scan the pages in the mapper
1359    // - scan the entries in each page to find NO_MORE_ENTRY
1360
1361    xptr_t     page_xp;                 // extended pointer on page descriptor
1362    xptr_t     base_xp;                 // extended pointer on page base
1363    uint8_t  * base;                    // local pointer on page base (array of bytes)
1364    uint32_t   page_id = 0;             // page index in mapper
1365    uint32_t   offset  = 0;             // position in page
1366    uint32_t   found   = 0;             // NO_MORE_ENTRY found
1367
1368    // loop on pages in mapper
1369    while ( found == 0 )
1370    {
1371        // get extended pointer on page descriptor in mapper
1372        page_xp  = mapper_remote_get_page( mapper_xp , page_id );
1373
1374        if ( page_xp == XPTR_NULL )
1375        {
1376            printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ );
1377            return -1;
1378        }
1379       
1380        // get pointer on page base
1381        base_xp = ppm_page2base( page_xp );
1382        base = GET_PTR( base_xp );
1383
1384        // loop on directory entries in this page
1385        while ( (offset < 4096) && (found == 0) )
1386        {
1387            if ( fatfs_get_record( LDIR_ORD, (base + offset) ) == NO_MORE_ENTRY )
1388            {
1389                found = 1;
1390            } 
1391            else
1392            {
1393                offset = offset + 32;
1394            }
1395        }  // end loop on entries
1396
1397        if ( found == 0 )
1398        {
1399            page_id++;
1400            offset = 0;
1401        }
1402    }  // end loop on pages
1403
1404    // Modify the directory mapper: depending on the name length,
1405    // the new child requires to write (3, 4, or 5) directory entries.
1406    // To actually register the new child, we use a 5 steps FSM
1407    // (one state per entry to be written), that is traversed as:
1408    // LFN3 -> LFN2 -> LFN1 -> NORMAL -> NOMORE
1409    // At most two pages are modified:
1410    // - the page containing the NO_MORE_ENTRY is always modified
1411    // - the following page can be modified if the name spread on to pages.
1412
1413    char * name = dentry->name;
1414
1415    uint32_t step;          // FSM state
1416
1417    if      ( nb_lfn == 1 ) step = 3;
1418    else if ( nb_lfn == 2 ) step = 4;
1419    else if ( nb_lfn == 3 ) step = 5;
1420   
1421    uint8_t  * entry;       // pointer on directory entry to be written
1422    uint32_t   i;           // byte index in one 32 bytes directory
1423    uint32_t   c;           // character index in name
1424
1425    while ( step )   
1426    {
1427        // when the new child is split on two pages,
1428        // we need to access a new page in mapper
1429        if ( offset >= 4096 )
1430        {
1431            // copy the modified page to IOC device
1432            fatfs_move_page( page_xp , IOC_SYNC_WRITE );   
1433
1434            // get the next page in FAT mapper
1435            page_xp  = mapper_remote_get_page( mapper_xp , page_id + 1 );
1436
1437            if ( page_xp == XPTR_NULL )
1438            {
1439                printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ );
1440                return -1;
1441            }
1442       
1443            // get pointer on page base
1444            base_xp = ppm_page2base( page_xp );
1445            base = GET_PTR( base_xp );
1446           
1447            // update offset
1448            offset = 0;
1449        }
1450
1451        // compute directory entry address
1452        entry = base + offset;
1453
1454#if (DEBUG_FATFS_ADD_DENTRY & 1)
1455cycle = (uint32_t)hal_get_cycles();
1456if( DEBUG_FATFS_ADD_DENTRY < cycle )
1457printk("\n[%s] FSM step = %d / offset = %x / nb_lfn = %d / cycle %d\n",
1458__FUNCTION__, step, offset, nb_lfn, cycle );
1459#endif
1460
1461        // write 32 bytes (one directory entry) per iteration
1462        switch ( step )
1463        {
1464            case 5:   // write LFN3 entry
1465            {
1466                c = 26;
1467                // scan the 32 bytes in dir_entry
1468                for ( i = 0 ; i < 32 ; i++ )
1469                {
1470                    if (i == 0)
1471                    {
1472                        if ( nb_lfn == 3) entry[i] = 0x43;
1473                        else              entry[i] = 0x03;
1474                    }
1475                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1476                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1477                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1478                              ( c < length ) )
1479                    {
1480                                          entry[i] = name[c];
1481                                          c++;
1482                    }
1483                    else if (i == 11)     entry[i] = 0x0F;
1484                    else if (i == 13)     entry[i] = checksum;
1485                    else                  entry[i] = 0x00;
1486                }
1487                step--;
1488                break;
1489            }
1490            case 4:   // write LFN2 entry 
1491            {
1492                c = 13;
1493                // scan the 32 bytes in dir_entry
1494                for ( i = 0 ; i < 32 ; i++ )
1495                {
1496                    if (i == 0)
1497                    {
1498                        if ( nb_lfn == 2) entry[i] = 0x42;
1499                        else              entry[i] = 0x02;
1500                    }
1501                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1502                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1503                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1504                              ( c < length ) )
1505                    {
1506                                          entry[i] = name[c];
1507                                          c++;
1508                    }
1509                    else if (i == 11)     entry[i] = 0x0F;
1510                    else if (i == 13)     entry[i] = checksum;
1511                    else                  entry[i] = 0x00;
1512                }
1513                step--;
1514                break;
1515            }
1516            case 3:   // Write LFN1 entry   
1517            {
1518                c = 0;
1519                // scan the 32 bytes in dir_entry
1520                for ( i = 0 ; i < 32 ; i++ )
1521                {
1522                    if (i == 0)
1523                    {
1524                        if ( nb_lfn == 1) entry[i] = 0x41;
1525                        else              entry[i] = 0x01;
1526                    }
1527                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1528                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1529                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1530                              ( c < length ) )
1531                    {
1532                                          entry[i] = name[c];
1533                                          c++;
1534                    }
1535                    else if (i == 11)     entry[i] = 0x0F;
1536                    else if (i == 13)     entry[i] = checksum;
1537                    else                  entry[i] = 0x00;
1538                }
1539                step--;
1540                break;
1541            }
1542            case 2:   // write NORMAL entry     
1543            {
1544                // scan the 32 bytes in dir_entry
1545                for ( i = 0 ; i < 32 ; i++ )
1546                {
1547                    if      ( i < 11 )                              // 8.3 SFN
1548                    {
1549                                          entry[i] = sfn[i];
1550                    }
1551                    else if (i == 11)                               // ATTR
1552                    {
1553                        if (type == INODE_TYPE_DIR)  entry[i] = 0x10;
1554                        else                         entry[i] = 0x20;
1555                    }
1556                    else if (i == 20)     entry[i] = cluster>>16;   // cluster.B2
1557                    else if (i == 21)     entry[i] = cluster>>24;   // cluster.B3
1558                    else if (i == 26)     entry[i] = cluster>>0;    // cluster.B0
1559                    else if (i == 27)     entry[i] = cluster>>8;    // cluster.B1
1560                    else if (i == 28)     entry[i] = size>>0;       // size.B0
1561                    else if (i == 29)     entry[i] = size>>8;       // size.B1
1562                    else if (i == 30)     entry[i] = size>>16;      // size.B2
1563                    else if (i == 31)     entry[i] = size>>24;      // size.B3
1564                    else                  entry[i] = 0x00;
1565                }
1566
1567                // update the "extend" field in dentry descriptor
1568                dentry->extend = (void*)(intptr_t)(((page_id<<12) + offset)>>5);
1569
1570                step--;
1571                break;
1572            }
1573            case 1:   // write NOMORE entry 
1574            {
1575                entry [0] = 0x00;
1576                step--;
1577                break;
1578            }
1579        } // end switch step
1580
1581        offset += 32;
1582
1583    } // exit while     
1584
1585#if (DEBUG_FATFS_ADD_DENTRY & 1)
1586cycle = (uint32_t)hal_get_cycles();
1587if( DEBUG_FATFS_ADD_DENTRY < cycle )
1588printk("\n[%s]  thread[%x,%x] before IOC access / cycle %d\n",
1589__FUNCTION__, this->process->pid, this->trdid, cycle );
1590#endif
1591
1592    // copy the modified page to the IOC device
1593    fatfs_move_page( page_xp , IOC_SYNC_WRITE );   
1594
1595#if DEBUG_FATFS_ADD_DENTRY
1596cycle = (uint32_t)hal_get_cycles();
1597if( DEBUG_FATFS_ADD_DENTRY < cycle )
1598printk("\n[%s]  thread[%x,%x] exit / parent <%s> / child <%s> / cycle %d\n",
1599__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1600#endif
1601
1602    return 0;
1603
1604}  // end fatfs_add_dentry()
1605
1606//////////////////////////////////////////////////
1607error_t fatfs_remove_dentry( vfs_inode_t  * inode,
1608                             vfs_dentry_t * dentry )
1609{
1610    xptr_t     mapper_xp;  // extended pointer on mapper
1611    mapper_t * mapper;     // local pointer on mapper
1612    xptr_t     page_xp;    // extended pointer on mapper page descriptor
1613    xptr_t     base_xp;    // extended pointer on mapper page base
1614    uint8_t  * base;       // local pointer on mapper page base
1615
1616#if DEBUG_FATFS_REMOVE_DENTRY
1617char       dir_name[CONFIG_VFS_MAX_NAME_LENGTH];
1618uint32_t   cycle = (uint32_t)hal_get_cycles();
1619thread_t * this  = CURRENT_THREAD;
1620vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
1621if( DEBUG_FATFS_REMOVE_DENTRY < cycle )
1622printk("\n[%s] thread[%x,%x] enter / parent <%s> / child <%s> / cycle %d\n",
1623__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1624#endif
1625
1626// check arguments
1627assert( (inode != NULL) , "inode pointer is NULL\n" );
1628assert( (dentry != NULL) , "dentry pointer is NULL\n" );
1629assert( (inode->type == INODE_TYPE_DIR) , "inode is not a directory\n" );
1630assert( (inode->mapper != NULL ) , "mapper pointer is NULL\n" );
1631
1632    // get pointers on directory mapper
1633    mapper    = inode->mapper;
1634    mapper_xp = XPTR( local_cxy , mapper );
1635
1636    // compute number of LFN entries
1637    uint32_t nb_lfn;
1638    uint32_t name_length = strlen( dentry->name );
1639
1640    if      ( name_length <= 13 ) nb_lfn  = 1;
1641    else if ( name_length <= 26 ) nb_lfn  = 2;
1642    else                          nb_lfn  = 3;
1643
1644    // we must invalidate (2, 3 or 4) 32 bytes entries:
1645    // the NORMAL entry (registered in dentry->extend) and all preceding LFN entries
1646    // At most two pages are modified:
1647    // - the page containing the NORMAL entry is always modified.
1648    // - the preceding page is modified when the name spread on two pages.
1649
1650    // get 32 bytes directory entry index from dentry->extend
1651    uint32_t  dentry_id  = (uint32_t)(intptr_t)dentry->extend; 
1652
1653    // get page index and offset in parent directory mapper
1654    uint32_t  page_id    = dentry_id >> 7;
1655    uint32_t  offset     = (dentry_id & 0x7F)<<5;
1656
1657#if DEBUG_FATFS_REMOVE_DENTRY & 1
1658if( DEBUG_FATFS_REMOVE_DENTRY < cycle )
1659printk("\n[%s] dentry_id %x / page_id %x / offset %x\n",
1660__FUNCTION__, dentry_id, page_id, offset );
1661#endif
1662
1663    // get extended pointer on page descriptor from parent directory mapper
1664    page_xp  = mapper_remote_get_page( mapper_xp , page_id );
1665
1666    if ( page_xp == XPTR_NULL )
1667    {
1668        printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ );
1669        return -1;
1670    }
1671       
1672    // get pointers on page base
1673    base_xp = ppm_page2base( page_xp );
1674    base    = GET_PTR( base_xp );
1675
1676    // invalidate NORMAL entry in directory cache
1677    base[offset] = 0xE5;
1678
1679    // invalidate LFN entries
1680    while ( nb_lfn )
1681    {
1682        if (offset == 0)  // we must load page (page_id - 1)
1683        {
1684
1685// check page_id
1686assert( (page_id > 0), "page_id and offset cannot be both 0\n" );
1687
1688            // copy the modified page to the IOC device
1689            fatfs_move_page( page_xp , IOC_SYNC_WRITE );   
1690
1691            // get extended pointer on page descriptor from parent directory mapper
1692            page_xp  = mapper_remote_get_page( mapper_xp , page_id );
1693
1694            if ( page_xp == XPTR_NULL )
1695            {
1696                printk("\n[ERROR] in %s : cannot access directory mapper\n", __FUNCTION__ );
1697                return -1;
1698            }
1699       
1700            // get pointers on page base
1701            base_xp = ppm_page2base( page_xp );
1702            base    = GET_PTR( base_xp );
1703
1704            // update offset
1705            offset = 4096;
1706        }
1707
1708        offset = offset - 32;
1709
1710// check for LFN entry
1711assert( (fatfs_get_record( DIR_ATTR, base + offset ) == ATTR_LONG_NAME_MASK ),
1712"this directory entry must be a LFN\n");
1713
1714        // invalidate LFN entry
1715        base[offset] = 0xE5;
1716
1717        nb_lfn--;
1718    }     
1719
1720    // copy the modified page to the IOC device
1721    fatfs_move_page( page_xp , IOC_SYNC_WRITE );   
1722   
1723
1724#if DEBUG_FATFS_REMOVE_DENTRY
1725cycle = (uint32_t)hal_get_cycles();
1726if( DEBUG_FATFS_REMOVE_DENTRY < cycle )
1727printk("\n[%s] thread[%x,%x] exit / parent %s / child %s / cycle %d\n",
1728__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1729#endif
1730
1731    return 0;
1732
1733}  // end fatfs_remove_dentry
1734
1735
1736//////////////////////////////////////////////////////////////////////////////////////////////
1737// This static function scan the pages of a mapper containing a FAT32 directory, identified
1738// by the <mapper> argument, to find the directory entry identified by the <name> argument,
1739// and return a pointer on the directory entry, described as and array of 32 bytes, and the
1740// index of this entry in the FAT32 mapper, seen as an array of 32 bytes entries.
1741// It is called by the fatfs_new_dentry() and fatfs_update_dentry() functions.
1742// It must be called by a thread running in the cluster containing the mapper.
1743//////////////////////////////////////////////////////////////////////////////////////////////
1744// @ mapper    : [in]  local pointer on directory mapper.
1745// @ name      : [in]  searched directory entry name.
1746// @ entry     : [out] buffer for the pointer on the 32 bytes directory entry (when found).
1747// @ index     : [out] buffer for the directory entry index in mapper.
1748// @ return 0 if found / return 1 if not found / return -1 if mapper access error.
1749//////////////////////////////////////////////////////////////////////////////////////////////
1750static error_t fatfs_scan_directory( mapper_t *  mapper,
1751                                     char     *  name,
1752                                     uint8_t  ** entry,
1753                                     uint32_t *  index )
1754{
1755    // Two embedded loops to scan the directory mapper:
1756    // - scan the parent directory mapper pages
1757    // - scan the directory entries in each 4 Kbytes page
1758
1759// check parent_inode and child_inode
1760assert( (mapper != NULL) , "mapper pointer is NULL\n" );
1761assert( (name   != NULL ), "child name is undefined\n" );
1762assert( (entry  != NULL ), "entry buffer undefined\n" );
1763
1764#if DEBUG_FATFS_SCAN_DIRECTORY
1765char       parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
1766uint32_t   cycle = (uint32_t)hal_get_cycles();
1767thread_t * this  = CURRENT_THREAD;
1768vfs_inode_get_name( XPTR( local_cxy , mapper->inode ) , parent_name );
1769if( DEBUG_FATFS_SCAN_DIRECTORY < cycle )
1770printk("\n[%s]  thread[%x,%x] enter to search child <%s> in parent <%s> / cycle %d\n",
1771__FUNCTION__, this->process->pid, this->trdid, name , parent_name , cycle );
1772#endif
1773
1774    char       cname[CONFIG_VFS_MAX_NAME_LENGTH];  // name extracted from directory entry
1775
1776    char       lfn1[16];         // buffer for one partial cname
1777    char       lfn2[16];         // buffer for one partial cname
1778    char       lfn3[16];         // buffer for one partial cname
1779    xptr_t     mapper_xp;        // extended pointer on mapper descriptor
1780    xptr_t     page_xp;          // extended pointer on page descriptor
1781    xptr_t     base_xp;          // extended pointer on page base
1782    uint8_t  * base;             // local pointer on page base
1783    uint8_t    attr;             // directory entry ATTR field
1784    uint8_t    ord;              // directory entry ORD field
1785    uint32_t   seq;              // sequence index
1786    uint32_t   lfn       = 0;    // LFN entries number
1787    int32_t    found     = 0;    // not yet = 0 / success = 1 / not found = 2 / error = -1
1788    uint32_t   page_id   = 0;    // page index in mapper
1789    uint32_t   offset    = 0;    // byte offset in page
1790
1791    mapper_xp = XPTR( local_cxy , mapper );
1792
1793    // scan the mapper pages
1794    while ( found == 0 )
1795    {
1796        // get one page
1797        page_xp = mapper_remote_get_page( mapper_xp , page_id );
1798
1799        if( page_xp == XPTR_NULL)
1800        {
1801            found = -1;
1802        }
1803
1804        // get page base
1805        base_xp = ppm_page2base( page_xp );
1806        base    = (uint8_t *)GET_PTR( base_xp );
1807
1808#if (DEBUG_FATFS_SCAN_DIRECTORY & 0x1)
1809if( DEBUG_FATFS_SCAN_DIRECTORY < cycle )
1810mapper_display_page( mapper_xp , page_xp , 256 );
1811#endif
1812        // scan this page until end of directory, end of page, or name found
1813        while( (offset < 4096) && (found == 0) )
1814        {
1815            attr = fatfs_get_record( DIR_ATTR , base + offset );   
1816            ord  = fatfs_get_record( LDIR_ORD , base + offset );   
1817
1818            if (ord == NO_MORE_ENTRY)                 // no more entry => break
1819            {
1820                found = 2;
1821            }
1822            else if ( ord == FREE_ENTRY )             // free entry => skip
1823            {
1824                offset = offset + 32;
1825            }
1826            else if ( attr == 0x28 )                  // volune_id => skip
1827            {
1828                offset = offset + 32;
1829            }
1830            else if ( attr == ATTR_LONG_NAME_MASK )   // LFN entry => get partial cname
1831            {
1832                seq = ord & 0x3;
1833                lfn = (seq > lfn) ? seq : lfn;   
1834                if      ( seq == 1 ) fatfs_get_name_from_long( base + offset, lfn1 );
1835                else if ( seq == 2 ) fatfs_get_name_from_long( base + offset, lfn2 );
1836                else if ( seq == 3 ) fatfs_get_name_from_long( base + offset, lfn3 );
1837                offset = offset + 32;
1838            }
1839            else                                 // NORMAL entry
1840            {
1841                // build the extracted name
1842                if      ( lfn == 0 )
1843                {
1844                    fatfs_get_name_from_short( base + offset , cname );
1845                }
1846                else if ( lfn == 1 )
1847                {
1848                    strcpy( cname      , lfn1 );
1849                }   
1850                else if ( lfn == 2 ) 
1851                {
1852                    strcpy( cname      , lfn1 );
1853                    strcpy( cname + 13 , lfn2 );
1854                }
1855                else if ( lfn == 3 ) 
1856                {
1857                    strcpy( cname      , lfn1 );
1858                    strcpy( cname + 13 , lfn2 );
1859                    strcpy( cname + 26 , lfn3 );
1860                }
1861
1862                // get dentry arguments if extracted cname == searched name
1863                if ( strcmp( name , cname ) == 0 )
1864                {
1865                    *entry = base + offset;
1866                    *index = ((page_id<<12) + offset)>>5; 
1867                    found     = 1;
1868                }
1869                offset = offset + 32;
1870                lfn    = 0;
1871            }
1872        }  // end loop on directory entries in page
1873
1874        page_id++;
1875        offset = 0;
1876
1877    }  // end loop on pages
1878
1879    if( found == 1 )
1880    {
1881
1882#if DEBUG_FATFS_SCAN_DIRECTORY
1883cycle = (uint32_t)hal_get_cycles();
1884if( DEBUG_FATFS_SCAN_DIRECTORY < cycle )
1885printk("\n[%s]  thread[%x,%x] exit / found child <%s> in <%s>\n",
1886__FUNCTION__, this->process->pid, this->trdid, name, parent_name );
1887#endif
1888        return 0;
1889    }
1890    else if( found == 2 )
1891    {
1892
1893#if DEBUG_FATFS_SCAN_DIRECTORY
1894cycle = (uint32_t)hal_get_cycles();
1895if( DEBUG_FATFS_SCAN_DIRECTORY < cycle )
1896printk("\n[%s]  thread[%x,%x] exit / child <%s> in <%s> not found\n",
1897__FUNCTION__, this->process->pid, this->trdid, name, parent_name );
1898#endif
1899        return 1;
1900    }
1901    else
1902    {
1903        printk("\n[ERROR] in %s : cannot get page %d from mapper\n",
1904        __FUNCTION__, page_id );
1905
1906        return -1;
1907    }
1908}  // end fatfs_scan_directory()
1909
1910
1911
1912/////////////////////////////////////////////////////
1913error_t fatfs_new_dentry( vfs_inode_t * parent_inode,
1914                          char        * name,
1915                          xptr_t        child_inode_xp )
1916{
1917    uint8_t      * entry;            // pointer on FAT32 directory entry (array of 32 bytes)
1918    uint32_t       index;            // index of FAT32 directory entry in mapper
1919    mapper_t     * mapper;           // pointer on directory mapper
1920    uint32_t       cluster;          // directory entry cluster
1921    uint32_t       size;             // directory entry size
1922    bool_t         is_dir;           // directory entry type (file/dir)
1923    xptr_t         root_xp;          // extended pointer on root of parent dentries
1924    xptr_t         iter_xp;          // iterator for this list
1925    cxy_t          child_inode_cxy;  // child inode cluster 
1926    vfs_inode_t  * child_inode_ptr;  // child inode local pointer
1927    xptr_t         dentry_xp;        // extended pointer on searched dentry descriptor
1928    cxy_t          dentry_cxy;       // cluster identifier of dentry (must be local_cxy)
1929    vfs_dentry_t * dentry_ptr;       // local pointer
1930    error_t        error;
1931
1932    char           parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
1933
1934// check arguments
1935assert( (parent_inode   != NULL)       , "parent_inode is NULL\n" );
1936assert( (name           != NULL)       , "name is NULL\n" );
1937assert( (child_inode_xp != XPTR_NULL ) , "child_inode is NULL\n" );
1938
1939    // get child inode cluster and local pointer
1940    child_inode_cxy = GET_CXY( child_inode_xp );
1941    child_inode_ptr = GET_PTR( child_inode_xp );
1942
1943    // build extended pointer on root of list of parent dentries
1944    root_xp = XPTR( child_inode_cxy , &child_inode_ptr->parents );
1945
1946// check child inode has at least one parent
1947assert( (xlist_is_empty( root_xp ) == false ), "child inode must have one parent\n");
1948
1949#if DEBUG_FATFS_NEW_DENTRY
1950uint32_t   cycle = (uint32_t)hal_get_cycles();
1951thread_t * this  = CURRENT_THREAD;
1952vfs_inode_get_name( XPTR( local_cxy , parent_inode ) , parent_name );
1953if( DEBUG_FATFS_NEW_DENTRY < cycle )
1954printk("\n[%s]  thread[%x,%x] enter for child <%s> in parent <%s> / cycle %d\n",
1955__FUNCTION__, this->process->pid, this->trdid, name , parent_name , cycle );
1956#endif
1957
1958    // get local pointer on parent mapper
1959    mapper = parent_inode->mapper;
1960
1961    // get pointer and index in mapper for searched directory entry
1962    error  = fatfs_scan_directory( mapper, name , &entry , &index );
1963
1964    // return non fatal error if not found
1965    if( error )
1966    {
1967        vfs_inode_get_name( XPTR( local_cxy , parent_inode ) , parent_name );
1968        printk("\n[ERROR] in %s : cannot find <%s> entry in <%s> directory mapper\n",
1969        __FUNCTION__, name , parent_name, name );
1970        return -1;
1971    }
1972 
1973
1974    // get relevant infos from FAT32 directory entry
1975    cluster = (fatfs_get_record( DIR_FST_CLUS_HI , entry ) << 16) |
1976              (fatfs_get_record( DIR_FST_CLUS_LO , entry )      ) ;
1977    is_dir  = (fatfs_get_record( DIR_ATTR        , entry ) & ATTR_DIRECTORY);
1978    size    =  fatfs_get_record( DIR_FILE_SIZE   , entry );
1979
1980    // scan list of parent dentries to search the parent_inode
1981    bool_t found = false;
1982    XLIST_FOREACH( root_xp , iter_xp )
1983    {
1984        // get pointers on dentry
1985        dentry_xp  = XLIST_ELEMENT( iter_xp , vfs_dentry_t , parents );
1986        dentry_cxy = GET_CXY( dentry_xp );
1987        dentry_ptr = GET_PTR( dentry_xp );
1988
1989        // get local pointer on current parent directory inode
1990        vfs_inode_t * current = hal_remote_lpt( XPTR( dentry_cxy , &dentry_ptr->parent ) );
1991
1992        // check if current parent is the searched parent
1993        if( XPTR( dentry_cxy , current ) == XPTR( local_cxy , parent_inode ) )
1994        {
1995            found = true;
1996            break;
1997        }
1998    }
1999
2000    if( found == false )
2001    { 
2002        vfs_inode_get_name( XPTR( local_cxy , parent_inode ) , parent_name );
2003        printk("\n[ERROR] in %s : cannot find <%s> directory in list of parents for <%s>\n",
2004        __FUNCTION__, parent_name, name );
2005        return -1;
2006    }
2007
2008    // update the child inode "type", "size", and "extend" fields
2009    vfs_inode_type_t type = (is_dir) ? INODE_TYPE_DIR : INODE_TYPE_FILE;
2010
2011    hal_remote_s32( XPTR( child_inode_cxy , &child_inode_ptr->type   ) , type );
2012    hal_remote_s32( XPTR( child_inode_cxy , &child_inode_ptr->size   ) , size );
2013    hal_remote_s32( XPTR( child_inode_cxy , &child_inode_ptr->extend ) , cluster );
2014
2015    // update the dentry "extend" field
2016    dentry_ptr->extend = (void *)(intptr_t)index;
2017
2018#if DEBUG_FATFS_NEW_DENTRY
2019cycle = (uint32_t)hal_get_cycles();
2020if( DEBUG_FATFS_NEW_DENTRY < cycle )
2021printk("\n[%s]  thread[%x,%x] exit for <%s> in <%s> / cluster_id %x / size %d  / cycle %d\n",
2022__FUNCTION__, this->process->pid, this->trdid, name, parent_name, cluster, size,  cycle );
2023#endif
2024
2025
2026#if (DEBUG_FATFS_NEW_DENTRY & 1)
2027if( DEBUG_FATFS_NEW_DENTRY < cycle )
2028{
2029    fatfs_display_fat( 0 , 0 , 64 );
2030    fatfs_display_fat( cluster >> 10 ,  (cluster & 0x3FF) , 32 );
2031}
2032#endif
2033
2034    return 0;
2035
2036}  // end fatfs_new_dentry()
2037
2038//////////////////////////////////////////////////
2039error_t fatfs_update_dentry( vfs_inode_t  * inode,
2040                             vfs_dentry_t * dentry,
2041                             uint32_t       size )
2042{
2043    uint8_t  * entry;    // pointer on FAT32 directory entry (array of 32 bytes)
2044    uint32_t   index;    // index of FAT32 directory entry in mapper
2045    mapper_t * mapper;   // pointer on directory mapper
2046    error_t    error;
2047
2048    char       dir_name[CONFIG_VFS_MAX_NAME_LENGTH];
2049
2050// check arguments
2051assert( (inode  != NULL) , "inode is NULL\n" );
2052assert( (dentry != NULL) , "dentry is NULL\n" );
2053
2054#if DEBUG_FATFS_UPDATE_DENTRY
2055uint32_t   cycle = (uint32_t)hal_get_cycles();
2056thread_t * this  = CURRENT_THREAD;
2057vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
2058if( DEBUG_FATFS_UPDATE_DENTRY < cycle )
2059printk("\n[%s]  thread[%x,%x] enter for <%s/%s> / size %d / cycle %d\n",
2060__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, size, cycle );
2061#endif
2062
2063    // get local pointer on mapper
2064    mapper = inode->mapper;
2065
2066    // get pointer and index in mapper for searched directory entry
2067    error  = fatfs_scan_directory( mapper, dentry->name , &entry , &index );
2068
2069    if( error )
2070    { 
2071        vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
2072        printk("\n[ERROR] in %s : cannot find <%s> in parent mapper <%s>\n",
2073        __FUNCTION__, dentry->name, dir_name );
2074        return -1;
2075    }
2076
2077    // get current size value
2078    uint32_t current_size = fatfs_get_record( DIR_FILE_SIZE , entry );
2079
2080    // update dentry in mapper & device only if required
2081    if( size != current_size )
2082    {
2083        // set size field in FAT32 directory entry
2084        fatfs_set_record( DIR_FILE_SIZE , entry , size );
2085
2086        // get pointer on modified page base
2087        void * base = (void *)((intptr_t)entry & (~CONFIG_PPM_PAGE_MASK)); 
2088
2089        // get extended pointer on modified page descriptor
2090        xptr_t page_xp = ppm_base2page( XPTR( local_cxy , base ) );
2091
2092        // synchronously update the modified page on device
2093        error = fatfs_move_page( page_xp , IOC_SYNC_WRITE );
2094
2095        if( error )
2096        { 
2097            vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
2098            printk("\n[ERROR] in %s : cannot update parent directory <%s> on device\n",
2099            __FUNCTION__, dir_name );
2100            return -1;
2101        }
2102    }
2103
2104#if DEBUG_FATFS_UPDATE_DENTRY
2105cycle = (uint32_t)hal_get_cycles();
2106if( DEBUG_FATFS_UPDATE_DENTRY < cycle )
2107printk("\n[%s]  thread[%x,%x] exit / updated size for <%s/%s> / cycle %d\n",
2108__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
2109#endif
2110
2111    return 0;
2112
2113}  // end fatfs_update_dentry()
2114
2115///////////////////////////////////////////////////////
2116error_t fatfs_get_user_dir( struct vfs_inode_s * inode,
2117                            struct dirent      * array, 
2118                            uint32_t             max_dirent,
2119                            uint32_t             min_dentry,
2120                            bool_t               detailed,
2121                            uint32_t           * entries,
2122                            bool_t             * done )
2123{
2124    // Two embedded loops to scan the directory mapper:
2125    // - scan the parent directory mapper pages starting always from page 0
2126    // - scan the 32 bytes NORMAL/LFN directory entries in each page
2127    // Only valid dentries are copied : dentry_id >= min_dentry && dirent_id < dirent_max
2128
2129#if DEBUG_FATFS_GET_USER_DIR
2130char       inode_name[CONFIG_VFS_MAX_NAME_LENGTH];
2131uint32_t   cycle = (uint32_t)hal_get_cycles();
2132thread_t * this  = CURRENT_THREAD;
2133vfs_inode_get_name( XPTR( local_cxy , inode ) , inode_name );
2134if( DEBUG_FATFS_GET_USER_DIR < cycle )
2135printk("\n[%s]  thread[%x,%x] enter for inode <%s> / cycle %d\n",
2136__FUNCTION__, this->process->pid, this->trdid, inode_name , cycle );
2137#endif
2138
2139    mapper_t * mapper    = inode->mapper;
2140    xptr_t     mapper_xp = XPTR( local_cxy , mapper );
2141
2142// check mapper pointer
2143assert( (mapper != NULL) , "mapper is NULL\n");
2144   
2145// TODO handle the detailed flag
2146assert( (detailed == false), "detailed argument not supported/n");
2147
2148    char       cname[CONFIG_VFS_MAX_NAME_LENGTH];  // name extracted from each dentry
2149
2150    char       lfn1[16];           // buffer for one partial cname
2151    char       lfn2[16];           // buffer for one partial cname
2152    char       lfn3[16];           // buffer for one partial cname
2153    xptr_t     page_xp;            // extended pointer on page descriptor
2154    xptr_t     base_xp;            // extended pointer on page base
2155    uint8_t  * base;               // local pointer on page base
2156    uint8_t    attr;               // directory entry ATTR field
2157    uint8_t    ord;                // directory entry ORD field
2158    uint32_t   seq;                // sequence index
2159    uint32_t   lfn       = 0;      // LFN entries number
2160    uint32_t   offset    = 0;      // byte offset in page
2161    uint32_t   page_id   = 0;      // page index in mapper
2162    uint32_t   dentry_id = 0;      // valid (i.e. copied) dentry index in mapper
2163    uint32_t   dirent_id = 0;      // slot index in dirent array to initialize
2164    bool_t     end       = false;  // true if end of directory found
2165
2166    // loop on mapper pages
2167    while ( (end == false) && (dirent_id < max_dirent) )
2168    {
2169        // get one page from mapper
2170        page_xp = mapper_remote_get_page( mapper_xp , page_id );
2171
2172        if( page_xp == XPTR_NULL) return -1;
2173
2174        // get page base
2175        base_xp = ppm_page2base( page_xp );
2176        base    = (uint8_t *)GET_PTR( base_xp );
2177
2178#if (DEBUG_FATFS_GET_USER_DIR & 0x1)
2179if( DEBUG_FATFS_GET_USER_DIR < cycle )
2180mapper_display_page( mapper_xp , page_id , 256 );
2181#endif
2182        // loop on NORMAL/LFN (32 bytes) directory entries in this page
2183        while( (end == false) && (offset < 4096) )
2184        {
2185            // compute condition to copy one dentry to dirent array
2186            bool_t valid = (dentry_id >= min_dentry) && (dirent_id <  max_dirent );
2187
2188            attr = fatfs_get_record( DIR_ATTR , base + offset );   
2189            ord  = fatfs_get_record( LDIR_ORD , base + offset );   
2190
2191            if (ord == NO_MORE_ENTRY)                 // no more entry => break
2192            {
2193                end = true;
2194            }
2195            else if ( ord == FREE_ENTRY )             // free entry => skip
2196            {
2197                offset = offset + 32;
2198            }
2199            else if ( attr == 0x28 )                  // volune_id => skip
2200            {
2201                offset = offset + 32;
2202            }
2203            else if ( attr == ATTR_LONG_NAME_MASK )   // LFN entry
2204            {
2205                if( valid )
2206                {
2207                    // get partial cname
2208                    seq = ord & 0x3;
2209                    lfn = (seq > lfn) ? seq : lfn;   
2210                    if      ( seq == 1 ) fatfs_get_name_from_long( base + offset, lfn1 );
2211                    else if ( seq == 2 ) fatfs_get_name_from_long( base + offset, lfn2 );
2212                    else if ( seq == 3 ) fatfs_get_name_from_long( base + offset, lfn3 );
2213                }
2214                offset = offset + 32;
2215            }
2216            else                                     // NORMAL entry
2217            {
2218                // increment dentry_id
2219                dentry_id++;
2220
2221                if( valid )
2222                {
2223                    // build the complete cname
2224                    if      ( lfn == 0 )
2225                    {
2226                        fatfs_get_name_from_short( base + offset , cname );
2227                    }
2228                    else if ( lfn == 1 )
2229                    {
2230                        strcpy( cname      , lfn1 );
2231                    }   
2232                    else if ( lfn == 2 ) 
2233                    {
2234                        strcpy( cname      , lfn1 );
2235                        strcpy( cname + 13 , lfn2 );
2236                    }
2237                    else if ( lfn == 3 ) 
2238                    {
2239                        strcpy( cname      , lfn1 );
2240                        strcpy( cname + 13 , lfn2 );
2241                        strcpy( cname + 26 , lfn3 );
2242                    }
2243                   
2244                    // copy cname into dirent array
2245                    strcpy( array[dirent_id].d_name , cname ); 
2246
2247                    // increment dirent_id
2248                    dirent_id++;
2249                }
2250                offset = offset + 32;
2251                lfn    = 0;
2252            }
2253        }  // end loop on directory entries in page
2254
2255        page_id++;
2256        offset = 0;
2257
2258    }  // end loop on pages
2259
2260    // return result of scan
2261    *done    = end;
2262    *entries = dirent_id;
2263
2264#if DEBUG_FATFS_GET_USER_DIR
2265cycle = (uint32_t)hal_get_cycles();
2266if( DEBUG_FATFS_GET_USER_DIR < cycle )
2267printk("\n[%s]  thread[%x,%x] exit for inode <%s> / %d entries / cycle %d\n",
2268__FUNCTION__, this->process->pid, this->trdid, inode_name, dirent_id, cycle );
2269#endif
2270
2271    return 0;
2272
2273}  // end fatfs_get_user_dir()
2274
2275///////////////////////////////////////////////
2276error_t fatfs_sync_inode( vfs_inode_t * inode )
2277{
2278
2279// check inode pointer and cluster index
2280assert( (inode != NULL)                  , "inode pointer undefined\n" );
2281assert( (inode->mapper != NULL )         , "mapper pointer undefined\n" );
2282assert( (inode->type == INODE_TYPE_FILE) , "inode must be a file\n" );     
2283
2284#if DEBUG_FATFS_SYNC_INODE
2285char       name[CONFIG_VFS_MAX_NAME_LENGTH];
2286uint32_t   cycle = (uint32_t)hal_get_cycles();
2287thread_t * this  = CURRENT_THREAD;
2288vfs_inode_get_name( XPTR( local_cxy , inode ) , name );
2289if( DEBUG_FATFS_SYNC_INODE < cycle )
2290printk("\n[%s] thread[%x,%x] enter for <%s> / cycle %d\n",
2291__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
2292#endif
2293
2294    error_t    error;
2295    mapper_t * mapper;
2296    page_t   * page;
2297    uint32_t   page_id;
2298
2299    // get mapper from inode
2300    mapper = inode->mapper;
2301
2302    // compute max number of pages in mapper from file size
2303    uint32_t size  = inode->size;
2304    uint32_t pages = size >> CONFIG_PPM_PAGE_SHIFT;
2305    if( size & CONFIG_PPM_PAGE_MASK ) pages++; 
2306         
2307    // get pointer on mapper radix tree
2308    grdxt_t * rt = &mapper->rt;
2309
2310    // scan all pages
2311    for( page_id = 0 ; page_id < pages ; page_id++ )
2312    {
2313        // get page descriptor from mapper
2314        page = grdxt_lookup( rt , page_id );
2315
2316        // check all existing pages
2317        if ( page != NULL )
2318        {
2319            if ( page->flags & PG_DIRTY )
2320            {
2321
2322#if (DEBUG_FATFS_SYNC_INODE & 1)
2323if( DEBUG_FATFS_SYNC_INODE < cycle )
2324printk("\n[%s] thread[%x,%x] synchronizes page %d from <%s> mapper to IOC device\n",
2325__FUNCTION__, page_id, name );
2326#endif
2327                // build extended pointer on page descriptor
2328                xptr_t page_xp = XPTR( local_cxy , page );
2329
2330                // move page from mapper to device
2331                error = fatfs_move_page( page_xp , IOC_WRITE );
2332
2333                if ( error )  return -1;
2334
2335                // reset page dirty flag
2336                ppm_page_undo_dirty( page_xp );
2337            }
2338        }
2339    }  // end loop on pages
2340
2341#if DEBUG_FATFS_SYNC_INODE
2342cycle = (uint32_t)hal_get_cycles();
2343if( DEBUG_FATFS_SYNC_INODE < cycle )
2344printk("\n[%s] thread[%x,%x] exit for <%s> / cycle %d\n",
2345__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
2346#endif
2347
2348    return 0;
2349
2350}  // end fatfs_sync_inode()
2351
2352
2353
2354
2355
2356
2357//////////////////////////////
2358error_t fatfs_sync_fat( void )
2359{
2360
2361#if DEBUG_FATFS_SYNC_FAT
2362uint32_t   cycle = (uint32_t)hal_get_cycles();
2363thread_t * this  = CURRENT_THREAD;
2364if( DEBUG_FATFS_SYNC_FAT < cycle )
2365printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
2366__FUNCTION__ , this->process->pid, this->trdid, cycle );
2367#endif
2368
2369    uint32_t   page_id;
2370    error_t    error;
2371
2372    // get FAT mapper pointers an cluster
2373    fatfs_ctx_t * fatfs_ctx  = fs_context[FS_TYPE_FATFS].extend;
2374    xptr_t        mapper_xp  = fatfs_ctx->fat_mapper_xp;
2375    cxy_t         mapper_cxy = GET_CXY( mapper_xp );
2376    mapper_t    * mapper_ptr = GET_PTR( mapper_xp );
2377
2378    // compute max number of 4 Kbytes pages in FAT mapper
2379    // TODO : this could be improved (see fatfs.h) [AG]
2380    uint32_t   pages = fatfs_ctx->fat_sectors_count >> 3;
2381         
2382    // get pointers on remote FAT mapper radix tree
2383    grdxt_t  * rt_ptr = &mapper_ptr->rt;
2384    xptr_t     rt_xp  = XPTR( mapper_cxy , rt_ptr );
2385
2386    // scan all pages
2387    for( page_id = 0 ; page_id < pages ; page_id++ )
2388    {
2389        // get extended pointer on page descriptor from FAT mapper
2390        xptr_t page_xp = grdxt_remote_lookup( rt_xp , page_id );
2391
2392        // check all existing pages
2393        if ( page_xp != XPTR_NULL )
2394        {
2395            page_t * page_ptr = GET_PTR( page_xp );
2396            uint32_t flags    = hal_remote_l32( XPTR( mapper_cxy , &page_ptr->flags ) );
2397
2398            if ( flags & PG_DIRTY )
2399            {
2400
2401#if (DEBUG_FATFS_SYNC_FAT & 1)
2402if( DEBUG_FATFS_SYNC_FAT < cycle )
2403printk("\n[%s] thread[%x,%x] synchronizes page %d from FAT mapper to IOC device\n",
2404__FUNCTION__, page_id );
2405#endif
2406                // move page from mapper to device
2407                error = fatfs_move_page( page_xp , IOC_SYNC_WRITE );
2408
2409                if ( error )  return -1;
2410
2411                // reset page dirty flag
2412                ppm_page_undo_dirty( page_xp );
2413            }
2414        }
2415    }  // end loop on pages
2416
2417#if DEBUG_FATFS_SYNC_FAT
2418cycle = (uint32_t)hal_get_cycles();
2419if( DEBUG_FATFS_SYNC_FAT < cycle )
2420printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
2421__FUNCTION__ , this->process->pid, this->trdid, cycle );
2422#endif
2423
2424    return 0;
2425
2426}  // end fatfs_sync_fat()
2427
2428////////////////////////////////////
2429error_t fatfs_sync_free_info( void )
2430{
2431    error_t       error;
2432    fatfs_ctx_t * fatfs_ctx_ptr;              // local pointer on fatfs context in cluster 0
2433    uint32_t      ctx_free_clusters;          // number of free clusters from fatfs context
2434    uint32_t      ctx_free_cluster_hint;      // free cluster hint from fatfs context
2435    uint32_t      ioc_free_clusters;          // number of free clusters from fatfs context
2436    uint32_t      ioc_free_cluster_hint;      // free cluster hint from fatfs context
2437    uint32_t      fs_info_lba;                // lba of FS_INFO sector on IOC device
2438    uint8_t     * fs_info_buffer;             // local pointer on FS_INFO buffer in cluster 0
2439    xptr_t        fs_info_buffer_xp;          // extended pointer on FS_INFO buffer in cluster 0
2440    uint8_t       tmp_buf[512];               // 512 bytes temporary buffer
2441    xptr_t        tmp_buf_xp;                 // extended pointer on temporary buffer
2442
2443#if DEBUG_FATFS_SYNC_FSINFO
2444uint32_t   cycle = (uint32_t)hal_get_cycles();
2445thread_t * this  = CURRENT_THREAD;
2446if( DEBUG_FATFS_SYNC_FSINFO < cycle )
2447printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
2448__FUNCTION__ , this->process->pid, this->trdid, cycle );
2449#endif
2450
2451    // get pointer on fatfs context in cluster 0
2452    fatfs_ctx_ptr = hal_remote_lpt( XPTR( 0 , &fs_context[FS_TYPE_FATFS].extend ) );
2453
2454    // get "free_clusters" and "free_cluster_hint" from fatfs context in cluster 0
2455    ctx_free_clusters     = hal_remote_l32( XPTR( 0 , &fatfs_ctx_ptr->free_clusters ) );
2456    ctx_free_cluster_hint = hal_remote_l32( XPTR( 0 , &fatfs_ctx_ptr->free_cluster_hint ) );
2457
2458    // get fs_info_lba
2459    fs_info_lba = hal_remote_l32( XPTR( 0 , &fatfs_ctx_ptr->fs_info_lba ) );
2460
2461    // build extended pointer on temporary buffer
2462    tmp_buf_xp = XPTR( local_cxy , tmp_buf );
2463
2464    // copy FS_INFO sector from IOC to local buffer
2465    error = dev_ioc_move_data( IOC_SYNC_READ , tmp_buf_xp , fs_info_lba , 1 );
2466
2467    if ( error )
2468    {
2469        printk("\n[ERROR] in %s : cannot access FS_INFO on IOC device\n", __FUNCTION__ );
2470        return -1;
2471    }
2472
2473    // get current values of "free_clusters" and "free_cluster_hint" from FS_INFO on IOC
2474    ioc_free_clusters     = fatfs_get_remote_record( FS_FREE_CLUSTERS     , tmp_buf_xp );
2475    ioc_free_cluster_hint = fatfs_get_remote_record( FS_FREE_CLUSTER_HINT , tmp_buf_xp );
2476
2477#if DEBUG_FATFS_SYNC_FSINFO
2478if( DEBUG_FATFS_SYNC_FSINFO < cycle )
2479printk("\n[%s] thread[%x,%x] / ctx_free %x / ioc_free %x / ctx_hint %x / ioc_hint %x\n",
2480__FUNCTION__ , this->process->pid, this->trdid, 
2481ctx_free_clusters, ioc_free_clusters, ctx_free_cluster_hint, ioc_free_cluster_hint );
2482#endif
2483
2484    // check values
2485    if( (ioc_free_clusters     != ctx_free_clusters) || 
2486        (ioc_free_cluster_hint != ctx_free_cluster_hint) )
2487    {
2488        printk("\n[WARNING] in %s : unconsistent free clusters info\n"
2489        " ioc_free %x / ctx_free %x / ioc_hint %x / ctx_hint %x\n",
2490        __FUNCTION__, ioc_free_clusters, ctx_free_clusters,
2491        ioc_free_cluster_hint, ctx_free_cluster_hint );
2492
2493        // get pointers on FS_INFO buffer in cluster 0
2494        fs_info_buffer    = hal_remote_lpt( XPTR( 0 , &fatfs_ctx_ptr->fs_info_buffer ) );
2495        fs_info_buffer_xp = XPTR( 0 , fs_info_buffer );
2496
2497        // update FS_INFO buffer in cluster 0
2498        fatfs_set_remote_record(FS_FREE_CLUSTERS    ,fs_info_buffer_xp,ctx_free_clusters );
2499        fatfs_set_remote_record(FS_FREE_CLUSTER_HINT,fs_info_buffer_xp,ctx_free_cluster_hint);
2500
2501        // update the FS_INFO sector on IOC device
2502        error = dev_ioc_move_data( IOC_SYNC_WRITE , fs_info_buffer_xp , fs_info_lba , 1 );
2503
2504        if ( error )
2505        {
2506            printk("\n[ERROR] in %s : cannot update FS_INFO on IOC device\n", __FUNCTION__ );
2507            return -1;
2508        }
2509    }
2510
2511#if DEBUG_FATFS_SYNC_FSINFO
2512cycle = (uint32_t)hal_get_cycles();
2513if( DEBUG_FATFS_SYNC_FSINFO < cycle )
2514printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
2515__FUNCTION__ , this->process->pid, this->trdid, cycle );
2516#endif
2517
2518    return 0;
2519
2520}  // end fatfs_sync_free_info()
2521
2522//////////////////////////////////////////////////////////
2523error_t fatfs_cluster_alloc( uint32_t * searched_cluster )
2524{
2525    error_t       error;
2526    uint32_t      page_id;        // page index in FAT mapper
2527    uint32_t      slot_id;        // slot index in page (1024 slots per page)
2528    uint32_t      cluster;        // first free cluster index in FAT
2529    uint32_t      free_clusters;  // total number of free clusters
2530    vfs_ctx_t   * vfs_ctx;        // local pointer on VFS context (same in all clusters)
2531    fatfs_ctx_t * loc_fatfs_ctx;  // local pointer on local FATFS context
2532    fatfs_ctx_t * fat_fatfs_ctx;  // local pointer on FATFS context in FAT cluster
2533    xptr_t        fat_mapper_xp;  // extended pointer on FAT mapper
2534    cxy_t         fat_cxy;        // Fat mapper cluster identifier
2535    xptr_t        page_xp;        // extended pointer on current page descriptor in mapper
2536    xptr_t        slot_xp;        // extended pointer on FAT slot defined by hint
2537    xptr_t        lock_xp;        // extended pointer on lock protecting free clusters info
2538    xptr_t        hint_xp;        // extended pointer on free_cluster_hint in FAT cluster
2539    xptr_t        free_xp;        // extended pointer on free_clusters_number in FAT cluster
2540
2541#if DEBUG_FATFS_CLUSTER_ALLOC
2542uint32_t   cycle = (uint32_t)hal_get_cycles();
2543thread_t * this  = CURRENT_THREAD;
2544if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
2545printk("\n[%s] thread[%x,%x] enter / cycle = %d\n",
2546__FUNCTION__, this->process->pid, this->trdid, cycle );
2547#endif
2548
2549    // get local pointer on VFS context (same in all clusters)
2550    vfs_ctx = &fs_context[FS_TYPE_FATFS];
2551
2552    // get local pointer on local FATFS context
2553    loc_fatfs_ctx = vfs_ctx->extend;
2554
2555    // get extended pointer on FAT mapper
2556    fat_mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
2557
2558    // get FAT cluster
2559    fat_cxy = GET_CXY( fat_mapper_xp );
2560   
2561    // get local pointer on FATFS context in FAT cluster
2562    fat_fatfs_ctx = hal_remote_lpt( XPTR( fat_cxy , &vfs_ctx->extend ) );
2563
2564    // build relevant extended pointers on free clusters info in mapper cluster
2565    lock_xp = XPTR( fat_cxy , &fat_fatfs_ctx->lock );
2566    hint_xp = XPTR( fat_cxy , &fat_fatfs_ctx->free_cluster_hint );
2567    free_xp = XPTR( fat_cxy , &fat_fatfs_ctx->free_clusters );
2568
2569    // take the FAT lock in write mode
2570    remote_rwlock_wr_acquire( lock_xp );
2571
2572    // get hint and free_clusters values from FATFS context in FAT cluster
2573    cluster       = hal_remote_l32( hint_xp ) + 1;
2574    free_clusters = hal_remote_l32( free_xp );
2575       
2576#if (DEBUG_FATFS_CLUSTER_ALLOC & 1)
2577if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
2578printk("\n[%s] thread[%x,%x] get free info : hint %x / free_clusters %x\n",
2579__FUNCTION__, this->process->pid, this->trdid, (cluster - 1), free_clusters );
2580#endif
2581
2582    // check "free_clusters"
2583    if ( free_clusters == 0 )
2584    {
2585        printk("\n[ERROR] in %s : no more free FATFS clusters\n", __FUNCTION__ );
2586        remote_rwlock_wr_release( lock_xp );
2587        return -1;
2588    }
2589    else if ( free_clusters < CONFIG_VFS_FREE_CLUSTERS_MIN )
2590    {
2591        printk("\n[WARNING] in %s : only %n free FATFS clusters\n", 
2592        __FUNCTION__, CONFIG_VFS_FREE_CLUSTERS_MIN );
2593    }
2594
2595    // get page index & slot index for selected cluster
2596    page_id  = cluster >> 10;
2597    slot_id  = cluster & 0x3FF;
2598
2599    // get relevant page descriptor from FAT mapper
2600    page_xp = mapper_remote_get_page( fat_mapper_xp , page_id );
2601
2602    if( page_xp == XPTR_NULL )
2603    {
2604        printk("\n[ERROR] in %s : cannot acces FAT mapper\n", __FUNCTION__ );
2605        remote_rwlock_wr_release( lock_xp );
2606        return -1;
2607    }
2608
2609    // build extended pointer on selected cluster slot in FAT mapper
2610    slot_xp = ppm_page2base( page_xp ) + (slot_id << 2);
2611         
2612    // check selected cluster actually free
2613    if( hal_remote_l32( slot_xp ) != FREE_CLUSTER )
2614    { 
2615        printk("\n[ERROR] in %s : selected cluster %x not free\n", __FUNCTION__, cluster );
2616        remote_rwlock_wr_release( lock_xp );
2617        return -1;
2618    }
2619
2620    // update free cluster info in FATFS context and in FS_INFO sector
2621    error = fatfs_free_clusters_decrement( XPTR( fat_cxy , fat_fatfs_ctx ) , cluster );
2622
2623    if( error )
2624    { 
2625        printk("\n[ERROR] in %s : cannot update free cluster info\n", __FUNCTION__ );
2626        remote_rwlock_wr_release( lock_xp );
2627        return -1;
2628    }
2629
2630    // update FAT mapper
2631    hal_remote_s32( slot_xp , END_OF_CHAIN_CLUSTER_MAX );
2632
2633    // we don't mark the FAT mapper page as dirty,
2634    // because we synchronously update FAT on IOC device
2635    error = fatfs_move_page( page_xp , IOC_SYNC_WRITE );
2636
2637    if( error )
2638    { 
2639        printk("\n[ERROR] in %s : cannot update FAT on IOC device\n", __FUNCTION__ );
2640        remote_rwlock_wr_release( lock_xp );
2641        return -1;
2642    }
2643
2644    // release FAT lock
2645    remote_rwlock_wr_release( lock_xp );
2646
2647#if DEBUG_FATFS_CLUSTER_ALLOC
2648cycle = (uint32_t)hal_get_cycles();
2649if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
2650printk("\n[%s] thread[%x,%x] exit / allocated cluster %x in FAT / cycle %d\n",
2651__FUNCTION__, this->process->pid, this->trdid, cluster, cycle );
2652#endif
2653
2654    *searched_cluster = cluster;
2655    return 0;
2656
2657}  // end fatfs_cluster_alloc()
2658
2659//////////////////////////////////////////////
2660error_t fatfs_release_inode( xptr_t inode_xp )
2661{
2662    vfs_ctx_t   * vfs_ctx;        // local pointer on VFS context (same in all clusters).
2663    fatfs_ctx_t * loc_fatfs_ctx;  // local pointer on local FATFS context
2664    cxy_t         fat_cxy;        // FAT cluster identifier
2665    xptr_t        fatfs_ctx_xp;   // extended pointer on FATFS context in FAT cluster
2666    fatfs_ctx_t * fatfs_ctx_ptr;  // local pointer on FATFS context in FAT cluster
2667    xptr_t        fat_mapper_xp;  // extended pointer on FAT mapper
2668    xptr_t        lock_xp;        // extended pointer on lock protecting FAT.
2669    xptr_t        first_xp;       // extended pointer on inode extension
2670    uint32_t      first_cluster;  // first cluster index for released inode
2671    vfs_inode_t * inode_ptr;      // local pointer on target inode
2672    cxy_t         inode_cxy;      // target inode cluster identifier
2673    error_t       error;
2674
2675// check inode pointer
2676assert( (inode_xp != XPTR_NULL) , "inode pointer is NULL\n" );
2677
2678    // get inode cluster and local pointer
2679    inode_ptr     = GET_PTR( inode_xp );
2680    inode_cxy     = GET_CXY( inode_xp );
2681
2682    // get first_cluster from inode extension
2683    first_xp      = XPTR( inode_cxy , &inode_ptr->extend );
2684    first_cluster = (uint32_t)(intptr_t)hal_remote_lpt( first_xp );
2685
2686// check first cluster index
2687assert( (first_cluster != 0) , "inode extend is NULL\n" );
2688
2689#if DEBUG_FATFS_RELEASE_INODE
2690char       name[CONFIG_VFS_MAX_NAME_LENGTH];
2691uint32_t   cycle = (uint32_t)hal_get_cycles();
2692thread_t * this  = CURRENT_THREAD;
2693vfs_inode_get_name( inode_xp , name );
2694if( DEBUG_FATFS_RELEASE_INODE < cycle )
2695printk("\n[%s] thread[%x,%x] enter for <%s> / first_cluster %x / cycle %d\n",
2696__FUNCTION__ , this->process->pid, this->trdid, name, first_cluster, cycle );
2697#endif
2698
2699    // get local pointer on VFS context (same in all clusters)
2700    vfs_ctx = &fs_context[FS_TYPE_FATFS];
2701
2702    // get local pointer on local FATFS context
2703    loc_fatfs_ctx = vfs_ctx->extend;
2704
2705    // get FAT mapper cluster
2706    fat_mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
2707    fat_cxy        = GET_CXY( fat_mapper_xp );
2708   
2709    // get pointers on FATFS context in FAT cluster
2710    fatfs_ctx_ptr  = hal_remote_lpt( XPTR( fat_cxy , &vfs_ctx->extend ) );
2711    fatfs_ctx_xp   = XPTR( fat_cxy , fatfs_ctx_ptr );
2712
2713    // get extended pointer on FAT lock in FAT cluster
2714    lock_xp = XPTR( fat_cxy , &fatfs_ctx_ptr->lock );
2715
2716    // take FAT lock in write mode
2717    remote_rwlock_wr_acquire( lock_xp );
2718
2719#if (DEBUG_FATFS_RELEASE_INODE & 0x11 == 0x11)
2720mapper_display_page( fat_mapper_xp , 0 , 4096 );
2721#endif
2722
2723    // call the recursive function to release all clusters from FAT mapper
2724    uint32_t dirty_page_min = 0xFFFFFFFF;
2725    uint32_t dirty_page_max = 0;
2726
2727    if ( fatfs_recursive_release( fat_mapper_xp,
2728                                  fatfs_ctx_xp,
2729                                  first_cluster,
2730                                  &dirty_page_min,
2731                                  &dirty_page_max ) )
2732    {
2733        printk("\n[ERROR] in %s : cannot update FAT mapper\n", __FUNCTION__ );
2734        remote_rwlock_wr_release( lock_xp );
2735        return -1;
2736    }
2737
2738#if (DEBUG_FATFS_RELEASE_INODE & 1)
2739if( DEBUG_FATFS_RELEASE_INODE < cycle )
2740printk("\n[%s] inode <%s> removed from FAT mapper\n", __FUNCTION__, name );
2741#endif
2742
2743#if (DEBUG_FATFS_RELEASE_INODE & 0x11 == 0x11)
2744mapper_display_page( fat_mapper_xp , 0 , 4096 );
2745#endif
2746
2747    // update FAT on IOC device (from FAT mapper)
2748    error = fatfs_update_ioc_fat( fatfs_ctx_xp,
2749                                  dirty_page_min,
2750                                  dirty_page_max );
2751
2752    if( error )
2753    {
2754        printk("\n[ERROR] in %s : cannot update FAT on IOC device\n", __FUNCTION__ );
2755        remote_rwlock_wr_release( lock_xp );
2756        return -1;
2757    }
2758
2759#if (DEBUG_FATFS_RELEASE_INODE & 1)
2760if( DEBUG_FATFS_RELEASE_INODE < cycle )
2761printk("\n[%s] inode <%s> removed from FAT on IOC device\n", __FUNCTION__, name );
2762#endif
2763
2764    // update FS-INFO on IOC device (from FATFS context)
2765    error = fatfs_update_ioc_fsinfo( fatfs_ctx_xp );
2766
2767    if( error )
2768    {
2769        printk("\n[ERROR] in %s: cannot update FSINFO on IOC device\n", __FUNCTION__ );
2770        remote_rwlock_wr_release( lock_xp );
2771        return -1;
2772    }
2773
2774#if (DEBUG_FATFS_RELEASE_INODE & 1)
2775if( DEBUG_FATFS_RELEASE_INODE < cycle )
2776printk("\n[%s] updated FS_INFO on IOC device for >%s>\n", __FUNCTION__, name );
2777#endif
2778
2779    // release FAT lock
2780    remote_rwlock_wr_release( lock_xp );
2781
2782#if DEBUG_FATFS_RELEASE_INODE
2783cycle = (uint32_t)hal_get_cycles();
2784if( DEBUG_FATFS_RELEASE_INODE < cycle )
2785printk("\n[%s] thread[%x,%x] removed <%s> inode from FATFS / cycle %d\n",
2786__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
2787#endif
2788
2789    return 0;
2790
2791}  // end fatfs_release_inode()
2792
2793////////////////////////////////////////////
2794error_t fatfs_move_page( xptr_t     page_xp,
2795                         cmd_type_t cmd_type )
2796{
2797    error_t       error;
2798    vfs_inode_t * inode_ptr;
2799    mapper_t    * mapper_ptr;     
2800    uint32_t      page_id;     // page index in mapper
2801
2802#if DEBUG_FATFS_MOVE_PAGE
2803uint32_t   cycle = (uint32_t)hal_get_cycles();
2804thread_t * this  = CURRENT_THREAD;
2805char       name[CONFIG_VFS_MAX_NAME_LENGTH];
2806#endif
2807
2808    // get page cluster and local pointer
2809    cxy_t    page_cxy = GET_CXY( page_xp );
2810    page_t * page_ptr = GET_PTR( page_xp );
2811
2812    // get mapper pointer and page index from page descriptor
2813    mapper_ptr = hal_remote_lpt( XPTR( page_cxy , &page_ptr->mapper ) );
2814    page_id    = hal_remote_l32( XPTR( page_cxy , &page_ptr->index ) );
2815
2816    // get pointer on local FATFS context
2817    fatfs_ctx_t * fatfs_ctx = fs_context[FS_TYPE_FATFS].extend;
2818
2819    // get page base address
2820    xptr_t    buffer_xp  = ppm_page2base( page_xp );
2821 
2822    // get inode pointer from mapper
2823    inode_ptr  = hal_remote_lpt( XPTR( page_cxy , &mapper_ptr->inode ) );
2824
2825    //////////////////////////////  FAT mapper  /////////////////////////////////////////
2826    if( inode_ptr == NULL )
2827    {
2828
2829#if DEBUG_FATFS_MOVE_PAGE
2830if( DEBUG_FATFS_MOVE_PAGE < cycle )
2831printk("\n[%s] thread[%x,%x] enters for %s /  page %d in FAT mapper / cycle %d\n",
2832__FUNCTION__, this->process->pid, this->trdid, dev_ioc_cmd_str(cmd_type), page_id, cycle );
2833#endif
2834        // get lba from FATFS context and page_id
2835        uint32_t      lba = fatfs_ctx->fat_begin_lba + (page_id << 3);
2836 
2837        // access IOC device
2838        error = dev_ioc_move_data( cmd_type , buffer_xp , lba , 8 );
2839
2840        if( error )
2841        {
2842            printk("\n[ERROR] in %s : cannot access device\n", __FUNCTION__ );
2843            return -1;
2844        }
2845
2846#if DEBUG_FATFS_MOVE_PAGE
2847if( DEBUG_FATFS_MOVE_PAGE < cycle )
2848printk("\n[%s] thread[%x,%x] exit / page %d in FAT mapper\n",
2849__FUNCTION__, this->process->pid, this->trdid, page_id, cycle );
2850#endif
2851
2852    }
2853    /////////////////////////  inode mapper  ////////////////////////////////////////////
2854    else                       
2855    {
2856
2857#if DEBUG_FATFS_MOVE_PAGE
2858vfs_inode_get_name( XPTR( page_cxy , inode_ptr ) , name );
2859if( DEBUG_FATFS_MOVE_PAGE < cycle )
2860printk("\n[%s] thread[%x,%x] enters for %s / page %d in <%s> mapper/ cycle %d\n",
2861__FUNCTION__, this->process->pid, this->trdid, 
2862dev_ioc_cmd_str( cmd_type ), page_id, name, cycle );
2863#endif
2864
2865        uint32_t  searched_cluster_id;
2866        uint32_t  first_cluster_id;
2867
2868        // get first_cluster_id from inode extension
2869        void * extend    = hal_remote_lpt( XPTR( page_cxy , &inode_ptr->extend ) );
2870        first_cluster_id = (uint32_t)(intptr_t)extend;
2871
2872        // compute searched_cluster_id
2873        if( page_id == 0 )            // no need to access FAT mapper
2874        {
2875            // searched cluster is first cluster
2876            searched_cluster_id = first_cluster_id;
2877        }
2878        else                        // FAT mapper access required
2879        {
2880            // scan FAT mapper to get searched_cluster_id
2881            error = fatfs_get_cluster( 0,                    // first page in mapper
2882                                       first_cluster_id,
2883                                       page_id,
2884                                       &searched_cluster_id );
2885            if( error )
2886            {
2887                printk("\n[ERROR] in %s : cannot get cluster_id\n", __FUNCTION__ );
2888                return -1;
2889            }
2890        }
2891
2892        // get lba for searched_cluster
2893        uint32_t lba = fatfs_lba_from_cluster( fatfs_ctx , searched_cluster_id );
2894
2895        // access IOC device to move 8 blocks
2896        error = dev_ioc_move_data( cmd_type , buffer_xp , lba , 8 );
2897
2898        if( error )
2899        {
2900            printk("\n[ERROR] in %s : cannot access device\n", __FUNCTION__ );
2901            return -1;
2902        }
2903
2904#if DEBUG_FATFS_MOVE_PAGE
2905if( DEBUG_FATFS_MOVE_PAGE < cycle )
2906vfs_inode_get_name( XPTR( page_cxy, inode_ptr ) , name );
2907printk("\n[%s] thread[%x,%x] exit / page %d in <%s> mapper / cluster_id %x\n",
2908__FUNCTION__, this->process->pid, this->trdid, page_id, name, searched_cluster_id );
2909#endif
2910
2911    }
2912
2913    return 0;
2914
2915}  // end fatfs_move_page()
2916
2917
Note: See TracBrowser for help on using the repository browser.