[PATCH v2] dosfs: Lazy update of FAT32 FS info sector

Sebastian Huber sebastian.huber at embedded-brains.de
Fri Nov 9 09:08:07 UTC 2012


The FAT32 FS info sector contains hints for the free cluster count and
the next free cluster.  The previous code read these values during mount
and replaced them with invalid values.  The shutdown operation updated
them with the current values.  These values are only hints.  Every FAT
implementation must cope with arbitrary values.  They are intended to
speed up certain operations.

Now we update the free cluster count and next free culster in the FAT32
FS info sector only during unmount or sync operations and only if the
values have changed.  This avoids writes to the FS info sector and
conforms to the behaviour of Linux and Windows.

The application can force an update of these values now with the fsync()
and fdatasync() operations.  Applications that only read will perform
not write operations to the FAT32 FS info sector.

The new fat_sync() function performs all non-file specific
synchronizations.
---
 cpukit/libfs/src/dosfs/fat.c        |  141 +++++++++++++++++++----------------
 cpukit/libfs/src/dosfs/fat.h        |   10 +-
 cpukit/libfs/src/dosfs/msdos.h      |    2 -
 cpukit/libfs/src/dosfs/msdos_file.c |    2 +-
 cpukit/libfs/src/dosfs/msdos_misc.c |   15 +----
 5 files changed, 84 insertions(+), 86 deletions(-)

diff --git a/cpukit/libfs/src/dosfs/fat.c b/cpukit/libfs/src/dosfs/fat.c
index d40aaf0..c2c3e89 100644
--- a/cpukit/libfs/src/dosfs/fat.c
+++ b/cpukit/libfs/src/dosfs/fat.c
@@ -574,16 +574,12 @@ fat_init_volume_info(fat_fs_info_t *fs_info, const char *device)
                     return -1;
                 }
 
-                vol->free_cls = FAT_GET_FSINFO_FREE_CLUSTER_COUNT(fs_info_sector);
-                vol->next_cl = FAT_GET_FSINFO_NEXT_FREE_CLUSTER(fs_info_sector);
-                rc = fat_fat32_update_fsinfo_sector(fs_info, FAT_UNDEFINED_VALUE,
-                                                    FAT_UNDEFINED_VALUE);
-                if ( rc != RC_OK )
-                {
-                    _fat_block_release(fs_info);
-                    close(vol->fd);
-                    return rc;
-                }
+                vol->free_cls_in_fs_info =
+                  FAT_GET_FSINFO_FREE_CLUSTER_COUNT(fs_info_sector);
+                vol->free_cls = vol->free_cls_in_fs_info;
+                vol->next_cl_in_fs_info =
+                  FAT_GET_FSINFO_NEXT_FREE_CLUSTER(fs_info_sector);
+                vol->next_cl = vol->next_cl_in_fs_info;
             }
         }
     }
@@ -645,6 +641,75 @@ fat_init_volume_info(fat_fs_info_t *fs_info, const char *device)
     return RC_OK;
 }
 
