Index: trunk/kernel/fs/fatfs.h
===================================================================
--- trunk/kernel/fs/fatfs.h	(revision 484)
+++ trunk/kernel/fs/fatfs.h	(revision 602)
@@ -3,5 +3,5 @@
  *
  * Author    Mohamed Lamine Karaoui (2014,2015)
- *           Alain Greiner (2016,2017)
+ *           Alain Greiner (2016,2017,2018)
  *
  * Copyright (c) UPMC Sorbonne Universites
@@ -27,5 +27,5 @@
 
 #include <hal_kernel_types.h>
-#include <rwlock.h>
+#include <remote_queuelock.h>
 #include <vfs.h>
 
@@ -35,4 +35,5 @@
 //
 // The FATFS extensions to the generic VFS are the following:
+//
 // 1) The vfs_ctx_t "extend" field is a void* pointing on the fatfs_ctx_t structure.
 //    This structure contains various general informations such as the total
@@ -41,6 +42,10 @@
 //    cluster index for the root directory. It contains also an extended pointer
 //    on the FAT mapper.
-// 2) The vfs_inode_t "extend" field is a void*, but contains for each inode,
+//
+// 2) The vfs_inode_t "extend" contains, for each inode,
 //    the first FAT cluster index (after cast to intptr).
+//
+// 3) The vfs_dentry_t "extend" field contains, for each dentry, the entry index
+//    in the FATFS directory (32 bytes per FATFS entry). 
 ///////////////////////////////////////////////////////////////////////////////////////////
 
@@ -163,20 +168,28 @@
 struct vfs_ctx_s;
 struct vfs_inode_s;
-
-/*****************************************************************************************
- * This structure defines a FATFS specific context (extension to VFS context). 
+struct vfs_dentry_s;
+
+/*****************************************************************************************
+ * This structure defines a FATFS specific context (extension to VFS context).
+ * This extension is replicated in all clusters.
+ *
+ * WARNING : Almost all fields are constant values, but the <free_cluster_hint> and
+ * <free_clusters> are shared variables. All kernel instances use the variables
+ * in cluster 0, using the <free_lock> remote busy_lock for exclusive access.
  ****************************************************************************************/
 
 typedef struct fatfs_ctx_s
 {
-    uint32_t          fat_sectors_count;     /*! number of sectors in FAT region        */
-    uint32_t          bytes_per_sector;      /*! number of bytes per sector             */
-    uint32_t          sectors_per_cluster;   /*! number of sectors per cluster          */
-    uint32_t          fat_begin_lba;         /*! lba of FAT region                      */
-    uint32_t          cluster_begin_lba;     /*! lba of data region                     */
-    uint32_t          root_dir_cluster;      /*! cluster index for the root directory   */
-    uint32_t          last_allocated_sector; /*! TODO ???                               */
-    uint32_t          last_allocated_index;  /*! TODO ???                               */
-    xptr_t            fat_mapper_xp;         /*! FAT mapper (in IO cluster)             */
+    uint32_t            fat_sectors_count;     /*! number of sectors in FAT region      */
+    uint32_t            bytes_per_sector;      /*! number of bytes per sector           */
+    uint32_t            sectors_per_cluster;   /*! number of sectors per cluster        */
+    uint32_t            fat_begin_lba;         /*! lba of FAT region                    */
+    uint32_t            cluster_begin_lba;     /*! lba of data region                   */
+    uint32_t            fs_info_lba;           /*! lba of FS_INFO sector                */
+    uint32_t            root_dir_cluster;      /*! cluster index for  root directory    */
+    xptr_t              fat_mapper_xp;         /*! extended pointer on FAT mapper       */
+    uint32_t            free_cluster_hint;     /*! start point to search free cluster   */
+    uint32_t            free_clusters;         /*! free clusters number                 */
+    remote_queuelock_t  free_lock;             /*! exclusive access to hint & number    */
 }
 fatfs_ctx_t;
@@ -186,11 +199,10 @@
 //////////////////////////////////////////////////////////////////////////////////////////
 
