dosfs: Remove fat_file_datasync()

The fat_file_datasync() read every cluster of the file into the cache
and then synchronized it step-by-step.  For unmodified buffers this is a
non-operation.  For modified buffers this will wake-up the swapout task
which performs then a single buffer write operation.  This is usually
quite inefficient.  Firstly we do single buffer writes, secondly we
may perform a lot of unnecessary read operations (for huge files this is
really bad), and thirdly this leads likely to cache evictions.

The synchronization procedure is replaced by a simple
rtems_bdbuf_sync_dev().  This has the side-effect that also buffers not
related to the file are synchronized, but since the modified list is
normally short this should be acceptable.
This commit is contained in:
Sebastian Huber
2012-05-11 13:58:43 +02:00
parent 84ab4fce24
commit 86ef0df976
14 changed files with 280 additions and 181 deletions
-59
View File
@@ -774,65 +774,6 @@ fat_file_mark_removed(
fat_fd->flags |= FAT_FILE_REMOVED;
}
/* fat_file_datasync --
* Synchronize fat-file - flush all buffered data to the media.
*
* PARAMETERS:
* mt_entry - mount table entry
* fat_fd - fat-file descriptor
*
* RETURNS:
* RC_OK on success, or -1 if error occured and errno set appropriately
*/
int
fat_file_datasync(
rtems_filesystem_mount_table_entry_t *mt_entry,
fat_file_fd_t *fat_fd
)
{
int rc = RC_OK;
rtems_status_code sc = RTEMS_SUCCESSFUL;
fat_fs_info_t *fs_info = mt_entry->fs_info;
uint32_t cur_cln = fat_fd->cln;
rtems_bdbuf_buffer *block = NULL;
uint32_t sec = 0;
uint32_t i = 0;
if (fat_fd->fat_file_size == 0)
return RC_OK;
/*
* we can use only one bdbuf :( and we also know that cache is useless
* for sync operation, so don't use it
*/
rc = fat_buf_release(fs_info);
if (rc != RC_OK)
return rc;
/* for each cluster of the file ... */
while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val)
{
sec = fat_cluster_num_to_sector_num(mt_entry, cur_cln);
/* for each sector in cluster ... */
for ( i = 0; i < fs_info->vol.spc; i++ )
{
/* ... sync it */
sc = rtems_bdbuf_read(fs_info->vol.dd, (sec + i), &block);
if (sc != RTEMS_SUCCESSFUL)
rtems_set_errno_and_return_minus_one( EIO );
sc = rtems_bdbuf_sync(block);
if ( sc != RTEMS_SUCCESSFUL )
rtems_set_errno_and_return_minus_one( EIO );
}
rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
if ( rc != RC_OK )
return rc;
}
return rc;
}
/* fat_file_size --
* Calculate fat-file size - fat-file is nothing that clusters chain, so
* go through all clusters in the chain and count it. Only
-5
View File
@@ -167,11 +167,6 @@ fat_file_truncate(rtems_filesystem_mount_table_entry_t *mt_entry,
fat_file_fd_t *fat_fd,
uint32_t new_length);
int
fat_file_datasync(rtems_filesystem_mount_table_entry_t *mt_entry,
fat_file_fd_t *fat_fd);
int
fat_file_ioctl(rtems_filesystem_mount_table_entry_t *mt_entry,
fat_file_fd_t *fat_fd,
+4
View File
@@ -399,6 +399,10 @@ 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
}
#endif
-31
View File
@@ -457,34 +457,3 @@ msdos_dir_stat(
* RETURNS:
*
*/
/* msdos_dir_sync --
* The following routine does a syncronization on a MSDOS directory node.
* DIR_WrtTime, DIR_WrtDate and DIR_fileSize fields of 32 Bytes Directory
* Entry Structure should not be updated for directories, so only call
* to corresponding fat-file routine.
*
* PARAMETERS:
* iop - file control block
*
* RETURNS:
* RC_OK on success, or -1 if error occured (errno set apropriately).
*/
int
msdos_dir_sync(rtems_libio_t *iop)
{
int rc = RC_OK;
rtems_status_code sc = RTEMS_SUCCESSFUL;
fat_file_fd_t *fat_fd = iop->pathinfo.node_access;
msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL)
rtems_set_errno_and_return_minus_one(EIO);
rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd);
rtems_semaphore_release(fs_info->vol_sema);
return rc;
}
+37 -83
View File
@@ -27,6 +27,40 @@
#include "msdos.h"
static int
msdos_file_update(rtems_libio_t *iop)
{
int rc = RC_OK;
fat_file_fd_t *fat_fd = iop->pathinfo.node_access;
/*
* if fat-file descriptor is not marked as "removed", synchronize
* size, first cluster number, write time and date fields of the file
*/
if (!FAT_FILE_IS_REMOVED(fat_fd))
{
rc = msdos_set_first_cluster_num(iop->pathinfo.mt_entry, fat_fd);
if (rc != RC_OK)
{
return rc;
}
rc = msdos_set_file_size(iop->pathinfo.mt_entry, fat_fd);
if (rc != RC_OK)
{
return rc;
}
rc = msdos_set_dir_wrt_time_and_date(iop->pathinfo.mt_entry, fat_fd);
if (rc != RC_OK)
{
return rc;
}
}
return rc;
}
/* msdos_file_close --
* Close fat-file which correspondes to the file. If fat-file descriptor
* which correspondes to the file is not marked "removed", synchronize
@@ -45,40 +79,13 @@ msdos_file_close(rtems_libio_t *iop)
int rc = RC_OK;
rtems_status_code sc = RTEMS_SUCCESSFUL;
msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
fat_file_fd_t *fat_fd = iop->pathinfo.node_access;
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL)
rtems_set_errno_and_return_minus_one(EIO);
/*
* if fat-file descriptor is not marked as "removed", synchronize
* size, first cluster number, write time and date fields of the file
*/
if (!FAT_FILE_IS_REMOVED(fat_fd))
{
rc = msdos_set_first_cluster_num(iop->pathinfo.mt_entry, fat_fd);
if (rc != RC_OK)
{
rtems_semaphore_release(fs_info->vol_sema);
return rc;
}
rc = msdos_set_file_size(iop->pathinfo.mt_entry, fat_fd);
if (rc != RC_OK)
{
rtems_semaphore_release(fs_info->vol_sema);
return rc;
}
rc = msdos_set_dir_wrt_time_and_date(iop->pathinfo.mt_entry, fat_fd);
if (rc != RC_OK)
{
rtems_semaphore_release(fs_info->vol_sema);
return rc;
}
}
rc = msdos_file_update(iop);
rtems_semaphore_release(fs_info->vol_sema);
return rc;
@@ -276,67 +283,14 @@ msdos_file_sync(rtems_libio_t *iop)
if (sc != RTEMS_SUCCESSFUL)
rtems_set_errno_and_return_minus_one(EIO);
/* synchronize file data */
rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd);
rc = msdos_file_update(iop);
if (rc != RC_OK)
{
rtems_semaphore_release(fs_info->vol_sema);
return rc;
}
/*
* if fat-file descriptor is not marked "removed" - synchronize file
* metadata
*/
if (!FAT_FILE_IS_REMOVED(fat_fd))
{
rc = msdos_set_first_cluster_num(iop->pathinfo.mt_entry, fat_fd);
if (rc != RC_OK)
{
rtems_semaphore_release(fs_info->vol_sema);
return rc;
}
rc = msdos_set_file_size(iop->pathinfo.mt_entry, fat_fd);
if (rc != RC_OK)
{
rtems_semaphore_release(fs_info->vol_sema);
return rc;
}
rc = msdos_set_dir_wrt_time_and_date(iop->pathinfo.mt_entry, fat_fd);
if (rc != RC_OK)
{
rtems_semaphore_release(fs_info->vol_sema);
return rc;
}
}
rtems_semaphore_release(fs_info->vol_sema);
return RC_OK;
}
/* msdos_file_datasync --
* Synchronize file - synchronize only file data (metadata is letf intact).
*
* PARAMETERS:
* iop - file control block
*
* RETURNS:
* RC_OK on success, or -1 if error occured (errno set appropriately)
*/
int
msdos_file_datasync(rtems_libio_t *iop)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
fat_file_fd_t *fat_fd = iop->pathinfo.node_access;
msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL)
rtems_set_errno_and_return_minus_one(EIO);
/* synchronize file data */
fat_file_datasync(iop->pathinfo.mt_entry, fat_fd);
rc = msdos_sync_unprotected(fs_info);
rtems_semaphore_release(fs_info->vol_sema);
return RC_OK;
+2 -2
View File
@@ -27,7 +27,7 @@ const rtems_filesystem_file_handlers_r msdos_dir_handlers = {
rtems_filesystem_default_lseek_directory,
msdos_dir_stat,
rtems_filesystem_default_ftruncate_directory,
msdos_dir_sync,
msdos_dir_sync,
msdos_sync,
msdos_sync,
rtems_filesystem_default_fcntl
};
+1 -1
View File
@@ -28,6 +28,6 @@ const rtems_filesystem_file_handlers_r msdos_file_handlers = {
msdos_file_stat,
msdos_file_ftruncate,
msdos_file_sync,
msdos_file_datasync,
msdos_sync,
rtems_filesystem_default_fcntl
};
+31
View File
@@ -1646,3 +1646,34 @@ int msdos_find_node_by_cluster_num_in_fat_file(
}
return MSDOS_NAME_NOT_FOUND_ERR;
}
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;
rtems_status_code sc = RTEMS_SUCCESSFUL;
msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL)
rtems_set_errno_and_return_minus_one(EIO);
rc = msdos_sync_unprotected(fs_info);
rtems_semaphore_release(fs_info->vol_sema);
return rc;
}
+1
View File
@@ -5,6 +5,7 @@
ACLOCAL_AMFLAGS = -I ../aclocal
SUBDIRS =
SUBDIRS += fsdosfssync01
SUBDIRS += imfs_fserror
SUBDIRS += imfs_fslink
SUBDIRS += imfs_fspatheval
+1
View File
@@ -79,6 +79,7 @@ AC_CHECK_SIZEOF([blkcnt_t])
# Explicitly list all Makefiles here
AC_CONFIG_FILES([Makefile
fsdosfssync01/Makefile
imfs_fserror/Makefile
imfs_fslink/Makefile
imfs_fspatheval/Makefile
@@ -0,0 +1,19 @@
rtems_tests_PROGRAMS = fsdosfssync01
fsdosfssync01_SOURCES = init.c
dist_rtems_tests_DATA = fsdosfssync01.scn fsdosfssync01.doc
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(top_srcdir)/../automake/compile.am
include $(top_srcdir)/../automake/leaf.am
AM_CPPFLAGS += -I$(top_srcdir)/../support/include
LINK_OBJS = $(fsdosfssync01_OBJECTS)
LINK_LIBS = $(fsdosfssync01_LDLIBS)
fsdosfssync01$(EXEEXT): $(fsdosfssync01_OBJECTS) $(fsdosfssync01_DEPENDENCIES)
@rm -f fsdosfssync01$(EXEEXT)
$(make-exe)
include $(top_srcdir)/../automake/local.am
@@ -0,0 +1,11 @@
This file describes the directives and concepts tested by this test set.
test set name: fsdosfssync01
directives:
TBD
concepts:
TBD
@@ -0,0 +1,2 @@
*** TEST FSDOSFSSYNC 1 ***
*** END OF TEST FSDOSFSSYNC 1 ***
+171
View File
@@ -0,0 +1,171 @@
/*
* Copyright (c) 2012 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Obere Lagerstr. 30
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "tmacros.h"
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <rtems/libio.h>
#include <rtems/blkdev.h>
#include <rtems/dosfs.h>
#include <rtems/ramdisk.h>
static void create_file(const char *file)
{
int fd;
int rv;
fd = creat(file, S_IRWXU | S_IRWXG | S_IRWXO);
rtems_test_assert(fd >= 0);
rv = fsync(fd);
rtems_test_assert(rv == 0);
rv = close(fd);
rtems_test_assert(rv == 0);
}
static void write_to_file(const char *file, bool sync)
{
int fd;
char buf [1];
ssize_t n;
off_t pos;
int rv;
fd = open(file, O_RDWR);
rtems_test_assert(fd >= 0);
n = write(fd, buf, sizeof(buf));
rtems_test_assert(n == (ssize_t) sizeof(buf));
pos = lseek(fd, 0, SEEK_END);
rtems_test_assert(pos == sizeof(buf));
if (sync) {
rv = fsync(fd);
rtems_test_assert(rv == 0);
}
rv = close(fd);
rtems_test_assert(rv == 0);
}
static void check_file_size(const char *file, off_t size)
{
int fd;
off_t pos;
int rv;
fd = open(file, O_RDWR);
rtems_test_assert(fd >= 0);
pos = lseek(fd, 0, SEEK_END);
rtems_test_assert(pos == size);
rv = close(fd);
rtems_test_assert(rv == 0);
}
static void test(const char *rda, const char *mnt, const char *file)
{
rtems_status_code sc;
int disk_fd;
int rv;
sc = rtems_disk_io_initialize();
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
disk_fd = open(rda, O_RDWR);
rtems_test_assert(disk_fd >= 0);
rv = msdos_format(rda, NULL);
rtems_test_assert(rv == 0);
rv = mount_and_make_target_path(
rda,
mnt,
RTEMS_FILESYSTEM_TYPE_DOSFS,
RTEMS_FILESYSTEM_READ_WRITE,
NULL
);
rtems_test_assert(rv == 0);
create_file(file);
rv = rtems_disk_fd_purge(disk_fd);
rtems_test_assert(rv == 0);
write_to_file(file, false);
rv = rtems_disk_fd_purge(disk_fd);
rtems_test_assert(rv == 0);
check_file_size(file, 0);
write_to_file(file, true);
rv = rtems_disk_fd_purge(disk_fd);
rtems_test_assert(rv == 0);
check_file_size(file, 1);
rv = unmount(mnt);
rtems_test_assert(rv == 0);
rv = close(disk_fd);
rtems_test_assert(rv == 0);
}
static void Init(rtems_task_argument arg)
{
puts("\n\n*** TEST FSDOSFSSYNC 1 ***");
test("/dev/rda", "/mnt", "/mnt/file");
puts("*** END OF TEST FSDOSFSSYNC 1 ***");
rtems_test_exit(0);
}
rtems_ramdisk_config rtems_ramdisk_configuration [] = {
{ .block_size = 512, .block_num = 1024 }
};
size_t rtems_ramdisk_configuration_size = 1;
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_APPLICATION_EXTRA_DRIVERS RAMDISK_DRIVER_TABLE_ENTRY
#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK
#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 6
#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
#define CONFIGURE_FILESYSTEM_DOSFS
#define CONFIGURE_MAXIMUM_TASKS 2
#define CONFIGURE_EXTRA_TASK_STACKS (8 * 1024)
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#define CONFIGURE_INIT
#include <rtems/confdefs.h>