cpukit/close.c: Fix reference counting under concurrent access.

Fixes issue with IOP being freed during close call.
This commit is contained in:
Aaron Nyholm
2025-10-07 13:22:06 +11:00
parent cec9935c33
commit a347ce1048

View File

@@ -52,7 +52,7 @@ int close(
rtems_set_errno_and_return_minus_one( EBADF ); rtems_set_errno_and_return_minus_one( EBADF );
} }
iop = rtems_libio_iop( fd ); LIBIO_GET_IOP( fd, iop );
flags = rtems_libio_iop_flags( iop ); flags = rtems_libio_iop_flags( iop );
while ( true ) { while ( true ) {
@@ -60,15 +60,10 @@ int close(
bool success; bool success;
if ( ( flags & LIBIO_FLAGS_OPEN ) == 0 ) { if ( ( flags & LIBIO_FLAGS_OPEN ) == 0 ) {
rtems_libio_iop_drop( iop );
rtems_set_errno_and_return_minus_one( EBADF ); rtems_set_errno_and_return_minus_one( EBADF );
} }
/* The expected flags depends on close when busy flag. If set
* there can be references held when calling the close handler */
if ( ( flags & LIBIO_FLAGS_CLOSE_BUSY ) == 0 ) {
flags &= LIBIO_FLAGS_FLAGS_MASK;
}
desired = flags & ~LIBIO_FLAGS_OPEN; desired = flags & ~LIBIO_FLAGS_OPEN;
success = _Atomic_Compare_exchange_uint( success = _Atomic_Compare_exchange_uint(
&iop->flags, &iop->flags,
@@ -82,14 +77,15 @@ int close(
break; break;
} }
if ( ( flags & LIBIO_FLAGS_REFERENCE_MASK ) != 0 ) { if ( ( flags & LIBIO_FLAGS_REFERENCE_MASK ) != LIBIO_FLAGS_REFERENCE_INC ) {
rtems_libio_iop_drop( iop );
rtems_set_errno_and_return_minus_one( EBUSY ); rtems_set_errno_and_return_minus_one( EBUSY );
} }
} }
rc = (*iop->pathinfo.handlers->close_h)( iop ); rc = (*iop->pathinfo.handlers->close_h)( iop );
rtems_libio_free( iop ); rtems_libio_iop_drop( iop );
return rc; return rc;
} }