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 +- 19 files changed, 141 insertions(+), 44 deletions(-) (limited to 'cpukit') 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; -- cgit v1.2.3