-/******************************************************************************************
- * This function scan the FAT (File Allocation Table), stored in the FAT mapper,
- * and returns the FATFS cluster index for a given page of a given file.
- * It must be called by a thread running in the cluster containing the FAT mapper.
- * We can use a RPC to scan the remote FAT mapper, because the RPC_FIFO will avoid 
- * contention in the cluster containing the FAT mapper, and the RPC latency is not 
- * critical compared to the device access latency.
+/*****************************************************************************************
+ * This function access the FAT (File Allocation Table), stored in the FAT mapper, and
+ * returns in <searched_cluster> the FATFS cluster index for a given page of a given 
+ * inode identified by the <first_cluster> and <page_id> arguments.
+ * It can be called by a thread running in any cluster, as it uses remote access
+ * primitives when the FAT mapper is remote.
  * The FAT is actually an array of uint32_t slots. Each slot in this array contains the 
  * index of another slot in this array, to form one linked list for each file stored on
@@ -198,38 +210,47 @@
  * FATFS cluster on the device. One FATFS cluster is supposed to contain one PPM page. 
  * For a given file, the entry point in the FAT is simply the index of the FATFS cluster 
- * containing the first page of the file. The mapper being a cache, this function 
- * automatically updates the FAT mapper from informations stored on device in case of miss.
- ******************************************************************************************
- * @ mapper	             : local pointer on the FAT mapper.
- * @ first_cluster   	 : index of the first FATFS cluster allocated to the file.
- * @ page_index          : index of searched page in file.
- * @ searched_cluster_id : [out] found FATFS cluster index.
- * @ return 0 if success / return EIO if a FAT mapper miss cannot be solved.
- *****************************************************************************************/
-error_t fatfs_get_cluster( struct mapper_s * mapper,
-                           uint32_t          first_cluster,
-                           uint32_t          page_index,
-                           uint32_t        * searched_cluster_id );
-
-/******************************************************************************************
+ * containing the first page of the file. The FAT mapper being a cache, this function 
+ * updates the FAT mapper from informations stored on IOC device in case of miss.
+ *****************************************************************************************
+ * @ first_cluster   	 : [in]  index of first FATFS cluster allocated to the file.
+ * @ page_id             : [in]  index of searched page in file.
+ * @ searched_cluster    : [out] found FATFS cluster index.
+ * @ return 0 if success / return -1 if a FAT mapper miss cannot be solved.
+ ****************************************************************************************/
+error_t fatfs_get_cluster( uint32_t   first_cluster,
+                           uint32_t   page_id,
+                           uint32_t * searched_cluster );
+
+/*****************************************************************************************
  * This function display the content of the FATFS context.
- *****************************************************************************************/
+ ****************************************************************************************/
 void fatfs_ctx_display( void );
 
+/*****************************************************************************************
+ * This function displays the content of a part of the File Allocation Table.
+ * It loads the requested page fom device to mapper if required.
+ *****************************************************************************************
+ * @ page_id   : page index in FAT mapper (one page is 4 Kbytes).
+ * @ nentries  : number of entries (one entry is 4 bytes).
+ ****************************************************************************************/
+void fatfs_display_fat( uint32_t  page_id,
+                        uint32_t  nentries );
+
+
 
 //////////////////////////////////////////////////////////////////////////////////////////
-// Generic API: These functions are called by the kernel,
+// Generic API: These functions are called by the kernel VFS,
 //              and must be implemented by all File Systems.
 //////////////////////////////////////////////////////////////////////////////////////////
 
