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

Last change on this file since 615 was 614, checked in by alain, 6 years ago

1) introduce a dev_ioc_sync_write() function in IOC API,

to improve the DEVFS synchronous update.

2) fix a big bug in both the user_dir_create() and user_dir_destroy()

functions: add an extended pointer on the reference client process
in the function's arguments.

File size: 81.3 KB
Line 
1/*
2 * fatfs.c - FATFS file system API implementation.
3 *
4 * Author    Alain Greiner (2016,2017,2018)
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
40//////////////////////////////////////////////////////////////////////////////////////////
41//          Extern  variables         
42//////////////////////////////////////////////////////////////////////////////////////////
43
44extern vfs_ctx_t     fs_context[FS_TYPES_NR];   // allocated in kernel_init.c file
45
46//////////////////////////////////////////////////////////////////////////////////////////
47//              FATFS specific static functions
48//////////////////////////////////////////////////////////////////////////////////////////
49
50//////////////////////////////////////////////////////////////////////////////////////////
51// These functions return the "offset" and "length" values of an
52// [offset,length] constant defined in the fatfs.h file.
53//////////////////////////////////////////////////////////////////////////////////////////
54
55static inline int get_length( int offset __attribute__((unused)), int length ) { return length; }
56
57static inline int get_offset( int offset, int length __attribute__((unused)) ) { return offset; }
58
59//////////////////////////////////////////////////////////////////////////////////////////
60// This static function returns the LBA of the first sector of a FAT cluster.
61// This function can be called by any thread running in any cluster.
62//////////////////////////////////////////////////////////////////////////////////////////
63// @ ctx          :     pointer on FATFS context.
64// @ cluster  : cluster index in FATFS.
65// @ return the lba value.
66//////////////////////////////////////////////////////////////////////////////////////////
67static inline uint32_t fatfs_lba_from_cluster( fatfs_ctx_t * ctx,
68                                               uint32_t      cluster )
69{
70    return (ctx->cluster_begin_lba + ((cluster - 2) << 3));
71}
72
73//////////////////////////////////////////////////////////////////////////////////////////
74// This function return an integer record value (one, two, or four bytes)
75// from a memory buffer, taking into account endianness.
76//////////////////////////////////////////////////////////////////////////////////////////
77// @ offset        : first byte of record in buffer.
78// @ size          : record length in bytes (1/2/4).
79// @ buffer        : pointer on buffer base.
80// @ little endian : the most significant byte has the highest address when true.
81// @ return the integer value in a 32 bits word.
82//////////////////////////////////////////////////////////////////////////////////////////
83static uint32_t fatfs_get_record( uint32_t    offset,
84                                  uint32_t    size,
85                                  uint8_t   * buffer,
86                                  uint32_t    little_endian )
87{
88    uint32_t n;
89    uint32_t res  = 0;
90
91    if ( little_endian )
92    {
93        for( n = size ; n > 0 ; n-- ) res = (res<<8) | buffer[offset+n-1];
94    }
95    else // big_endian
96    {
97        for( n = 0 ; n < size ; n++ ) res = (res<<8) | buffer[offset+n];
98    }
99    return res;
100
101}  // end fatfs_get_record()
102
103//////////////////////////////////////////////////////////////////////////////////////////
104// This function writes one, two, or four bytes from a 32 bits integer to a memory buffer,
105// taking into account endianness.
106//////////////////////////////////////////////////////////////////////////////////////////
107// @ offset        : first byte of record in buffer.
108// @ size          : record length in bytes (1/2/4).
109// @ buffer        : pointer on buffer base.
110// @ little endian : the most significant byte has the highest address when true.
111// @ return the integer value in a 32 bits word.
112//////////////////////////////////////////////////////////////////////////////////////////
113static void fatfs_set_record( uint32_t    offset,
114                              uint32_t    size,
115                              uint8_t   * buffer,
116                              uint32_t    little_endian,
117                              uint32_t    value )
118{
119    uint32_t n;
120
121    if ( little_endian )
122    {
123        for( n = size ; n > 0 ; n-- ) buffer[offset+n-1] = (uint8_t)(value>>((n-1)<<3));
124    }
125    else // big_endian
126    {
127        for( n = 0 ; n < size ; n++ ) buffer[offset+n] = (uint8_t)(value>>((size-1-n)<<3));
128    }
129
130}  // end fatfs_set_record()
131
132//////////////////////////////////////////////////////////////////////////////////////////
133// This static function retun in the <name> buffer a short name stored in
134// a SFN FATFS directory entry.
135/////////////////////////i////////////////////////////////////////////////////////////////
136// @ buffer   : pointer on buffer containing the directory entry.
137// @ name     : [out] buffer allocated by the caller.
138//////////////////////////////////////////////////////////////////////////////////////////
139static void fatfs_get_name_from_short( uint8_t * buffer,
140                                       char    * name )
141{
142    uint32_t i;
143    uint32_t j = 0;
144
145    // get name
146    for ( i = 0; i < 8 && buffer[i] != ' '; i++ )
147    {
148        name[j] = to_lower( buffer[i] );
149        j++;
150    }
151
152    // get extension
153    for ( i = 8; i < 8 + 3 && buffer[i] != ' '; i++ )
154    {
155        // we entered the loop so there is an extension. add the dot
156        if ( i == 8 )
157        {
158            name[j] = '.';
159            j++;
160        }
161
162        name[j] = to_lower( buffer[i] );
163        j++;
164    }
165
166    name[j] = '\0';
167
168}  // fatfs_get_name_from_short()
169
170//////////////////////////////////////////////////////////////////////////////////////////
171// This static function retun in the <name> buffer a partial name stored in
172// a LFN FATFS directory entry.
173/////////////////////////i////////////////////////////////////////////////////////////////
174// @ buffer   : pointer on buffer containing the directory entry.
175// @ name     : [out] buffer allocated by the caller.
176//////////////////////////////////////////////////////////////////////////////////////////
177static void fatfs_get_name_from_long( uint8_t * buffer,
178                                      char    * name )
179{
180    uint32_t   name_offset   = 0;
181    uint32_t   buffer_offset = get_length(LDIR_ORD);
182    uint32_t   l_name_1      = get_length(LDIR_NAME_1);
183    uint32_t   l_name_2      = get_length(LDIR_NAME_2);
184    uint32_t   l_name_3      = get_length(LDIR_NAME_3);
185    uint32_t   l_attr        = get_length(LDIR_ATTR);
186    uint32_t   l_type        = get_length(LDIR_TYPE);
187    uint32_t   l_chksum      = get_length(LDIR_CHKSUM);
188    uint32_t   l_rsvd        = get_length(LDIR_RSVD);
189
190    uint32_t   j             = 0;
191    uint32_t   eof           = 0;
192
193    while ( (buffer_offset != DIR_ENTRY_SIZE)  && (!eof) )
194    {
195        while (j != l_name_1 && !eof )
196        {
197            if ( (buffer[buffer_offset] == 0x00) || 
198                 (buffer[buffer_offset] == 0xFF) )
199            {
200                eof = 1;
201                continue;
202            }
203            name[name_offset] = buffer[buffer_offset];
204            buffer_offset += 2;
205            j += 2;
206            name_offset++;
207        }
208
209        buffer_offset += (l_attr + l_type + l_chksum);
210        j = 0;
211
212        while (j != l_name_2 && !eof )
213        {
214            if ( (buffer[buffer_offset] == 0x00) || 
215                 (buffer[buffer_offset] == 0xFF) )
216            {
217                eof = 1;
218                continue;
219            }
220            name[name_offset] = buffer[buffer_offset];
221            buffer_offset += 2;
222            j += 2;
223            name_offset++;
224        }
225
226        buffer_offset += l_rsvd;
227        j = 0;
228
229        while (j != l_name_3 && !eof )
230        {
231            if ( (buffer[buffer_offset] == 0x00) || 
232                 (buffer[buffer_offset] == 0xFF) )
233            {
234                eof = 1;
235                continue;
236            }
237            name[name_offset] = buffer[buffer_offset];
238            buffer_offset += 2;
239            j += 2;
240            name_offset++;
241        }
242    }
243    name[name_offset] = 0;
244
245} // end fatfs_get_name_from_long()
246
247//////////////////////////////////////////////////////////////////////////////////////////
248// This static function analyse the <name> input argument, and returns in other
249// output arguments various informations required to store the name in FATFS directory.
250// The <name> length cannot be larger than 31 characters :
251// - Short name (less than 13 characters) require 1 LFN entry.
252// - Medium names (from 14 to 26 characters require 2 LFN entries.
253// - Large names (up to 31 characters) require 3 LFN entries.
254//////////////////////////////////////////////////////////////////////////////////////////
255// @ name     : [in]  complete directory entry name.
256// @ length   : [out] total number of characters in name.
257// @ nb_lfn   : [out] number of LFN entries required to store the name.
258// @ sfn      : [out] a legal SFN name extracted from name / upper case and 8-3 format.
259// @ checksum : [out] checksum to be stored in SFN.
260// @ returns 0 on success / returns 1 if the name length is larger than 31 characters.
261//////////////////////////////////////////////////////////////////////////////////////////
262static error_t fatfs_name_format( const char  * name,
263                                  uint32_t    * length,
264                                  uint32_t    * nb_lfn,
265                                  char        * sfn,
266                                  uint8_t     * checksum )
267{
268    // compute name length
269    uint32_t name_length = strlen( name );
270    *length = name_length;
271
272    uint32_t suffix_length = 0;
273    uint32_t prefix_length = 0;
274    uint32_t dot_found     = 0;
275    uint32_t i;
276
277    // compute prefix and suffix length
278    // only the last '.' is taken into account
279    for ( i=0 ; i<name_length ; i++ )
280    {
281        if (name[i] == '.' )
282        {
283            if ( dot_found ) 
284            {
285                prefix_length += suffix_length + 1;
286                suffix_length =  0;
287            }
288            else
289            {
290                dot_found = 1;
291            }
292        }
293        else
294        { 
295            if ( dot_found)  suffix_length++;
296            else             prefix_length++;
297        }
298    } 
299
300    // build SFN prefix (8bits)
301    if (prefix_length <= 8)
302    {
303        for( i=0 ; i<8 ; i++)
304        {
305            if ( i<prefix_length ) sfn[i] = to_upper( name[i] );
306            else                   sfn[i] = 0x20;
307        }
308    }
309    else
310    {
311        for( i=0 ; i<6 ; i++)
312        {
313            sfn[i] = to_upper( name[i] );
314        }
315        sfn[6] = 0x7E;
316        sfn[7] = 0x31;
317    }
318
319    // build SFN suffix (3 bits)
320    if ( suffix_length == 0 )
321    {
322        sfn[8]  = 0x20;
323        sfn[9]  = 0x20;
324        sfn[10] = 0x20;
325    }
326    else if ( suffix_length == 1 )
327    {
328        sfn[8]  = to_upper( name[name_length-1] );
329        sfn[9]  = 0x20;
330        sfn[10] = 0x20;
331    }
332    else if ( suffix_length == 2 )
333    {
334        sfn[8]  = to_upper( name[name_length-2] );
335        sfn[9]  = to_upper( name[name_length-1] );
336        sfn[10] = 0x20;
337    }
338    else
339    {
340        sfn[8]  = to_upper( name[name_length-suffix_length] );
341        sfn[9]  = to_upper( name[name_length-suffix_length+1] );
342        sfn[10] = to_upper( name[name_length-suffix_length+2] );
343    }
344
345    // compute 8 bits checksum
346    uint8_t sum = 0;
347    for ( i=0 ; i<11 ; i++ )
348    {
349        sum = (((sum & 0x01)<<7) | ((sum & 0xFE)>>1)) + sfn[i];
350    }
351    *checksum = sum;
352
353    // set nb_lfn and length values
354    if      ( name_length <= 13 )
355    {
356        *nb_lfn  = 1;
357        return 0;
358    }
359    else if ( name_length <= 26 )
360    {
361        *nb_lfn  = 2;
362        return 0;
363    }
364    else if ( name_length <= 31 )
365    {
366        *nb_lfn  = 3;
367        return 0;
368    }
369    else
370    {
371        return 1;
372    }
373}   // end fatfs_name_format() 
374
375//////////////////////////////////////////////////////////////////////////////////////////
376// This static function - atomically - decrements "free_clusters", and updates
377// the "free_cluster_hint" shared variables in the FATFS context in the FAT cluster.
378// It scan the FAT to find the first free slot larger than the <cluster> argument,
379// and set "free_cluster_hint" <= (free - 1).
380//
381// WARNING : The free_lock protecting exclusive access to these variables
382//           must be taken by the calling function.
383//////////////////////////////////////////////////////////////////////////////////////////
384// @ cluster     : recently allocated cluster index in FAT.
385//////////////////////////////////////////////////////////////////////////////////////////
386static error_t fatfs_free_clusters_decrement( uint32_t  cluster )
387{
388    fatfs_ctx_t * loc_ctx;      // local pointer on local FATFS context
389    fatfs_ctx_t * fat_ctx;      // local pointer on FATFS in cluster containing FAT mapper
390    cxy_t         mapper_cxy;   // cluster identifier for cluster containing FAT mapper
391    xptr_t        mapper_xp;    // extended pointer on FAT mapper
392    xptr_t        hint_xp;      // extended pointer on "free_cluster_hint" shared variable
393    xptr_t        numb_xp;      // extended pointer on "free_clusters" shared variable
394    uint32_t      numb;         // "free_clusters" variable current value
395    uint32_t      page_id;      // page index in FAT mapper
396    uint32_t      slot_id;      // slot index in one page of FAT (1024 slots per page)
397    uint32_t      page_max;     // max number of pages in FAT mapper
398    xptr_t        page_xp;      // extended pointer on current page in FAT mapper
399    xptr_t        slot_xp;      // extended pointer on current slot in FAT mapper
400
401#if DEBUG_FATFS_FREE_CLUSTERS
402uint32_t   cycle = (uint32_t)hal_get_cycles();
403thread_t * this  = CURRENT_THREAD;
404if( DEBUG_FATFS_FREE_CLUSTERS < (uint32_t)hal_get_cycles() )
405printk("\n[%s] thread[%x,%x] enter for allocated cluster %x / cycle %d\n",
406__FUNCTION__, this->process->pid, this->trdid, cluster , cycle );
407#endif
408
409    // get local pointer on local FATFS context
410    loc_ctx = fs_context[FS_TYPE_FATFS].extend;
411
412    // get cluster containing FAT mapper
413    mapper_xp  = loc_ctx->fat_mapper_xp;
414    mapper_cxy = GET_CXY( mapper_xp ); 
415
416    // get local pointer on FATFS context in FAT cluster
417    fat_ctx = hal_remote_lpt( XPTR( mapper_cxy , &fs_context[FS_TYPE_FATFS].extend ) );
418
419    // build extended pointers on free_clusters, and free_cluster_hint
420    hint_xp = XPTR( mapper_cxy , &fat_ctx->free_cluster_hint );
421    numb_xp = XPTR( mapper_cxy , &fat_ctx->free_clusters );
422
423    // update "free_clusters"
424    numb = hal_remote_l32( numb_xp );
425    hal_remote_s32( numb_xp , numb - 1 );
426
427    // scan FAT mapper to find the first free slot > cluster
428    // and update "free_cluster_hint" as (free - 1)
429    page_id  = (cluster + 1) >> 10;
430    slot_id  = (cluster + 1) & 0x3FF;
431    page_max = (loc_ctx->fat_sectors_count >> 3);
432
433    // scan FAT mapper / loop on pages
434    while ( page_id < page_max )           
435    {
436        // get current page from mapper
437        page_xp = mapper_remote_get_page( mapper_xp , page_id );
438
439        if( page_xp == XPTR_NULL )
440        {
441            printk("\n[ERROR] in %s : cannot access FAT mapper\n", __FUNCTION__ );
442            return -1;
443        }
444
445        // scan FAT mapper / loop on slots
446        while ( slot_id < 1024 )
447        {
448            // get extended pointer on current slot
449            slot_xp = ppm_page2base( page_xp ) + (slot_id << 2);
450
451            // test FAT slot value
452            if ( hal_remote_l32( slot_xp ) == FREE_CLUSTER )
453            {
454                // update "free_cluster_hint" <= (free - 1)
455                hal_remote_s32( hint_xp , (page_id << 10) + slot_id - 1 );
456
457#if DEBUG_FATFS_FREE_CLUSTERS
458cycle = (uint32_t)hal_get_cycles();
459if( DEBUG_FATFS_FREE_CLUSTERS < (uint32_t)hal_get_cycles() )
460printk("\n[%s] thread[%x,%x] exit / hint %x / free_clusters %x / cycle %d\n",
461__FUNCTION__, this->process->pid, this->trdid,
462hal_remote_l32(hint_xp), hal_remote_l32(numb_xp), cycle );
463#endif
464                return 0;
465            }
466
467            // increment  slot_id
468            slot_id++;
469
470        }  // end loop on slots
471
472        // update loop variables
473        page_id++;
474        slot_id = 0;
475
476    }  // end loop on pages
477
478    // return error if no free cluster found
479    printk("\n[ERROR] in %s : No free cluster found\n", __FUNCTION__ );
480    return -1;
481   
482}  // end fatfs_free_clusters_decrement()
483
484//////////////////////////////////////////////////////////////////////////////////////////
485// This static function atomically increments <free_clusters>, and updates
486// the <free_cluster_hint> shared variables in the FATFS context in the FAT cluster.
487// If the released cluster index is smaller than the current (hint + 1) value,
488// it set "free_cluster_hint" <= cluster - 1.
489//
490// WARNING : The free_lock protecting exclusive access to these variables
491//           must be taken by the calling function.
492//////////////////////////////////////////////////////////////////////////////////////////
493// @ cluster     : recently released cluster index in FAT.
494//////////////////////////////////////////////////////////////////////////////////////////
495static void fatfs_free_clusters_increment( uint32_t  cluster )
496{
497    fatfs_ctx_t * loc_ctx;      // local pointer on local FATFS context
498    fatfs_ctx_t * fat_ctx;      // local pointer on FATFS in cluster containing FAT mapper
499    cxy_t         fat_cxy;      // cluster identifier for cluster containing FAT mapper
500    xptr_t        hint_xp;      // extended pointer on "free_cluster_hint" shared variable
501    xptr_t        numb_xp;      // extended pointer on "free_clusters" shared variable
502    uint32_t      hint;         // "free_cluster_hint" variable current value
503    uint32_t      numb;         // "free_clusters" variable current value
504
505    // get local pointer on local FATFS context
506    loc_ctx = fs_context[FS_TYPE_FATFS].extend;
507
508    // get cluster containing FAT mapper
509    fat_cxy = GET_CXY( loc_ctx->fat_mapper_xp );
510
511    // get local pointer on FATFS context in FAT cluster
512    fat_ctx = hal_remote_lpt( XPTR( fat_cxy , &fs_context[FS_TYPE_FATFS].extend ) );
513
514    // build extended pointers free_lock, free_clusters, and free_cluster_hint
515    hint_xp = XPTR( fat_cxy , &fat_ctx->free_cluster_hint );
516    numb_xp = XPTR( fat_cxy , &fat_ctx->free_clusters );
517
518    // get current value of free_cluster_hint and free_clusters
519    hint = hal_remote_l32( hint_xp );
520    numb = hal_remote_l32( numb_xp );
521
522    // update free_cluster_hint if required
523    if ( cluster < (hint + 1) ) hal_remote_s32( hint_xp , (cluster - 1) );
524
525    // update free_clusters
526    hal_remote_s32( numb_xp , numb + 1 );
527
528#if DEBUG_FATFS_FREE_CLUSTERS
529thread_t * this = CURRENT_THREAD;
530if( DEBUG_FATFS_FREE_CLUSTERS < (uint32_t)hal_get_cycles() )
531printk("\n[%s] thread[%x,%x] updates free cluster info : hint %x / number %x\n",
532__FUNCTION__, this->process->pid, this->trdid,
533hal_remote_l32( hint_xp ), hal_remote_l32( numb_xp ) );
534#endif
535
536}  // end fatfs_free_clusters_increment()
537
538//////////////////////////////////////////////////////////////////////////////////////////
539// This recursive function is called by the generic function fatfs_release_all_clusters()
540// It release all clusters allocated to a given inode in the FAT mapper.
541// The removal is done in reverse order of the linked list (from last to first).
542// It does NOT update the FS on the IOC device.
543//////////////////////////////////////////////////////////////////////////////////////////
544// @ fat_mapper_xp : extended pointer on FAT mapper.
545// @ cluster       : cluster index in FAT.
546// @ return 0 if success / return -1 if error (cannot access FAT)
547//////////////////////////////////////////////////////////////////////////////////////////
548static error_t fatfs_recursive_release( xptr_t    fat_mapper_xp,
549                                        uint32_t  cluster )
550{
551    uint32_t next;
552
553    // get next cluster from FAT mapper
554    if ( mapper_remote_get_32( fat_mapper_xp , cluster , &next ) ) return -1;
555
556#if (DEBUG_FATFS_RELEASE_INODE & 1)
557thread_t * this = CURRENT_THREAD;
558if ( DEBUG_FATFS_RELEASE_INODE < (uint32_t)hal_get_cycles() )
559printk("\n[%s] thread[%x,%x] access FAT for cluster %x / next %x\n",
560__FUNCTION__, this->process->pid, this->trdid, cluster, next );
561#endif
562
563    if ( next < END_OF_CHAIN_CLUSTER_MIN )  // non terminal case
564    {
565        // call fatfs_recursive_release() on next cluster
566        if ( fatfs_recursive_release( fat_mapper_xp , next ) ) return -1;
567    }       
568
569    // update current cluster in FAT mapper
570    if ( mapper_remote_set_32( fat_mapper_xp, cluster , FREE_CLUSTER ) ) return -1;
571
572    // Update free_cluster_hint and free_clusters in FAT context
573    fatfs_free_clusters_increment( cluster );
574
575    return 0;
576
577}  // end fatfs_recursive_release()
578
579
580//////////////////////////////////////////////////////////////////////////////////////////
581//              FATFS specific extern functions
582//////////////////////////////////////////////////////////////////////////////////////////
583
584//////////////////////////////
585void fatfs_ctx_display( void )
586{
587    // get pointer on local FATFS context
588    vfs_ctx_t   * vfs_ctx   = &fs_context[FS_TYPE_FATFS];
589    fatfs_ctx_t * fatfs_ctx = (fatfs_ctx_t *)vfs_ctx->extend;
590
591    printk("\n*** FAT context ***\n" 
592           "- fat_sectors       = %d\n"
593           "- sector size       = %d\n"
594           "- cluster size      = %d\n"
595           "- fat_first_lba     = %d\n"
596           "- data_first_lba    = %d\n"
597           "- root_dir_cluster  = %d\n"
598           "- free_clusters     = %d\n"
599           "- free_cluster_hint = %d\n"
600           "- fat_mapper_xp     = %l\n",
601           fatfs_ctx->fat_sectors_count,
602           fatfs_ctx->bytes_per_sector,
603           fatfs_ctx->sectors_per_cluster * fatfs_ctx->bytes_per_sector,
604           fatfs_ctx->fat_begin_lba,
605           fatfs_ctx->cluster_begin_lba,
606           fatfs_ctx->root_dir_cluster,
607           fatfs_ctx->free_clusters,
608           fatfs_ctx->free_cluster_hint,
609           fatfs_ctx->fat_mapper_xp );
610
611}  // end fatfs_ctx_display()
612
613//////////////////////////////////////////
614void fatfs_display_fat( uint32_t  page_id,
615                        uint32_t  nentries )
616{
617    uint32_t line;
618    uint32_t maxline;
619
620    // copute numner of lines to display
621    maxline = nentries >> 3;
622    if( nentries & 0x7 ) maxline++;
623
624    // get pointer on local FATFS context
625    vfs_ctx_t   * vfs_ctx   = &fs_context[FS_TYPE_FATFS];
626    fatfs_ctx_t * fatfs_ctx = (fatfs_ctx_t *)vfs_ctx->extend;
627
628    // get extended pointer on FAT mapper
629    xptr_t fat_mapper_xp = fatfs_ctx->fat_mapper_xp;
630
631    // get extended pointer and cluster of FAT mapper requested page
632    xptr_t     page_xp  = mapper_remote_get_page( fat_mapper_xp , page_id );
633
634    // get extended pointer on requested page base
635    xptr_t     base_xp  = ppm_page2base( page_xp );
636
637    printk("\n***** FAT content / page %d *****\n", page_id );
638    for( line = 0 ; line < maxline ; line++ )
639    {
640        printk("%x : %X | %X | %X | %X | %X | %X | %X | %X\n", (line<<3),
641        hal_remote_l32( base_xp + ((line<<5)      ) ),
642        hal_remote_l32( base_xp + ((line<<5) + 4  ) ),
643        hal_remote_l32( base_xp + ((line<<5) + 8  ) ),
644        hal_remote_l32( base_xp + ((line<<5) + 12 ) ),
645        hal_remote_l32( base_xp + ((line<<5) + 16 ) ),
646        hal_remote_l32( base_xp + ((line<<5) + 20 ) ),
647        hal_remote_l32( base_xp + ((line<<5) + 24 ) ),
648        hal_remote_l32( base_xp + ((line<<5) + 28 ) ) );
649    }
650
651}  // end fatfs_display_fat()
652
653///////////////////////////////////////////////////////
654error_t fatfs_get_cluster( uint32_t   first_cluster_id,
655                           uint32_t   searched_page_index,
656                           uint32_t * searched_cluster_id )
657{
658    xptr_t     current_page_xp;        // pointer on current page descriptor
659    uint32_t * buffer;                 // pointer on current page (array of uint32_t)
660    uint32_t   current_page_index;     // index of current page in FAT
661    uint32_t   current_page_offset;    // offset of slot in current page
662    uint32_t   page_count_in_file;     // index of page in file (index in linked list)
663    uint32_t   next_cluster_id;        // content of current FAT slot
664
665assert( (searched_page_index > 0) ,
666"no FAT access required for first page\n");
667
668#if DEBUG_FATFS_GET_CLUSTER
669uint32_t   cycle = (uint32_t)hal_get_cycles();
670thread_t * this  = CURRENT_THREAD;
671if( DEBUG_FATFS_GET_CLUSTER < cycle )
672printk("\n[%s] thread[%x,%x] enter / first_cluster_id %d / searched_index / cycle %d\n",
673__FUNCTION__, this->process->pid, this->trdid, first_cluster_id, searched_page_index, cycle );
674#endif
675
676    // get local pointer on local FATFS context
677    fatfs_ctx_t * ctx = fs_context[FS_TYPE_FATFS].extend;
678
679    // get extended pointer and cluster on FAT mapper
680    xptr_t mapper_xp  = ctx->fat_mapper_xp;
681    cxy_t  mapper_cxy = GET_CXY( mapper_xp );
682
683    // initialize loop variable (1024 slots per page)
684    current_page_index  = first_cluster_id >> 10;
685    current_page_offset = first_cluster_id & 0x3FF;
686    page_count_in_file  = 0;
687    next_cluster_id     = 0xFFFFFFFF;
688
689    // scan FAT (i.e. traverse FAT linked list)
690    while( page_count_in_file < searched_page_index )
691    {
692        // get pointer on current page descriptor
693        current_page_xp = mapper_remote_get_page( mapper_xp , current_page_index );
694
695        if( current_page_xp == XPTR_NULL )
696        {
697            // TODO
698            return -1;
699        }
700
701        // get pointer on buffer for current page
702        xptr_t base_xp = ppm_page2base( current_page_xp );
703        buffer = (uint32_t *)GET_PTR( base_xp );
704
705        // get FAT slot content
706        next_cluster_id = hal_remote_l32( XPTR( mapper_cxy , &buffer[current_page_offset] ) );
707
708#if (DEBUG_FATFS_GET_CLUSTER & 1)
709if( DEBUG_FATFS_GET_CLUSTER < cycle )
710printk("\n[%s] traverse FAT / current_page_index = %d\n"
711"current_page_offset = %d / next_cluster_id = %d\n",
712__FUNCTION__, current_page_index, current_page_offset , next_cluster_id );
713#endif
714
715        // update loop variables
716        current_page_index  = next_cluster_id >> 10;
717        current_page_offset = next_cluster_id & 0x3FF;
718        page_count_in_file++;
719    }
720
721    if( next_cluster_id == 0xFFFFFFFF ) return -1;
722   
723#if DEBUG_FATFS_GET_CLUSTER
724cycle = (uint32_t)hal_get_cycles();
725if( DEBUG_FATFS_GET_CLUSTER < cycle )
726printk("\n[%s] thread[%x,%x] exit / searched_cluster_id = %d / cycle %d\n",
727__FUNCTION__, this->process->pid, this->trdid, next_cluster_id / cycle );
728#endif
729
730    *searched_cluster_id = next_cluster_id;
731    return 0;
732
733}  // end fatfs_get_cluster()
734
735
736
737///////////////////////////////////////////////////////////////////////////////////////
738// Generic API : the following functions are called by the kernel VFS
739//               and must be defined by all supported file systems.
740///////////////////////////////////////////////////////////////////////////////////////
741
742/////////////////////////////////////
743fatfs_ctx_t * fatfs_ctx_alloc( void )
744{
745    kmem_req_t    req;
746        req.type    = KMEM_FATFS_CTX;
747        req.size    = sizeof(fatfs_ctx_t);
748    req.flags   = AF_KERNEL | AF_ZERO;
749
750        return (fatfs_ctx_t *)kmem_alloc( &req );
751}
752
753//////////////////////////////////////////////
754void fatfs_ctx_init( fatfs_ctx_t * fatfs_ctx )
755{
756    error_t       error;
757    kmem_req_t    req;
758    uint8_t     * buffer;
759
760#if DEBUG_FATFS_CTX_INIT
761uint32_t cycle = (uint32_t)hal_get_cycles();
762if( DEBUG_FATFS_CTX_INIT < cycle )
763printk("\n[%s] thread[%x,%x] enter for fatfs_ctx = %x / cycle %d\n",
764__FUNCTION__ , this->process->pid, this->trdid, fatfs_ctx , cycle );
765#endif
766
767// check argument
768assert( (fatfs_ctx != NULL) , "pointer on FATFS context is NULL\n" );
769
770// check only cluster 0 does FATFS init
771assert( (local_cxy == 0) , "only cluster 0 can initialize FATFS\n");
772
773    // allocate a 512 bytes buffer to store the boot record
774        req.type    = KMEM_512_BYTES;
775    req.flags   = AF_KERNEL | AF_ZERO;
776        buffer      = (uint8_t *)kmem_alloc( &req );
777
778    if( buffer == NULL ) 
779    {
780        printk("\n[PANIC] in %s : cannot allocate buffer\n", __FUNCTION__ );
781        hal_core_sleep();
782    }
783     
784    // load the BOOT record from device
785    error = dev_ioc_sync_read( buffer , 0 , 1 );
786
787    if ( error )
788    {
789        printk("\n[PANIC] in %s : cannot access boot record\n", __FUNCTION__ );
790        hal_core_sleep();
791    }
792
793#if (DEBUG_FATFS_CTX_INIT & 0x1)
794if( DEBUG_FATFS_CTX_INIT < cycle )
795{
796    uint32_t   line;
797    uint32_t   byte = 0;
798    printk("\n***** %s : FAT boot record\n", __FUNCTION__ );
799    for ( line = 0 ; line < 32 ; line++ )
800    {
801        printk(" %X | %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x |\n",
802               byte,
803               buffer[byte+ 0],buffer[byte+ 1],buffer[byte+ 2],buffer[byte+ 3],
804               buffer[byte+ 4],buffer[byte+ 5],buffer[byte+ 6],buffer[byte+ 7],
805               buffer[byte+ 8],buffer[byte+ 9],buffer[byte+10],buffer[byte+11],
806               buffer[byte+12],buffer[byte+13],buffer[byte+14],buffer[byte+15] );
807
808         byte += 16;
809    }
810}
811#endif
812
813    // get sector size from boot record
814    uint32_t sector_size = fatfs_get_record( BPB_BYTSPERSEC , buffer , 1 );
815    if ( sector_size != 512 )
816    {
817        printk("\n[PANIC] in %s : sector size must be 512 bytes\n", __FUNCTION__ );
818        hal_core_sleep();
819    }
820
821    // get cluster size from boot record
822    uint32_t nb_sectors = fatfs_get_record( BPB_SECPERCLUS , buffer , 1 );
823    if ( nb_sectors != 8 )
824    {
825        printk("\n[PANIC] in %s : cluster size must be 8 sectors\n", __FUNCTION__ );
826        hal_core_sleep();
827    }
828
829    // get number of FAT copies from boot record
830    uint32_t nb_fats = fatfs_get_record( BPB_NUMFATS , buffer , 1 );
831    if ( nb_fats != 1 )
832    {
833        printk("\n[PANIC] in %s : number of FAT copies must be 1\n", __FUNCTION__ );
834        hal_core_sleep();
835    }
836
837    // get number of sectors in FAT from boot record
838    uint32_t fat_sectors = fatfs_get_record( BPB_FAT32_FATSZ32 , buffer , 1 );
839    if ( (fat_sectors & 0xF) != 0 )
840    {
841        printk("\n[PANIC] in %s : FAT size not multiple of 16 sectors\n", __FUNCTION__ );
842        hal_core_sleep();
843    }
844
845    // get root cluster from boot record
846    uint32_t root_cluster = fatfs_get_record( BPB_FAT32_ROOTCLUS , buffer , 1 );
847    if ( root_cluster != 2 ) 
848    {
849        printk("\n[PANIC] in %s : root cluster index must be 2\n", __FUNCTION__ );
850        hal_core_sleep();
851    }
852
853    // get FAT lba from boot record
854    uint32_t fat_lba = fatfs_get_record( BPB_RSVDSECCNT , buffer , 1 );
855
856    // get FS_INFO sector lba from boot record
857    uint32_t fs_info_lba = fatfs_get_record( BPB_FAT32_FSINFO , buffer , 1 );
858
859    // load the FS_INFO record from device
860    error = dev_ioc_sync_read( buffer , fs_info_lba , 1 );
861
862    if ( error )
863    {
864        printk("\n[PANIC] in %s : cannot access FS_INFO record\n", __FUNCTION__ );
865        hal_core_sleep();
866    }
867
868    // get free clusters number from FS_INFO record
869    uint32_t free_clusters = fatfs_get_record( FS_FREE_CLUSTERS , buffer , 1 );
870    if ( free_clusters >= fat_sectors << 7 )
871    {
872        printk("\n[PANIC] in %s : unconsistent free_clusters\n", __FUNCTION__ );
873        hal_core_sleep();
874    }
875
876    // get cluster hint from FS_INFO record
877    uint32_t free_cluster_hint = fatfs_get_record( FS_FREE_CLUSTER_HINT , buffer , 1 );
878    if ( free_cluster_hint >= fat_sectors << 7 )
879    {
880        printk("\n[PANIC] in %s : unconsistent free_cluster_hint\n", __FUNCTION__ );
881        hal_core_sleep();
882    }
883
884    // release the 512 bytes buffer
885    req.type = KMEM_512_BYTES;
886    req.ptr  = buffer;
887    kmem_free( &req );
888
889    // allocate a mapper for the FAT itself
890    mapper_t * fat_mapper = mapper_create( FS_TYPE_FATFS );
891    if ( fat_mapper == NULL )
892    {
893        printk("\n[PANIC] in %s : no memory for FAT mapper\n", __FUNCTION__ );
894        hal_core_sleep();
895    }
896
897    // WARNING : the inode field MUST be NULL for the FAT mapper
898    fat_mapper->inode = NULL;
899
900    // initialize the FATFS context
901    fatfs_ctx->fat_begin_lba         = fat_lba;
902    fatfs_ctx->fat_sectors_count     = fat_sectors; 
903    fatfs_ctx->bytes_per_sector      = sector_size;
904    fatfs_ctx->sectors_per_cluster   = nb_sectors;
905    fatfs_ctx->cluster_begin_lba     = fat_lba + fat_sectors;
906    fatfs_ctx->root_dir_cluster      = 2;
907    fatfs_ctx->fat_mapper_xp         = XPTR( local_cxy , fat_mapper );
908    fatfs_ctx->free_clusters         = free_clusters;
909    fatfs_ctx->free_cluster_hint     = free_cluster_hint;
910
911    remote_queuelock_init( XPTR( local_cxy , &fatfs_ctx->free_lock ) , LOCK_FATFS_FREE );
912
913#if DEBUG_FATFS_CTX_INIT
914cycle = (uint32_t)hal_get_cycles();
915if( DEBUG_FATFS_CTX_INIT < cycle )
916printk("\n[%s]  thread[%x,%x] exit for fatfs_ctx = %x / cycle %d\n",
917__FUNCTION__, this->process->pid, this->trdid, fatfs_ctx, cycle );
918#endif
919
920}  // end fatfs_ctx_init()
921
922/////////////////////////////////////////////////
923void fatfs_ctx_destroy( fatfs_ctx_t * fatfs_ctx )
924{
925    kmem_req_t    req;
926    req.type = KMEM_FATFS_CTX;
927    req.ptr  = fatfs_ctx;
928    kmem_free( &req );
929}
930
931///////////////////////////////////////////////
932error_t fatfs_add_dentry( vfs_inode_t  * inode,
933                          vfs_dentry_t * dentry )
934{
935    error_t       error;
936    uint32_t      length;        // dentry name length
937    uint32_t      nb_lfn;        // number or required LFN
938    char          sfn[11];       // buffer for SFN name
939    uint8_t       checksum;      // name checksum
940    mapper_t    * mapper;        // loal pointer on parent inode mapper
941    xptr_t        mapper_xp;     // extended pointer on parent inode mapper
942    xptr_t        child_xp;      // extended pointer on child inode
943    cxy_t         child_cxy;     // child inode cluster
944    vfs_inode_t * child_ptr;     // child inode local pointer
945    uint32_t      size;          // child inode size
946    uint32_t      type;          // child inode type
947    uint32_t      cluster;       // child inode cluster index
948
949#if DEBUG_FATFS_ADD_DENTRY
950char       dir_name[CONFIG_VFS_MAX_NAME_LENGTH];
951uint32_t   cycle = (uint32_t)hal_get_cycles();
952thread_t * this  = CURRENT_THREAD;
953vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
954if( DEBUG_FATFS_ADD_DENTRY < cycle )
955printk("\n[%s]  thread[%x,%x] enter / parent <%s> / child <%s> / cycle %d\n",
956__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
957#endif
958
959// check arguments
960assert( (inode != NULL) , "inode pointer is NULL\n" );
961assert( (dentry != NULL) , "dentry pointer is NULL\n" );
962assert( (inode->type == INODE_TYPE_DIR) , "inode is not a directory\n" );
963assert( (inode->mapper != NULL ) , "mapper pointer is NULL\n" );
964 
965    // get pointers on directory mapper
966    mapper    = inode->mapper;
967    mapper_xp = XPTR( local_cxy , mapper );
968
969    // get extended pointers on remote child inode
970    child_xp  = dentry->child_xp;
971    child_cxy = GET_CXY( child_xp );
972    child_ptr = GET_PTR( child_xp );
973
974    // get relevant infos from child inode
975    type    =                     hal_remote_l32( XPTR( child_cxy , &child_ptr->type ) );
976    size    =                     hal_remote_l32( XPTR( child_cxy , &child_ptr->size ) );
977    cluster = (uint32_t)(intptr_t)hal_remote_lpt( XPTR( child_cxy , &child_ptr->extend ) );
978
979    // analyse dentry name
980    error = fatfs_name_format( dentry->name,
981                               &length,
982                               &nb_lfn,
983                               sfn,
984                               &checksum );
985    if ( error )
986    {
987        printk("\n[ERROR] in %s : dentry name > 31 bytes\n", __FUNCTION__ );
988        return -1;
989    }
990                               
991    // Search end of directory with two embedded loops:
992    // - scan the pages in the mapper
993    // - scan the entries in each page to find NO_MORE_ENTRY
994
995    xptr_t     page_xp;                 // extended pointer on page descriptor
996    xptr_t     base_xp;                 // extended pointer on page base
997    uint8_t  * base;                    // local pointer on page base (array of bytes)
998    uint32_t   page_id = 0;             // page index in mapper
999    uint32_t   offset  = 0;             // position in page
1000    uint32_t   found   = 0;             // NO_MORE_ENTRY found
1001
1002    // loop on pages in mapper
1003    while ( found == 0 )
1004    {
1005        // get extended pointer on page descriptor in mapper
1006        page_xp  = mapper_remote_get_page( mapper_xp , page_id );
1007
1008        if ( page_xp == XPTR_NULL )
1009        {
1010            printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ );
1011            return -1;
1012        }
1013       
1014        // get pointer on page base
1015        base_xp = ppm_page2base( page_xp );
1016        base = GET_PTR( base_xp );
1017
1018        // loop on directory entries in this page
1019        while ( (offset < 4096) && (found == 0) )
1020        {
1021            if ( fatfs_get_record( LDIR_ORD, (base + offset), 0 ) == NO_MORE_ENTRY )
1022            {
1023                found = 1;
1024            } 
1025            else
1026            {
1027                offset = offset + 32;
1028            }
1029        }  // end loop on entries
1030
1031        if ( found == 0 )
1032        {
1033            page_id++;
1034            offset = 0;
1035        }
1036    }  // end loop on pages
1037
1038    // Modify the directory mapper: depending on the name length,
1039    // the new child requires to write (3, 4, or 5) directory entries.
1040    // To actually register the new child, we use a 5 steps FSM
1041    // (one state per entry to be written), that is traversed as:
1042    // LFN3 -> LFN2 -> LFN1 -> NORMAL -> NOMORE
1043    // At most two pages are modified:
1044    // - the page containing the NO_MORE_ENTRY is always modified
1045    // - the following page can be modified if the name spread on to pages.
1046
1047    char * name = dentry->name;
1048
1049    uint32_t step;          // FSM state
1050
1051    if      ( nb_lfn == 1 ) step = 3;
1052    else if ( nb_lfn == 2 ) step = 4;
1053    else if ( nb_lfn == 3 ) step = 5;
1054   
1055    uint8_t  * entry;       // pointer on directory entry to be written
1056    uint32_t   i;           // byte index in one 32 bytes directory
1057    uint32_t   c;           // character index in name
1058
1059    while ( step )   
1060    {
1061        // when the new child is split on two pages,
1062        // we need to access a new page in mapper
1063        if ( offset >= 4096 )
1064        {
1065            // copy the modified page to IOC device
1066            fatfs_move_page( page_xp , IOC_SYNC_WRITE );   
1067
1068            // get the next page in FAT mapper
1069            page_xp  = mapper_remote_get_page( mapper_xp , page_id + 1 );
1070
1071            if ( page_xp == XPTR_NULL )
1072            {
1073                printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ );
1074                return -1;
1075            }
1076       
1077            // get pointer on page base
1078            base_xp = ppm_page2base( page_xp );
1079            base = GET_PTR( base_xp );
1080           
1081            // update offset
1082            offset = 0;
1083        }
1084
1085        // compute directory entry address
1086        entry = base + offset;
1087
1088#if (DEBUG_FATFS_ADD_DENTRY & 1)
1089if( DEBUG_FATFS_ADD_DENTRY < cycle )
1090printk("\n[%s] FSM step = %d / offset = %x / nb_lfn = %d\n",
1091__FUNCTION__, step, offset, nb_lfn );
1092#endif
1093
1094        // write 32 bytes (one directory entry) per iteration
1095        switch ( step )
1096        {
1097            case 5:   // write LFN3 entry
1098            {
1099                c = 26;
1100                // scan the 32 bytes in dir_entry
1101                for ( i = 0 ; i < 32 ; i++ )
1102                {
1103                    if (i == 0)
1104                    {
1105                        if ( nb_lfn == 3) entry[i] = 0x43;
1106                        else              entry[i] = 0x03;
1107                    }
1108                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1109                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1110                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1111                              ( c < length ) )
1112                    {
1113                                          entry[i] = name[c];
1114                                          c++;
1115                    }
1116                    else if (i == 11)     entry[i] = 0x0F;
1117                    else if (i == 13)     entry[i] = checksum;
1118                    else                  entry[i] = 0x00;
1119                }
1120                step--;
1121                break;
1122            }
1123            case 4:   // write LFN2 entry 
1124            {
1125                c = 13;
1126                // scan the 32 bytes in dir_entry
1127                for ( i = 0 ; i < 32 ; i++ )
1128                {
1129                    if (i == 0)
1130                    {
1131                        if ( nb_lfn == 2) entry[i] = 0x42;
1132                        else              entry[i] = 0x02;
1133                    }
1134                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1135                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1136                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1137                              ( c < length ) )
1138                    {
1139                                          entry[i] = name[c];
1140                                          c++;
1141                    }
1142                    else if (i == 11)     entry[i] = 0x0F;
1143                    else if (i == 13)     entry[i] = checksum;
1144                    else                  entry[i] = 0x00;
1145                }
1146                step--;
1147                break;
1148            }
1149            case 3:   // Write LFN1 entry   
1150            {
1151                c = 0;
1152                // scan the 32 bytes in dir_entry
1153                for ( i = 0 ; i < 32 ; i++ )
1154                {
1155                    if (i == 0)
1156                    {
1157                        if ( nb_lfn == 1) entry[i] = 0x41;
1158                        else              entry[i] = 0x01;
1159                    }
1160                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1161                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1162                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1163                              ( c < length ) )
1164                    {
1165                                          entry[i] = name[c];
1166                                          c++;
1167                    }
1168                    else if (i == 11)     entry[i] = 0x0F;
1169                    else if (i == 13)     entry[i] = checksum;
1170                    else                  entry[i] = 0x00;
1171                }
1172                step--;
1173                break;
1174            }
1175            case 2:   // write NORMAL entry     
1176            {
1177                // scan the 32 bytes in dir_entry
1178                for ( i = 0 ; i < 32 ; i++ )
1179                {
1180                    if      ( i < 11 )                              // 8.3 SFN
1181                    {
1182                                          entry[i] = sfn[i];
1183                    }
1184                    else if (i == 11)                               // ATTR
1185                    {
1186                        if (type == INODE_TYPE_DIR)  entry[i] = 0x10;
1187                        else                         entry[i] = 0x20;
1188                    }
1189                    else if (i == 20)     entry[i] = cluster>>16;   // cluster.B2
1190                    else if (i == 21)     entry[i] = cluster>>24;   // cluster.B3
1191                    else if (i == 26)     entry[i] = cluster>>0;    // cluster.B0
1192                    else if (i == 27)     entry[i] = cluster>>8;    // cluster.B1
1193                    else if (i == 28)     entry[i] = size>>0;       // size.B0
1194                    else if (i == 29)     entry[i] = size>>8;       // size.B1
1195                    else if (i == 30)     entry[i] = size>>16;      // size.B2
1196                    else if (i == 31)     entry[i] = size>>24;      // size.B3
1197                    else                  entry[i] = 0x00;
1198                }
1199
1200                // update the "extend" field in dentry descriptor
1201                dentry->extend = (void*)(intptr_t)(((page_id<<12) + offset)>>5);
1202
1203                step--;
1204                break;
1205            }
1206            case 1:   // write NOMORE entry 
1207            {
1208                entry [0] = 0x00;
1209                step--;
1210                break;
1211            }
1212        } // end switch step
1213
1214        offset += 32;
1215
1216    } // exit while     
1217
1218    // copy the modified page to the IOC device
1219    fatfs_move_page( page_xp , IOC_SYNC_WRITE );   
1220
1221#if DEBUG_FATFS_ADD_DENTRY
1222cycle = (uint32_t)hal_get_cycles();
1223if( DEBUG_FATFS_ADD_DENTRY < cycle )
1224printk("\n[%s]  thread[%x,%x] exit / parent <%s> / child <%s> / cycle %d\n",
1225__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1226#endif
1227
1228    return 0;
1229
1230}  // end fatfs_add_dentry()
1231
1232//////////////////////////////////////////////////
1233error_t fatfs_remove_dentry( vfs_inode_t  * inode,
1234                             vfs_dentry_t * dentry )
1235{
1236    xptr_t     mapper_xp;  // extended pointer on mapper
1237    mapper_t * mapper;     // local pointer on mapper
1238    xptr_t     page_xp;    // extended pointer on mapper page descriptor
1239    xptr_t     base_xp;    // extended pointer on mapper page base
1240    uint8_t  * base;       // local pointer on mapper page base
1241
1242#if DEBUG_FATFS_REMOVE_DENTRY
1243char       dir_name[CONFIG_VFS_MAX_NAME_LENGTH];
1244uint32_t   cycle = (uint32_t)hal_get_cycles();
1245thread_t * this  = CURRENT_THREAD;
1246vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
1247if( DEBUG_FATFS_REMOVE_DENTRY < cycle )
1248printk("\n[%s] thread[%x,%x] enter / parent <%s> / child <%s> / cycle %d\n",
1249__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1250#endif
1251
1252// check arguments
1253assert( (inode != NULL) , "inode pointer is NULL\n" );
1254assert( (dentry != NULL) , "dentry pointer is NULL\n" );
1255assert( (inode->type == INODE_TYPE_DIR) , "inode is not a directory\n" );
1256assert( (inode->mapper != NULL ) , "mapper pointer is NULL\n" );
1257
1258    // get pointers on directory mapper
1259    mapper    = inode->mapper;
1260    mapper_xp = XPTR( local_cxy , mapper );
1261
1262    // compute number of LFN entries
1263    uint32_t nb_lfn;
1264    uint32_t name_length = strlen( dentry->name );
1265
1266    if      ( name_length <= 13 ) nb_lfn  = 1;
1267    else if ( name_length <= 26 ) nb_lfn  = 2;
1268    else                          nb_lfn  = 3;
1269
1270    // we must invalidate (2, 3 or 4) 32 bytes entries:
1271    // the NORMAL entry (registered in dentry->extend) and all preceding LFN entries
1272    // At most two pages are modified:
1273    // - the page containing the NORMAL entry is always modified.
1274    // - the preceding page is modified when the name spread on two pages.
1275
1276    // get 32 bytes directory entry index from dentry->extend
1277    uint32_t  dentry_id  = (uint32_t)(intptr_t)dentry->extend; 
1278
1279    // get page index and offset in parent directory mapper
1280    uint32_t  page_id    = dentry_id >> 7;
1281    uint32_t  offset     = (dentry_id & 0x7F)<<5;
1282
1283#if DEBUG_FATFS_REMOVE_DENTRY & 1
1284if( DEBUG_FATFS_REMOVE_DENTRY < cycle )
1285printk("\n[%s] dentry_id %x / page_id %x / offset %x\n",
1286__FUNCTION__, dentry_id, page_id, offset );
1287#endif
1288
1289    // get extended pointer on page descriptor from parent directory mapper
1290    page_xp  = mapper_remote_get_page( mapper_xp , page_id );
1291
1292    if ( page_xp == XPTR_NULL )
1293    {
1294        printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ );
1295        return -1;
1296    }
1297       
1298    // get pointers on page base
1299    base_xp = ppm_page2base( page_xp );
1300    base    = GET_PTR( base_xp );
1301
1302    // invalidate NORMAL entry in directory cache
1303    base[offset] = 0xE5;
1304
1305    // invalidate LFN entries
1306    while ( nb_lfn )
1307    {
1308        if (offset == 0)  // we must load page (page_id - 1)
1309        {
1310
1311// check page_id
1312assert( (page_id > 0), "page_id and offset cannot be both 0\n" );
1313
1314            // copy the modified page to the IOC device
1315            fatfs_move_page( page_xp , IOC_SYNC_WRITE );   
1316
1317            // get extended pointer on page descriptor from parent directory mapper
1318            page_xp  = mapper_remote_get_page( mapper_xp , page_id );
1319
1320            if ( page_xp == XPTR_NULL )
1321            {
1322                printk("\n[ERROR] in %s : cannot access directory mapper\n", __FUNCTION__ );
1323                return -1;
1324            }
1325       
1326            // get pointers on page base
1327            base_xp = ppm_page2base( page_xp );
1328            base    = GET_PTR( base_xp );
1329
1330            // update offset
1331            offset = 4096;
1332        }
1333
1334        offset = offset - 32;
1335
1336// check for LFN entry
1337assert( (fatfs_get_record( DIR_ATTR, base + offset, 0 ) == ATTR_LONG_NAME_MASK ),
1338"this directory entry must be a LFN\n");
1339
1340        // invalidate LFN entry
1341        base[offset] = 0xE5;
1342
1343        nb_lfn--;
1344    }     
1345
1346    // copy the modified page to the IOC device
1347    fatfs_move_page( page_xp , IOC_SYNC_WRITE );   
1348   
1349
1350#if DEBUG_FATFS_REMOVE_DENTRY
1351cycle = (uint32_t)hal_get_cycles();
1352if( DEBUG_FATFS_REMOVE_DENTRY < cycle )
1353printk("\n[%s] thread[%x,%x] exit / parent %s / child %s / cycle %d\n",
1354__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1355#endif
1356
1357    return 0;
1358
1359}  // end fatfs_remove_dentry
1360
1361/////////////////////////////////////////////////////
1362error_t fatfs_get_dentry( vfs_inode_t * parent_inode,
1363                          char        * name,
1364                          xptr_t        child_inode_xp )
1365{
1366    // Two embedded loops to scan the directory mapper:
1367    // - scan the parent directory mapper pages
1368    // - scan the directory entries in each 4 Kbytes page
1369
1370#if DEBUG_FATFS_GET_DENTRY
1371char       parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
1372uint32_t   cycle = (uint32_t)hal_get_cycles();
1373thread_t * this  = CURRENT_THREAD;
1374vfs_inode_get_name( XPTR( local_cxy , parent_inode ) , parent_name );
1375if( DEBUG_FATFS_GET_DENTRY < cycle )
1376printk("\n[%s]  thread[%x,%x] enter for child <%s> in parent <%s> / cycle %d\n",
1377__FUNCTION__, this->process->pid, this->trdid, name , parent_name , cycle );
1378#endif
1379
1380// check parent_inode and child_inode
1381assert( (parent_inode != NULL) , "parent_inode is NULL\n" );
1382assert( (child_inode_xp != XPTR_NULL ) , "child_inode is XPTR_NULL\n" );
1383
1384    mapper_t * mapper    = parent_inode->mapper;
1385    xptr_t     mapper_xp = XPTR( local_cxy , mapper );
1386
1387// check parent mapper
1388assert( (mapper != NULL) , "parent mapper is NULL\n");
1389   
1390    char       cname[CONFIG_VFS_MAX_NAME_LENGTH];  // name extracter from each directory entry
1391
1392    char       lfn1[16];         // buffer for one partial cname
1393    char       lfn2[16];         // buffer for one partial cname
1394    char       lfn3[16];         // buffer for one partial cname
1395    xptr_t     page_xp;          // extended pointer on page descriptor
1396    xptr_t     base_xp;          // extended pointer on page base
1397    uint8_t  * base;             // local pointer on page base
1398    uint8_t    attr;             // directory entry ATTR field
1399    uint8_t    ord;              // directory entry ORD field
1400    uint32_t   seq;              // sequence index
1401    uint32_t   lfn       = 0;    // LFN entries number
1402    uint32_t   size      = 0;    // searched file/dir size (bytes)
1403    uint32_t   cluster   = 0;    // searched file/dir cluster index
1404    uint32_t   is_dir    = 0;    // searched file/dir type
1405    int32_t    found     = 0;    // not found (0) / name found (1) / end of dir (-1)
1406    uint32_t   page_id   = 0;    // page index in mapper
1407    uint32_t   dentry_id = 0;    // directory entry index
1408    uint32_t   offset    = 0;    // byte offset in page
1409
1410    // scan the parent directory mapper
1411    while ( found == 0 )
1412    {
1413        // get one page
1414        page_xp = mapper_remote_get_page( mapper_xp , page_id );
1415
1416        if( page_xp == XPTR_NULL) return EIO;
1417
1418        // get page base
1419        base_xp = ppm_page2base( page_xp );
1420        base    = (uint8_t *)GET_PTR( base_xp );
1421
1422#if (DEBUG_FATFS_GET_DENTRY & 0x1)
1423if( DEBUG_FATFS_GET_DENTRY < cycle )
1424mapper_display_page( mapper_xp , page_id , 256 );
1425#endif
1426        // scan this page until end of directory, end of page, or name found
1427        while( (offset < 4096) && (found == 0) )
1428        {
1429            attr = fatfs_get_record( DIR_ATTR , base + offset , 0 );   
1430            ord  = fatfs_get_record( LDIR_ORD , base + offset , 0 );   
1431
1432            if (ord == NO_MORE_ENTRY)                 // no more entry => break
1433            {
1434                found = -1;
1435            }
1436            else if ( ord == FREE_ENTRY )             // free entry => skip
1437            {
1438                offset = offset + 32;
1439            }
1440            else if ( attr == 0x28 )                  // volune_id => skip
1441            {
1442                offset = offset + 32;
1443            }
1444            else if ( attr == ATTR_LONG_NAME_MASK )   // LFN entry => get partial cname
1445            {
1446                seq = ord & 0x3;
1447                lfn = (seq > lfn) ? seq : lfn;   
1448                if      ( seq == 1 ) fatfs_get_name_from_long( base + offset, lfn1 );
1449                else if ( seq == 2 ) fatfs_get_name_from_long( base + offset, lfn2 );
1450                else if ( seq == 3 ) fatfs_get_name_from_long( base + offset, lfn3 );
1451                offset = offset + 32;
1452            }
1453            else                                 // NORMAL entry
1454            {
1455                // build the extracted name
1456                if      ( lfn == 0 )
1457                {
1458                    fatfs_get_name_from_short( base + offset , cname );
1459                }
1460                else if ( lfn == 1 )
1461                {
1462                    strcpy( cname      , lfn1 );
1463                }   
1464                else if ( lfn == 2 ) 
1465                {
1466                    strcpy( cname      , lfn1 );
1467                    strcpy( cname + 13 , lfn2 );
1468                }
1469                else if ( lfn == 3 ) 
1470                {
1471                    strcpy( cname      , lfn1 );
1472                    strcpy( cname + 13 , lfn2 );
1473                    strcpy( cname + 26 , lfn3 );
1474                }
1475
1476                // get dentry arguments if extracted cname == searched name
1477                if ( strcmp( name , cname ) == 0 )
1478                {
1479                    cluster = (fatfs_get_record( DIR_FST_CLUS_HI , base + offset , 1 ) << 16) |
1480                              (fatfs_get_record( DIR_FST_CLUS_LO , base + offset , 1 )      ) ;
1481                    dentry_id = ((page_id<<12) + offset)>>5;
1482                    is_dir    = ((attr & ATTR_DIRECTORY) == ATTR_DIRECTORY);
1483                    size      = fatfs_get_record( DIR_FILE_SIZE , base + offset , 1 );
1484                    found     = 1;
1485                }
1486                offset = offset + 32;
1487                lfn    = 0;
1488            }
1489        }  // end loop on directory entries in page
1490
1491        page_id++;
1492        offset = 0;
1493
1494    }  // end loop on pages
1495
1496    // analyse the result of scan
1497
1498    if ( found == -1 )  // found end of directory => failure
1499    {
1500
1501#if DEBUG_FATFS_GET_DENTRY
1502cycle = (uint32_t)hal_get_cycles();
1503if( DEBUG_FATFS_GET_DENTRY < cycle )
1504printk("\n[%s]  thread[%x,%x] exit / child <%s> not found / cycle %d\n",
1505__FUNCTION__, this->process->pid, this->trdid, name, cycle );
1506#endif
1507
1508        return -1;
1509    }
1510
1511    // get child inode cluster and local pointer
1512    cxy_t          inode_cxy = GET_CXY( child_inode_xp );
1513    vfs_inode_t  * inode_ptr = GET_PTR( child_inode_xp );
1514
1515    // build extended pointer on parent dentried root
1516    xptr_t parents_root_xp = XPTR( inode_cxy , &inode_ptr->parents );
1517
1518// check child inode has at least one parent
1519assert( (xlist_is_empty( parents_root_xp ) == false ), "child inode must have one parent\n");
1520
1521    // get dentry pointers and cluster
1522    xptr_t         dentry_xp  = XLIST_FIRST( parents_root_xp , vfs_dentry_t , parents );
1523    vfs_dentry_t * dentry_ptr = GET_PTR( dentry_xp );
1524    cxy_t          dentry_cxy = GET_CXY( dentry_xp );
1525
1526// check dentry descriptor in same cluster as parent inode
1527assert( (dentry_cxy == local_cxy) , "illegal dentry cluster\n" );
1528
1529    // update the child inode "type", "size", and "extend" fields
1530    vfs_inode_type_t type = (is_dir) ? INODE_TYPE_DIR : INODE_TYPE_FILE;
1531
1532    hal_remote_s32( XPTR( inode_cxy , &inode_ptr->type   ) , type );
1533    hal_remote_s32( XPTR( inode_cxy , &inode_ptr->size   ) , size );
1534    hal_remote_s32( XPTR( inode_cxy , &inode_ptr->extend ) , cluster );
1535
1536    // update the dentry "extend" field
1537    dentry_ptr->extend = (void *)(intptr_t)dentry_id;
1538
1539#if DEBUG_FATFS_GET_DENTRY
1540cycle = (uint32_t)hal_get_cycles();
1541if( DEBUG_FATFS_GET_DENTRY < cycle )
1542printk("\n[%s]  thread[%x,%x] exit / child <%s> loaded in <%s> / cycle %d\n",
1543__FUNCTION__, this->process->pid, this->trdid, name, parent_name, cycle );
1544#endif
1545
1546    return 0;
1547
1548}  // end fatfs_get_dentry()
1549
1550///////////////////////////////////////////////////////
1551error_t fatfs_get_user_dir( struct vfs_inode_s * inode,
1552                            struct dirent      * array, 
1553                            uint32_t             max_dirent,
1554                            uint32_t             min_dentry,
1555                            bool_t               detailed,
1556                            uint32_t           * entries,
1557                            bool_t             * done )
1558{
1559    // Two embedded loops to scan the directory mapper:
1560    // - scan the parent directory mapper pages starting always from page 0
1561    // - scan the 32 bytes NORMAL/LFN directory entries in each page
1562    // Only valid dentries are copied : dentry_id >= min_dentry && dirent_id < dirent_max
1563
1564#if DEBUG_FATFS_GET_USER_DIR
1565char       inode_name[CONFIG_VFS_MAX_NAME_LENGTH];
1566uint32_t   cycle = (uint32_t)hal_get_cycles();
1567thread_t * this  = CURRENT_THREAD;
1568vfs_inode_get_name( XPTR( local_cxy , inode ) , inode_name );
1569if( DEBUG_FATFS_GET_USER_DIR < cycle )
1570printk("\n[%s]  thread[%x,%x] enter for inode <%s> / cycle %d\n",
1571__FUNCTION__, this->process->pid, this->trdid, inode_name , cycle );
1572#endif
1573
1574    mapper_t * mapper    = inode->mapper;
1575    xptr_t     mapper_xp = XPTR( local_cxy , mapper );
1576
1577// check mapper pointer
1578assert( (mapper != NULL) , "mapper is NULL\n");
1579   
1580// TODO handle the detailed flag
1581assert( (detailed == false), "detailed argument not supported/n");
1582
1583    char       cname[CONFIG_VFS_MAX_NAME_LENGTH];  // name extracted from each dentry
1584
1585    char       lfn1[16];           // buffer for one partial cname
1586    char       lfn2[16];           // buffer for one partial cname
1587    char       lfn3[16];           // buffer for one partial cname
1588    xptr_t     page_xp;            // extended pointer on page descriptor
1589    xptr_t     base_xp;            // extended pointer on page base
1590    uint8_t  * base;               // local pointer on page base
1591    uint8_t    attr;               // directory entry ATTR field
1592    uint8_t    ord;                // directory entry ORD field
1593    uint32_t   seq;                // sequence index
1594    uint32_t   lfn       = 0;      // LFN entries number
1595    uint32_t   offset    = 0;      // byte offset in page
1596    uint32_t   page_id   = 0;      // page index in mapper
1597    uint32_t   dentry_id = 0;      // valid (i.e. copied) dentry index in mapper
1598    uint32_t   dirent_id = 0;      // slot index in dirent array to initialize
1599    bool_t     end       = false;  // true if end of directory found
1600
1601    // loop on mapper pages
1602    while ( (end == false) && (dirent_id < max_dirent) )
1603    {
1604        // get one page from mapper
1605        page_xp = mapper_remote_get_page( mapper_xp , page_id );
1606
1607        if( page_xp == XPTR_NULL) return -1;
1608
1609        // get page base
1610        base_xp = ppm_page2base( page_xp );
1611        base    = (uint8_t *)GET_PTR( base_xp );
1612
1613#if (DEBUG_FATFS_GET_USER_DIR & 0x1)
1614if( DEBUG_FATFS_GET_USER_DIR < cycle )
1615mapper_display_page( mapper_xp , page_id , 256 );
1616#endif
1617        // loop on NORMAL/LFN (32 bytes) directory entries in this page
1618        while( (end == false) && (offset < 4096) )
1619        {
1620            // compute condition to copy one dentry to dirent array
1621            bool_t valid = (dentry_id >= min_dentry) && (dirent_id <  max_dirent );
1622
1623            attr = fatfs_get_record( DIR_ATTR , base + offset , 0 );   
1624            ord  = fatfs_get_record( LDIR_ORD , base + offset , 0 );   
1625
1626            if (ord == NO_MORE_ENTRY)                 // no more entry => break
1627            {
1628                end = true;
1629            }
1630            else if ( ord == FREE_ENTRY )             // free entry => skip
1631            {
1632                offset = offset + 32;
1633            }
1634            else if ( attr == 0x28 )                  // volune_id => skip
1635            {
1636                offset = offset + 32;
1637            }
1638            else if ( attr == ATTR_LONG_NAME_MASK )   // LFN entry
1639            {
1640                if( valid )
1641                {
1642                    // get partial cname
1643                    seq = ord & 0x3;
1644                    lfn = (seq > lfn) ? seq : lfn;   
1645                    if      ( seq == 1 ) fatfs_get_name_from_long( base + offset, lfn1 );
1646                    else if ( seq == 2 ) fatfs_get_name_from_long( base + offset, lfn2 );
1647                    else if ( seq == 3 ) fatfs_get_name_from_long( base + offset, lfn3 );
1648                }
1649                offset = offset + 32;
1650            }
1651            else                                     // NORMAL entry
1652            {
1653                // increment dentry_id
1654                dentry_id++;
1655
1656                if( valid )
1657                {
1658                    // build the complete cname
1659                    if      ( lfn == 0 )
1660                    {
1661                        fatfs_get_name_from_short( base + offset , cname );
1662                    }
1663                    else if ( lfn == 1 )
1664                    {
1665                        strcpy( cname      , lfn1 );
1666                    }   
1667                    else if ( lfn == 2 ) 
1668                    {
1669                        strcpy( cname      , lfn1 );
1670                        strcpy( cname + 13 , lfn2 );
1671                    }
1672                    else if ( lfn == 3 ) 
1673                    {
1674                        strcpy( cname      , lfn1 );
1675                        strcpy( cname + 13 , lfn2 );
1676                        strcpy( cname + 26 , lfn3 );
1677                    }
1678                   
1679                    // copy cname into dirent array
1680                    strcpy( array[dirent_id].d_name , cname ); 
1681
1682                    // increment dirent_id
1683                    dirent_id++;
1684                }
1685                offset = offset + 32;
1686                lfn    = 0;
1687            }
1688        }  // end loop on directory entries in page
1689
1690        page_id++;
1691        offset = 0;
1692
1693    }  // end loop on pages
1694
1695    // return result of scan
1696    *done    = end;
1697    *entries = dirent_id;
1698
1699#if DEBUG_FATFS_GET_USER_DIR
1700cycle = (uint32_t)hal_get_cycles();
1701if( DEBUG_FATFS_GET_USER_DIR < cycle )
1702printk("\n[%s]  thread[%x,%x] exit for inode <%s> / %d entries / cycle %d\n",
1703__FUNCTION__, this->process->pid, this->trdid, inode_name, dirent_id, cycle );
1704#endif
1705
1706    return 0;
1707
1708}  // end fatfs_get_user_dir()
1709
1710///////////////////////////////////////////////
1711error_t fatfs_sync_inode( vfs_inode_t * inode )
1712{
1713
1714// check inode pointer and cluster index
1715assert( (inode != NULL)                  , "inode pointer undefined\n" );
1716assert( (inode->mapper != NULL )         , "mapper pointer undefined\n" );
1717assert( (inode->type == INODE_TYPE_FILE) , "inode must be a file\n" );     
1718
1719#if DEBUG_FATFS_SYNC_INODE
1720char       name[CONFIG_VFS_MAX_NAME_LENGTH];
1721uint32_t   cycle = (uint32_t)hal_get_cycles();
1722thread_t * this  = CURRENT_THREAD;
1723vfs_inode_get_name( XPTR( local_cxy , inode ) , name );
1724if( DEBUG_FATFS_SYNC_INODE < cycle )
1725printk("\n[%s] thread[%x,%x] enter for <%s> / cycle %d\n",
1726__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
1727#endif
1728
1729    error_t    error;
1730    mapper_t * mapper;
1731    page_t   * page;
1732    uint32_t   page_id;
1733
1734    // get mapper from inode
1735    mapper = inode->mapper;
1736
1737    // compute max number of pages in mapper from file size
1738    uint32_t size  = inode->size;
1739    uint32_t pages = size >> CONFIG_PPM_PAGE_SHIFT;
1740    if( size & CONFIG_PPM_PAGE_MASK ) pages++; 
1741         
1742    // get pointer on mapper radix tree
1743    grdxt_t * rt = &mapper->rt;
1744
1745    // scan all pages
1746    for( page_id = 0 ; page_id < pages ; page_id++ )
1747    {
1748        // get page descriptor from mapper
1749        page = grdxt_lookup( rt , page_id );
1750
1751        // check all existing pages
1752        if ( page != NULL )
1753        {
1754            if ( page->flags & PG_DIRTY )
1755            {
1756
1757#if (DEBUG_FATFS_SYNC_INODE & 1)
1758if( DEBUG_FATFS_SYNC_INODE < cycle )
1759printk("\n[%s] thread[%x,%x] synchronizes page %d from <%s> mapper to IOC device\n",
1760__FUNCTION__, page_id, name );
1761#endif
1762                // build extended pointer on page descriptor
1763                xptr_t page_xp = XPTR( local_cxy , page );
1764
1765                // move page from mapper to device
1766                error = fatfs_move_page( page_xp , IOC_WRITE );
1767
1768                if ( error )  return -1;
1769
1770                // reset page dirty flag
1771                ppm_page_undo_dirty( page_xp );
1772            }
1773        }
1774    }  // end loop on pages
1775
1776#if DEBUG_FATFS_SYNC_INODE
1777cycle = (uint32_t)hal_get_cycles();
1778if( DEBUG_FATFS_SYNC_INODE < cycle )
1779printk("\n[%s] thread[%x,%x] exit for <%s> / cycle %d\n",
1780__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
1781#endif
1782
1783    return 0;
1784
1785}  // end fatfs_sync_inode()
1786
1787//////////////////////////////
1788error_t fatfs_sync_fat( void )
1789{
1790
1791#if DEBUG_FATFS_SYNC_FAT
1792uint32_t   cycle = (uint32_t)hal_get_cycles();
1793thread_t * this  = CURRENT_THREAD;
1794if( DEBUG_FATFS_SYNC_FAT < cycle )
1795printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
1796__FUNCTION__ , this->process->pid, this->trdid, cycle );
1797#endif
1798
1799    uint32_t   page_id;
1800    error_t    error;
1801
1802    // get FAT mapper pointers an cluster
1803    fatfs_ctx_t * fatfs_ctx  = fs_context[FS_TYPE_FATFS].extend;
1804    xptr_t        mapper_xp  = fatfs_ctx->fat_mapper_xp;
1805    cxy_t         mapper_cxy = GET_CXY( mapper_xp );
1806    mapper_t    * mapper_ptr = GET_PTR( mapper_xp );
1807
1808    // compute max number of 4 Kbytes pages in FAT mapper
1809    // TODO : this could be improved (see fatfs.h) [AG]
1810    uint32_t   pages = fatfs_ctx->fat_sectors_count >> 3;
1811         
1812    // get pointers on remote FAT mapper radix tree
1813    grdxt_t  * rt_ptr = &mapper_ptr->rt;
1814    xptr_t     rt_xp  = XPTR( mapper_cxy , rt_ptr );
1815
1816    // scan all pages
1817    for( page_id = 0 ; page_id < pages ; page_id++ )
1818    {
1819        // get extended pointer on page descriptor from FAT mapper
1820        xptr_t page_xp = grdxt_remote_lookup( rt_xp , page_id );
1821
1822        // check all existing pages
1823        if ( page_xp != XPTR_NULL )
1824        {
1825            page_t * page_ptr = GET_PTR( page_xp );
1826            uint32_t flags    = hal_remote_l32( XPTR( mapper_cxy , &page_ptr->flags ) );
1827
1828            if ( flags & PG_DIRTY )
1829            {
1830
1831#if (DEBUG_FATFS_SYNC_FAT & 1)
1832if( DEBUG_FATFS_SYNC_FAT < cycle )
1833printk("\n[%s] thread[%x,%x] synchronizes page %d from FAT mapper to IOC device\n",
1834__FUNCTION__, page_id );
1835#endif
1836                // move page from mapper to device
1837                error = fatfs_move_page( page_xp , IOC_SYNC_WRITE );
1838
1839                if ( error )  return -1;
1840
1841                // reset page dirty flag
1842                ppm_page_undo_dirty( page_xp );
1843            }
1844        }
1845    }  // end loop on pages
1846
1847#if DEBUG_FATFS_SYNC_FAT
1848cycle = (uint32_t)hal_get_cycles();
1849if( DEBUG_FATFS_SYNC_FAT < cycle )
1850printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
1851__FUNCTION__ , this->process->pid, this->trdid, cycle );
1852#endif
1853
1854    return 0;
1855
1856}  // end fatfs_sync_fat()
1857
1858////////////////////////////////////
1859error_t fatfs_sync_free_info( void )
1860{
1861
1862#if DEBUG_FATFS_SYNC_FSINFO
1863uint32_t   cycle = (uint32_t)hal_get_cycles();
1864thread_t * this  = CURRENT_THREAD;
1865if( DEBUG_FATFS_SYNC_FSINFO < cycle )
1866printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
1867__FUNCTION__ , this->process->pid, this->trdid, cycle );
1868#endif
1869
1870    uint8_t     * buffer;   // dynamically allocated aligned 512 bytes buffer
1871    kmem_req_t    req;
1872    error_t       error;
1873
1874    // get FS_INFO lba, free_ from FATFS context
1875    fatfs_ctx_t * fatfs_ctx  = fs_context[FS_TYPE_FATFS].extend;
1876    uint32_t      lba        = fatfs_ctx->fs_info_lba;
1877    uint32_t      hint       = fatfs_ctx->free_cluster_hint;
1878    uint32_t      number     = fatfs_ctx->free_clusters;
1879
1880    // allocate buffer to store the FS_INFO sector
1881        req.type    = KMEM_512_BYTES;
1882    req.flags   = AF_KERNEL | AF_ZERO;
1883        buffer      = (uint8_t *)kmem_alloc( &req );
1884    if( buffer == NULL ) 
1885    {
1886        printk("\n[PANIC] in %s : cannot allocate buffer\n", __FUNCTION__ );
1887        return ENOMEM;
1888    }
1889     
1890    // load the FS_INFO sector from device to buffer
1891    error = dev_ioc_read( buffer , lba , 1 );
1892    if ( error )
1893    {
1894        printk("\n[PANIC] in %s : cannot read FS_INFO record\n", __FUNCTION__ );
1895        return EIO;
1896    }
1897
1898    // update buffer
1899    fatfs_set_record( FS_FREE_CLUSTERS     , buffer , 1 , number );
1900    fatfs_set_record( FS_FREE_CLUSTER_HINT , buffer , 1 , hint );
1901
1902    // write modified FS_INFO sector from buffer to device
1903    error = dev_ioc_write( buffer , lba , 1 );
1904    if ( error )
1905    {
1906        printk("\n[PANIC] in %s : cannot write FS_INFO record\n", __FUNCTION__ );
1907        return EIO;
1908    }
1909
1910    // release the 512 bytes buffer
1911    req.type = KMEM_512_BYTES;
1912    req.ptr  = buffer;
1913    kmem_free( &req );
1914
1915#if DEBUG_FATFS_SYNC_FSINFO
1916cycle = (uint32_t)hal_get_cycles();
1917if( DEBUG_FATFS_SYNC_FSINFO < cycle )
1918printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
1919__FUNCTION__ , this->process->pid, this->trdid, cycle );
1920#endif
1921
1922    return 0;
1923
1924}  // end fatfs_sync_fs_info()
1925
1926//////////////////////////////////////////////////////////
1927error_t fatfs_cluster_alloc( uint32_t * searched_cluster )
1928{
1929    uint32_t      page_id;        // page index in mapper
1930    uint32_t      slot_id;        // slot index in page (1024 slots per page)
1931    uint32_t      hint;           // first free cluster index in FAT
1932    uint32_t      free_clusters;  // total number of free clusters
1933    vfs_ctx_t   * vfs_ctx;        // local pointer on VFS context (same in all clusters)
1934    fatfs_ctx_t * loc_fatfs_ctx;  // local pointer on local FATFS context
1935    fatfs_ctx_t * fat_fatfs_ctx;  // local pointer on FATFS context in FAT cluster
1936    xptr_t        mapper_xp;      // extended pointer on FAT mapper
1937    cxy_t         mapper_cxy;     // Fat mapper cluster identifier
1938    xptr_t        page_xp;        // extended pointer on current page descriptor in mapper
1939    xptr_t        slot_xp;        // extended pointer on FAT slot defined by hint
1940    xptr_t        lock_xp;        // extended pointer on lock protecting free clusters info
1941    xptr_t        hint_xp;        // extended pointer on free_cluster_hint in FAT cluster
1942    xptr_t        numb_xp;        // extended pointer on free_clusters_number in FAT cluster
1943
1944#if DEBUG_FATFS_CLUSTER_ALLOC
1945uint32_t   cycle = (uint32_t)hal_get_cycles();
1946thread_t * this  = CURRENT_THREAD;
1947if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
1948printk("\n[%s] thread[%x,%x] enter / cycle = %d\n",
1949__FUNCTION__, this->process->pid, this->trdid, cycle );
1950#endif
1951
1952    // get local pointer on VFS context (same in all clusters)
1953    vfs_ctx = &fs_context[FS_TYPE_FATFS];
1954
1955    // get local pointer on local FATFS context
1956    loc_fatfs_ctx = vfs_ctx->extend;
1957
1958    // get extended pointer and cluster on FAT mapper
1959    mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
1960    mapper_cxy = GET_CXY( mapper_xp );
1961   
1962    // get local pointer on FATFS context in FAT cluster
1963    fat_fatfs_ctx = hal_remote_lpt( XPTR( mapper_cxy , &vfs_ctx->extend ) );
1964
1965    // build relevant extended pointers in on free clusters info in FAT cluster
1966    lock_xp = XPTR( mapper_cxy , &fat_fatfs_ctx->free_lock );
1967    hint_xp = XPTR( mapper_cxy , &fat_fatfs_ctx->free_cluster_hint );
1968    numb_xp = XPTR( mapper_cxy , &fat_fatfs_ctx->free_clusters );
1969
1970    // take the lock protecting free clusters
1971    remote_queuelock_acquire( lock_xp );
1972
1973    // get hint and free_clusters values from FATFS context
1974    hint          = hal_remote_l32( hint_xp );
1975    free_clusters = hal_remote_l32( numb_xp );
1976       
1977    // get page index & slot index for the first free cluster
1978    page_id  = (hint + 1) >> 10;
1979    slot_id  = (hint + 1) & 0x3FF;
1980
1981    // get relevant page from mapper
1982    page_xp = mapper_remote_get_page( mapper_xp , page_id );
1983
1984    if( page_xp == XPTR_NULL )
1985    {
1986        printk("\n[ERROR] in %s : cannot acces FAT mapper\n", __FUNCTION__ );
1987        return -1;
1988    }
1989
1990    // build extended pointer on free cluster slot
1991    slot_xp = ppm_page2base( page_xp ) + (slot_id<<2);
1992         
1993#if (DEBUG_FATFS_CLUSTER_ALLOC & 1)
1994if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
1995printk("\n[%s] thread[%x,%x] get free info / hint %x / free_clusters %x\n",
1996__FUNCTION__, this->process->pid, this->trdid, hint, free_clusters );
1997#endif
1998
1999    // check "free_clusters"
2000    if ( free_clusters == 0 )
2001    {
2002        printk("\n[ERROR] in %s : no more free FATFS clusters\n", __FUNCTION__ );
2003        remote_queuelock_acquire( lock_xp );
2004        return -1;
2005    }
2006    else if ( free_clusters < CONFIG_VFS_FREE_CLUSTERS_MIN )
2007    {
2008        printk("\n[WARNING] in %s : only %n free FATFS clusters\n", 
2009        __FUNCTION__, CONFIG_VFS_FREE_CLUSTERS_MIN );
2010    }
2011
2012    // check "hint"
2013    if( hal_remote_l32( slot_xp ) != FREE_CLUSTER )
2014    { 
2015        printk("\n[ERROR] in %s : illegal hint cluster\n", __FUNCTION__ );
2016        remote_queuelock_acquire( lock_xp );
2017        return -1;
2018    }
2019
2020    // update allocated cluster in FAT mapper
2021    hal_remote_s32( slot_xp , END_OF_CHAIN_CLUSTER_MAX );
2022
2023    // update free cluster info
2024    fatfs_free_clusters_decrement( hint + 1 );
2025
2026    // release free clusters busylock
2027    remote_queuelock_release( lock_xp );
2028
2029#if DEBUG_FATFS_CLUSTER_ALLOC
2030cycle = (uint32_t)hal_get_cycles();
2031if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
2032printk("\n[%s] thread[%x,%x] exit / cluster %x / cycle %d\n",
2033__FUNCTION__, this->process->pid, this->trdid, hint + 1, cycle );
2034#endif
2035
2036    *searched_cluster = hint + 1;
2037    return 0;
2038
2039}  // end fat_cluster_alloc()
2040
2041//////////////////////////////////////////////
2042error_t fatfs_release_inode( xptr_t inode_xp )
2043{
2044    vfs_ctx_t   * vfs_ctx;        // local pointer on VFS context (same in all clusters).
2045    fatfs_ctx_t * loc_fatfs_ctx;  // local pointer on local FATFS context
2046    fatfs_ctx_t * fat_fatfs_ctx;  // local pointer on FATFS context in FAT cluster
2047    xptr_t        mapper_xp;      // extended pointer on FAT mapper
2048    cxy_t         mapper_cxy;     // Fat mapper cluster identifier
2049    xptr_t        lock_xp;        // extended pointer on lock protecting free clusters info.
2050    xptr_t        first_xp;       // extended pointer on inode extension
2051    uint32_t      first_cluster;  // first cluster index for released inode
2052    vfs_inode_t * inode_ptr;
2053    cxy_t         inode_cxy;
2054
2055// check inode pointer
2056assert( (inode_xp != XPTR_NULL) , "inode pointer is NULL\n" );
2057
2058    // get first_cluster from inode extension
2059    inode_ptr     = GET_PTR( inode_xp );
2060    inode_cxy     = GET_CXY( inode_xp );
2061    first_xp      = XPTR( inode_cxy , &inode_ptr->extend );
2062    first_cluster = (uint32_t)(intptr_t)hal_remote_lpt( first_xp );
2063
2064// check first cluster index
2065assert( (first_cluster != 0) , "inode extend is NULL\n" );
2066
2067#if DEBUG_FATFS_RELEASE_INODE
2068char       name[CONFIG_VFS_MAX_NAME_LENGTH];
2069uint32_t   cycle = (uint32_t)hal_get_cycles();
2070thread_t * this  = CURRENT_THREAD;
2071vfs_inode_get_name( inode_xp , name );
2072if( DEBUG_FATFS_RELEASE_INODE < cycle )
2073printk("\n[%s] thread[%x,%x] enter for <%s> / first_cluster %x / cycle %d\n",
2074__FUNCTION__ , this->process->pid, this->trdid, name, first_cluster, cycle );
2075#endif
2076
2077    // get local pointer on VFS context (same in all clusters)
2078    vfs_ctx = &fs_context[FS_TYPE_FATFS];
2079
2080    // get local pointer on local FATFS context
2081    loc_fatfs_ctx = vfs_ctx->extend;
2082
2083    // get extended pointer and cluster on FAT mapper
2084    mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
2085    mapper_cxy = GET_CXY( mapper_xp );
2086   
2087    // get local pointer on FATFS context in FAT cluster
2088    fat_fatfs_ctx = hal_remote_lpt( XPTR( mapper_cxy , &vfs_ctx->extend ) );
2089
2090    // get extended pointer on free clusters lock in FAT cluster
2091    lock_xp = XPTR( mapper_cxy , &fat_fatfs_ctx->free_lock );
2092
2093    // take lock protecting free clusters
2094    remote_queuelock_acquire( lock_xp );
2095
2096    // call the recursive function to release all clusters from FAT mapper
2097    if ( fatfs_recursive_release( mapper_xp , first_cluster ) )
2098    {
2099        printk("\n[ERROR] in %s : cannot update FAT mapper\n", __FUNCTION__ );
2100        remote_queuelock_release( lock_xp );
2101        return -1;
2102    }
2103
2104    // release lock protecting free cluster
2105    remote_queuelock_release( lock_xp );
2106
2107#if (DEBUG_FATFS_RELEASE_INODE & 1)
2108if( DEBUG_FATFS_RELEASE_INODE < cycle )
2109printk("\n[%s] inode <%s> removed from FAT mapper\n", __FUNCTION__, name );
2110#endif
2111
2112    // update FAT on IOC device (from FAT mapper)
2113    if ( fatfs_sync_fat() )
2114    {
2115        printk("\n[ERROR] in %s : cannot update FAT on device\n", __FUNCTION__ );
2116        return -1;
2117    }
2118
2119#if (DEBUG_FATFS_RELEASE_INODE & 1)
2120if( DEBUG_FATFS_RELEASE_INODE < cycle )
2121printk("\n[%s] inode <%s> removed from FAT on IOC device\n", __FUNCTION__, name );
2122#endif
2123
2124    // update FS-INFO sector on IOC device (from FATFS context)
2125    if ( fatfs_sync_free_info() )
2126    {
2127        printk("\n[ERROR] in %s: cannot update FS_INFO on device\n", __FUNCTION__ );
2128        return -1;
2129    }
2130
2131#if DEBUG_FATFS_RELEASE_INODE
2132cycle = (uint32_t)hal_get_cycles();
2133if( DEBUG_FATFS_RELEASE_INODE < cycle )
2134printk("\n[%s] thread[%x,%x] removed <%s> inode from FATFS / cycle %d\n",
2135__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
2136#endif
2137
2138    return 0;
2139
2140}  // end fatfs_release_inode()
2141
2142////////////////////////////////////////////
2143error_t fatfs_move_page( xptr_t     page_xp,
2144                         cmd_type_t cmd_type )
2145{
2146    error_t       error;
2147    vfs_inode_t * inode_ptr;
2148    mapper_t    * mapper_ptr;     
2149    uint32_t      page_id;     // page index in mapper
2150
2151#if DEBUG_FATFS_MOVE_PAGE
2152uint32_t   cycle = (uint32_t)hal_get_cycles();
2153thread_t * this  = CURRENT_THREAD;
2154char       name[CONFIG_VFS_MAX_NAME_LENGTH];
2155#endif
2156
2157    // get page cluster an local pointer
2158    cxy_t    page_cxy = GET_CXY( page_xp );
2159    page_t * page_ptr = GET_PTR( page_xp );
2160
2161    // get mapper pointer and page index from page descriptor
2162    mapper_ptr = hal_remote_lpt( XPTR( page_cxy , &page_ptr->mapper ) );
2163    page_id    = hal_remote_l32( XPTR( page_cxy , &page_ptr->index ) );
2164
2165    // get pointer on local FATFS context
2166    fatfs_ctx_t * fatfs_ctx = fs_context[FS_TYPE_FATFS].extend;
2167
2168    // get page base address
2169    xptr_t    base_xp = ppm_page2base( page_xp );
2170    uint8_t * buffer  = (uint8_t *)GET_PTR( base_xp );
2171 
2172    // get inode pointer from mapper
2173    inode_ptr  = hal_remote_lpt( XPTR( page_cxy , &mapper_ptr->inode ) );
2174
2175    ////////////////////////////// it is the FAT mapper
2176    if( inode_ptr == NULL )
2177    {
2178        // get lba from FATFS context and page_id
2179        uint32_t      lba        = fatfs_ctx->fat_begin_lba + (page_id << 3);
2180 
2181        // access device
2182        if     ( cmd_type == IOC_SYNC_READ  ) error = dev_ioc_sync_read ( buffer , lba , 8 );
2183        else if( cmd_type == IOC_SYNC_WRITE ) error = dev_ioc_sync_write( buffer , lba , 8 );
2184        else if( cmd_type == IOC_READ       ) error = dev_ioc_read      ( buffer , lba , 8 );
2185        else if( cmd_type == IOC_WRITE      ) error = dev_ioc_write     ( buffer , lba , 8 );
2186        else                                  error = -1;
2187
2188        if( error ) return EIO;
2189
2190#if (DEBUG_FATFS_MOVE_PAGE & 0x1)
2191if( DEBUG_FATFS_MOVE_PAGE < cycle )
2192mapper_display_page( XPTR(page_cxy , mapper_ptr) , page_id );
2193#endif
2194
2195#if DEBUG_FATFS_MOVE_PAGE
2196cycle = (uint32_t)hal_get_cycles();
2197if( DEBUG_FATFS_MOVE_PAGE < cycle )
2198{
2199    if ( (cmd_type == IOC_READ) || (cmd_type == IOC_SYNC_READ) )
2200         printk("\n[%s] thread[%x,%x] load page %d of FAT / cycle %d\n",
2201         __FUNCTION__, this->process->pid, this->trdid, page_id, cycle );
2202    else
2203        printk("\n[%s] thread[%x,%x] sync page %d of FAT / cycle %d\n",
2204        __FUNCTION__, this->process->pid, this->trdid, page_id, cycle );
2205}
2206#endif
2207
2208    }
2209    ///////////////////////// it is an inode mapper
2210    else                       
2211    {
2212
2213#if DEBUG_FATFS_MOVE_PAGE
2214vfs_inode_get_name( XPTR( page_cxy , inode_ptr ) , name );
2215#endif
2216
2217        uint32_t  searched_cluster;
2218        uint32_t  first_cluster;
2219
2220        // get first_cluster from inode extension
2221        void * extend = hal_remote_lpt( XPTR( page_cxy , &inode_ptr->extend ) );
2222        first_cluster = (uint32_t)(intptr_t)extend;
2223
2224        // compute searched_cluster
2225        if( page_id == 0 )            // no need to access FAT mapper
2226        {
2227            // searched cluster is first cluster
2228            searched_cluster = first_cluster;
2229        }
2230        else                        // FAT mapper access required
2231        {
2232            // access FAT mapper to get searched cluster
2233            error = fatfs_get_cluster( first_cluster,
2234                                       page_id,
2235                                       &searched_cluster );
2236            if( error )  return EIO;
2237        }
2238
2239        // get lba from searched_cluster
2240        uint32_t lba = fatfs_lba_from_cluster( fatfs_ctx , searched_cluster );
2241
2242        // access device
2243        if     ( cmd_type == IOC_SYNC_READ  ) error = dev_ioc_sync_read ( buffer , lba , 8 );
2244        else if( cmd_type == IOC_SYNC_WRITE ) error = dev_ioc_sync_write( buffer , lba , 8 );
2245        else if( cmd_type == IOC_READ       ) error = dev_ioc_read      ( buffer , lba , 8 );
2246        else if( cmd_type == IOC_WRITE      ) error = dev_ioc_write     ( buffer , lba , 8 );
2247        else                                  error = -1;
2248
2249        if( error ) return EIO;
2250
2251#if (DEBUG_FATFS_MOVE_PAGE & 0x1)
2252if( DEBUG_FATFS_MOVE_PAGE < cycle )
2253mapper_display_page( XPTR(page_cxy , mapper_ptr) , page_id );
2254#endif
2255
2256#if DEBUG_FATFS_MOVE_PAGE
2257cycle = (uint32_t)hal_get_cycles();
2258if(DEBUG_FATFS_MOVE_PAGE < cycle)
2259{
2260    if ( (cmd_type == IOC_READ) || (cmd_type == IOC_SYNC_READ) )
2261        printk("\n[%s] thread[%x,%x] load page %d of <%s> inode / cycle %d\n",
2262        __FUNCTION__, this->process->pid, this->trdid, page_id, name, cycle );
2263    else
2264        printk("\n[%s] thread[%x,%x] sync page %d of <%s> inode / cycle %d\n",
2265        __FUNCTION__, this->process->pid, this->trdid, page_id, name, cycle );
2266}
2267#endif
2268
2269    }
2270
2271    return 0;
2272
2273}  // end fatfs_move_page()
2274
2275
Note: See TracBrowser for help on using the repository browser.