+/* fat_fat32_update_fsinfo_sector --
+ *     Synchronize fsinfo sector for FAT32 volumes
+ *
+ * PARAMETERS:
+ *     fs_info    - FS info
+ *
+ * RETURNS:
+ *     RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+static int
+fat_fat32_update_fsinfo_sector(fat_fs_info_t *fs_info)
+{
+    ssize_t ret1 = 0, ret2 = 0;
+
+    if (fs_info->vol.type == FAT_FAT32)
+    {
+        uint32_t free_count = fs_info->vol.free_cls;
+        uint32_t next_free = fs_info->vol.next_cl;
+
+        if (free_count != fs_info->vol.free_cls_in_fs_info)
+        {
+            uint32_t le_free_count = CT_LE_L(free_count);
+
+            fs_info->vol.free_cls_in_fs_info = free_count;
+
+            ret1 = _fat_block_write(fs_info,
+                                    fs_info->vol.info_sec,
+                                    FAT_FSINFO_FREE_CLUSTER_COUNT_OFFSET,
+                                    sizeof(le_free_count),
+                                    &le_free_count);
+        }
+
+        if (next_free != fs_info->vol.next_cl_in_fs_info)
+        {
+            uint32_t le_next_free = CT_LE_L(next_free);
+
+            fs_info->vol.next_cl_in_fs_info = next_free;
+
+            ret2 = _fat_block_write(fs_info,
+                                    fs_info->vol.info_sec,
+                                    FAT_FSINFO_NEXT_FREE_CLUSTER_OFFSET,
+                                    sizeof(le_next_free),
+                                    &le_next_free);
+        }
+    }
+
+    if ( (ret1 < 0) || (ret2 < 0) )
+        return -1;
+
+    return RC_OK;
+}
+
+int
+fat_sync(fat_fs_info_t *fs_info)
+{
+    int rc = RC_OK;
+
+    rc = fat_fat32_update_fsinfo_sector(fs_info);
+    if ( rc != RC_OK )
+        rc = -1;
+
+    fat_buf_release(fs_info);
+
+    if (rtems_bdbuf_syncdev(fs_info->vol.dd) != RTEMS_SUCCESSFUL)
+        rc = -1;
+
+    return rc;
+}
+
 /* fat_shutdown_drive --
  *     Free all allocated resources and synchronize all necessary data
  *
@@ -661,17 +726,8 @@ fat_shutdown_drive(fat_fs_info_t *fs_info)
     int            rc = RC_OK;
     int            i = 0;
 
-    if (fs_info->vol.type & FAT_FAT32)
-    {
-        rc = fat_fat32_update_fsinfo_sector(fs_info, fs_info->vol.free_cls,
-                                            fs_info->vol.next_cl);
-        if ( rc != RC_OK )
-            rc = -1;
-    }
-
-    fat_buf_release(fs_info);
-
-    if (rtems_bdbuf_syncdev(fs_info->vol.dd) != RTEMS_SUCCESSFUL)
+    rc = fat_sync(fs_info);
+    if ( rc != RC_OK )
         rc = -1;
 
     for (i = 0; i < FAT_HASH_SIZE; i++)
@@ -849,46 +905,3 @@ fat_ino_is_unique(
 
     return (ino >= fs_info->uino_base);
 }
-
-/* fat_fat32_update_fsinfo_sector --
- *     Synchronize fsinfo sector for FAT32 volumes
- *
- * PARAMETERS:
- *     fs_info    - FS info
- *     free_count - count of free clusters
- *     next_free  - the next free cluster num
- *
- * RETURNS:
- *     RC_OK on success, or -1 if error occured (errno set appropriately)
- */
-int
-fat_fat32_update_fsinfo_sector(
-    fat_fs_info_t                        *fs_info,
-    uint32_t                              free_count,
-    uint32_t                              next_free
-    )
-{
-    ssize_t                 ret1 = 0, ret2 = 0;
-    uint32_t                le_free_count = 0;
-    uint32_t                le_next_free = 0;
-
-    le_free_count = CT_LE_L(free_count);
-    le_next_free = CT_LE_L(next_free);
-
-    ret1 = _fat_block_write(fs_info,
-                            fs_info->vol.info_sec,
-                            FAT_FSINFO_FREE_CLUSTER_COUNT_OFFSET,
-                            4,
-                            (char *)(&le_free_count));
-
-    ret2 = _fat_block_write(fs_info,
-                            fs_info->vol.info_sec,
-                            FAT_FSINFO_NEXT_FREE_CLUSTER_OFFSET,
-                            4,
-                            (char *)(&le_next_free));
-
-    if ( (ret1 < 0) || (ret2 < 0) )
-        return -1;
-
-    return RC_OK;
-}
diff --git a/cpukit/libfs/src/dosfs/fat.h b/cpukit/libfs/src/dosfs/fat.h
index 3a9c9c6..260d8aa 100644
--- a/cpukit/libfs/src/dosfs/fat.h
+++ b/cpukit/libfs/src/dosfs/fat.h
@@ -313,7 +313,11 @@ typedef struct fat_vol_s
     uint32_t           rdir_cl;        /* first cluster of the root directory */
     uint16_t           info_sec;       /* FSInfo Sector Structure location */
     uint32_t           free_cls;       /* last known free clusters count */
