/* * fatfs.c - FATFS file system API implementation. * * Author Alain Greiner (2016,2017,2018,2019) * * Copyright (c) UPMC Sorbonne Universites * * This file is part of ALMOS-MKH. * * ALMOS-MKH is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2.0 of the License. * * ALMOS-MKH is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ALMOS-MKH; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define LITTLE_ENDIAN 1 ////////////////////////////////////////////////////////////////////////////////////////// // Extern variables ////////////////////////////////////////////////////////////////////////////////////////// extern vfs_ctx_t fs_context[FS_TYPES_NR]; // allocated in kernel_init.c file ////////////////////////////////////////////////////////////////////////////////////////// // FATFS specific static functions ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// // These functions return the "offset" and "length" values of an // [offset,length] constant defined in the fatfs.h file. ////////////////////////////////////////////////////////////////////////////////////////// static inline int get_length( int offset __attribute__((unused)), int length ) { return length; } static inline int get_offset( int offset, int length __attribute__((unused)) ) { return offset; } ////////////////////////////////////////////////////////////////////////////////////////// // This static function returns the LBA of the first sector of a FAT cluster. // This function can be called by any thread running in any cluster. ////////////////////////////////////////////////////////////////////////////////////////// // @ ctx : pointer on FATFS context. // @ cluster : cluster index in FATFS. // @ return the lba value. ////////////////////////////////////////////////////////////////////////////////////////// static inline uint32_t fatfs_lba_from_cluster( fatfs_ctx_t * ctx, uint32_t cluster ) { return (ctx->cluster_begin_lba + ((cluster - 2) << 3)); } ////////////////////////////////////////////////////////////////////////////////////////// // This function return an integer record value (one, two, or four bytes) from a local // array of bytes, taking into account the global LITTLE_ENDIAN parameter: // if LITTLE_ENDIAN is true, the most significant byte has the highest address. ////////////////////////////////////////////////////////////////////////////////////////// // @ offset : first byte in array. // @ nbytes : record length in bytes (1/2/4). // @ buffer : local pointer on byte array. // @ return the integer value in a 32 bits word. ////////////////////////////////////////////////////////////////////////////////////////// static uint32_t fatfs_get_record( uint32_t offset, uint32_t nbytes, uint8_t * buffer ) { uint32_t i; uint32_t res = 0; if ( LITTLE_ENDIAN ) { for( i = nbytes ; i > 0 ; i-- ) res = (res<<8) | buffer[offset+i-1]; } else { for( i = 0 ; i < nbytes ; i++ ) res = (res<<8) | buffer[offset+i]; } return res; } // end fatfs_get_record() ////////////////////////////////////////////////////////////////////////////////////////// // This function return an integer record value (one, two, or four bytes) from a remote // array of bytes, taking into account the global LITTLE_ENDIAN parameter: // if LITTLE_ENDIAN is true, the most significant byte has the highest address. ////////////////////////////////////////////////////////////////////////////////////////// // @ offset : first byte in array. // @ nbytes : record length in bytes (1/2/4). // @ buffer_xp : extended pointer on byte array. // @ return the integer value in a 32 bits word. ////////////////////////////////////////////////////////////////////////////////////////// static uint32_t fatfs_get_remote_record( uint32_t offset, uint32_t nbytes, xptr_t buffer_xp ) { uint32_t i; uint32_t res = 0; if ( LITTLE_ENDIAN ) { for( i = nbytes ; i > 0 ; i-- ) { res = (res<<8) | hal_remote_lb( buffer_xp+offset+i-1 ); } } else { for( i = 0 ; i < nbytes ; i++ ) { res = (res<<8) | hal_remote_lb( buffer_xp+offset+i ); } } return res; } // end fatfs_get_remote_record() ////////////////////////////////////////////////////////////////////////////////////////// // This function writes one, two, or four bytes from a 32 bits integer to a local // array of bytes, taking into account the global LITTLE_ENDIAN parameter: // if LITTLE_ENDIAN is true, the most significant byte has the highest address. ////////////////////////////////////////////////////////////////////////////////////////// // @ offset : first byte in array. // @ nbytes : record length in bytes (1/2/4). // @ buffer : local pointer on byte array. // @ value : 32 bits integer value. ////////////////////////////////////////////////////////////////////////////////////////// static void fatfs_set_record( uint32_t offset, uint32_t nbytes, uint8_t * buffer, uint32_t value ) { uint32_t i; if ( LITTLE_ENDIAN ) { for( i = nbytes ; i > 0 ; i-- ) buffer[offset+i-1] = (uint8_t)(value>>((i-1)<<3)); } else { for( i = 0 ; i < nbytes ; i++ ) buffer[offset+i] = (uint8_t)(value>>((nbytes-1-i)<<3)); } } // end fatfs_set_record() ////////////////////////////////////////////////////////////////////////////////////////// // This function writes one, two, or four bytes from a 32 bits integer to a remote // array of bytes, taking into account the global LITTLE_ENDIAN parameter: // if LITTLE_ENDIAN is true, the most significant byte has the highest address. ////////////////////////////////////////////////////////////////////////////////////////// // @ offset : first byte in array. // @ nbytes : record length in bytes (1/2/4). // @ buffer_xp : extended pointer on byte array. // @ value : 32 bits integer value. ////////////////////////////////////////////////////////////////////////////////////////// static void fatfs_set_remote_record( uint32_t offset, uint32_t nbytes, xptr_t buffer_xp, uint32_t value ) { uint32_t i; if ( LITTLE_ENDIAN ) { for( i = nbytes ; i > 0 ; i-- ) { hal_remote_sb( (buffer_xp+offset+i-1) , (uint8_t)(value>>((i-1)<<3)) ); } } else { for( i = 0 ; i < nbytes ; i++ ) { hal_remote_sb( (buffer_xp+offset+i) , (uint8_t)(value>>((nbytes-1-i)<<3)) ); } } } // end fatfs_set_record() ////////////////////////////////////////////////////////////////////////////////////////// // This static function retun in the buffer a short name stored in // a SFN FATFS directory entry. /////////////////////////i//////////////////////////////////////////////////////////////// // @ buffer : pointer on buffer containing the directory entry. // @ name : [out] buffer allocated by the caller. ////////////////////////////////////////////////////////////////////////////////////////// static void fatfs_get_name_from_short( uint8_t * buffer, char * name ) { uint32_t i; uint32_t j = 0; // get name for ( i = 0; i < 8 && buffer[i] != ' '; i++ ) { name[j] = to_lower( buffer[i] ); j++; } // get extension for ( i = 8; i < 8 + 3 && buffer[i] != ' '; i++ ) { // we entered the loop so there is an extension. add the dot if ( i == 8 ) { name[j] = '.'; j++; } name[j] = to_lower( buffer[i] ); j++; } name[j] = '\0'; } // fatfs_get_name_from_short() ////////////////////////////////////////////////////////////////////////////////////////// // This static function retun in the buffer a partial name stored in // a LFN FATFS directory entry. /////////////////////////i//////////////////////////////////////////////////////////////// // @ buffer : pointer on buffer containing the directory entry. // @ name : [out] buffer allocated by the caller. ////////////////////////////////////////////////////////////////////////////////////////// static void fatfs_get_name_from_long( uint8_t * buffer, char * name ) { uint32_t name_offset = 0; uint32_t buffer_offset = get_length(LDIR_ORD); uint32_t l_name_1 = get_length(LDIR_NAME_1); uint32_t l_name_2 = get_length(LDIR_NAME_2); uint32_t l_name_3 = get_length(LDIR_NAME_3); uint32_t l_attr = get_length(LDIR_ATTR); uint32_t l_type = get_length(LDIR_TYPE); uint32_t l_chksum = get_length(LDIR_CHKSUM); uint32_t l_rsvd = get_length(LDIR_RSVD); uint32_t j = 0; uint32_t eof = 0; while ( (buffer_offset != DIR_ENTRY_SIZE) && (!eof) ) { while (j != l_name_1 && !eof ) { if ( (buffer[buffer_offset] == 0x00) || (buffer[buffer_offset] == 0xFF) ) { eof = 1; continue; } name[name_offset] = buffer[buffer_offset]; buffer_offset += 2; j += 2; name_offset++; } buffer_offset += (l_attr + l_type + l_chksum); j = 0; while (j != l_name_2 && !eof ) { if ( (buffer[buffer_offset] == 0x00) || (buffer[buffer_offset] == 0xFF) ) { eof = 1; continue; } name[name_offset] = buffer[buffer_offset]; buffer_offset += 2; j += 2; name_offset++; } buffer_offset += l_rsvd; j = 0; while (j != l_name_3 && !eof ) { if ( (buffer[buffer_offset] == 0x00) || (buffer[buffer_offset] == 0xFF) ) { eof = 1; continue; } name[name_offset] = buffer[buffer_offset]; buffer_offset += 2; j += 2; name_offset++; } } name[name_offset] = 0; } // end fatfs_get_name_from_long() ////////////////////////////////////////////////////////////////////////////////////////// // This static function analyse the input argument, and returns in other // output arguments various informations required to store the name in FATFS directory. // The length cannot be larger than 31 characters : // - Short name (less than 13 characters) require 1 LFN entry. // - Medium names (from 14 to 26 characters require 2 LFN entries. // - Large names (up to 31 characters) require 3 LFN entries. ////////////////////////////////////////////////////////////////////////////////////////// // @ name : [in] complete directory entry name. // @ length : [out] total number of characters in name. // @ nb_lfn : [out] number of LFN entries required to store the name. // @ sfn : [out] a legal SFN name extracted from name / upper case and 8-3 format. // @ checksum : [out] checksum to be stored in SFN. // @ returns 0 on success / returns 1 if the name length is larger than 31 characters. ////////////////////////////////////////////////////////////////////////////////////////// static error_t fatfs_name_format( const char * name, uint32_t * length, uint32_t * nb_lfn, char * sfn, uint8_t * checksum ) { // compute name length uint32_t name_length = strlen( name ); *length = name_length; uint32_t suffix_length = 0; uint32_t prefix_length = 0; uint32_t dot_found = 0; uint32_t i; // compute prefix and suffix length // only the last '.' is taken into account for ( i=0 ; i>1)) + sfn[i]; } *checksum = sum; // set nb_lfn and length values if ( name_length <= 13 ) { *nb_lfn = 1; return 0; } else if ( name_length <= 26 ) { *nb_lfn = 2; return 0; } else if ( name_length <= 31 ) { *nb_lfn = 3; return 0; } else { return 1; } } // end fatfs_name_format() ////////////////////////////////////////////////////////////////////////////////////////// // This static function synchronously updates the FAT on IOC device. // It scan the FAT mapper to copy on IOC device all dirty pages in the interval // defined by the & arguments. // It can be called by a thread running in any cluster. // WARNING : We don't take the lock protecting the FAT mapper, because the FAT lock // (in FATFS context) must be taken by the calling function. ////////////////////////////////////////////////////////////////////////////////////////// // @ fatfs_ctx_xp : extended pointer on FATFS context in FAT cluster. // @ page_min : first page to be checked. // @ page_max : last page to be checked // @ return 0 if success, return -1 if the FS_INFO sector cannot be updated. ////////////////////////////////////////////////////////////////////////////////////////// static error_t fatfs_update_ioc_fat( xptr_t fatfs_ctx_xp, uint32_t page_min, uint32_t page_max ) { #if DEBUG_FATFS_UPDATE_IOC uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; if( DEBUG_FATFS_UPDATE_IOC < cycle ) printk("\n[%s] thread[%x,%x] enter / page_min %d / page_max %d / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, page_min, page_max, cycle ); #endif error_t error; cxy_t fat_cxy; // FAT cluster identifier fatfs_ctx_t * fatfs_ctx; // local pointer on FATFS context in FAT cluster xptr_t fat_mapper_xp; // extended pointer on FAT mapper mapper_t * fat_mapper_ptr; // local pointer on FAT mapper uint32_t page_id; // current page index in FAT mapper xptr_t rt_xp; // extended pointer on FAT mapper radix tree xptr_t page_xp; // extended pointer on current page in FAT mapper page_t * page_ptr; // local pointer on current page uint32_t flags; // current page flags // get pointer and cluster on FATFS context in FAT cluster fat_cxy = GET_CXY( fatfs_ctx_xp ); fatfs_ctx = GET_PTR( fatfs_ctx_xp ); // get FAT mapper pointers from FATFS context fat_mapper_xp = hal_remote_l64( XPTR( fat_cxy , &fatfs_ctx->fat_mapper_xp ) ); fat_mapper_ptr = GET_PTR( fat_mapper_xp ); // check FAT cluster assert( (fat_cxy == GET_CXY( fat_mapper_xp )) , "unconsistent FAT cluster" ); // build extended pointer on FAT mapper radix tree rt_xp = XPTR( fat_cxy , &fat_mapper_ptr->rt ); // scan all pages in [min,max] interval for( page_id = page_min ; page_id <= page_max ; page_id++ ) { // get extended pointer on page descriptor from FAT mapper page_xp = grdxt_remote_lookup( rt_xp , page_id ); // check only existing pages if ( page_xp != XPTR_NULL ) { page_ptr = GET_PTR( page_xp ); flags = hal_remote_l32( XPTR( fat_cxy , &page_ptr->flags ) ); // copy only dirty pages if ( flags & PG_DIRTY ) { #if (DEBUG_FATFS_UPDATE_IOC & 1) if( DEBUG_FATFS_UPDATE_IOC < cycle ) printk("\n[%s] thread[%x,%x] copy page %d from FAT mapper to IOC device\n", __FUNCTION__, page_id ); #endif // move page from mapper to device error = fatfs_move_page( page_xp , IOC_SYNC_WRITE ); if ( error ) return -1; // reset page dirty flag ppm_page_undo_dirty( page_xp ); } } } // end loop on pages #if DEBUG_FATFS_UPDATE_IOC cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_UPDATE_IOC < cycle ) printk("\n[%s] thread[%x,%x] exit / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, cycle ); #endif return 0; } // end fatfs_update_ioc_fat() ////////////////////////////////////////////////////////////////////////////////////////// // This static function synchronously updates the FS_INFO sector on IOC device, // from values contained in the FATFS context in FAT cluster. // It uses and updates the FS_INFO buffer allocated in the FAT cluster. // It can be called by a thread running in any cluster. ////////////////////////////////////////////////////////////////////////////////////////// // @ fatfs_ctx_xp : extended pointer on FATFS context in FAT cluster. // @ return 0 if success, return -1 if the FS_INFO sector cannot be updated. ////////////////////////////////////////////////////////////////////////////////////////// static error_t fatfs_update_ioc_fsinfo( xptr_t fatfs_ctx_xp ) { cxy_t fat_cxy; // FAT cluster identifier fatfs_ctx_t * fatfs_ctx_ptr; // local pointer on fatfs context in FAT cluster uint32_t free_clusters; // current vale of "free_clusters" in fatfs context uint32_t free_cluster_hint; // current vale of "free_cluster_hint" in fatfs context uint8_t * fs_info_buffer_ptr; // local pointer on FS_INFO buffer in FAT cluster xptr_t fs_info_buffer_xp; // extended pointer on FS_INFO buffer in FAT cluster uint32_t fs_info_lba; // FS_INFO sector lba on IOC device // get cluster and local pointer on FAT cluster context fat_cxy = GET_CXY( fatfs_ctx_xp ); fatfs_ctx_ptr = GET_PTR( fatfs_ctx_xp ); // force FATFS context update hal_fence(); // get relevant info from fatfs context in FAT cluster fs_info_lba = hal_remote_l32( XPTR( fat_cxy , &fatfs_ctx_ptr->fs_info_lba ) ); free_clusters = hal_remote_l32( XPTR( fat_cxy , &fatfs_ctx_ptr->free_clusters ) ); free_cluster_hint = hal_remote_l32( XPTR( fat_cxy , &fatfs_ctx_ptr->free_cluster_hint ) ); fs_info_buffer_ptr = hal_remote_lpt( XPTR( fat_cxy , &fatfs_ctx_ptr->fs_info_buffer ) ); // build extended pointer on FS_INFO buffer in FAT cluster fs_info_buffer_xp = XPTR( fat_cxy , fs_info_buffer_ptr ); // update the FS_INFO buffer in FAT cluster fatfs_set_remote_record( FS_FREE_CLUSTERS , fs_info_buffer_xp , free_clusters ); fatfs_set_remote_record( FS_FREE_CLUSTER_HINT , fs_info_buffer_xp , free_cluster_hint ); // update the FS_INFO sector on IOC device return dev_ioc_sync_write( fs_info_buffer_xp , fs_info_lba , 1 ); } // end fatfs_update_ioc_fsinfo() ////////////////////////////////////////////////////////////////////////////////////////// // This static function decrements the "free_clusters" variable, and updates the // "free_cluster_hint" variable in the FATFS context in FAT cluster, identified // by the argument, when a new has been allocated from FAT. // It scan all slots in the FAT mapper seen as an array of 32 bits words, looking for the // first free slot larger than the argument, to update "free_cluster_hint". // It synchronously updates the FS_INFO sector on the IOC device. // It can be called by a thead running in any cluster. // The lock protecting exclusive access to the FAT must be taken by the calling function. ////////////////////////////////////////////////////////////////////////////////////////// // @ fatfs_ctx_xp : extended pointer on FATFS context in FAT cluster. // @ cluster : recently allocated cluster index in FAT. // @ return 0 if success, return -1 if the FS_INFO sector cannot be updated. ////////////////////////////////////////////////////////////////////////////////////////// static error_t fatfs_free_clusters_decrement( xptr_t fatfs_ctx_xp, uint32_t cluster ) { error_t error; cxy_t fat_cxy; // FAT cluster identifier fatfs_ctx_t * fat_ctx_ptr; // local pointer on fatfs context in FAT cluster xptr_t fat_mapper_xp; // extended pointer on FAT mapper xptr_t hint_xp; // extended pointer on "free_cluster_hint" shared variable xptr_t numb_xp; // extended pointer on "free_clusters" shared variable uint32_t numb; // "free_clusters" variable current value uint32_t hint; // "free_cluster_hint" variable current value uint32_t page_id; // page index in FAT mapper uint32_t slot_id; // slot index in one page of FAT (1024 slots per page) uint32_t page_max; // max number of pages in FAT mapper xptr_t page_xp; // extended pointer on current page in FAT mapper xptr_t base_xp; // extended pointer on current page base xptr_t slot_xp; // extended pointer on current slot in FAT mapper #if DEBUG_FATFS_FREE_CLUSTERS uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; if( DEBUG_FATFS_FREE_CLUSTERS < cycle ) printk("\n[%s] thread[%x,%x] enter for allocated cluster %x / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, cluster , cycle ); #endif // get FAT cluster an local pointer on fatfs context in FAT cluster fat_cxy = GET_CXY( fatfs_ctx_xp ); fat_ctx_ptr = GET_PTR( fatfs_ctx_xp ); // build extended pointers on free_clusters, and free_cluster_hint in fatfs context hint_xp = XPTR( fat_cxy , &fat_ctx_ptr->free_cluster_hint ); numb_xp = XPTR( fat_cxy , &fat_ctx_ptr->free_clusters ); // update "free_clusters" value numb = hal_remote_l32( numb_xp ) - 1; hal_remote_s32( numb_xp , numb ); // get extended pointer on FAT mapper fat_mapper_xp = hal_remote_l64( XPTR( fat_cxy , &fat_ctx_ptr->fat_mapper_xp ) ); // initialise variables to scan the FAT mapper // and find the first free slot > cluster page_id = (cluster + 1) >> 10; slot_id = (cluster + 1) & 0x3FF; page_max = hal_remote_l32( XPTR( fat_cxy, &fat_ctx_ptr->fat_sectors_count ) ) >> 3; // scan FAT mapper / loop on pages while ( page_id < page_max ) { // get current page from mapper page_xp = mapper_remote_get_page( fat_mapper_xp , page_id ); if( page_xp == XPTR_NULL ) { printk("\n[ERROR] in %s : cannot access FAT mapper\n", __FUNCTION__ ); return -1; } // get extended pointer on page base_xp = ppm_page2base( page_xp ); // scan FAT mapper / loop on slots while ( slot_id < 1024 ) { // get extended pointer on current slot slot_xp = base_xp + (slot_id << 2); // test slot value if ( hal_remote_l32( slot_xp ) == FREE_CLUSTER ) { // update "free_cluster_hint" value hint = (page_id << 10) + slot_id - 1; hal_remote_s32( hint_xp , hint ); // update FS_INFO sector on IOC device error = fatfs_update_ioc_fat( fatfs_ctx_xp, page_id, page_id ); if( error ) { printk("\n[ERROR] in %s : cannot update FS_INFO on IOC\n", __FUNCTION__ ); return -1; } #if DEBUG_FATFS_FREE_CLUSTERS cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_FREE_CLUSTERS < (uint32_t)hal_get_cycles() ) printk("\n[%s] thread[%x,%x] exit / hint %x / free %x / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, hal_remote_l32(hint_xp), hal_remote_l32(numb_xp), cycle ); #endif return 0; } // update slot_id slot_id = 0; } // end loop on slots // update page_id & slot_id variables page_id++; slot_id = 0; } // end loop on pages // return error if no free cluster found printk("\n[ERROR] in %s : No free cluster found\n", __FUNCTION__ ); return -1; } // end fatfs_free_clusters_decrement() ////////////////////////////////////////////////////////////////////////////////////////// // This static function increments the "free_clusters" variable, and updates the // "free_cluster_hint" variables in the FATFS context in FAT cluster, identified // by the argument, when a FATFS cluster is released. // If the released cluster index is smaller than the current (hint) value, // it set "free_cluster_hint" <= cluster. // It does NOT update the FS_INFO sector on the IOC device. // It can be called by a thead running in any cluster. // The lock protecting exclusive access to the FAT must be taken by the calling function. ////////////////////////////////////////////////////////////////////////////////////////// // @ fatfs_ctx_xp : extended pointer on FATFS context in FAT cluster. // @ cluster : recently released cluster index in FAT. // @ return 0 if success, return -1 if the FS_INFO sector cannot be updated. ////////////////////////////////////////////////////////////////////////////////////////// static error_t fatfs_free_clusters_increment( xptr_t fatfs_ctx_xp, uint32_t cluster ) { error_t error; cxy_t fat_cxy; // FAT cluster identifier fatfs_ctx_t * fat_ctx_ptr; // local pointer on fatfs context in FAT cluster xptr_t hint_xp; // extended pointer on "free_cluster_hint" shared variable xptr_t numb_xp; // extended pointer on "free_clusters" shared variable uint32_t hint; // "free_cluster_hint" variable current value uint32_t numb; // "free_clusters" variable current value #if DEBUG_FATFS_FREE_CLUSTERS uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; if( DEBUG_FATFS_FREE_CLUSTERS < cycle ) printk("\n[%s] thread[%x,%x] enter for released cluster %x / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, cluster , cycle ); #endif // get FAT cluster an local pointer on fatfs context in FAT cluster fat_cxy = GET_CXY( fatfs_ctx_xp ); fat_ctx_ptr = GET_PTR( fatfs_ctx_xp ); // build extended pointers on free_clusters, and free_cluster_hint hint_xp = XPTR( fat_cxy , &fat_ctx_ptr->free_cluster_hint ); numb_xp = XPTR( fat_cxy , &fat_ctx_ptr->free_clusters ); // get current value of free_cluster_hint and free_clusters hint = hal_remote_l32( hint_xp ); numb = hal_remote_l32( numb_xp ); // update "numb" and "hint" variables as required numb++; if ( (cluster - 1) < hint ) hint = cluster - 1; // update free_clusters hal_remote_s32( numb_xp , numb ); hal_remote_s32( hint_xp , hint ); // update FS_INFO sector on IOC device error = fatfs_update_ioc_fsinfo( fatfs_ctx_xp ); if( error ) { printk("\n[ERROR] in %s : cannot update FS_INFO on IOC\n", __FUNCTION__ ); return -1; } #if DEBUG_FATFS_FREE_CLUSTERS cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_FREE_CLUSTERS < (uint32_t)hal_get_cycles() ) printk("\n[%s] thread[%x,%x] exit / hint %x / free %x / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, hal_remote_l32( hint_xp ), hal_remote_l32( numb_xp ), cycle ); #endif return 0; } // end fatfs_free_clusters_increment() ////////////////////////////////////////////////////////////////////////////////////////// // This recursive function is called by the generic function fatfs_release_inode(). // It release all FATFS clusters allocated to a given inode to the FAT mapper. // It can be called by a thread running in any cluster, as it use remote pointers // to access both the FAT mapper and the FATFS context in the FAT cluster, defined // by the and arguments. // The removal is done in reverse order of the linked list (from last cluster to first). // It returns in the and buffers the indexes of the // modified pages in the FAT mapper. // It updates the FAT mapper and the free_cluster info in the FATFS context, but does NOT // update the FAT and the FS_INFO on IOC device. ////////////////////////////////////////////////////////////////////////////////////////// // @ fat_mapper_xp : [in] extended pointer on FAT mapper. // @ fatfs_ctx_xp : [in] extended pointer on FATFS context in FAT cluster. // @ cluster : [in] index of cluster to be released from FAT mapper. // @ dirty_page_min : [out] pointer on buffer for min dirty page index. // @ dirty_page_max : [out] pointer on buffer for max dirty page index. // @ return 0 if success / return -1 if error. ////////////////////////////////////////////////////////////////////////////////////////// static error_t fatfs_recursive_release( xptr_t fat_mapper_xp, xptr_t fatfs_ctx_xp, uint32_t cluster, uint32_t * dirty_page_min, uint32_t * dirty_page_max ) { uint32_t next; // next cluster index uint32_t page_id; // page index in FAT mapper uint32_t word_id; // word index in page // get page index and word index from cluster page_id = cluster >> 10; word_id = cluster & 0x3FF; // get next cluster index from FAT mapper if ( mapper_remote_get_32( fat_mapper_xp, page_id, word_id, &next ) ) return -1; #if (DEBUG_FATFS_RELEASE_INODE & 1) thread_t * this = CURRENT_THREAD; if ( DEBUG_FATFS_RELEASE_INODE < (uint32_t)hal_get_cycles() ) printk("\n[%s] thread[%x,%x] access FAT for cluster %x / next %x\n", __FUNCTION__, this->process->pid, this->trdid, cluster, next ); #endif if ( next < END_OF_CHAIN_CLUSTER_MIN ) // non terminal case { // call fatfs_recursive_release() on next cluster if ( fatfs_recursive_release( fat_mapper_xp, fatfs_ctx_xp, next, dirty_page_min, dirty_page_max ) ) return -1; } // update FAT mapper if ( mapper_remote_set_32( fat_mapper_xp, page_id, word_id, FREE_CLUSTER ) ) return -1; // update dirty_page_min / dirty_page_max buffers if( page_id < *dirty_page_min ) *dirty_page_min = page_id; if( page_id > *dirty_page_max ) *dirty_page_max = page_id; // Update free_cluster info in FATFS context return fatfs_free_clusters_increment( fatfs_ctx_xp , cluster ); } // end fatfs_recursive_release() ////////////////////////////////////////////////////////////////////////////////////////// // FATFS specific extern functions ////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////// void fatfs_display_ctx( cxy_t cxy ) { // get pointer on local FATFS context vfs_ctx_t * vfs_ctx = &fs_context[FS_TYPE_FATFS]; fatfs_ctx_t * ctx = hal_remote_lpt( XPTR( cxy , &vfs_ctx->extend ) ); uint32_t fat_sectors = hal_remote_l32( XPTR( cxy , &ctx->fat_sectors_count ) ); uint32_t sector_size = hal_remote_l32( XPTR( cxy , &ctx->bytes_per_sector ) ); uint32_t sec_per_clus = hal_remote_l32( XPTR( cxy , &ctx->sectors_per_cluster ) ); uint32_t fat_lba = hal_remote_l32( XPTR( cxy , &ctx->fat_begin_lba ) ); uint32_t data_lba = hal_remote_l32( XPTR( cxy , &ctx->cluster_begin_lba ) ); uint32_t fsinfo_lba = hal_remote_l32( XPTR( cxy , &ctx->fs_info_lba ) ); uint32_t root_dir_clus = hal_remote_l32( XPTR( cxy , &ctx->root_dir_cluster ) ); uint32_t free_clusters = hal_remote_l32( XPTR( cxy , &ctx->free_clusters ) ); uint32_t free_cluster_hint = hal_remote_l32( XPTR( cxy , &ctx->free_cluster_hint ) ); xptr_t mapper_xp = hal_remote_l64( XPTR( cxy , &ctx->fat_mapper_xp ) ); void * fs_info_buffer = hal_remote_lpt( XPTR( cxy , &ctx->fs_info_buffer ) ); printk("\n*** FAT context in cluster %x\n" "- fat_sectors = %d\n" "- sector size = %d\n" "- cluster size = %d\n" "- fat_lba = %x\n" "- data_lba = %x\n" "- fsinfo_lba = %x\n" "- root_dir_cluster = %x\n" "- free_clusters = %x\n" "- free_cluster_hint = %x\n" "- fat_mapper_ptr = %x\n" "- fs_info_buffer = %x\n", cxy, fat_sectors, sector_size, sector_size * sec_per_clus, fat_lba, data_lba, fsinfo_lba, root_dir_clus, free_clusters, free_cluster_hint, GET_PTR( mapper_xp ), fs_info_buffer ); } // end fatfs_ctx_display() ////////////////////////////////////////// void fatfs_display_fat( uint32_t page_id, uint32_t nentries ) { uint32_t line; uint32_t maxline; // compute number of lines to display maxline = nentries >> 3; if( nentries & 0x7 ) maxline++; // get pointer on local FATFS context vfs_ctx_t * vfs_ctx = &fs_context[FS_TYPE_FATFS]; fatfs_ctx_t * loc_fatfs_ctx = (fatfs_ctx_t *)vfs_ctx->extend; // get extended pointer on FAT mapper xptr_t fat_mapper_xp = loc_fatfs_ctx->fat_mapper_xp; // get FAT cluster identifier cxy_t fat_cxy = GET_CXY( fat_mapper_xp ); // get pointer on FATFS context in FAT cluster fatfs_ctx_t * fat_fatfs_ctx = hal_remote_lpt( XPTR( fat_cxy , &vfs_ctx->extend ) ); // get current value of hint and free_clusters uint32_t hint = hal_remote_l32( XPTR( fat_cxy , &fat_fatfs_ctx->free_cluster_hint ) ); uint32_t free = hal_remote_l32( XPTR( fat_cxy , &fat_fatfs_ctx->free_clusters ) ); // get extended pointer on requested page in FAT mapper xptr_t page_xp = mapper_remote_get_page( fat_mapper_xp , page_id ); // get extended pointer on requested page base xptr_t base_xp = ppm_page2base( page_xp ); void * base = GET_PTR( base_xp ); printk("\n***** FAT mapper / cxy %x / page_id %d / base %x / free_clusters %x / hint %x\n", fat_cxy, page_id, base, free, hint ); for( line = 0 ; line < maxline ; line++ ) { printk("%x : %X | %X | %X | %X | %X | %X | %X | %X\n", (line<<3), hal_remote_l32( base_xp + ((line<<5) ) ), hal_remote_l32( base_xp + ((line<<5) + 4 ) ), hal_remote_l32( base_xp + ((line<<5) + 8 ) ), hal_remote_l32( base_xp + ((line<<5) + 12 ) ), hal_remote_l32( base_xp + ((line<<5) + 16 ) ), hal_remote_l32( base_xp + ((line<<5) + 20 ) ), hal_remote_l32( base_xp + ((line<<5) + 24 ) ), hal_remote_l32( base_xp + ((line<<5) + 28 ) ) ); } } // end fatfs_display_fat() /////////////////////////////////////////////////////// error_t fatfs_get_cluster( uint32_t first_cluster_id, uint32_t searched_page_index, uint32_t * searched_cluster_id ) { xptr_t current_page_xp; // pointer on current page descriptor uint32_t * buffer; // pointer on current page (array of uint32_t) uint32_t current_page_index; // index of current page in FAT uint32_t current_slot_index; // index of slot in current page uint32_t page_count_in_file; // index of page in file (index in linked list) uint32_t next_cluster_id; // content of current FAT slot xptr_t lock_xp; // extended pointer on FAT lock assert( (searched_page_index > 0) , "no FAT access required for first page\n"); #if DEBUG_FATFS_GET_CLUSTER uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; if( DEBUG_FATFS_GET_CLUSTER < cycle ) printk("\n[%s] thread[%x,%x] enter / first_cluster_id %d / searched_index %d / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, first_cluster_id, searched_page_index, cycle ); #endif // get local pointer on VFS context (same in all clusters) vfs_ctx_t * vfs_ctx = &fs_context[FS_TYPE_FATFS]; // get local pointer on local FATFS context fatfs_ctx_t * loc_fatfs_ctx = vfs_ctx->extend; // get extended pointer and cluster on FAT mapper xptr_t fat_mapper_xp = loc_fatfs_ctx->fat_mapper_xp; cxy_t fat_cxy = GET_CXY( fat_mapper_xp ); // get local pointer on FATFS context in FAT cluster fatfs_ctx_t * fat_fatfs_ctx = hal_remote_lpt( XPTR( fat_cxy , &vfs_ctx->extend ) ); // build extended pointer on FAT lock in FAT cluster lock_xp = XPTR( fat_cxy , &fat_fatfs_ctx->lock ); // take FAT lock in read mode remote_rwlock_rd_acquire( lock_xp ); // initialize loop variable (1024 slots per page) current_page_index = first_cluster_id >> 10; current_slot_index = first_cluster_id & 0x3FF; page_count_in_file = 0; next_cluster_id = 0xFFFFFFFF; // scan FAT mapper (i.e. traverse FAT linked list) while( page_count_in_file < searched_page_index ) { // get pointer on current page descriptor in FAT mapper current_page_xp = mapper_remote_get_page( fat_mapper_xp , current_page_index ); if( current_page_xp == XPTR_NULL ) { printk("\n[ERROR] in %s : cannot get next page from FAT mapper\n", __FUNCTION__); remote_rwlock_rd_release( lock_xp ); return -1; } // get pointer on buffer for current page xptr_t base_xp = ppm_page2base( current_page_xp ); buffer = (uint32_t *)GET_PTR( base_xp ); // get FAT slot content next_cluster_id = hal_remote_l32( XPTR( fat_cxy, &buffer[current_slot_index] ) ); #if (DEBUG_FATFS_GET_CLUSTER & 1) if( DEBUG_FATFS_GET_CLUSTER < cycle ) printk("\n[%s] traverse FAT / current_page_index = %d\n" "current_slot_index = %d / next_cluster_id = %d\n", __FUNCTION__, current_page_index, current_slot_index , next_cluster_id ); #endif // update loop variables current_page_index = next_cluster_id >> 10; current_slot_index = next_cluster_id & 0x3FF; page_count_in_file++; } if( next_cluster_id == 0xFFFFFFFF ) { printk("\n[ERROR] in %s : searched_cluster_id not found in FAT\n", __FUNCTION__ ); remote_rwlock_rd_release( lock_xp ); return -1; } // release FAT lock remote_rwlock_rd_release( lock_xp ); #if DEBUG_FATFS_GET_CLUSTER cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_GET_CLUSTER < cycle ) printk("\n[%s] thread[%x,%x] exit / searched_cluster_id = %d / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, next_cluster_id / cycle ); #endif *searched_cluster_id = next_cluster_id; return 0; } // end fatfs_get_cluster() /////////////////////////////////////////////////////////////////////////////////////// // Generic API : the following functions are called by the kernel VFS // and must be defined by all supported file systems. /////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////// fatfs_ctx_t * fatfs_ctx_alloc( void ) { kmem_req_t req; req.type = KMEM_KCM; req.order = bits_log2( sizeof(fatfs_ctx_t) ); req.flags = AF_KERNEL | AF_ZERO; return kmem_alloc( &req ); } ////////////////////////////////////////////// void fatfs_ctx_init( fatfs_ctx_t * fatfs_ctx ) { error_t error; kmem_req_t req; uint8_t * buffer; xptr_t buffer_xp; #if DEBUG_FATFS_CTX_INIT uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; if( DEBUG_FATFS_CTX_INIT < cycle ) printk("\n[%s] thread[%x,%x] enter for fatfs_ctx = %x / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, fatfs_ctx , cycle ); #endif // check argument assert( (fatfs_ctx != NULL) , "pointer on FATFS context is NULL" ); // check only cluster 0 does FATFS initialization assert( (local_cxy == 0) , "only cluster 0 can initialize FATFS"); // allocate a permanent 512 bytes buffer to store // - temporarily the BOOT sector // - permanently the FS_INFO sector req.type = KMEM_KCM; req.order = 9; // 512 bytes req.flags = AF_KERNEL | AF_ZERO; buffer = kmem_alloc( &req ); if( buffer == NULL ) { printk("\n[PANIC] in %s : cannot allocate buffer\n", __FUNCTION__ ); hal_core_sleep(); } buffer_xp = XPTR( local_cxy , buffer ); // load the BOOT record from device error = dev_ioc_sync_read( buffer_xp , 0 , 1 ); if ( error ) { printk("\n[PANIC] in %s : cannot access boot record\n", __FUNCTION__ ); hal_core_sleep(); } #if (DEBUG_FATFS_CTX_INIT & 0x1) if( DEBUG_FATFS_CTX_INIT < cycle ) putb( "boot record", buffer , 256 ); #endif // get sector size from boot record uint32_t sector_size = fatfs_get_record( BPB_BYTSPERSEC , buffer ); if ( sector_size != 512 ) { printk("\n[PANIC] in %s : sector size must be 512 bytes\n", __FUNCTION__ ); hal_core_sleep(); } // get cluster size from boot record uint32_t nb_sectors = fatfs_get_record( BPB_SECPERCLUS , buffer ); if ( nb_sectors != 8 ) { printk("\n[PANIC] in %s : cluster size must be 8 sectors\n", __FUNCTION__ ); hal_core_sleep(); } // get number of FAT copies from boot record uint32_t nb_fats = fatfs_get_record( BPB_NUMFATS , buffer ); if ( nb_fats != 1 ) { printk("\n[PANIC] in %s : number of FAT copies must be 1\n", __FUNCTION__ ); hal_core_sleep(); } // get number of sectors in FAT from boot record uint32_t fat_sectors = fatfs_get_record( BPB_FAT32_FATSZ32 , buffer ); if ( (fat_sectors & 0xF) != 0 ) { printk("\n[PANIC] in %s : FAT size not multiple of 16 sectors\n", __FUNCTION__ ); hal_core_sleep(); } // get root cluster from boot record uint32_t root_cluster = fatfs_get_record( BPB_FAT32_ROOTCLUS , buffer ); if ( root_cluster != 2 ) { printk("\n[PANIC] in %s : root cluster index must be 2\n", __FUNCTION__ ); hal_core_sleep(); } // get FAT lba from boot record uint32_t fat_lba = fatfs_get_record( BPB_RSVDSECCNT , buffer ); // get FS_INFO sector lba from boot record uint32_t fs_info_lba = fatfs_get_record( BPB_FAT32_FSINFO , buffer ); // load the FS_INFO record from device error = dev_ioc_sync_read( buffer_xp , fs_info_lba , 1 ); if ( error ) { printk("\n[PANIC] in %s : cannot access FS_INFO record\n", __FUNCTION__ ); hal_core_sleep(); } // get free_clusters number from FS_INFO record uint32_t free_clusters = fatfs_get_record( FS_FREE_CLUSTERS , buffer ); if ( free_clusters >= fat_sectors << 7 ) { printk("\n[PANIC] in %s : unconsistent free_clusters\n", __FUNCTION__ ); hal_core_sleep(); } // get free_cluster_hint from FS_INFO record uint32_t free_cluster_hint = fatfs_get_record( FS_FREE_CLUSTER_HINT , buffer ); if ( free_cluster_hint >= fat_sectors << 7 ) { printk("\n[PANIC] in %s : unconsistent free_cluster_hint\n", __FUNCTION__ ); hal_core_sleep(); } // allocate a mapper for the FAT itself mapper_t * fat_mapper = mapper_create( FS_TYPE_FATFS ); if ( fat_mapper == NULL ) { printk("\n[PANIC] in %s : no memory for FAT mapper\n", __FUNCTION__ ); hal_core_sleep(); } // the inode field is NULL for the FAT mapper fat_mapper->inode = NULL; // initialize the FATFS context fatfs_ctx->fat_begin_lba = fat_lba; fatfs_ctx->fat_sectors_count = fat_sectors; fatfs_ctx->bytes_per_sector = sector_size; fatfs_ctx->sectors_per_cluster = nb_sectors; fatfs_ctx->cluster_begin_lba = fat_lba + fat_sectors; fatfs_ctx->root_dir_cluster = 2; fatfs_ctx->fat_mapper_xp = XPTR( local_cxy , fat_mapper ); fatfs_ctx->fs_info_lba = fs_info_lba; fatfs_ctx->free_clusters = free_clusters; fatfs_ctx->free_cluster_hint = free_cluster_hint; fatfs_ctx->fs_info_buffer = buffer; remote_rwlock_init( XPTR( local_cxy , &fatfs_ctx->lock ) , LOCK_FATFS_FAT ); #if (DEBUG_FATFS_CTX_INIT & 0x1) if( DEBUG_FATFS_CTX_INIT < cycle ) fatfs_ctx_display( fatfs_ctx ); #endif #if DEBUG_FATFS_CTX_INIT cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_CTX_INIT < cycle ) printk("\n[%s] thread[%x,%x] exit for fatfs_ctx = %x / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, fatfs_ctx, cycle ); #endif } // end fatfs_ctx_init() ///////////////////////////////////////////////// void fatfs_ctx_destroy( fatfs_ctx_t * fatfs_ctx ) { kmem_req_t req; req.type = KMEM_KCM; req.ptr = fatfs_ctx; kmem_free( &req ); } /////////////////////////////////////////////// error_t fatfs_add_dentry( vfs_inode_t * inode, vfs_dentry_t * dentry ) { error_t error; uint32_t length; // dentry name length uint32_t nb_lfn; // number or required LFN char sfn[11]; // buffer for SFN name uint8_t checksum; // name checksum mapper_t * mapper; // loal pointer on parent inode mapper xptr_t mapper_xp; // extended pointer on parent inode mapper xptr_t child_xp; // extended pointer on child inode cxy_t child_cxy; // child inode cluster vfs_inode_t * child_ptr; // child inode local pointer uint32_t size; // child inode size uint32_t type; // child inode type uint32_t cluster; // child inode cluster index #if DEBUG_FATFS_ADD_DENTRY char dir_name[CONFIG_VFS_MAX_NAME_LENGTH]; uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name ); if( DEBUG_FATFS_ADD_DENTRY < cycle ) printk("\n[%s] thread[%x,%x] enter / parent <%s> / child <%s> / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle ); #endif // check arguments assert( (inode != NULL) , "inode pointer is NULL\n" ); assert( (dentry != NULL) , "dentry pointer is NULL\n" ); assert( (inode->mapper != NULL ) , "mapper pointer is NULL\n" ); // get pointers on directory mapper mapper = inode->mapper; mapper_xp = XPTR( local_cxy , mapper ); // get extended pointers on remote child inode child_xp = dentry->child_xp; child_cxy = GET_CXY( child_xp ); child_ptr = GET_PTR( child_xp ); // get relevant infos from child inode type = hal_remote_l32( XPTR( child_cxy , &child_ptr->type ) ); size = hal_remote_l32( XPTR( child_cxy , &child_ptr->size ) ); cluster = (uint32_t)(intptr_t)hal_remote_lpt( XPTR( child_cxy , &child_ptr->extend ) ); // analyse dentry name error = fatfs_name_format( dentry->name, &length, &nb_lfn, sfn, &checksum ); if ( error ) { printk("\n[ERROR] in %s : dentry name > 31 bytes\n", __FUNCTION__ ); return -1; } // Search end of directory with two embedded loops: // - scan the pages in the mapper // - scan the entries in each page to find NO_MORE_ENTRY xptr_t page_xp; // extended pointer on page descriptor xptr_t base_xp; // extended pointer on page base uint8_t * base; // local pointer on page base (array of bytes) uint32_t page_id = 0; // page index in mapper uint32_t offset = 0; // position in page uint32_t found = 0; // NO_MORE_ENTRY found // loop on pages in mapper while ( found == 0 ) { // get extended pointer on page descriptor in mapper page_xp = mapper_remote_get_page( mapper_xp , page_id ); if ( page_xp == XPTR_NULL ) { printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ ); return -1; } // get pointer on page base base_xp = ppm_page2base( page_xp ); base = GET_PTR( base_xp ); // loop on directory entries in this page while ( (offset < 4096) && (found == 0) ) { if ( fatfs_get_record( LDIR_ORD, (base + offset) ) == NO_MORE_ENTRY ) { found = 1; } else { offset = offset + 32; } } // end loop on entries if ( found == 0 ) { page_id++; offset = 0; } } // end loop on pages // Modify the directory mapper: depending on the name length, // the new child requires to write (3, 4, or 5) directory entries. // To actually register the new child, we use a 5 steps FSM // (one state per entry to be written), that is traversed as: // LFN3 -> LFN2 -> LFN1 -> NORMAL -> NOMORE // At most two pages are modified: // - the page containing the NO_MORE_ENTRY is always modified // - the following page can be modified if the name spread on to pages. char * name = dentry->name; uint32_t step; // FSM state if ( nb_lfn == 1 ) step = 3; else if ( nb_lfn == 2 ) step = 4; else if ( nb_lfn == 3 ) step = 5; uint8_t * entry; // pointer on directory entry to be written uint32_t i; // byte index in one 32 bytes directory uint32_t c; // character index in name while ( step ) { // when the new child is split on two pages, // we need to access a new page in mapper if ( offset >= 4096 ) { // copy the modified page to IOC device fatfs_move_page( page_xp , IOC_SYNC_WRITE ); // get the next page in FAT mapper page_xp = mapper_remote_get_page( mapper_xp , page_id + 1 ); if ( page_xp == XPTR_NULL ) { printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ ); return -1; } // get pointer on page base base_xp = ppm_page2base( page_xp ); base = GET_PTR( base_xp ); // update offset offset = 0; } // compute directory entry address entry = base + offset; #if (DEBUG_FATFS_ADD_DENTRY & 1) cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_ADD_DENTRY < cycle ) printk("\n[%s] FSM step = %d / offset = %x / nb_lfn = %d / cycle %d\n", __FUNCTION__, step, offset, nb_lfn, cycle ); #endif // write 32 bytes (one directory entry) per iteration switch ( step ) { case 5: // write LFN3 entry { c = 26; // scan the 32 bytes in dir_entry for ( i = 0 ; i < 32 ; i++ ) { if (i == 0) { if ( nb_lfn == 3) entry[i] = 0x43; else entry[i] = 0x03; } else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1)) || ((i >= 14) && (i<=25) && ((i&1)==0)) || ((i >= 28) && (i<=31) && ((i&1)==0)) ) && ( c < length ) ) { entry[i] = name[c]; c++; } else if (i == 11) entry[i] = 0x0F; else if (i == 13) entry[i] = checksum; else entry[i] = 0x00; } step--; break; } case 4: // write LFN2 entry { c = 13; // scan the 32 bytes in dir_entry for ( i = 0 ; i < 32 ; i++ ) { if (i == 0) { if ( nb_lfn == 2) entry[i] = 0x42; else entry[i] = 0x02; } else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1)) || ((i >= 14) && (i<=25) && ((i&1)==0)) || ((i >= 28) && (i<=31) && ((i&1)==0)) ) && ( c < length ) ) { entry[i] = name[c]; c++; } else if (i == 11) entry[i] = 0x0F; else if (i == 13) entry[i] = checksum; else entry[i] = 0x00; } step--; break; } case 3: // Write LFN1 entry { c = 0; // scan the 32 bytes in dir_entry for ( i = 0 ; i < 32 ; i++ ) { if (i == 0) { if ( nb_lfn == 1) entry[i] = 0x41; else entry[i] = 0x01; } else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1)) || ((i >= 14) && (i<=25) && ((i&1)==0)) || ((i >= 28) && (i<=31) && ((i&1)==0)) ) && ( c < length ) ) { entry[i] = name[c]; c++; } else if (i == 11) entry[i] = 0x0F; else if (i == 13) entry[i] = checksum; else entry[i] = 0x00; } step--; break; } case 2: // write NORMAL entry { // scan the 32 bytes in dir_entry for ( i = 0 ; i < 32 ; i++ ) { if ( i < 11 ) // 8.3 SFN { entry[i] = sfn[i]; } else if (i == 11) // ATTR { if (type == INODE_TYPE_DIR) entry[i] = 0x10; else entry[i] = 0x20; } else if (i == 20) entry[i] = cluster>>16; // cluster.B2 else if (i == 21) entry[i] = cluster>>24; // cluster.B3 else if (i == 26) entry[i] = cluster>>0; // cluster.B0 else if (i == 27) entry[i] = cluster>>8; // cluster.B1 else if (i == 28) entry[i] = size>>0; // size.B0 else if (i == 29) entry[i] = size>>8; // size.B1 else if (i == 30) entry[i] = size>>16; // size.B2 else if (i == 31) entry[i] = size>>24; // size.B3 else entry[i] = 0x00; } // update the "extend" field in dentry descriptor dentry->extend = (void*)(intptr_t)(((page_id<<12) + offset)>>5); step--; break; } case 1: // write NOMORE entry { entry [0] = 0x00; step--; break; } } // end switch step offset += 32; } // exit while #if (DEBUG_FATFS_ADD_DENTRY & 1) cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_ADD_DENTRY < cycle ) printk("\n[%s] thread[%x,%x] before IOC access / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, cycle ); #endif // copy the modified page to the IOC device fatfs_move_page( page_xp , IOC_SYNC_WRITE ); #if DEBUG_FATFS_ADD_DENTRY cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_ADD_DENTRY < cycle ) printk("\n[%s] thread[%x,%x] exit / parent <%s> / child <%s> / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle ); #endif return 0; } // end fatfs_add_dentry() ////////////////////////////////////////////////// error_t fatfs_remove_dentry( vfs_inode_t * inode, vfs_dentry_t * dentry ) { xptr_t mapper_xp; // extended pointer on mapper mapper_t * mapper; // local pointer on mapper xptr_t page_xp; // extended pointer on mapper page descriptor xptr_t base_xp; // extended pointer on mapper page base uint8_t * base; // local pointer on mapper page base #if DEBUG_FATFS_REMOVE_DENTRY char dir_name[CONFIG_VFS_MAX_NAME_LENGTH]; uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name ); if( DEBUG_FATFS_REMOVE_DENTRY < cycle ) printk("\n[%s] thread[%x,%x] enter / parent <%s> / child <%s> / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle ); #endif // check arguments assert( (inode != NULL) , "inode pointer is NULL\n" ); assert( (dentry != NULL) , "dentry pointer is NULL\n" ); assert( (inode->type == INODE_TYPE_DIR) , "inode is not a directory\n" ); assert( (inode->mapper != NULL ) , "mapper pointer is NULL\n" ); // get pointers on directory mapper mapper = inode->mapper; mapper_xp = XPTR( local_cxy , mapper ); // compute number of LFN entries uint32_t nb_lfn; uint32_t name_length = strlen( dentry->name ); if ( name_length <= 13 ) nb_lfn = 1; else if ( name_length <= 26 ) nb_lfn = 2; else nb_lfn = 3; // we must invalidate (2, 3 or 4) 32 bytes entries: // the NORMAL entry (registered in dentry->extend) and all preceding LFN entries // At most two pages are modified: // - the page containing the NORMAL entry is always modified. // - the preceding page is modified when the name spread on two pages. // get 32 bytes directory entry index from dentry->extend uint32_t dentry_id = (uint32_t)(intptr_t)dentry->extend; // get page index and offset in parent directory mapper uint32_t page_id = dentry_id >> 7; uint32_t offset = (dentry_id & 0x7F)<<5; #if DEBUG_FATFS_REMOVE_DENTRY & 1 if( DEBUG_FATFS_REMOVE_DENTRY < cycle ) printk("\n[%s] dentry_id %x / page_id %x / offset %x\n", __FUNCTION__, dentry_id, page_id, offset ); #endif // get extended pointer on page descriptor from parent directory mapper page_xp = mapper_remote_get_page( mapper_xp , page_id ); if ( page_xp == XPTR_NULL ) { printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ ); return -1; } // get pointers on page base base_xp = ppm_page2base( page_xp ); base = GET_PTR( base_xp ); // invalidate NORMAL entry in directory cache base[offset] = 0xE5; // invalidate LFN entries while ( nb_lfn ) { if (offset == 0) // we must load page (page_id - 1) { // check page_id assert( (page_id > 0), "page_id and offset cannot be both 0\n" ); // copy the modified page to the IOC device fatfs_move_page( page_xp , IOC_SYNC_WRITE ); // get extended pointer on page descriptor from parent directory mapper page_xp = mapper_remote_get_page( mapper_xp , page_id ); if ( page_xp == XPTR_NULL ) { printk("\n[ERROR] in %s : cannot access directory mapper\n", __FUNCTION__ ); return -1; } // get pointers on page base base_xp = ppm_page2base( page_xp ); base = GET_PTR( base_xp ); // update offset offset = 4096; } offset = offset - 32; // check for LFN entry assert( (fatfs_get_record( DIR_ATTR, base + offset ) == ATTR_LONG_NAME_MASK ), "this directory entry must be a LFN\n"); // invalidate LFN entry base[offset] = 0xE5; nb_lfn--; } // copy the modified page to the IOC device fatfs_move_page( page_xp , IOC_SYNC_WRITE ); #if DEBUG_FATFS_REMOVE_DENTRY cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_REMOVE_DENTRY < cycle ) printk("\n[%s] thread[%x,%x] exit / parent %s / child %s / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle ); #endif return 0; } // end fatfs_remove_dentry ////////////////////////////////////////////////////////////////////////////////////////////// // This static function scan the pages of a mapper containing a FAT32 directory, identified // by the argument, to find the directory entry identified by the argument, // and return a pointer on the directory entry, described as and array of 32 bytes, and the // incex of this entry in the FAT32 mapper, seen as an array of 32 bytes entries. // It is called by the fatfs_new_dentry() and fatfs_update_dentry() functions. // It must be called by a thread running in the cluster containing the mapper. ////////////////////////////////////////////////////////////////////////////////////////////// // @ mapper : [in] local pointer on directory mapper. // @ name : [in] searched directory entry name. // @ entry : [out] buffer for the pointer on the 32 bytes directory entry (when found). // @ index : [out] buffer for the directory entry index in mapper. // @ return 0 if found / return 1 if not found / return -1 if mapper access error. ////////////////////////////////////////////////////////////////////////////////////////////// error_t fatfs_scan_directory( mapper_t * mapper, char * name, uint8_t ** entry, uint32_t * index ) { // Two embedded loops to scan the directory mapper: // - scan the parent directory mapper pages // - scan the directory entries in each 4 Kbytes page // check parent_inode and child_inode assert( (mapper != NULL) , "mapper pointer is NULL\n" ); assert( (name != NULL ), "child name is undefined\n" ); assert( (entry != NULL ), "entry buffer undefined\n" ); #if DEBUG_FATFS_SCAN_DIRECTORY char parent_name[CONFIG_VFS_MAX_NAME_LENGTH]; uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; vfs_inode_get_name( XPTR( local_cxy , mapper->inode ) , parent_name ); if( DEBUG_FATFS_SCAN_DIRECTORY < cycle ) printk("\n[%s] thread[%x,%x] enter to search child <%s> in parent <%s> / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, name , parent_name , cycle ); #endif char cname[CONFIG_VFS_MAX_NAME_LENGTH]; // name extracted from each directory entry char lfn1[16]; // buffer for one partial cname char lfn2[16]; // buffer for one partial cname char lfn3[16]; // buffer for one partial cname xptr_t mapper_xp; // extended pointer on mapper descriptor xptr_t page_xp; // extended pointer on page descriptor xptr_t base_xp; // extended pointer on page base uint8_t * base; // local pointer on page base uint8_t attr; // directory entry ATTR field uint8_t ord; // directory entry ORD field uint32_t seq; // sequence index uint32_t lfn = 0; // LFN entries number int32_t found = 0; // not yet = 0 / success = 1 / not found = 2 / error = -1 uint32_t page_id = 0; // page index in mapper uint32_t offset = 0; // byte offset in page mapper_xp = XPTR( local_cxy , mapper ); // scan the mapper pages while ( found == 0 ) { // get one page page_xp = mapper_remote_get_page( mapper_xp , page_id ); if( page_xp == XPTR_NULL) { found = -1; } // get page base base_xp = ppm_page2base( page_xp ); base = (uint8_t *)GET_PTR( base_xp ); #if (DEBUG_FATFS_SCAN_DIRECTORY & 0x1) if( DEBUG_FATFS_SCAN_DIRECTORY < cycle ) mapper_display_page( mapper_xp , page_id , 256 ); #endif // scan this page until end of directory, end of page, or name found while( (offset < 4096) && (found == 0) ) { attr = fatfs_get_record( DIR_ATTR , base + offset ); ord = fatfs_get_record( LDIR_ORD , base + offset ); if (ord == NO_MORE_ENTRY) // no more entry => break { found = 2; } else if ( ord == FREE_ENTRY ) // free entry => skip { offset = offset + 32; } else if ( attr == 0x28 ) // volune_id => skip { offset = offset + 32; } else if ( attr == ATTR_LONG_NAME_MASK ) // LFN entry => get partial cname { seq = ord & 0x3; lfn = (seq > lfn) ? seq : lfn; if ( seq == 1 ) fatfs_get_name_from_long( base + offset, lfn1 ); else if ( seq == 2 ) fatfs_get_name_from_long( base + offset, lfn2 ); else if ( seq == 3 ) fatfs_get_name_from_long( base + offset, lfn3 ); offset = offset + 32; } else // NORMAL entry { // build the extracted name if ( lfn == 0 ) { fatfs_get_name_from_short( base + offset , cname ); } else if ( lfn == 1 ) { strcpy( cname , lfn1 ); } else if ( lfn == 2 ) { strcpy( cname , lfn1 ); strcpy( cname + 13 , lfn2 ); } else if ( lfn == 3 ) { strcpy( cname , lfn1 ); strcpy( cname + 13 , lfn2 ); strcpy( cname + 26 , lfn3 ); } // get dentry arguments if extracted cname == searched name if ( strcmp( name , cname ) == 0 ) { *entry = base + offset; *index = ((page_id<<12) + offset)>>5; found = 1; } offset = offset + 32; lfn = 0; } } // end loop on directory entries in page page_id++; offset = 0; } // end loop on pages if( found == 1 ) { #if DEBUG_FATFS_SCAN_DIRECTORY cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_SCAN_DIRECTORY < cycle ) printk("\n[%s] thread[%x,%x] exit / found child <%s> in <%s>\n", __FUNCTION__, this->process->pid, this->trdid, name, parent_name ); #endif return 0; } else if( found == 2 ) { #if DEBUG_FATFS_SCAN_DIRECTORY cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_SCAN_DIRECTORY < cycle ) printk("\n[%s] thread[%x,%x] exit / child <%s> in <%s> not found\n", __FUNCTION__, this->process->pid, this->trdid, name, parent_name ); #endif return 1; } else { printk("\n[ERROR] in %s : cannot get page %d from mapper\n", __FUNCTION__, page_id ); return -1; } } // end fatfs_scan_directory() ///////////////////////////////////////////////////// error_t fatfs_new_dentry( vfs_inode_t * parent_inode, char * name, xptr_t child_inode_xp ) { uint8_t * entry; // pointer on FAT32 directory entry (array of 32 bytes) uint32_t index; // index of FAT32 directory entry in mapper mapper_t * mapper; // pointer on directory mapper uint32_t cluster; // directory entry cluster uint32_t size; // directory entry size bool_t is_dir; // directory entry type (file/dir) xptr_t root_xp; // extended pointer on root of parent dentries xptr_t iter_xp; // iterator for this list cxy_t child_inode_cxy; // child inode cluster vfs_inode_t * child_inode_ptr; // child inode local pointer xptr_t dentry_xp; // extended pointer on searched dentry descriptor cxy_t dentry_cxy; // cluster identifier of dentry (must be local_cxy) vfs_dentry_t * dentry_ptr; // local pointer error_t error; char dir_name[CONFIG_VFS_MAX_NAME_LENGTH]; // check arguments assert( (parent_inode != NULL) , "parent_inode is NULL\n" ); assert( (name != NULL) , "name is NULL\n" ); assert( (child_inode_xp != XPTR_NULL ) , "child_inode is NULL\n" ); // get child inode cluster and local pointer child_inode_cxy = GET_CXY( child_inode_xp ); child_inode_ptr = GET_PTR( child_inode_xp ); // build extended pointer on root of list of parent dentries root_xp = XPTR( child_inode_cxy , &child_inode_ptr->parents ); // check child inode has at least one parent assert( (xlist_is_empty( root_xp ) == false ), "child inode must have one parent\n"); #if DEBUG_FATFS_GET_DENTRY uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; vfs_inode_get_name( XPTR( local_cxy , parent_inode ) , dir_name ); if( DEBUG_FATFS_GET_DENTRY < cycle ) printk("\n[%s] thread[%x,%x] enter for child <%s> in parent <%s> / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, name , dir_name , cycle ); #endif // get local pointer on parent mapper mapper = parent_inode->mapper; // get pointer and index in mapper for searched directory entry error = fatfs_scan_directory( mapper, name , &entry , &index ); // return non fatal error if not found if( error ) return -1; // get relevant infos from FAT32 directory entry cluster = (fatfs_get_record( DIR_FST_CLUS_HI , entry ) << 16) | (fatfs_get_record( DIR_FST_CLUS_LO , entry ) ) ; is_dir = (fatfs_get_record( DIR_ATTR , entry ) & ATTR_DIRECTORY); size = fatfs_get_record( DIR_FILE_SIZE , entry ); // scan list of parent dentries to search the parent_inode bool_t found = false; XLIST_FOREACH( root_xp , iter_xp ) { // get pointers on dentry dentry_xp = XLIST_ELEMENT( iter_xp , vfs_dentry_t , parents ); dentry_cxy = GET_CXY( dentry_xp ); dentry_ptr = GET_PTR( dentry_xp ); // get local pointer on current parent directory inode vfs_inode_t * current = hal_remote_lpt( XPTR( dentry_cxy , &dentry_ptr->parent ) ); // check if current parent is the searched parent if( XPTR( dentry_cxy , current ) == XPTR( local_cxy , parent_inode ) ) { found = true; break; } } if( found == false ) { vfs_inode_get_name( XPTR( local_cxy , parent_inode ) , dir_name ); printk("\n[ERROR] in %s : cannot find <%s> directory in list of parents for <%s>\n", __FUNCTION__, dir_name, name ); return -1; } // update the child inode "type", "size", and "extend" fields vfs_inode_type_t type = (is_dir) ? INODE_TYPE_DIR : INODE_TYPE_FILE; hal_remote_s32( XPTR( child_inode_cxy , &child_inode_ptr->type ) , type ); hal_remote_s32( XPTR( child_inode_cxy , &child_inode_ptr->size ) , size ); hal_remote_s32( XPTR( child_inode_cxy , &child_inode_ptr->extend ) , cluster ); // update the dentry "extend" field dentry_ptr->extend = (void *)(intptr_t)index; #if DEBUG_FATFS_GET_DENTRY cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_GET_DENTRY < cycle ) printk("\n[%s] thread[%x,%x] exit / intialised inode & dentry for <%s> in <%s> / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, name, dir_name, cycle ); #endif return 0; } // end fatfs_new_dentry() ////////////////////////////////////////////////// error_t fatfs_update_dentry( vfs_inode_t * inode, vfs_dentry_t * dentry, uint32_t size ) { uint8_t * entry; // pointer on FAT32 directory entry (array of 32 bytes) uint32_t index; // index of FAT32 directory entry in mapper mapper_t * mapper; // pointer on directory mapper error_t error; char dir_name[CONFIG_VFS_MAX_NAME_LENGTH]; // check arguments assert( (inode != NULL) , "inode is NULL\n" ); assert( (dentry != NULL) , "dentry is NULL\n" ); assert( (size != 0 ) , "size is 0\n" ); #if DEBUG_FATFS_UPDATE_DENTRY uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name ); if( DEBUG_FATFS_UPDATE_DENTRY < cycle ) printk("\n[%s] thread[%x,%x] enter for <%s/%s> / size %d / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, size, cycle ); #endif // get local pointer on mapper mapper = inode->mapper; // get pointer and index in mapper for searched directory entry error = fatfs_scan_directory( mapper, dentry->name , &entry , &index ); if( error ) { vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name ); printk("\n[ERROR] in %s : cannot find <%s> in parent mapper <%s>\n", __FUNCTION__, dentry->name, dir_name ); return -1; } // set size in FAT32 directory entry fatfs_set_record( DIR_FILE_SIZE , entry , size ); // get local pointer on modified page base void * base = (void *)((intptr_t)entry & (~CONFIG_PPM_PAGE_MASK)); // get extended pointer on modified page descriptor xptr_t page_xp = ppm_base2page( XPTR( local_cxy , base ) ); // synchronously update the modified page on device error = fatfs_move_page( page_xp , IOC_SYNC_WRITE ); if( error ) { vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name ); printk("\n[ERROR] in %s : cannot update parent directory <%s> on device\n", __FUNCTION__, dir_name ); return -1; } #if DEBUG_FATFS_UPDATE_DENTRY cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_UPDATE_DENTRY < cycle ) printk("\n[%s] thread[%x,%x] exit / updated size for <%s/%s> / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle ); #endif return 0; } // end fatfs_update_dentry() /////////////////////////////////////////////////////// error_t fatfs_get_user_dir( struct vfs_inode_s * inode, struct dirent * array, uint32_t max_dirent, uint32_t min_dentry, bool_t detailed, uint32_t * entries, bool_t * done ) { // Two embedded loops to scan the directory mapper: // - scan the parent directory mapper pages starting always from page 0 // - scan the 32 bytes NORMAL/LFN directory entries in each page // Only valid dentries are copied : dentry_id >= min_dentry && dirent_id < dirent_max #if DEBUG_FATFS_GET_USER_DIR char inode_name[CONFIG_VFS_MAX_NAME_LENGTH]; uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; vfs_inode_get_name( XPTR( local_cxy , inode ) , inode_name ); if( DEBUG_FATFS_GET_USER_DIR < cycle ) printk("\n[%s] thread[%x,%x] enter for inode <%s> / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, inode_name , cycle ); #endif mapper_t * mapper = inode->mapper; xptr_t mapper_xp = XPTR( local_cxy , mapper ); // check mapper pointer assert( (mapper != NULL) , "mapper is NULL\n"); // TODO handle the detailed flag assert( (detailed == false), "detailed argument not supported/n"); char cname[CONFIG_VFS_MAX_NAME_LENGTH]; // name extracted from each dentry char lfn1[16]; // buffer for one partial cname char lfn2[16]; // buffer for one partial cname char lfn3[16]; // buffer for one partial cname xptr_t page_xp; // extended pointer on page descriptor xptr_t base_xp; // extended pointer on page base uint8_t * base; // local pointer on page base uint8_t attr; // directory entry ATTR field uint8_t ord; // directory entry ORD field uint32_t seq; // sequence index uint32_t lfn = 0; // LFN entries number uint32_t offset = 0; // byte offset in page uint32_t page_id = 0; // page index in mapper uint32_t dentry_id = 0; // valid (i.e. copied) dentry index in mapper uint32_t dirent_id = 0; // slot index in dirent array to initialize bool_t end = false; // true if end of directory found // loop on mapper pages while ( (end == false) && (dirent_id < max_dirent) ) { // get one page from mapper page_xp = mapper_remote_get_page( mapper_xp , page_id ); if( page_xp == XPTR_NULL) return -1; // get page base base_xp = ppm_page2base( page_xp ); base = (uint8_t *)GET_PTR( base_xp ); #if (DEBUG_FATFS_GET_USER_DIR & 0x1) if( DEBUG_FATFS_GET_USER_DIR < cycle ) mapper_display_page( mapper_xp , page_id , 256 ); #endif // loop on NORMAL/LFN (32 bytes) directory entries in this page while( (end == false) && (offset < 4096) ) { // compute condition to copy one dentry to dirent array bool_t valid = (dentry_id >= min_dentry) && (dirent_id < max_dirent ); attr = fatfs_get_record( DIR_ATTR , base + offset ); ord = fatfs_get_record( LDIR_ORD , base + offset ); if (ord == NO_MORE_ENTRY) // no more entry => break { end = true; } else if ( ord == FREE_ENTRY ) // free entry => skip { offset = offset + 32; } else if ( attr == 0x28 ) // volune_id => skip { offset = offset + 32; } else if ( attr == ATTR_LONG_NAME_MASK ) // LFN entry { if( valid ) { // get partial cname seq = ord & 0x3; lfn = (seq > lfn) ? seq : lfn; if ( seq == 1 ) fatfs_get_name_from_long( base + offset, lfn1 ); else if ( seq == 2 ) fatfs_get_name_from_long( base + offset, lfn2 ); else if ( seq == 3 ) fatfs_get_name_from_long( base + offset, lfn3 ); } offset = offset + 32; } else // NORMAL entry { // increment dentry_id dentry_id++; if( valid ) { // build the complete cname if ( lfn == 0 ) { fatfs_get_name_from_short( base + offset , cname ); } else if ( lfn == 1 ) { strcpy( cname , lfn1 ); } else if ( lfn == 2 ) { strcpy( cname , lfn1 ); strcpy( cname + 13 , lfn2 ); } else if ( lfn == 3 ) { strcpy( cname , lfn1 ); strcpy( cname + 13 , lfn2 ); strcpy( cname + 26 , lfn3 ); } // copy cname into dirent array strcpy( array[dirent_id].d_name , cname ); // increment dirent_id dirent_id++; } offset = offset + 32; lfn = 0; } } // end loop on directory entries in page page_id++; offset = 0; } // end loop on pages // return result of scan *done = end; *entries = dirent_id; #if DEBUG_FATFS_GET_USER_DIR cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_GET_USER_DIR < cycle ) printk("\n[%s] thread[%x,%x] exit for inode <%s> / %d entries / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, inode_name, dirent_id, cycle ); #endif return 0; } // end fatfs_get_user_dir() /////////////////////////////////////////////// error_t fatfs_sync_inode( vfs_inode_t * inode ) { // check inode pointer and cluster index assert( (inode != NULL) , "inode pointer undefined\n" ); assert( (inode->mapper != NULL ) , "mapper pointer undefined\n" ); assert( (inode->type == INODE_TYPE_FILE) , "inode must be a file\n" ); #if DEBUG_FATFS_SYNC_INODE char name[CONFIG_VFS_MAX_NAME_LENGTH]; uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; vfs_inode_get_name( XPTR( local_cxy , inode ) , name ); if( DEBUG_FATFS_SYNC_INODE < cycle ) printk("\n[%s] thread[%x,%x] enter for <%s> / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, name, cycle ); #endif error_t error; mapper_t * mapper; page_t * page; uint32_t page_id; // get mapper from inode mapper = inode->mapper; // compute max number of pages in mapper from file size uint32_t size = inode->size; uint32_t pages = size >> CONFIG_PPM_PAGE_SHIFT; if( size & CONFIG_PPM_PAGE_MASK ) pages++; // get pointer on mapper radix tree grdxt_t * rt = &mapper->rt; // scan all pages for( page_id = 0 ; page_id < pages ; page_id++ ) { // get page descriptor from mapper page = grdxt_lookup( rt , page_id ); // check all existing pages if ( page != NULL ) { if ( page->flags & PG_DIRTY ) { #if (DEBUG_FATFS_SYNC_INODE & 1) if( DEBUG_FATFS_SYNC_INODE < cycle ) printk("\n[%s] thread[%x,%x] synchronizes page %d from <%s> mapper to IOC device\n", __FUNCTION__, page_id, name ); #endif // build extended pointer on page descriptor xptr_t page_xp = XPTR( local_cxy , page ); // move page from mapper to device error = fatfs_move_page( page_xp , IOC_WRITE ); if ( error ) return -1; // reset page dirty flag ppm_page_undo_dirty( page_xp ); } } } // end loop on pages #if DEBUG_FATFS_SYNC_INODE cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_SYNC_INODE < cycle ) printk("\n[%s] thread[%x,%x] exit for <%s> / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, name, cycle ); #endif return 0; } // end fatfs_sync_inode() ////////////////////////////// error_t fatfs_sync_fat( void ) { #if DEBUG_FATFS_SYNC_FAT uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; if( DEBUG_FATFS_SYNC_FAT < cycle ) printk("\n[%s] thread[%x,%x] enter / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, cycle ); #endif uint32_t page_id; error_t error; // get FAT mapper pointers an cluster fatfs_ctx_t * fatfs_ctx = fs_context[FS_TYPE_FATFS].extend; xptr_t mapper_xp = fatfs_ctx->fat_mapper_xp; cxy_t mapper_cxy = GET_CXY( mapper_xp ); mapper_t * mapper_ptr = GET_PTR( mapper_xp ); // compute max number of 4 Kbytes pages in FAT mapper // TODO : this could be improved (see fatfs.h) [AG] uint32_t pages = fatfs_ctx->fat_sectors_count >> 3; // get pointers on remote FAT mapper radix tree grdxt_t * rt_ptr = &mapper_ptr->rt; xptr_t rt_xp = XPTR( mapper_cxy , rt_ptr ); // scan all pages for( page_id = 0 ; page_id < pages ; page_id++ ) { // get extended pointer on page descriptor from FAT mapper xptr_t page_xp = grdxt_remote_lookup( rt_xp , page_id ); // check all existing pages if ( page_xp != XPTR_NULL ) { page_t * page_ptr = GET_PTR( page_xp ); uint32_t flags = hal_remote_l32( XPTR( mapper_cxy , &page_ptr->flags ) ); if ( flags & PG_DIRTY ) { #if (DEBUG_FATFS_SYNC_FAT & 1) if( DEBUG_FATFS_SYNC_FAT < cycle ) printk("\n[%s] thread[%x,%x] synchronizes page %d from FAT mapper to IOC device\n", __FUNCTION__, page_id ); #endif // move page from mapper to device error = fatfs_move_page( page_xp , IOC_SYNC_WRITE ); if ( error ) return -1; // reset page dirty flag ppm_page_undo_dirty( page_xp ); } } } // end loop on pages #if DEBUG_FATFS_SYNC_FAT cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_SYNC_FAT < cycle ) printk("\n[%s] thread[%x,%x] exit / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, cycle ); #endif return 0; } // end fatfs_sync_fat() //////////////////////////////////// error_t fatfs_sync_free_info( void ) { error_t error; fatfs_ctx_t * fatfs_ctx_ptr; // local pointer on fatfs context in cluster 0 uint32_t ctx_free_clusters; // number of free clusters from fatfs context uint32_t ctx_free_cluster_hint; // free cluster hint from fatfs context uint32_t ioc_free_clusters; // number of free clusters from fatfs context uint32_t ioc_free_cluster_hint; // free cluster hint from fatfs context uint32_t fs_info_lba; // lba of FS_INFO sector on IOC device uint8_t * fs_info_buffer; // local pointer on FS_INFO buffer in cluster 0 xptr_t fs_info_buffer_xp; // extended pointer on FS_INFO buffer in cluster 0 uint8_t tmp_buf[512]; // 512 bytes temporary buffer xptr_t tmp_buf_xp; // extended pointer on temporary buffer #if DEBUG_FATFS_SYNC_FSINFO uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; if( DEBUG_FATFS_SYNC_FSINFO < cycle ) printk("\n[%s] thread[%x,%x] enter / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, cycle ); #endif // get pointer on fatfs context in cluster 0 fatfs_ctx_ptr = hal_remote_lpt( XPTR( 0 , &fs_context[FS_TYPE_FATFS].extend ) ); // get "free_clusters" and "free_cluster_hint" from fatfs context in cluster 0 ctx_free_clusters = hal_remote_l32( XPTR( 0 , &fatfs_ctx_ptr->free_clusters ) ); ctx_free_cluster_hint = hal_remote_l32( XPTR( 0 , &fatfs_ctx_ptr->free_cluster_hint ) ); // get fs_info_lba fs_info_lba = hal_remote_l32( XPTR( 0 , &fatfs_ctx_ptr->fs_info_lba ) ); // build extended pointer on temporary buffer tmp_buf_xp = XPTR( local_cxy , tmp_buf ); // copy FS_INFO sector from IOC to local buffer error = dev_ioc_sync_read( tmp_buf_xp , fs_info_lba , 1 ); if ( error ) { printk("\n[ERROR] in %s : cannot access FS_INFO on IOC device\n", __FUNCTION__ ); return -1; } // get current values of "free_clusters" and "free_cluster_hint" from FS_INFO on IOC ioc_free_clusters = fatfs_get_remote_record( FS_FREE_CLUSTERS , tmp_buf_xp ); ioc_free_cluster_hint = fatfs_get_remote_record( FS_FREE_CLUSTER_HINT , tmp_buf_xp ); #if DEBUG_FATFS_SYNC_FSINFO if( DEBUG_FATFS_SYNC_FSINFO < cycle ) printk("\n[%s] thread[%x,%x] / ctx_free %x / ioc_free %x / ctx_hint %x / ioc_hint %x\n", __FUNCTION__ , this->process->pid, this->trdid, ctx_free_clusters, ioc_free_clusters, ctx_free_cluster_hint, ioc_free_cluster_hint ); #endif // check values if( (ioc_free_clusters != ctx_free_clusters) || (ioc_free_cluster_hint != ctx_free_cluster_hint) ) { printk("\n[WARNING] in %s : unconsistent free clusters info\n" " ioc_free %x / ctx_free %x / ioc_hint %x / ctx_hint %x\n", __FUNCTION__, ioc_free_clusters, ctx_free_clusters, ioc_free_cluster_hint, ctx_free_cluster_hint ); // get pointers on FS_INFO buffer in cluster 0 fs_info_buffer = hal_remote_lpt( XPTR( 0 , &fatfs_ctx_ptr->fs_info_buffer ) ); fs_info_buffer_xp = XPTR( 0 , fs_info_buffer ); // update FS_INFO buffer in cluster 0 fatfs_set_remote_record(FS_FREE_CLUSTERS ,fs_info_buffer_xp,ctx_free_clusters ); fatfs_set_remote_record(FS_FREE_CLUSTER_HINT,fs_info_buffer_xp,ctx_free_cluster_hint); // update the FS_INFO sector on IOC device error = dev_ioc_sync_write( fs_info_buffer_xp , fs_info_lba , 1 ); if ( error ) { printk("\n[ERROR] in %s : cannot update FS_INFO on IOC device\n", __FUNCTION__ ); return -1; } } #if DEBUG_FATFS_SYNC_FSINFO cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_SYNC_FSINFO < cycle ) printk("\n[%s] thread[%x,%x] exit / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, cycle ); #endif return 0; } // end fatfs_sync_free_info() ////////////////////////////////////////////////////////// error_t fatfs_cluster_alloc( uint32_t * searched_cluster ) { error_t error; uint32_t page_id; // page index in FAT mapper uint32_t slot_id; // slot index in page (1024 slots per page) uint32_t cluster; // first free cluster index in FAT uint32_t free_clusters; // total number of free clusters vfs_ctx_t * vfs_ctx; // local pointer on VFS context (same in all clusters) fatfs_ctx_t * loc_fatfs_ctx; // local pointer on local FATFS context fatfs_ctx_t * fat_fatfs_ctx; // local pointer on FATFS context in FAT cluster xptr_t fat_mapper_xp; // extended pointer on FAT mapper cxy_t fat_cxy; // Fat mapper cluster identifier xptr_t page_xp; // extended pointer on current page descriptor in mapper xptr_t slot_xp; // extended pointer on FAT slot defined by hint xptr_t lock_xp; // extended pointer on lock protecting free clusters info xptr_t hint_xp; // extended pointer on free_cluster_hint in FAT cluster xptr_t free_xp; // extended pointer on free_clusters_number in FAT cluster #if DEBUG_FATFS_CLUSTER_ALLOC uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; if( DEBUG_FATFS_CLUSTER_ALLOC < cycle ) printk("\n[%s] thread[%x,%x] enter / cycle = %d\n", __FUNCTION__, this->process->pid, this->trdid, cycle ); #endif // get local pointer on VFS context (same in all clusters) vfs_ctx = &fs_context[FS_TYPE_FATFS]; // get local pointer on local FATFS context loc_fatfs_ctx = vfs_ctx->extend; // get extended pointer on FAT mapper fat_mapper_xp = loc_fatfs_ctx->fat_mapper_xp; // get FAT cluster fat_cxy = GET_CXY( fat_mapper_xp ); // get local pointer on FATFS context in FAT cluster fat_fatfs_ctx = hal_remote_lpt( XPTR( fat_cxy , &vfs_ctx->extend ) ); // build relevant extended pointers on free clusters info in mapper cluster lock_xp = XPTR( fat_cxy , &fat_fatfs_ctx->lock ); hint_xp = XPTR( fat_cxy , &fat_fatfs_ctx->free_cluster_hint ); free_xp = XPTR( fat_cxy , &fat_fatfs_ctx->free_clusters ); // take the FAT lock in write mode remote_rwlock_wr_acquire( lock_xp ); // get hint and free_clusters values from FATFS context in FAT cluster cluster = hal_remote_l32( hint_xp ) + 1; free_clusters = hal_remote_l32( free_xp ); #if (DEBUG_FATFS_CLUSTER_ALLOC & 1) if( DEBUG_FATFS_CLUSTER_ALLOC < cycle ) printk("\n[%s] thread[%x,%x] get free info : hint %x / free_clusters %x\n", __FUNCTION__, this->process->pid, this->trdid, (cluster - 1), free_clusters ); #endif // check "free_clusters" if ( free_clusters == 0 ) { printk("\n[ERROR] in %s : no more free FATFS clusters\n", __FUNCTION__ ); remote_rwlock_wr_release( lock_xp ); return -1; } else if ( free_clusters < CONFIG_VFS_FREE_CLUSTERS_MIN ) { printk("\n[WARNING] in %s : only %n free FATFS clusters\n", __FUNCTION__, CONFIG_VFS_FREE_CLUSTERS_MIN ); } // get page index & slot index for selected cluster page_id = cluster >> 10; slot_id = cluster & 0x3FF; // get relevant page descriptor from FAT mapper page_xp = mapper_remote_get_page( fat_mapper_xp , page_id ); if( page_xp == XPTR_NULL ) { printk("\n[ERROR] in %s : cannot acces FAT mapper\n", __FUNCTION__ ); remote_rwlock_wr_release( lock_xp ); return -1; } // build extended pointer on selected cluster slot in FAT mapper slot_xp = ppm_page2base( page_xp ) + (slot_id << 2); // check selected cluster actually free if( hal_remote_l32( slot_xp ) != FREE_CLUSTER ) { printk("\n[ERROR] in %s : selected cluster %x not free\n", __FUNCTION__, cluster ); remote_rwlock_wr_release( lock_xp ); return -1; } // update free cluster info in FATFS context and in FS_INFO sector error = fatfs_free_clusters_decrement( XPTR( fat_cxy , fat_fatfs_ctx ) , cluster ); if( error ) { printk("\n[ERROR] in %s : cannot update free cluster info\n", __FUNCTION__ ); remote_rwlock_wr_release( lock_xp ); return -1; } // update FAT mapper hal_remote_s32( slot_xp , END_OF_CHAIN_CLUSTER_MAX ); // we don't mark the FAT mapper page as dirty, // because we synchronously update FAT on IOC device error = fatfs_move_page( page_xp , IOC_SYNC_WRITE ); if( error ) { printk("\n[ERROR] in %s : cannot update FAT on IOC device\n", __FUNCTION__ ); remote_rwlock_wr_release( lock_xp ); return -1; } // release FAT lock remote_rwlock_wr_release( lock_xp ); #if DEBUG_FATFS_CLUSTER_ALLOC cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_CLUSTER_ALLOC < cycle ) printk("\n[%s] thread[%x,%x] exit / allocated cluster %x in FAT / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, cluster, cycle ); #endif *searched_cluster = cluster; return 0; } // end fat_cluster_alloc() ////////////////////////////////////////////// error_t fatfs_release_inode( xptr_t inode_xp ) { vfs_ctx_t * vfs_ctx; // local pointer on VFS context (same in all clusters). fatfs_ctx_t * loc_fatfs_ctx; // local pointer on local FATFS context cxy_t fat_cxy; // FAT cluster identifier xptr_t fatfs_ctx_xp; // extended pointer on FATFS context in FAT cluster fatfs_ctx_t * fatfs_ctx_ptr; // local pointer on FATFS context in FAT cluster xptr_t fat_mapper_xp; // extended pointer on FAT mapper xptr_t lock_xp; // extended pointer on lock protecting FAT. xptr_t first_xp; // extended pointer on inode extension uint32_t first_cluster; // first cluster index for released inode vfs_inode_t * inode_ptr; // local pointer on target inode cxy_t inode_cxy; // target inode cluster identifier error_t error; // check inode pointer assert( (inode_xp != XPTR_NULL) , "inode pointer is NULL\n" ); // get inode cluster and local pointer inode_ptr = GET_PTR( inode_xp ); inode_cxy = GET_CXY( inode_xp ); // get first_cluster from inode extension first_xp = XPTR( inode_cxy , &inode_ptr->extend ); first_cluster = (uint32_t)(intptr_t)hal_remote_lpt( first_xp ); // check first cluster index assert( (first_cluster != 0) , "inode extend is NULL\n" ); #if DEBUG_FATFS_RELEASE_INODE char name[CONFIG_VFS_MAX_NAME_LENGTH]; uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; vfs_inode_get_name( inode_xp , name ); if( DEBUG_FATFS_RELEASE_INODE < cycle ) printk("\n[%s] thread[%x,%x] enter for <%s> / first_cluster %x / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, name, first_cluster, cycle ); #endif // get local pointer on VFS context (same in all clusters) vfs_ctx = &fs_context[FS_TYPE_FATFS]; // get local pointer on local FATFS context loc_fatfs_ctx = vfs_ctx->extend; // get FAT mapper cluster fat_mapper_xp = loc_fatfs_ctx->fat_mapper_xp; fat_cxy = GET_CXY( fat_mapper_xp ); // get pointers on FATFS context in FAT cluster fatfs_ctx_ptr = hal_remote_lpt( XPTR( fat_cxy , &vfs_ctx->extend ) ); fatfs_ctx_xp = XPTR( fat_cxy , fatfs_ctx_ptr ); // get extended pointer on FAT lock in FAT cluster lock_xp = XPTR( fat_cxy , &fatfs_ctx_ptr->lock ); // take FAT lock in write mode remote_rwlock_wr_acquire( lock_xp ); #if (DEBUG_FATFS_RELEASE_INODE & 0x11 == 0x11) mapper_display_page( fat_mapper_xp , 0 , 4096 ); #endif // call the recursive function to release all clusters from FAT mapper uint32_t dirty_page_min = 0xFFFFFFFF; uint32_t dirty_page_max = 0; if ( fatfs_recursive_release( fat_mapper_xp, fatfs_ctx_xp, first_cluster, &dirty_page_min, &dirty_page_max ) ) { printk("\n[ERROR] in %s : cannot update FAT mapper\n", __FUNCTION__ ); remote_rwlock_wr_release( lock_xp ); return -1; } #if (DEBUG_FATFS_RELEASE_INODE & 1) if( DEBUG_FATFS_RELEASE_INODE < cycle ) printk("\n[%s] inode <%s> removed from FAT mapper\n", __FUNCTION__, name ); #endif #if (DEBUG_FATFS_RELEASE_INODE & 0x11 == 0x11) mapper_display_page( fat_mapper_xp , 0 , 4096 ); #endif // update FAT on IOC device (from FAT mapper) error = fatfs_update_ioc_fat( fatfs_ctx_xp, dirty_page_min, dirty_page_max ); if( error ) { printk("\n[ERROR] in %s : cannot update FAT on IOC device\n", __FUNCTION__ ); remote_rwlock_wr_release( lock_xp ); return -1; } #if (DEBUG_FATFS_RELEASE_INODE & 1) if( DEBUG_FATFS_RELEASE_INODE < cycle ) printk("\n[%s] inode <%s> removed from FAT on IOC device\n", __FUNCTION__, name ); #endif // update FS-INFO on IOC device (from FATFS context) error = fatfs_update_ioc_fsinfo( fatfs_ctx_xp ); if( error ) { printk("\n[ERROR] in %s: cannot update FSINFO on IOC device\n", __FUNCTION__ ); remote_rwlock_wr_release( lock_xp ); return -1; } #if (DEBUG_FATFS_RELEASE_INODE & 1) if( DEBUG_FATFS_RELEASE_INODE < cycle ) printk("\n[%s] updated FS_INFO on IOC device for >%s>\n", __FUNCTION__, name ); #endif // release FAT lock remote_rwlock_wr_release( lock_xp ); #if DEBUG_FATFS_RELEASE_INODE cycle = (uint32_t)hal_get_cycles(); if( DEBUG_FATFS_RELEASE_INODE < cycle ) printk("\n[%s] thread[%x,%x] removed <%s> inode from FATFS / cycle %d\n", __FUNCTION__ , this->process->pid, this->trdid, name, cycle ); #endif return 0; } // end fatfs_release_inode() //////////////////////////////////////////// error_t fatfs_move_page( xptr_t page_xp, cmd_type_t cmd_type ) { error_t error; vfs_inode_t * inode_ptr; mapper_t * mapper_ptr; uint32_t page_id; // page index in mapper #if DEBUG_FATFS_MOVE_PAGE uint32_t cycle = (uint32_t)hal_get_cycles(); thread_t * this = CURRENT_THREAD; char name[CONFIG_VFS_MAX_NAME_LENGTH]; #endif // get page cluster an local pointer cxy_t page_cxy = GET_CXY( page_xp ); page_t * page_ptr = GET_PTR( page_xp ); // get mapper pointer and page index from page descriptor mapper_ptr = hal_remote_lpt( XPTR( page_cxy , &page_ptr->mapper ) ); page_id = hal_remote_l32( XPTR( page_cxy , &page_ptr->index ) ); // get pointer on local FATFS context fatfs_ctx_t * fatfs_ctx = fs_context[FS_TYPE_FATFS].extend; // get page base address xptr_t buffer_xp = ppm_page2base( page_xp ); uint8_t * buffer_ptr = (uint8_t *)GET_PTR( buffer_xp ); // get inode pointer from mapper inode_ptr = hal_remote_lpt( XPTR( page_cxy , &mapper_ptr->inode ) ); #if DEBUG_FATFS_MOVE_PAGE if( DEBUG_FATFS_MOVE_PAGE < cycle ) printk("\n[%s] thread[%x,%x] enters : %s / cxy %x / mapper %x / inode %x / page %x\n", __FUNCTION__, this->process->pid, this->trdid, dev_ioc_cmd_str( cmd_type ), page_cxy, mapper_ptr, inode_ptr, buffer_ptr ); #endif ////////////////////////////// FAT mapper if( inode_ptr == NULL ) { // get lba from FATFS context and page_id uint32_t lba = fatfs_ctx->fat_begin_lba + (page_id << 3); // access device if (cmd_type == IOC_SYNC_READ ) error = dev_ioc_sync_read ( buffer_xp , lba , 8 ); else if(cmd_type == IOC_SYNC_WRITE) error = dev_ioc_sync_write( buffer_xp , lba , 8 ); else if(cmd_type == IOC_READ ) error = dev_ioc_read ( buffer_ptr , lba , 8 ); else if(cmd_type == IOC_WRITE ) error = dev_ioc_write ( buffer_ptr , lba , 8 ); else error = -1; if( error ) { printk("\n[ERROR] in %s : cannot access device\n", __FUNCTION__ ); return -1; } #if DEBUG_FATFS_MOVE_PAGE if( DEBUG_FATFS_MOVE_PAGE < cycle ) { if ( (cmd_type == IOC_READ) || (cmd_type == IOC_SYNC_READ) ) printk("\n[%s] thread[%x,%x] load FAT mapper page %d from IOC / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, page_id, cycle ); else printk("\n[%s] thread[%x,%x] sync FAT mapper page %d to IOC / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, page_id, cycle ); } #endif } ///////////////////////// inode mapper else { #if DEBUG_FATFS_MOVE_PAGE vfs_inode_get_name( XPTR( page_cxy , inode_ptr ) , name ); #endif uint32_t searched_cluster; uint32_t first_cluster; // get first_cluster from inode extension void * extend = hal_remote_lpt( XPTR( page_cxy , &inode_ptr->extend ) ); first_cluster = (uint32_t)(intptr_t)extend; // compute searched_cluster if( page_id == 0 ) // no need to access FAT mapper { // searched cluster is first cluster searched_cluster = first_cluster; } else // FAT mapper access required { // access FAT mapper to get searched cluster error = fatfs_get_cluster( first_cluster, page_id, &searched_cluster ); if( error ) { printk("\n[ERROR] in %s : cannot access FAT mapper\n", __FUNCTION__ ); return -1; } } // get lba for searched_cluster uint32_t lba = fatfs_lba_from_cluster( fatfs_ctx , searched_cluster ); // access device if (cmd_type == IOC_SYNC_READ ) error = dev_ioc_sync_read ( buffer_xp , lba , 8 ); else if(cmd_type == IOC_SYNC_WRITE) error = dev_ioc_sync_write( buffer_xp , lba , 8 ); else if(cmd_type == IOC_READ ) error = dev_ioc_read ( buffer_ptr , lba , 8 ); else if(cmd_type == IOC_WRITE ) error = dev_ioc_write ( buffer_ptr , lba , 8 ); else error = -1; if( error ) { printk("\n[ERROR] in %s : cannot access device\n", __FUNCTION__ ); return -1; } #if DEBUG_FATFS_MOVE_PAGE if( DEBUG_FATFS_MOVE_PAGE < cycle ) { if ( (cmd_type == IOC_READ) || (cmd_type == IOC_SYNC_READ) ) printk("\n[%s] thread[%x,%x] load page %d of <%s> / cluster_id %x / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, page_id, name, searched_cluster, cycle ); else printk("\n[%s] thread[%x,%x] sync page %d of <%s> / cluster_id %x / cycle %d\n", __FUNCTION__, this->process->pid, this->trdid, page_id, name, searched_cluster, cycle ); } #endif } return 0; } // end fatfs_move_page()