From baef823cd550449bfbcc36625b9571389d8ad1af Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 13 Sep 2017 09:22:19 +0200 Subject: libio: Add hold/drop iop reference Check iop reference count in close() and return -1 with errno set to EBUSY in case the file descriptor is still in use. Update #3132. --- cpukit/libcsupport/include/rtems/libio.h | 8 +- cpukit/libcsupport/include/rtems/libio_.h | 75 ++- cpukit/libcsupport/src/close.c | 41 +- cpukit/libcsupport/src/fchdir.c | 1 + cpukit/libcsupport/src/fchmod.c | 2 + cpukit/libcsupport/src/fchown.c | 2 + cpukit/libcsupport/src/fcntl.c | 2 + cpukit/libcsupport/src/fdatasync.c | 5 +- cpukit/libcsupport/src/fpathconf.c | 4 +- cpukit/libcsupport/src/fstat.c | 5 +- cpukit/libcsupport/src/fsync.c | 5 +- cpukit/libcsupport/src/ftruncate.c | 1 + cpukit/libcsupport/src/ioctl.c | 1 + cpukit/libcsupport/src/libio.c | 10 +- cpukit/libcsupport/src/lseek.c | 5 +- cpukit/libcsupport/src/open.c | 6 +- cpukit/libcsupport/src/read.c | 5 +- cpukit/libcsupport/src/write.c | 5 +- cpukit/posix/src/shmopen.c | 2 +- testsuites/fstests/Makefile.am | 1 + testsuites/fstests/configure.ac | 1 + testsuites/fstests/fsclose01/Makefile.am | 19 + testsuites/fstests/fsclose01/fsclose01.doc | 26 ++ testsuites/fstests/fsclose01/fsclose01.scn | 2 + testsuites/fstests/fsclose01/init.c | 511 +++++++++++++++++++++ testsuites/sptests/Makefile.am | 1 + testsuites/sptests/configure.ac | 1 + testsuites/sptests/spintrcritical24/Makefile.am | 22 + testsuites/sptests/spintrcritical24/init.c | 150 ++++++ .../sptests/spintrcritical24/spintrcritical24.doc | 13 + .../sptests/spintrcritical24/spintrcritical24.scn | 2 + 31 files changed, 890 insertions(+), 44 deletions(-) create mode 100644 testsuites/fstests/fsclose01/Makefile.am create mode 100644 testsuites/fstests/fsclose01/fsclose01.doc create mode 100644 testsuites/fstests/fsclose01/fsclose01.scn create mode 100644 testsuites/fstests/fsclose01/init.c create mode 100644 testsuites/sptests/spintrcritical24/Makefile.am create mode 100644 testsuites/sptests/spintrcritical24/init.c create mode 100644 testsuites/sptests/spintrcritical24/spintrcritical24.doc create mode 100644 testsuites/sptests/spintrcritical24/spintrcritical24.scn diff --git a/cpukit/libcsupport/include/rtems/libio.h b/cpukit/libcsupport/include/rtems/libio.h index 2a67496800..804929915a 100644 --- a/cpukit/libcsupport/include/rtems/libio.h +++ b/cpukit/libcsupport/include/rtems/libio.h @@ -37,6 +37,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -1319,7 +1320,7 @@ extern const rtems_filesystem_limits_and_options_t struct rtems_libio_tt { rtems_driver_name_t *driver; off_t offset; /* current offset into file */ - uint32_t flags; + Atomic_Uint flags; rtems_filesystem_location_info_t pathinfo; uint32_t data0; /* private to "driver" */ void *data1; /* ... */ @@ -1371,12 +1372,13 @@ typedef struct { #define LIBIO_FLAGS_APPEND 0x0200U /* all writes append */ #define LIBIO_FLAGS_CLOSE_ON_EXEC 0x0800U /* close on process exec() */ #define LIBIO_FLAGS_READ_WRITE (LIBIO_FLAGS_READ | LIBIO_FLAGS_WRITE) +#define LIBIO_FLAGS_REFERENCE_INC 0x1000U /** @} */ -static inline uint32_t rtems_libio_iop_flags( const rtems_libio_t *iop ) +static inline unsigned int rtems_libio_iop_flags( const rtems_libio_t *iop ) { - return iop->flags; + return _Atomic_Load_uint( &iop->flags, ATOMIC_ORDER_RELAXED ); } /** diff --git a/cpukit/libcsupport/include/rtems/libio_.h b/cpukit/libcsupport/include/rtems/libio_.h index adf137d2f6..dc1fe9808a 100644 --- a/cpukit/libcsupport/include/rtems/libio_.h +++ b/cpukit/libcsupport/include/rtems/libio_.h @@ -104,7 +104,11 @@ static inline void rtems_libio_iop_flags_initialize( uint32_t flags ) { - iop->flags = LIBIO_FLAGS_OPEN | flags; + _Atomic_Store_uint( + &iop->flags, + LIBIO_FLAGS_OPEN | flags, + ATOMIC_ORDER_RELEASE + ); } /** @@ -115,16 +119,12 @@ static inline void rtems_libio_iop_flags_initialize( * * @return The previous flags. */ -static inline uint32_t rtems_libio_iop_flags_set( +static inline unsigned int rtems_libio_iop_flags_set( rtems_libio_t *iop, - uint32_t set + unsigned int set ) { - uint32_t flags; - - flags = iop->flags; - iop->flags = flags | set; - return flags; + return _Atomic_Fetch_or_uint( &iop->flags, set, ATOMIC_ORDER_RELAXED ); } /** @@ -135,16 +135,12 @@ static inline uint32_t rtems_libio_iop_flags_set( * * @return The previous flags. */ -static inline uint32_t rtems_libio_iop_flags_clear( +static inline unsigned int rtems_libio_iop_flags_clear( rtems_libio_t *iop, - uint32_t clear + unsigned int clear ) { - uint32_t flags; - - flags = iop->flags; - iop->flags = flags & ~clear; - return flags; + return _Atomic_Fetch_and_uint( &iop->flags, ~clear, ATOMIC_ORDER_RELAXED ); } /** @@ -161,6 +157,36 @@ static inline rtems_libio_t *rtems_libio_iop( int fd ) return &rtems_libio_iops[ fd ]; } +/** + * @brief Holds a refernece to the iop. + * + * @param[in] iop The iop. + * + * @return The flags corresponding to the specified iop. + */ +static inline unsigned int rtems_libio_iop_hold( rtems_libio_t *iop ) +{ + return _Atomic_Fetch_add_uint( + &iop->flags, + LIBIO_FLAGS_REFERENCE_INC, + ATOMIC_ORDER_ACQUIRE + ); +} + +/** + * @brief Drops a refernece to the iop. + * + * @param[in] iop The iop. + */ +static inline void rtems_libio_iop_drop( rtems_libio_t *iop ) +{ + _Atomic_Fetch_sub_uint( + &iop->flags, + LIBIO_FLAGS_REFERENCE_INC, + ATOMIC_ORDER_RELEASE + ); +} + /* * rtems_libio_iop_to_descriptor * @@ -192,13 +218,14 @@ static inline rtems_libio_t *rtems_libio_iop( int fd ) */ #define LIBIO_GET_IOP( _fd, _iop ) \ do { \ - uint32_t _flags; \ + unsigned int _flags; \ if ( (uint32_t) ( _fd ) >= rtems_libio_number_iops ) { \ rtems_set_errno_and_return_minus_one( EBADF ); \ } \ _iop = rtems_libio_iop( _fd ); \ - _flags = _iop->flags; \ + _flags = rtems_libio_iop_hold( _iop ); \ if ( ( _flags & LIBIO_FLAGS_OPEN ) == 0 ) { \ + rtems_libio_iop_drop( _iop ); \ rtems_set_errno_and_return_minus_one( EBADF ); \ } \ } while ( 0 ) @@ -211,16 +238,17 @@ static inline rtems_libio_t *rtems_libio_iop( int fd ) */ #define LIBIO_GET_IOP_WITH_ACCESS( _fd, _iop, _access_flags, _access_error ) \ do { \ - uint32_t _flags; \ - uint32_t _mandatory; \ + unsigned int _flags; \ + unsigned int _mandatory; \ if ( (uint32_t) ( _fd ) >= rtems_libio_number_iops ) { \ rtems_set_errno_and_return_minus_one( EBADF ); \ } \ _iop = rtems_libio_iop( _fd ); \ - _flags = _iop->flags; \ + _flags = rtems_libio_iop_hold( _iop ); \ _mandatory = LIBIO_FLAGS_OPEN | ( _access_flags ); \ if ( ( _flags & _mandatory ) != _mandatory ) { \ int _error; \ + rtems_libio_iop_drop( _iop ); \ if ( ( _flags & LIBIO_FLAGS_OPEN ) == 0 ) { \ _error = EBADF; \ } else { \ @@ -357,12 +385,12 @@ rtems_libio_t *rtems_libio_allocate(void); /** * Convert UNIX fnctl(2) flags to ones that RTEMS drivers understand */ -uint32_t rtems_libio_fcntl_flags( int fcntl_flags ); +unsigned int rtems_libio_fcntl_flags( int fcntl_flags ); /** * Convert RTEMS internal flags to UNIX fnctl(2) flags */ -int rtems_libio_to_fcntl_flags( uint32_t flags ); +int rtems_libio_to_fcntl_flags( unsigned int flags ); /** * This routine frees the resources associated with an IOP (file descriptor) @@ -932,7 +960,7 @@ static inline ssize_t rtems_libio_iovec_eval( int fd, const struct iovec *iov, int iovcnt, - uint32_t flags, + unsigned int flags, rtems_libio_iovec_adapter adapter ) { @@ -978,6 +1006,7 @@ static inline ssize_t rtems_libio_iovec_eval( total = ( *adapter )( iop, iov, iovcnt, total ); } + rtems_libio_iop_drop( iop ); return total; } diff --git a/cpukit/libcsupport/src/close.c b/cpukit/libcsupport/src/close.c index 7eaeb64fea..d478e231c6 100644 --- a/cpukit/libcsupport/src/close.c +++ b/cpukit/libcsupport/src/close.c @@ -24,12 +24,45 @@ int close( int fd ) { - rtems_libio_t *iop; - int rc; + rtems_libio_t *iop; + unsigned int flags; + int rc; - LIBIO_GET_IOP( fd, iop ); + if ( (uint32_t) fd >= rtems_libio_number_iops ) { + rtems_set_errno_and_return_minus_one( EBADF ); + } - rtems_libio_iop_flags_clear( iop, LIBIO_FLAGS_OPEN ); + iop = rtems_libio_iop( fd ); + flags = rtems_libio_iop_flags( iop ); + + while ( true ) { + unsigned int desired; + bool success; + + if ( ( flags & LIBIO_FLAGS_OPEN ) == 0 ) { + rtems_set_errno_and_return_minus_one( EBADF ); + } + + /* The expected flags */ + flags &= LIBIO_FLAGS_REFERENCE_INC - 1U; + + desired = flags & ~LIBIO_FLAGS_OPEN; + success = _Atomic_Compare_exchange_uint( + &iop->flags, + &flags, + desired, + ATOMIC_ORDER_ACQ_REL, + ATOMIC_ORDER_RELAXED + ); + + if ( success ) { + break; + } + + if ( ( flags & ~( LIBIO_FLAGS_REFERENCE_INC - 1U ) ) != 0 ) { + rtems_set_errno_and_return_minus_one( EBUSY ); + } + } rc = (*iop->pathinfo.handlers->close_h)( iop ); diff --git a/cpukit/libcsupport/src/fchdir.c b/cpukit/libcsupport/src/fchdir.c index ece73ab3ec..df37458ead 100644 --- a/cpukit/libcsupport/src/fchdir.c +++ b/cpukit/libcsupport/src/fchdir.c @@ -59,6 +59,7 @@ int fchdir( int fd ) } } rtems_filesystem_instance_unlock( &iop->pathinfo ); + rtems_libio_iop_drop( iop ); if ( rv == 0 ) { rv = rtems_filesystem_chdir( &loc ); diff --git a/cpukit/libcsupport/src/fchmod.c b/cpukit/libcsupport/src/fchmod.c index 126b015501..13e7fdd380 100644 --- a/cpukit/libcsupport/src/fchmod.c +++ b/cpukit/libcsupport/src/fchmod.c @@ -75,5 +75,7 @@ int fchmod( int fd, mode_t mode ) rtems_filesystem_instance_unlock( &iop->pathinfo ); + rtems_libio_iop_drop( iop ); + return rv; } diff --git a/cpukit/libcsupport/src/fchown.c b/cpukit/libcsupport/src/fchown.c index bd787d89e3..8c3d9b2c6c 100644 --- a/cpukit/libcsupport/src/fchown.c +++ b/cpukit/libcsupport/src/fchown.c @@ -72,5 +72,7 @@ int fchown( int fd, uid_t owner, gid_t group ) rtems_filesystem_instance_unlock( &iop->pathinfo ); + rtems_libio_iop_drop( iop ); + return rv; } diff --git a/cpukit/libcsupport/src/fcntl.c b/cpukit/libcsupport/src/fcntl.c index a7fcfbc041..ddbf5538f9 100644 --- a/cpukit/libcsupport/src/fcntl.c +++ b/cpukit/libcsupport/src/fcntl.c @@ -213,6 +213,8 @@ static int vfcntl( ret = -1; } } + + rtems_libio_iop_drop( iop ); return ret; } diff --git a/cpukit/libcsupport/src/fdatasync.c b/cpukit/libcsupport/src/fdatasync.c index 14e66726e6..bf90957f0f 100644 --- a/cpukit/libcsupport/src/fdatasync.c +++ b/cpukit/libcsupport/src/fdatasync.c @@ -28,6 +28,7 @@ int fdatasync( ) { rtems_libio_t *iop; + int rv; LIBIO_GET_IOP_WITH_ACCESS( fd, iop, LIBIO_FLAGS_WRITE, EBADF ); @@ -35,5 +36,7 @@ int fdatasync( * Now process the fdatasync(). */ - return (*iop->pathinfo.handlers->fdatasync_h)( iop ); + rv = (*iop->pathinfo.handlers->fdatasync_h)( iop ); + rtems_libio_iop_drop( iop ); + return rv; } diff --git a/cpukit/libcsupport/src/fpathconf.c b/cpukit/libcsupport/src/fpathconf.c index db323136c7..d08ac9c776 100644 --- a/cpukit/libcsupport/src/fpathconf.c +++ b/cpukit/libcsupport/src/fpathconf.c @@ -82,9 +82,11 @@ long fpathconf( return_value = the_limits->posix_sync_io; break; default: - rtems_set_errno_and_return_minus_one( EINVAL ); + errno = EINVAL; + return_value = -1; break; } + rtems_libio_iop_drop( iop ); return return_value; } diff --git a/cpukit/libcsupport/src/fstat.c b/cpukit/libcsupport/src/fstat.c index 4a10d166bd..3a1241a862 100644 --- a/cpukit/libcsupport/src/fstat.c +++ b/cpukit/libcsupport/src/fstat.c @@ -26,6 +26,7 @@ int fstat( ) { rtems_libio_t *iop; + int rv; /* * Check to see if we were passed a valid pointer. @@ -44,7 +45,9 @@ int fstat( */ memset( sbuf, 0, sizeof(struct stat) ); - return (*iop->pathinfo.handlers->fstat_h)( &iop->pathinfo, sbuf ); + rv = (*iop->pathinfo.handlers->fstat_h)( &iop->pathinfo, sbuf ); + rtems_libio_iop_drop( iop ); + return rv; } /* diff --git a/cpukit/libcsupport/src/fsync.c b/cpukit/libcsupport/src/fsync.c index 6332180721..428f82abd0 100644 --- a/cpukit/libcsupport/src/fsync.c +++ b/cpukit/libcsupport/src/fsync.c @@ -31,6 +31,7 @@ int fsync( ) { rtems_libio_t *iop; + int rv; LIBIO_GET_IOP( fd, iop ); @@ -38,5 +39,7 @@ int fsync( * Now process the fsync(). */ - return (*iop->pathinfo.handlers->fsync_h)( iop ); + rv = (*iop->pathinfo.handlers->fsync_h)( iop ); + rtems_libio_iop_drop( iop ); + return rv; } diff --git a/cpukit/libcsupport/src/ftruncate.c b/cpukit/libcsupport/src/ftruncate.c index 401510b2ff..99a9c6b5ef 100644 --- a/cpukit/libcsupport/src/ftruncate.c +++ b/cpukit/libcsupport/src/ftruncate.c @@ -32,6 +32,7 @@ int ftruncate( int fd, off_t length ) LIBIO_GET_IOP_WITH_ACCESS( fd, iop, LIBIO_FLAGS_WRITE, EINVAL ); rv = (*iop->pathinfo.handlers->ftruncate_h)( iop, length ); + rtems_libio_iop_drop( iop ); } else { errno = EINVAL; rv = -1; diff --git a/cpukit/libcsupport/src/ioctl.c b/cpukit/libcsupport/src/ioctl.c index 9fa7fa15a2..b2be524075 100644 --- a/cpukit/libcsupport/src/ioctl.c +++ b/cpukit/libcsupport/src/ioctl.c @@ -51,5 +51,6 @@ int ioctl( rc = (*iop->pathinfo.handlers->ioctl_h)( iop, command, buffer ); va_end( ap ); + rtems_libio_iop_drop( iop ); return rc; } diff --git a/cpukit/libcsupport/src/libio.c b/cpukit/libcsupport/src/libio.c index 0cc2b98c0b..26fa7b2f67 100644 --- a/cpukit/libcsupport/src/libio.c +++ b/cpukit/libcsupport/src/libio.c @@ -58,16 +58,16 @@ static const rtems_assoc_t status_flags_assoc[] = { { 0, 0, 0 }, }; -uint32_t rtems_libio_fcntl_flags( int fcntl_flags ) +unsigned int rtems_libio_fcntl_flags( int fcntl_flags ) { - uint32_t flags = 0; + unsigned int flags = 0; uint32_t access_modes; /* * Access mode is a small integer */ - access_modes = (uint32_t) (fcntl_flags & O_ACCMODE); + access_modes = (unsigned int) (fcntl_flags & O_ACCMODE); fcntl_flags &= ~O_ACCMODE; flags = rtems_assoc_local_by_remote( access_modes_assoc, access_modes ); @@ -75,7 +75,7 @@ uint32_t rtems_libio_fcntl_flags( int fcntl_flags ) * Everything else is single bits */ - flags |= rtems_assoc_local_by_remote_bitfield( + flags |= (unsigned int ) rtems_assoc_local_by_remote_bitfield( status_flags_assoc, (uint32_t) fcntl_flags ); @@ -83,7 +83,7 @@ uint32_t rtems_libio_fcntl_flags( int fcntl_flags ) return flags; } -int rtems_libio_to_fcntl_flags( uint32_t flags ) +int rtems_libio_to_fcntl_flags( unsigned int flags ) { int fcntl_flags = 0; diff --git a/cpukit/libcsupport/src/lseek.c b/cpukit/libcsupport/src/lseek.c index 16271eba09..00307e3e0d 100644 --- a/cpukit/libcsupport/src/lseek.c +++ b/cpukit/libcsupport/src/lseek.c @@ -20,10 +20,13 @@ off_t lseek( int fd, off_t offset, int whence ) { rtems_libio_t *iop; + off_t rv; LIBIO_GET_IOP( fd, iop ); - return (*iop->pathinfo.handlers->lseek_h)( iop, offset, whence ); + rv = (*iop->pathinfo.handlers->lseek_h)( iop, offset, whence ); + rtems_libio_iop_drop( iop ); + return rv; } /* diff --git a/cpukit/libcsupport/src/open.c b/cpukit/libcsupport/src/open.c index 22773454ba..8558e207d3 100644 --- a/cpukit/libcsupport/src/open.c +++ b/cpukit/libcsupport/src/open.c @@ -99,7 +99,11 @@ static int do_open( rtems_filesystem_eval_path_extract_currentloc( &ctx, &iop->pathinfo ); rtems_filesystem_eval_path_cleanup( &ctx ); - iop->flags = rtems_libio_fcntl_flags( oflag ); + _Atomic_Store_uint( + &iop->flags, + rtems_libio_fcntl_flags( oflag ), + ATOMIC_ORDER_RELAXED + ); rv = (*iop->pathinfo.handlers->open_h)( iop, path, oflag, mode ); diff --git a/cpukit/libcsupport/src/read.c b/cpukit/libcsupport/src/read.c index d55ff180ae..03c39120bb 100644 --- a/cpukit/libcsupport/src/read.c +++ b/cpukit/libcsupport/src/read.c @@ -31,6 +31,7 @@ ssize_t read( ) { rtems_libio_t *iop; + ssize_t n; rtems_libio_check_buffer( buffer ); rtems_libio_check_count( count ); @@ -40,7 +41,9 @@ ssize_t read( /* * Now process the read(). */ - return (*iop->pathinfo.handlers->read_h)( iop, buffer, count ); + n = (*iop->pathinfo.handlers->read_h)( iop, buffer, count ); + rtems_libio_iop_drop( iop ); + return n; } #if defined(RTEMS_NEWLIB) && !defined(HAVE__READ_R) diff --git a/cpukit/libcsupport/src/write.c b/cpukit/libcsupport/src/write.c index f44962afd8..a90b291ed8 100644 --- a/cpukit/libcsupport/src/write.c +++ b/cpukit/libcsupport/src/write.c @@ -34,6 +34,7 @@ ssize_t write( ) { rtems_libio_t *iop; + ssize_t n; rtems_libio_check_buffer( buffer ); rtems_libio_check_count( count ); @@ -43,5 +44,7 @@ ssize_t write( /* * Now process the write() request. */ - return (*iop->pathinfo.handlers->write_h)( iop, buffer, count ); + n = (*iop->pathinfo.handlers->write_h)( iop, buffer, count ); + rtems_libio_iop_drop( iop ); + return n; } diff --git a/cpukit/posix/src/shmopen.c b/cpukit/posix/src/shmopen.c index f6c9f58cb4..59e9e9da22 100644 --- a/cpukit/posix/src/shmopen.c +++ b/cpukit/posix/src/shmopen.c @@ -225,7 +225,7 @@ int shm_open( const char *name, int oflag, mode_t mode ) POSIX_Shm_Control *shm; size_t len; Objects_Get_by_name_error obj_err; - uint32_t flags; + unsigned int flags; if ( shm_check_oflag( oflag ) != 0 ) { return -1; diff --git a/testsuites/fstests/Makefile.am b/testsuites/fstests/Makefile.am index 1302fe009a..158a797a2c 100644 --- a/testsuites/fstests/Makefile.am +++ b/testsuites/fstests/Makefile.am @@ -2,6 +2,7 @@ ACLOCAL_AMFLAGS = -I ../aclocal _SUBDIRS = _SUBDIRS += fsbdpart01 +_SUBDIRS += fsclose01 _SUBDIRS += fsdosfsformat01 _SUBDIRS += fsdosfsname01 _SUBDIRS += fsdosfsname02 diff --git a/testsuites/fstests/configure.ac b/testsuites/fstests/configure.ac index e5dc840ba8..37a92bbca5 100644 --- a/testsuites/fstests/configure.ac +++ b/testsuites/fstests/configure.ac @@ -78,6 +78,7 @@ AC_CHECK_SIZEOF([blkcnt_t]) # Explicitly list all Makefiles here AC_CONFIG_FILES([Makefile fsbdpart01/Makefile +fsclose01/Makefile fsdosfsformat01/Makefile fsdosfsname01/Makefile fsdosfsname02/Makefile diff --git a/testsuites/fstests/fsclose01/Makefile.am b/testsuites/fstests/fsclose01/Makefile.am new file mode 100644 index 0000000000..dc2da84b82 --- /dev/null +++ b/testsuites/fstests/fsclose01/Makefile.am @@ -0,0 +1,19 @@ +rtems_tests_PROGRAMS = fsclose01 +fsclose01_SOURCES = init.c + +dist_rtems_tests_DATA = fsclose01.scn fsclose01.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 = $(fsclose01_OBJECTS) +LINK_LIBS = $(fsclose01_LDLIBS) + +fsclose01$(EXEEXT): $(fsclose01_OBJECTS) $(fsclose01_DEPENDENCIES) + @rm -f fsclose01$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/fstests/fsclose01/fsclose01.doc b/testsuites/fstests/fsclose01/fsclose01.doc new file mode 100644 index 0000000000..29277a4a91 --- /dev/null +++ b/testsuites/fstests/fsclose01/fsclose01.doc @@ -0,0 +1,26 @@ +This file describes the directives and concepts tested by this test set. + +test set name: fsclose01 + +directives: + + - close() + - fcntl() + - fdatasync() + - fchdir() + - fchmod() + - fchown() + - fstat() + - fsync() + - ftruncate() + - ioctl() + - lseek() + - read() + - readv() + - write() + - writev() + +concepts: + + - Ensure the close() return -1 with errno set to EBUSY in case the file + descriptor is still in use. diff --git a/testsuites/fstests/fsclose01/fsclose01.scn b/testsuites/fstests/fsclose01/fsclose01.scn new file mode 100644 index 0000000000..3da936932f --- /dev/null +++ b/testsuites/fstests/fsclose01/fsclose01.scn @@ -0,0 +1,2 @@ +*** BEGIN OF TEST FSCLOSE 1 *** +*** END OF TEST FSCLOSE 1 *** diff --git a/testsuites/fstests/fsclose01/init.c b/testsuites/fstests/fsclose01/init.c new file mode 100644 index 0000000000..a9de652b51 --- /dev/null +++ b/testsuites/fstests/fsclose01/init.c @@ -0,0 +1,511 @@ +/* + * Copyright (c) 2012, 2017 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 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.org/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +const char rtems_test_name[] = "FSCLOSE 1"; + +typedef enum { + ACTION_ClOSE, + ACTION_FCNTL, + ACTION_FDATASYNC, + ACTION_FCHDIR, + ACTION_FCHMOD, + ACTION_FCHOWN, + /* ACTION_FPATHCONF, not easy to test */ + ACTION_FSTAT, + ACTION_FSYNC, + ACTION_FTRUNCATE, + ACTION_IOCTL, + ACTION_LSEEK, + ACTION_READ, + ACTION_READV, + ACTION_WRITE, + ACTION_WRITEV +} test_action; + +typedef struct { + rtems_id worker_id; + int fd; + test_action action; + bool wait_in_close; + bool wait_in_fstat; + int close_count; + int fcntl_count; + int fdatasync_count; + int fstat_count; + int fsync_count; + int ftruncate_count; + int ioctl_count; + int lseek_count; + int open_count; + int read_count; + int readv_count; + int write_count; + int writev_count; +} test_context; + +static test_context test_instance; + +static void wait(void) +{ + rtems_status_code sc; + + sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void wakeup_worker(const test_context *ctx) +{ + rtems_status_code sc; + + sc = rtems_event_transient_send(ctx->worker_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static int handler_open( + rtems_libio_t *iop, + const char *path, + int oflag, + mode_t mode +) +{ + test_context *ctx; + + ctx = IMFS_generic_get_context_by_iop(iop); + ++ctx->open_count; + + return 0; +} + +static int handler_close( + rtems_libio_t *iop +) +{ + test_context *ctx; + + ctx = IMFS_generic_get_context_by_iop(iop); + ++ctx->close_count; + + if (ctx->wait_in_close) { + ctx->wait_in_close = false; + wait(); + } + + return 0; +} + +static ssize_t handler_read( + rtems_libio_t *iop, + void *buffer, + size_t count +) +{ + test_context *ctx; + + ctx = IMFS_generic_get_context_by_iop(iop); + ++ctx->read_count; + + wait(); + return 0; +} + +static ssize_t handler_write( + rtems_libio_t *iop, + const void *buffer, + size_t count +) +{ + test_context *ctx; + + ctx = IMFS_generic_get_context_by_iop(iop); + ++ctx->write_count; + + wait(); + return 0; +} + +static int handler_ioctl( + rtems_libio_t *iop, + ioctl_command_t request, + void *buffer +) +{ + test_context *ctx; + + ctx = IMFS_generic_get_context_by_iop(iop); + ++ctx->ioctl_count; + + wait(); + return 0; +} + +static off_t handler_lseek( + rtems_libio_t *iop, + off_t length, + int whence +) +{ + test_context *ctx; + + ctx = IMFS_generic_get_context_by_iop(iop); + ++ctx->lseek_count; + + wait(); + return 0; +} + +static int handler_fstat( + const rtems_filesystem_location_info_t *loc, + struct stat *buf +) +{ + test_context *ctx; + + buf->st_mode = S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO; + ctx = IMFS_generic_get_context_by_location(loc); + ++ctx->fstat_count; + + if (ctx->wait_in_fstat) { + ctx->wait_in_fstat = false; + wait(); + } + + return 0; +} + +static int handler_ftruncate( + rtems_libio_t *iop, + off_t length +) +{ + test_context *ctx; + + ctx = IMFS_generic_get_context_by_iop(iop); + ++ctx->ftruncate_count; + + wait(); + return 0; +} + +static int handler_fsync( + rtems_libio_t *iop +) +{ + test_context *ctx; + + ctx = IMFS_generic_get_context_by_iop(iop); + ++ctx->fsync_count; + + wait(); + return 0; +} + +static int handler_fdatasync( + rtems_libio_t *iop +) +{ + test_context *ctx; + + ctx = IMFS_generic_get_context_by_iop(iop); + ++ctx->fdatasync_count; + + wait(); + return 0; +} + +static int handler_fcntl( + rtems_libio_t *iop, + int cmd +) +{ + test_context *ctx; + + ctx = IMFS_generic_get_context_by_iop(iop); + ++ctx->fcntl_count; + + wait(); + return 0; +} + +static ssize_t handler_readv( + rtems_libio_t *iop, + const struct iovec *iov, + int iovcnt, + ssize_t total +) +{ + test_context *ctx; + + ctx = IMFS_generic_get_context_by_iop(iop); + ++ctx->readv_count; + + wait(); + return 0; +} + +static ssize_t handler_writev( + rtems_libio_t *iop, + const struct iovec *iov, + int iovcnt, + ssize_t total +) +{ + test_context *ctx; + + ctx = IMFS_generic_get_context_by_iop(iop); + ++ctx->writev_count; + + wait(); + return 0; +} + +static const rtems_filesystem_file_handlers_r node_handlers = { + .open_h = handler_open, + .close_h = handler_close, + .read_h = handler_read, + .write_h = handler_write, + .ioctl_h = handler_ioctl, + .lseek_h = handler_lseek, + .fstat_h = handler_fstat, + .ftruncate_h = handler_ftruncate, + .fsync_h = handler_fsync, + .fdatasync_h = handler_fdatasync, + .fcntl_h = handler_fcntl, + .readv_h = handler_readv, + .writev_h = handler_writev +}; + +static const IMFS_node_control node_control = { + .handlers = &node_handlers, + .node_initialize = IMFS_node_initialize_generic, + .node_remove = IMFS_node_remove_default, + .node_destroy = IMFS_node_destroy_default +}; + +static void worker_task(rtems_task_argument arg) +{ + test_context *ctx; + int rv; + char buf[1]; + ssize_t n; + off_t off; + struct iovec iov = { + .iov_base = &buf[0], + .iov_len = sizeof(buf) + }; + struct stat st; + + ctx = (test_context *) arg; + + while (true) { + wait(); + + switch (ctx->action) { + case ACTION_ClOSE: + ctx->wait_in_close = true; + rv = close(ctx->fd); + rtems_test_assert(rv == 0); + break; + case ACTION_FCNTL: + rv = fcntl(ctx->fd, F_GETFD); + rtems_test_assert(rv >= 0); + break; + case ACTION_FDATASYNC: + rv = fdatasync(ctx->fd); + rtems_test_assert(rv == 0); + break; + case ACTION_FCHDIR: + ctx->wait_in_fstat = true; + rv = fchdir(ctx->fd); + rtems_test_assert(rv == -1); + rtems_test_assert(errno == ENOTDIR); + break; + case ACTION_FCHMOD: + rv = fstat(ctx->fd, &st); + rtems_test_assert(rv == 0); + ctx->wait_in_fstat = true; + rv = fchmod(ctx->fd, st.st_mode); + rtems_test_assert(rv == 0); + break; + case ACTION_FCHOWN: + rv = fstat(ctx->fd, &st); + rtems_test_assert(rv == 0); + ctx->wait_in_fstat = true; + rv = fchown(ctx->fd, st.st_uid, st.st_gid); + rtems_test_assert(rv == 0); + break; + case ACTION_FSTAT: + ctx->wait_in_fstat = true; + rv = fstat(ctx->fd, &st); + rtems_test_assert(rv == 0); + break; + case ACTION_FSYNC: + rv = fsync(ctx->fd); + rtems_test_assert(rv == 0); + break; + case ACTION_FTRUNCATE: + rv = ftruncate(ctx->fd, 0); + rtems_test_assert(rv == 0); + break; + case ACTION_IOCTL: + rv = ioctl(ctx->fd, 0); + rtems_test_assert(rv == 0); + break; + case ACTION_LSEEK: + off = lseek(ctx->fd, off, SEEK_SET); + rtems_test_assert(off == 0); + break; + case ACTION_READ: + n = read(ctx->fd, buf, sizeof(buf)); + rtems_test_assert(n == 0); + break; + case ACTION_READV: + n = readv(ctx->fd, &iov, 1); + rtems_test_assert(n == 0); + break; + case ACTION_WRITE: + n = write(ctx->fd, buf, sizeof(buf)); + rtems_test_assert(n == 0); + break; + case ACTION_WRITEV: + n = writev(ctx->fd, &iov, 1); + rtems_test_assert(n == 0); + break; + default: + rtems_test_assert(0); + break; + } + } +} + +static void test(test_context *ctx) +{ + const char *path = "generic"; + int rv; + rtems_status_code sc; + test_action ac; + + rv = IMFS_make_generic_node( + path, + S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, + &node_control, + ctx + ); + rtems_test_assert(rv == 0); + + sc = rtems_task_create( + rtems_build_name('W', 'O', 'R', 'K'), + 1, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &ctx->worker_id + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_start( + ctx->worker_id, + worker_task, + (rtems_task_argument) ctx + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + for (ac = ACTION_ClOSE; ac <= ACTION_WRITEV; ++ac) { + ctx->action = ac; + ctx->fd = open(path, O_RDWR); + rtems_test_assert(ctx->fd >= 0); + + wakeup_worker(ctx); + rv = close(ctx->fd); + rtems_test_assert(rv == -1); + + if (ac == ACTION_ClOSE) { + rtems_test_assert(errno == EBADF); + } else { + rtems_test_assert(errno == EBUSY); + } + + wakeup_worker(ctx); + rv = close(ctx->fd); + + if (ac == ACTION_ClOSE) { + rtems_test_assert(rv == -1); + rtems_test_assert(errno == EBADF); + } else { + rtems_test_assert(rv == 0); + } + } + + sc = rtems_task_delete(ctx->worker_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + rv = unlink(path); + rtems_test_assert(rv == 0); + + rtems_test_assert(ctx->close_count == 15); + rtems_test_assert(ctx->fcntl_count == 1); + rtems_test_assert(ctx->fdatasync_count == 1); + rtems_test_assert(ctx->fstat_count == 38); + rtems_test_assert(ctx->fsync_count == 1); + rtems_test_assert(ctx->ftruncate_count == 1); + rtems_test_assert(ctx->ioctl_count == 1); + rtems_test_assert(ctx->lseek_count == 1); + rtems_test_assert(ctx->open_count == 15); + rtems_test_assert(ctx->read_count == 1); + rtems_test_assert(ctx->readv_count == 1); + rtems_test_assert(ctx->write_count == 1); + rtems_test_assert(ctx->writev_count == 1); +} + +static void Init(rtems_task_argument arg) +{ + TEST_BEGIN(); + test(&test_instance); + TEST_END(); + rtems_test_exit(0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER + +#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 4 + +#define CONFIGURE_MAXIMUM_TASKS 2 + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT_TASK_PRIORITY 2 +#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES + +#define CONFIGURE_INIT + +#include diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am index 890dd38571..e873718e72 100644 --- a/testsuites/sptests/Makefile.am +++ b/testsuites/sptests/Makefile.am @@ -33,6 +33,7 @@ _SUBDIRS = \ spsignal_err01 spport_err01 spmsgq_err01 spmsgq_err02 spsem_err01 \ spsem_err02 sptask_err01 spevent_err03 sptask_err03 sptask_err02 \ sptask_err04 spclock_err01 +_SUBDIRS += spintrcritical24 _SUBDIRS += spfatal29 _SUBDIRS += spfatal30 _SUBDIRS += spfatal31 diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac index 88d6ed6aa2..7bdb02c9a7 100644 --- a/testsuites/sptests/configure.ac +++ b/testsuites/sptests/configure.ac @@ -36,6 +36,7 @@ AM_CONDITIONAL(HAS_SMP,test "$rtems_cv_RTEMS_SMP" = "yes") # Explicitly list all Makefiles here AC_CONFIG_FILES([Makefile +spintrcritical24/Makefile spfatal31/Makefile spfatal30/Makefile spmutex01/Makefile diff --git a/testsuites/sptests/spintrcritical24/Makefile.am b/testsuites/sptests/spintrcritical24/Makefile.am new file mode 100644 index 0000000000..798666e361 --- /dev/null +++ b/testsuites/sptests/spintrcritical24/Makefile.am @@ -0,0 +1,22 @@ +rtems_tests_PROGRAMS = spintrcritical24 +spintrcritical24_SOURCES = init.c +spintrcritical24_SOURCES += ../spintrcritical_support/intrcritical.h +spintrcritical24_SOURCES += ../spintrcritical_support/intrcritical.c + +dist_rtems_tests_DATA = spintrcritical24.scn spintrcritical24.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 +AM_CPPFLAGS += -I$(top_srcdir)/spintrcritical_support + +LINK_OBJS = $(spintrcritical24_OBJECTS) +LINK_LIBS = $(spintrcritical24_LDLIBS) + +spintrcritical24$(EXEEXT): $(spintrcritical24_OBJECTS) $(spintrcritical24_DEPENDENCIES) + @rm -f spintrcritical24$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/sptests/spintrcritical24/init.c b/testsuites/sptests/spintrcritical24/init.c new file mode 100644 index 0000000000..8f60c1ce70 --- /dev/null +++ b/testsuites/sptests/spintrcritical24/init.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2017 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 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.org/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include + +#include +#include + +const char rtems_test_name[] = "SPINTRCRITICAL 24"; + +typedef struct { + int fd; + long append_count; + long no_append_count; +} test_context; + +static test_context test_instance; + +static const char path[] = "generic"; + +static int handler_close(rtems_libio_t *iop) +{ + test_context *ctx; + + ctx = IMFS_generic_get_context_by_iop(iop); + + if (rtems_libio_iop_is_append(iop)) { + ++ctx->append_count; + } else { + ++ctx->no_append_count; + } + + return 0; +} + +static const rtems_filesystem_file_handlers_r node_handlers = { + .open_h = rtems_filesystem_default_open, + .close_h = handler_close, + .fstat_h = rtems_filesystem_default_fstat, + .fcntl_h = rtems_filesystem_default_fcntl +}; + +static const IMFS_node_control node_control = { + .handlers = &node_handlers, + .node_initialize = IMFS_node_initialize_generic, + .node_remove = IMFS_node_remove_default, + .node_destroy = IMFS_node_destroy_default +}; + +static void do_fcntl(rtems_id timer, void *arg) +{ + /* The arg is NULL */ + test_context *ctx; + int rv; + + ctx = &test_instance; + + rv = fcntl(ctx->fd, F_SETFL, O_APPEND); + + if (rv != 0) { + rtems_test_assert(rv == -1); + rtems_test_assert(errno == EBADF); + } +} + +static bool test_body(void *arg) +{ + test_context *ctx; + int rv; + + ctx = arg; + + ctx->fd = open(path, O_RDWR); + rtems_test_assert(ctx->fd >= 0); + + rv = close(ctx->fd); + rtems_test_assert(rv == 0); + + return false; +} + +static void test(test_context *ctx) +{ + const char *path = "generic"; + int rv; + + rv = IMFS_make_generic_node( + path, + S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, + &node_control, + ctx + ); + rtems_test_assert(rv == 0); + + interrupt_critical_section_test(test_body, ctx, do_fcntl); + + /* There is no reliable indicator if the test case has been hit */ + rtems_test_assert(ctx->append_count > 0); + rtems_test_assert(ctx->no_append_count > 0); + + rv = unlink(path); + rtems_test_assert(rv == 0); +} + +static void Init(rtems_task_argument arg) +{ + TEST_BEGIN(); + test(&test_instance); + TEST_END(); + rtems_test_exit(0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER + +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 + +#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 4 + +#define CONFIGURE_MAXIMUM_TASKS 1 +#define CONFIGURE_MAXIMUM_TIMERS 1 +#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1 + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT + +#include diff --git a/testsuites/sptests/spintrcritical24/spintrcritical24.doc b/testsuites/sptests/spintrcritical24/spintrcritical24.doc new file mode 100644 index 0000000000..c8714bedf2 --- /dev/null +++ b/testsuites/sptests/spintrcritical24/spintrcritical24.doc @@ -0,0 +1,13 @@ +This file describes the directives and concepts tested by this test set. + +test set name: spintrcritical24 + +directives: + + - fcntl() + - close() + +concepts: + + - Try to ensure that a close completes successful in case it is interrupted + by a call to fcntl() altering the iop flags. diff --git a/testsuites/sptests/spintrcritical24/spintrcritical24.scn b/testsuites/sptests/spintrcritical24/spintrcritical24.scn new file mode 100644 index 0000000000..3f2eef3853 --- /dev/null +++ b/testsuites/sptests/spintrcritical24/spintrcritical24.scn @@ -0,0 +1,2 @@ +*** BEGIN OF TEST SPINTRCRITICAL 24 *** +*** END OF TEST SPINTRCRITICAL 24 *** -- cgit v1.2.3