+    uint32_t           free_cls_in_fs_info; /* last known free clusters count
+                                               in FS info sector */
     uint32_t           next_cl;        /* next free cluster number */
+    uint32_t           next_cl_in_fs_info; /* next free cluster number in FS
+                                              info sector */
     uint8_t            mirror;         /* mirroring enabla/disable */
     uint32_t           afat_loc;       /* active FAT location */
     uint8_t            afat;           /* the number of active FAT */
@@ -500,11 +504,7 @@ fat_free_unique_ino(fat_fs_info_t                        *fs_info,
                     uint32_t                              ino);
 
 int
-fat_fat32_update_fsinfo_sector(
-  fat_fs_info_t                        *fs_info,
-  uint32_t                              free_count,
-  uint32_t                              next_free
-  );
+fat_sync(fat_fs_info_t *fs_info);
 
 #ifdef __cplusplus
 }
diff --git a/cpukit/libfs/src/dosfs/msdos.h b/cpukit/libfs/src/dosfs/msdos.h
index f762656..26bf906 100644
--- a/cpukit/libfs/src/dosfs/msdos.h
+++ b/cpukit/libfs/src/dosfs/msdos.h
@@ -397,8 +397,6 @@ int msdos_get_dotdot_dir_info_cluster_num_and_offset(
     char                                 *dir_entry
 );
 
-int msdos_sync_unprotected(msdos_fs_info_t *fs_info);
-
 int msdos_sync(rtems_libio_t *iop);
 
 #ifdef __cplusplus
diff --git a/cpukit/libfs/src/dosfs/msdos_file.c b/cpukit/libfs/src/dosfs/msdos_file.c
index 595bd3f..0406be0 100644
--- a/cpukit/libfs/src/dosfs/msdos_file.c
+++ b/cpukit/libfs/src/dosfs/msdos_file.c
@@ -290,7 +290,7 @@ msdos_file_sync(rtems_libio_t *iop)
         return rc;
     }
 
-    rc = msdos_sync_unprotected(fs_info);
+    rc = fat_sync(&fs_info->fat);
 
     rtems_semaphore_release(fs_info->vol_sema);
     return RC_OK;
diff --git a/cpukit/libfs/src/dosfs/msdos_misc.c b/cpukit/libfs/src/dosfs/msdos_misc.c
index fade1e9..f4de0d5 100644
--- a/cpukit/libfs/src/dosfs/msdos_misc.c
+++ b/cpukit/libfs/src/dosfs/msdos_misc.c
@@ -1646,19 +1646,6 @@ int msdos_find_node_by_cluster_num_in_fat_file(
 }
 
 int
-msdos_sync_unprotected(msdos_fs_info_t *fs_info)
-{
-    int rc = fat_buf_release(&fs_info->fat);
-    rtems_status_code sc = rtems_bdbuf_syncdev(fs_info->fat.vol.dd);
-    if (sc != RTEMS_SUCCESSFUL) {
-	errno = EIO;
-	rc = -1;
-    }
-
-    return rc;
-}
-
-int
 msdos_sync(rtems_libio_t *iop)
 {
     int                rc = RC_OK;
@@ -1670,7 +1657,7 @@ msdos_sync(rtems_libio_t *iop)
     if (sc != RTEMS_SUCCESSFUL)
         rtems_set_errno_and_return_minus_one(EIO);
 
-    rc = msdos_sync_unprotected(fs_info);
+    rc = fat_sync(&fs_info->fat);
 
     rtems_semaphore_release(fs_info->vol_sema);
     return rc;
-- 
1.7.7




More information about the devel mailing list