-/******************************************************************************************
+/*****************************************************************************************
  * This fuction allocates memory from local cluster for a FATFS context descriptor.
- ******************************************************************************************
+ *****************************************************************************************
  * @ return a pointer on the created context / return NULL if failure.
- *****************************************************************************************/
+ ****************************************************************************************/
 fatfs_ctx_t * fatfs_ctx_alloc( void );
 
 /*****************************************************************************************
- * This function access the boot device, and initialises the FATFS context
+ * This function access the boot device, and initialises the local FATFS context
  * from informations contained in the boot record. 
  *****************************************************************************************
@@ -246,22 +267,53 @@
 
 /*****************************************************************************************
- * This function moves a page from/to the mapper to/from the FATFS file system on device.
- * It must be called by a thread running in cluster containing the mapper.
- * The pointer on the mapper and the page index in file are found in the page descriptor.
- * WARNING : The inode field in the mapper MUST be NULL for the FAT mapper, as this
- * is used to implement a specific behaviour to access the FAT zone on device.
- *****************************************************************************************
- * @ page      : local pointer on page descriptor.
- * @ to_mapper : transfer direction
- * @ return 0 if success / return EIO if error. 
- ****************************************************************************************/
-error_t fatfs_mapper_move_page( struct page_s * page,
-                                bool_t          to_mapper );
-
-/*****************************************************************************************
- * This function scan an existing parent directory, identified by the <parent> argument,
- * to find a directory entry identified by the <name> argument and update the remote
- * child inode descriptor, identified by the <child_xp> argument.
- * It set the "type", "size", and "extend" (FAT cluster index) fields in child inode.
+ * This function implements the generic vfs_fs_add_dentry() function for the FATFS.
+ *****************************************************************************************
+ * This function updates a directory identified by the <inode> argument
+ * to add a new directory entry identified by the <dentry> argument.
+ * All modified pages in directory mapper are synchronously updated on IOC device.
+ * It must be called by a thread running in the cluster containing the inode.
+ *
+ * Implementation note : this function works in two steps:
+ * - It scan the set of 32 bytes FATFS directry entries, using two embedded loops  
+ *   to find the end of directory (NO_MORE_ENTRY marker).
+ * - Then it writes 3, 4, or 5 directory entries (depending on the name length), using 
+ *   a 5 steps FSM (one state per entry to be written), updates on IOC device the 
+ *   modified pages, and updates the dentry extension field, that must contain 
+ *   the dentry index in FATFS directory.
+ *****************************************************************************************
+ * @ inode    : local pointer on directory inode.
+ * @ dentry   : local pointer on dentry.
+ * @ return 0 if success / return ENOENT if not found, or EIO if no access to IOC device.
+ ****************************************************************************************/
+error_t fatfs_add_dentry( struct vfs_inode_s  * inode,
+                          struct vfs_dentry_s * dentry );
+
+/*****************************************************************************************
+ * This function implements the generic vfs_fs_remove_dentry() function for the FATFS.
+ *****************************************************************************************
+ * This function updates a directory identified by the <inode> argument
+ * to remove a directory entry identified by the <dentry> argument.
+ * All modified pages in directory mapper are synchronously updated on IOC device.
+ * It must be called by a thread running in the cluster containing the inode.
+ *
+ * Implementation note: this function uses the dentry extension to directly access 
+ * the NORMAL directory entry and invalidate all involved LFN entries. Then it
+ * updates the modified pages on IOC device.
+ *****************************************************************************************
+ * @ inode    : local pointer on directory inode.
+ * @ dentry   : local pointer on dentry.
+ * @ return 0 if success / return ENOENT if not found, or EIO if no access to IOC device.
+ ****************************************************************************************/
+error_t fatfs_remove_dentry( struct vfs_inode_s  * inode,
+                             struct vfs_dentry_s * dentry );
+
+/*****************************************************************************************
+ * This function implements the generic vfs_fs_child_init() function for the FATFS.
+ *****************************************************************************************
+ * It scan the mapper of an existing parent directory, identified by the <parent> 
+ * argument, to find a directory entry identified by the <name> argument.
+ * It updates the existing remote child inode, identified by the <child_xp> argument,
+ * - it set the "type", "size", and "extend" fields in inode descriptor.
+ * - it set the " extend" field in dentry descriptor.
  * It must be called by a thread running in the cluster containing the parent inode.
  *****************************************************************************************
@@ -271,7 +323,111 @@
  * @ return 0 if success / return ENOENT if child not found.
  ****************************************************************************************/
