From f08c71339c05cb462a32a11e3150d71603340e94 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 16 Mar 2017 11:54:29 +0100 Subject: libio: Fix deadlock in location management Perform a context-dependent deferred location release to avoid a deadlock on the file system instance locks, for example during a chdir(). Close #2936. --- cpukit/libcsupport/include/rtems/libio_.h | 5 ++++- cpukit/libcsupport/src/chdir.c | 2 +- cpukit/libcsupport/src/chroot.c | 4 ++-- cpukit/libcsupport/src/mount.c | 2 +- cpukit/libcsupport/src/privateenv.c | 4 ++-- cpukit/libcsupport/src/sup_fs_eval_path.c | 4 ++-- cpukit/libcsupport/src/sup_fs_location.c | 9 +++++---- 7 files changed, 17 insertions(+), 13 deletions(-) (limited to 'cpukit') diff --git a/cpukit/libcsupport/include/rtems/libio_.h b/cpukit/libcsupport/include/rtems/libio_.h index 0c5e9ed30b..c2fb975bf7 100644 --- a/cpukit/libcsupport/include/rtems/libio_.h +++ b/cpukit/libcsupport/include/rtems/libio_.h @@ -507,11 +507,14 @@ rtems_filesystem_global_location_t *rtems_filesystem_global_location_obtain( * deferred. The next obtain call will do the actual release. * * @param[in] global_loc The global file system location. It must not be NULL. + * @param[in] deferred If true, then do a deferred release, otherwise release + * it immediately. * * @see rtems_filesystem_global_location_obtain(). */ void rtems_filesystem_global_location_release( - rtems_filesystem_global_location_t *global_loc + rtems_filesystem_global_location_t *global_loc, + bool deferred ); void rtems_filesystem_location_detach( diff --git a/cpukit/libcsupport/src/chdir.c b/cpukit/libcsupport/src/chdir.c index 4bcb30075e..83a359a982 100644 --- a/cpukit/libcsupport/src/chdir.c +++ b/cpukit/libcsupport/src/chdir.c @@ -39,7 +39,7 @@ int rtems_filesystem_chdir( rtems_filesystem_location_info_t *loc ) ); } else { rtems_filesystem_location_error( &global_loc->location, ENOTDIR ); - rtems_filesystem_global_location_release( global_loc ); + rtems_filesystem_global_location_release( global_loc, true ); rv = -1; } diff --git a/cpukit/libcsupport/src/chroot.c b/cpukit/libcsupport/src/chroot.c index 9ec4ad470f..0c498e6a6f 100644 --- a/cpukit/libcsupport/src/chroot.c +++ b/cpukit/libcsupport/src/chroot.c @@ -80,7 +80,7 @@ int chroot( const char *path ) } if ( rv != 0 ) { - rtems_filesystem_global_location_release( new_root_loc ); + rtems_filesystem_global_location_release( new_root_loc, true ); } } else { rv = -1; @@ -89,7 +89,7 @@ int chroot( const char *path ) rtems_filesystem_eval_path_cleanup( &ctx ); if ( rv != 0 ) { - rtems_filesystem_global_location_release( new_current_loc ); + rtems_filesystem_global_location_release( new_current_loc, false ); } return rv; diff --git a/cpukit/libcsupport/src/mount.c b/cpukit/libcsupport/src/mount.c index 0d66477fe3..5328d24e7f 100644 --- a/cpukit/libcsupport/src/mount.c +++ b/cpukit/libcsupport/src/mount.c @@ -126,7 +126,7 @@ static int register_subordinate_file_system( ); rtems_filesystem_mt_unlock(); } else { - rtems_filesystem_global_location_release( mt_point_node ); + rtems_filesystem_global_location_release( mt_point_node, true ); } } else { rtems_filesystem_eval_path_error( &ctx, EBUSY ); diff --git a/cpukit/libcsupport/src/privateenv.c b/cpukit/libcsupport/src/privateenv.c index 29821e4045..00fc4129ad 100644 --- a/cpukit/libcsupport/src/privateenv.c +++ b/cpukit/libcsupport/src/privateenv.c @@ -44,8 +44,8 @@ void rtems_libio_free_user_env(void *arg) bool uses_global_env = env == &rtems_global_user_env; if (!uses_global_env) { - rtems_filesystem_global_location_release(env->current_directory); - rtems_filesystem_global_location_release(env->root_directory); + rtems_filesystem_global_location_release(env->current_directory, false); + rtems_filesystem_global_location_release(env->root_directory, false); free(env); } } diff --git a/cpukit/libcsupport/src/sup_fs_eval_path.c b/cpukit/libcsupport/src/sup_fs_eval_path.c index 459fa6bfc8..a05472f834 100644 --- a/cpukit/libcsupport/src/sup_fs_eval_path.c +++ b/cpukit/libcsupport/src/sup_fs_eval_path.c @@ -301,8 +301,8 @@ void rtems_filesystem_eval_path_cleanup( { free_location(&ctx->currentloc); rtems_filesystem_instance_unlock(&ctx->startloc->location); - rtems_filesystem_global_location_release(ctx->startloc); - rtems_filesystem_global_location_release(ctx->rootloc); + rtems_filesystem_global_location_release(ctx->startloc, false); + rtems_filesystem_global_location_release(ctx->rootloc, false); } void rtems_filesystem_eval_path_cleanup_with_parent( diff --git a/cpukit/libcsupport/src/sup_fs_location.c b/cpukit/libcsupport/src/sup_fs_location.c index ddda4d15eb..c8956f26cf 100644 --- a/cpukit/libcsupport/src/sup_fs_location.c +++ b/cpukit/libcsupport/src/sup_fs_location.c @@ -105,7 +105,7 @@ void rtems_filesystem_global_location_assign( *lhs_global_loc_ptr = rhs_global_loc; rtems_filesystem_mt_entry_unlock(lock_context); - rtems_filesystem_global_location_release(lhs_global_loc); + rtems_filesystem_global_location_release(lhs_global_loc, true); } static void release_with_count( @@ -183,10 +183,11 @@ rtems_filesystem_global_location_t *rtems_filesystem_global_location_obtain( } void rtems_filesystem_global_location_release( - rtems_filesystem_global_location_t *global_loc + rtems_filesystem_global_location_t *global_loc, + bool deferred ) { - if (_Thread_Dispatch_is_enabled()) { + if (!deferred) { release_with_count(global_loc, 1); } else { rtems_interrupt_lock_context lock_context; @@ -232,7 +233,7 @@ void rtems_filesystem_do_unmount( rtems_filesystem_mt_lock(); rtems_chain_extract_unprotected(&mt_entry->mt_node); rtems_filesystem_mt_unlock(); - rtems_filesystem_global_location_release(mt_entry->mt_point_node); + rtems_filesystem_global_location_release(mt_entry->mt_point_node, false); (*mt_entry->ops->fsunmount_me_h)(mt_entry); if (mt_entry->unmount_task != 0) { -- cgit v1.2.3