From 86ef0df976faf1b060347a07744814458aa42619 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 9 May 2012 14:33:51 +0200 Subject: 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. --- cpukit/libfs/src/dosfs/fat_file.c | 59 ------- cpukit/libfs/src/dosfs/fat_file.h | 5 - cpukit/libfs/src/dosfs/msdos.h | 4 + cpukit/libfs/src/dosfs/msdos_dir.c | 31 ---- cpukit/libfs/src/dosfs/msdos_file.c | 116 +++++--------- cpukit/libfs/src/dosfs/msdos_handlers_dir.c | 4 +- cpukit/libfs/src/dosfs/msdos_handlers_file.c | 2 +- cpukit/libfs/src/dosfs/msdos_misc.c | 31 ++++ testsuites/fstests/Makefile.am | 1 + testsuites/fstests/configure.ac | 1 + testsuites/fstests/fsdosfssync01/Makefile.am | 19 +++ testsuites/fstests/fsdosfssync01/fsdosfssync01.doc | 11 ++ testsuites/fstests/fsdosfssync01/fsdosfssync01.scn | 2 + testsuites/fstests/fsdosfssync01/init.c | 171 +++++++++++++++++++++ 14 files changed, 278 insertions(+), 179 deletions(-) create mode 100644 testsuites/fstests/fsdosfssync01/Makefile.am create mode 100644 testsuites/fstests/fsdosfssync01/fsdosfssync01.doc create mode 100644 testsuites/fstests/fsdosfssync01/fsdosfssync01.scn create mode 100644 testsuites/fstests/fsdosfssync01/init.c diff --git a/cpukit/libfs/src/dosfs/fat_file.c b/cpukit/libfs/src/dosfs/fat_file.c index a10347ccc4..73ea076819 100644 --- a/cpukit/libfs/src/dosfs/fat_file.c +++ b/cpukit/libfs/src/dosfs/fat_file.c @@ -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 diff --git a/cpukit/libfs/src/dosfs/fat_file.h b/cpukit/libfs/src/dosfs/fat_file.h index 30614c8f46..3a338a59ea 100644 --- a/cpukit/libfs/src/dosfs/fat_file.h +++ b/cpukit/libfs/src/dosfs/fat_file.h @@ -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, diff --git a/cpukit/libfs/src/dosfs/msdos.h b/cpukit/libfs/src/dosfs/msdos.h index 0696b8f1fb..409c41897e 100644 --- a/cpukit/libfs/src/dosfs/msdos.h +++ b/cpukit/libfs/src/dosfs/msdos.h @@ -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 diff --git a/cpukit/libfs/src/dosfs/msdos_dir.c b/cpukit/libfs/src/dosfs/msdos_dir.c index 38ea6675f7..8bd807dc1b 100644 --- a/cpukit/libfs/src/dosfs/msdos_dir.c +++ b/cpukit/libfs/src/dosfs/msdos_dir.c @@ -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; -} diff --git a/cpukit/libfs/src/dosfs/msdos_file.c b/cpukit/libfs/src/dosfs/msdos_file.c index f68e44f948..176ec8e8db 100644 --- a/cpukit/libfs/src/dosfs/msdos_file.c +++ b/cpukit/libfs/src/dosfs/msdos_file.c @@ -27,30 +27,11 @@ #include "msdos.h" -/* 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 - * size, first cluster number, write time and date fields of the file. - * - * PARAMETERS: - * iop - file control block - * - * RETURNS: - * RC_OK, if file closed successfully, or -1 if error occured (errno set - * appropriately) - */ -int -msdos_file_close(rtems_libio_t *iop) +static int +msdos_file_update(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); + int rc = RC_OK; + fat_file_fd_t *fat_fd = iop->pathinfo.node_access; /* * if fat-file descriptor is not marked as "removed", synchronize @@ -61,25 +42,51 @@ msdos_file_close(rtems_libio_t *iop) 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; } } + 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 + * size, first cluster number, write time and date fields of the file. + * + * PARAMETERS: + * iop - file control block + * + * RETURNS: + * RC_OK, if file closed successfully, or -1 if error occured (errno set + * appropriately) + */ +int +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; + + 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_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; diff --git a/cpukit/libfs/src/dosfs/msdos_handlers_dir.c b/cpukit/libfs/src/dosfs/msdos_handlers_dir.c index 8c7dcdc0a5..7da9c1ec77 100644 --- a/cpukit/libfs/src/dosfs/msdos_handlers_dir.c +++ b/cpukit/libfs/src/dosfs/msdos_handlers_dir.c @@ -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 }; diff --git a/cpukit/libfs/src/dosfs/msdos_handlers_file.c b/cpukit/libfs/src/dosfs/msdos_handlers_file.c index 12cdaa048e..e4494f884e 100644 --- a/cpukit/libfs/src/dosfs/msdos_handlers_file.c +++ b/cpukit/libfs/src/dosfs/msdos_handlers_file.c @@ -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 }; diff --git a/cpukit/libfs/src/dosfs/msdos_misc.c b/cpukit/libfs/src/dosfs/msdos_misc.c index d11bd83f52..511ac44dda 100644 --- a/cpukit/libfs/src/dosfs/msdos_misc.c +++ b/cpukit/libfs/src/dosfs/msdos_misc.c @@ -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; +} diff --git a/testsuites/fstests/Makefile.am b/testsuites/fstests/Makefile.am index f765a89af4..43832760a0 100644 --- a/testsuites/fstests/Makefile.am +++ b/testsuites/fstests/Makefile.am @@ -5,6 +5,7 @@ ACLOCAL_AMFLAGS = -I ../aclocal SUBDIRS = +SUBDIRS += fsdosfssync01 SUBDIRS += imfs_fserror SUBDIRS += imfs_fslink SUBDIRS += imfs_fspatheval diff --git a/testsuites/fstests/configure.ac b/testsuites/fstests/configure.ac index 833a85c21a..ccf9ee0bcf 100644 --- a/testsuites/fstests/configure.ac +++ b/testsuites/fstests/configure.ac @@ -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 diff --git a/testsuites/fstests/fsdosfssync01/Makefile.am b/testsuites/fstests/fsdosfssync01/Makefile.am new file mode 100644 index 0000000000..eb557f11e2 --- /dev/null +++ b/testsuites/fstests/fsdosfssync01/Makefile.am @@ -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 diff --git a/testsuites/fstests/fsdosfssync01/fsdosfssync01.doc b/testsuites/fstests/fsdosfssync01/fsdosfssync01.doc new file mode 100644 index 0000000000..98b558a4f5 --- /dev/null +++ b/testsuites/fstests/fsdosfssync01/fsdosfssync01.doc @@ -0,0 +1,11 @@ +This file describes the directives and concepts tested by this test set. + +test set name: fsdosfssync01 + +directives: + + TBD + +concepts: + + TBD diff --git a/testsuites/fstests/fsdosfssync01/fsdosfssync01.scn b/testsuites/fstests/fsdosfssync01/fsdosfssync01.scn new file mode 100644 index 0000000000..c181dbf72c --- /dev/null +++ b/testsuites/fstests/fsdosfssync01/fsdosfssync01.scn @@ -0,0 +1,2 @@ +*** TEST FSDOSFSSYNC 1 *** +*** END OF TEST FSDOSFSSYNC 1 *** diff --git a/testsuites/fstests/fsdosfssync01/init.c b/testsuites/fstests/fsdosfssync01/init.c new file mode 100644 index 0000000000..72481b29b8 --- /dev/null +++ b/testsuites/fstests/fsdosfssync01/init.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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 -- cgit v1.2.3