-error_t fatfs_inode_load( struct vfs_inode_s * parent_inode,
+error_t fatfs_child_init( struct vfs_inode_s * parent_inode,
                           char               * name,
                           xptr_t               child_inode_xp );
 
+/*****************************************************************************************
+ * This function implements the generic vfs_fs_sync_inode() function for the FATFS.
+ *****************************************************************************************
+ * It updates the FATFS on the IOC device for a given inode identified by 
+ * the <inode> argument. It scan all pages registered in the associated mapper,
+ * and copies from mapper to device each page marked as dirty.
+ * WARNING : The target <inode> cannot be a directory, because all modifications in a 
+ * directory * are synchronously done on the IOC device by the two fatfs_add_dentry() 
+ * and fatfs_remove_dentry() functions.
+ *****************************************************************************************
+ * @ inode   : local pointer on inode.
+ * @ return 0 if success / return EIO if failure during device access. 
+ ****************************************************************************************/
+error_t fatfs_sync_inode( struct vfs_inode_s * inode );
+
+/*****************************************************************************************
+ * This function implements the generic vfs_fs_sync_fat() function for the FATFS.
+ *****************************************************************************************
+ * It updates the FATFS on the IOC device for the FAT itself.
+ * It scan all clusters registered in the FAT mapper, and copies from mapper to device 
+ * each page marked as dirty.
+ *
+ * TODO : the current implementation check ALL pages in the FAT region, even if most
+ * pages are empty, and not copied in mapper. It is sub-optimal.
+ * - A first solution is to maintain in the FAT context two "dirty_min" and "dirty_max"
+ *  variables defining the smallest/largest dirty page index in FAT mapper... 
+ *****************************************************************************************
+ * @ return 0 if success / return EIO if failure during device access.
+ ****************************************************************************************/
+error_t fatfs_sync_fat( void );
+
+/*****************************************************************************************
+ * This function implements the generic vfs_fs_sync_fsinfo() function for the FATFS.
+ *****************************************************************************************
+ * It updates the FS_INFO sector on the IOC device. 
+ * It copies the <free_cluster_hint> and <free_clusters> variables from
+ * the FATFS context in cluster 0 to the FS_INFO sector on device. 
+ *****************************************************************************************
+ * @ return 0 if success / return EIO if failure during device access.
+ ****************************************************************************************/
+error_t fatfs_sync_free_info( void );
+
+/*****************************************************************************************
+ * This function implements the generic vfs_fs_cluster_alloc() function for the FATFS.
+ *****************************************************************************************
+ * It access the FAT (File allocation table), stored in the FAT mapper, and returns
+ * in <searched_cluster> the FATFS cluster index of a free cluster.
+ * It can be called by a thread running in any cluster, as it uses remote access
+ * primitives when the FAT mapper is remote. It takes the "free_lock" stored in the 
+ * FATFS context located in the same cluster as the FAT mapper itself, to get exclusive
+ * access to the FAT. It uses (and updates) the <free_cluster_hint> and <free_clusters> 
+ * shared variables in this FATFS context.
+ * It updates the FAT mapper, and synchronously updates the FAT region on IOC device. 
+ * The FAT mapper being a cache, this function updates the FAT mapper from informations
+ * stored on IOC device in case of miss.
+ *****************************************************************************************
+ * @ searched_cluster    : [out] found FATFS cluster index.
+ * @ return 0 if success / return -1 if no more free clusters on IOC device.
+ ****************************************************************************************/
+error_t fatfs_cluster_alloc( uint32_t * searched_cluster );
+
+/*****************************************************************************************
+ * This function implements the generic vfs_fs_release_inode() function for the FATFS.
+ *****************************************************************************************
+ * It releases all clusters allocated to a file/directory identified by the <inode_xp>
+ * argument. All released clusters are marked FREE_CLUSTER in the FAT mapper. 
+ * This function calls the recursive function fatfs_cluster_release() to release 
+ * the clusters in reverse order of the linked list (from last to first). 
+ * When the FAT mapper has been updated, it calls the fatfs_sync_fat() function to
+ * synchronously update all dirty pages in the FAT mapper to the IOC device.
+ * Finally the FS-INFO sector on the IOC device is updated.
+ *****************************************************************************************
+ * @ inode_xp   : extended pointer on inode.
+ * @ return 0 if success / return EIO if failure during device access.
+ ****************************************************************************************/
+error_t fatfs_release_inode( xptr_t inode_xp );
+
+/*****************************************************************************************
+ * This function implements the generic vfs_fs_move_page() function for the FATFS.
+ *****************************************************************************************
+ * This function moves a page from/to the mapper to/from the FATFS file system on device.
+ * The page must have been previously allocated and registered in the mapper, but the  
+ * page - and the mapper - can be located in another cluster than the calling thread.
+ * The pointer on the mapper and the page index in file are found in the page descriptor.
+ * It is used both for the regular file/directory mappers, and for the FAT mapper.
+ * For the FAT mapper, it access the FATFS to get the location on IOC device.
+ * For a regular file, it access the FAT mapper to get the cluster index on IOC device.
+ * It can be called by any thread running in any cluster.
+ *
+ * WARNING : For the FAT mapper, the inode field in the mapper MUST be NULL, as this
+ * is used to indicate that the corresponding mapper is the FAT mapper.
+ *****************************************************************************************
+ * @ page_xp   : extended pointer on page descriptor.
+ * @ to_mapper : true for device->mapper / false for mapper->device
+ * @ return 0 if success / return EIO if error during device access. 
+ ****************************************************************************************/
+error_t fatfs_move_page( xptr_t  page_xp,
+                         bool_t  to_mapper );
+
+
+
+
+
+
 #endif	/* _FATFS_H_ */
