From 847ad441cda2466680107b0b7607a8ceca3b17d4 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 23 May 2012 11:39:50 +0200 Subject: Filesystem: Wait for unmount() to finish --- cpukit/libcsupport/include/rtems/libio.h | 22 ++++++++-- cpukit/libcsupport/include/rtems/libio_.h | 10 +++++ cpukit/libcsupport/src/sup_fs_location.c | 9 ++++ cpukit/libcsupport/src/unmount.c | 49 +++++++++++++++++---- testsuites/fstests/fsrdwr/init.c | 4 ++ testsuites/psxtests/psxmount/psxmount.scn | 71 +++++++++++++++++-------------- testsuites/psxtests/psxmount/test.c | 32 +++++++++----- 7 files changed, 143 insertions(+), 54 deletions(-) diff --git a/cpukit/libcsupport/include/rtems/libio.h b/cpukit/libcsupport/include/rtems/libio.h index b59ec0fb54..fe391d9044 100644 --- a/cpukit/libcsupport/include/rtems/libio.h +++ b/cpukit/libcsupport/include/rtems/libio.h @@ -1459,6 +1459,13 @@ struct rtems_filesystem_mount_table_entry_tt { * string. */ char *dev; + + /** + * The task that initiated the unmount process. After unmount process + * completion this task will be notified via the + * @ref RTEMS_FILESYSTEM_UNMOUNT_EVENT. + */ + rtems_id unmount_task; }; /** @@ -1513,9 +1520,18 @@ int rtems_filesystem_unregister( /** * @brief Unmounts the file system at @a mount_path. * - * @todo Due to file system implementation shortcomings it is possible to - * unmount file systems in use. This likely leads to heap corruption. Unmount - * only file systems which are not in use by the application. + * The function waits for the unmount process completion. In case the calling + * thread uses resources of the unmounted file system the function may never + * return. In case the calling thread has its root or current directory in the + * unmounted file system the function returns with an error status and errno is + * set to EBUSY. + * + * The unmount process completion notification uses the RTEMS classic API + * event @ref RTEMS_FILESYSTEM_UNMOUNT_EVENT. It is a fatal error to terminate + * the calling thread while waiting for this event. + * + * A concurrent unmount request for the same file system instance has + * unpredictable effects. * * @retval 0 Successful operation. * @retval -1 An error occured. The @c errno indicates the error. diff --git a/cpukit/libcsupport/include/rtems/libio_.h b/cpukit/libcsupport/include/rtems/libio_.h index 418f4a31ec..1e4bb84ecd 100644 --- a/cpukit/libcsupport/include/rtems/libio_.h +++ b/cpukit/libcsupport/include/rtems/libio_.h @@ -38,6 +38,16 @@ extern "C" { #define RTEMS_LIBIO_SEM rtems_build_name('L', 'B', 'I', 'O') #define RTEMS_LIBIO_IOP_SEM(n) rtems_build_name('L', 'B', 'I', n) +/** + * @brief Event to signal an unmount process completion. + * + * This event should equal the RTEMS_BDBUF_TRANSFER_SYNC event to avoid too + * many events reserved for the file system. + * + * @see rtems_filesystem_do_unmount() and unmount(). + */ +#define RTEMS_FILESYSTEM_UNMOUNT_EVENT RTEMS_EVENT_1 + extern rtems_id rtems_libio_semaphore; /* diff --git a/cpukit/libcsupport/src/sup_fs_location.c b/cpukit/libcsupport/src/sup_fs_location.c index 4ebf5f04d7..f991024762 100644 --- a/cpukit/libcsupport/src/sup_fs_location.c +++ b/cpukit/libcsupport/src/sup_fs_location.c @@ -213,5 +213,14 @@ void rtems_filesystem_do_unmount( rtems_filesystem_mt_unlock(); rtems_filesystem_global_location_release(mt_entry->mt_point_node); (*mt_entry->ops->fsunmount_me_h)(mt_entry); + + if (mt_entry->unmount_task != 0) { + rtems_status_code sc = + rtems_event_send(mt_entry->unmount_task, RTEMS_FILESYSTEM_UNMOUNT_EVENT); + if (sc != RTEMS_SUCCESSFUL) { + rtems_fatal_error_occurred(0xdeadbeef); + } + } + free(mt_entry); } diff --git a/cpukit/libcsupport/src/unmount.c b/cpukit/libcsupport/src/unmount.c index b58955d33c..ad45220fd5 100644 --- a/cpukit/libcsupport/src/unmount.c +++ b/cpukit/libcsupport/src/unmount.c @@ -22,6 +22,18 @@ #include +static bool contains_root_or_current_directory( + const rtems_filesystem_mount_table_entry_t *mt_entry +) +{ + const rtems_filesystem_location_info_t *root = + &rtems_filesystem_root->location; + const rtems_filesystem_location_info_t *current = + &rtems_filesystem_current->location; + + return mt_entry == root->mt_entry || mt_entry == current->mt_entry; +} + int unmount( const char *path ) { int rv = 0; @@ -32,16 +44,23 @@ int unmount( const char *path ) rtems_filesystem_mount_table_entry_t *mt_entry = currentloc->mt_entry; if ( rtems_filesystem_location_is_root( currentloc ) ) { - const rtems_filesystem_operations_table *mt_point_ops = - mt_entry->mt_point_node->location.mt_entry->ops; + if ( !contains_root_or_current_directory( mt_entry ) ) { + const rtems_filesystem_operations_table *mt_point_ops = + mt_entry->mt_point_node->location.mt_entry->ops; - rv = (*mt_point_ops->unmount_h)( mt_entry ); - if ( rv == 0 ) { - rtems_filesystem_mt_entry_declare_lock_context( lock_context ); + rv = (*mt_point_ops->unmount_h)( mt_entry ); + if ( rv == 0 ) { + rtems_id self_task_id = rtems_task_self(); + rtems_filesystem_mt_entry_declare_lock_context( lock_context ); - rtems_filesystem_mt_entry_lock( lock_context ); - mt_entry->mounted = false; - rtems_filesystem_mt_entry_unlock( lock_context ); + rtems_filesystem_mt_entry_lock( lock_context ); + mt_entry->unmount_task = self_task_id; + mt_entry->mounted = false; + rtems_filesystem_mt_entry_unlock( lock_context ); + } + } else { + errno = EBUSY; + rv = -1; } } else { errno = EACCES; @@ -50,5 +69,19 @@ int unmount( const char *path ) rtems_filesystem_eval_path_cleanup( &ctx ); + if ( rv == 0 ) { + rtems_event_set out; + rtems_status_code sc = rtems_event_receive( + RTEMS_FILESYSTEM_UNMOUNT_EVENT, + RTEMS_EVENT_ALL | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &out + ); + + if ( sc != RTEMS_SUCCESSFUL ) { + rtems_fatal_error_occurred( 0xdeadbeef ); + } + } + return rv; } diff --git a/testsuites/fstests/fsrdwr/init.c b/testsuites/fstests/fsrdwr/init.c index 6e43756b9f..ca2a62869d 100644 --- a/testsuites/fstests/fsrdwr/init.c +++ b/testsuites/fstests/fsrdwr/init.c @@ -256,13 +256,17 @@ truncate_test03 (void) rtems_test_assert (fd >= 0); n = write (fd, databuf, len); rtems_test_assert (n == len); + status = close (fd); + rtems_test_assert (status == 0); /* * Truncate it to the half size */ status = truncate (name01, len / 2); + rtems_test_assert (status == 0); status = truncate (name01, len); + rtems_test_assert (status == 0); /* * verify the data diff --git a/testsuites/psxtests/psxmount/psxmount.scn b/testsuites/psxtests/psxmount/psxmount.scn index 88c1fa9fbe..440344af99 100644 --- a/testsuites/psxtests/psxmount/psxmount.scn +++ b/testsuites/psxtests/psxmount/psxmount.scn @@ -1,5 +1,3 @@ - - *** MOUNT/UNMOUNT TEST *** chdir to the root directory @@ -25,30 +23,30 @@ create /b/my_file Verify /b/my_file create c/y/my_mount_point/my_dir/d Verify c/y/my_mount_point/my_dir/d -Attempting to mount IMFS file system at /c/z/my_mount_point -2nd file system successfully mounted at /c/z/my_mount_point +Attempting to mount IMFS file system at /c/z/my_mount_point +2nd file system successfully mounted at /c/z/my_mount_point chdir to /c/z/my_mount_point. chdir() status : 0 Creating a series of directories under /c/z/my_mount_point -Creating: a 0 2 Success -Creating: b 0 2 Success -Creating: c 0 2 Success -Creating: d 0 2 Success -Creating: e 0 2 Success -Creating: f 0 2 Success -Creating: c/y 0 2 Success -Creating: c/z 0 2 Success -Creating: c/x 0 2 Success -Creating: c/y/a3333 0 2 Success -Creating: c/y/j123 0 2 Success -Creating: c/y/my_mount_point 0 2 Success -Creating: c/y/my_mount_point/my_dir 0 2 Success -Creating: c/y/my_mount_point/my_dir/d 0 2 Success -Creating: c/z/my_mount_point 0 2 Success -Creating: /c/z/my_mount_point/a/../../my_mount_point/a/g 0 2 Success +Creating: a 0 0 Success +Creating: b 0 0 Success +Creating: c 0 0 Success +Creating: d 0 0 Success +Creating: e 0 0 Success +Creating: f 0 0 Success +Creating: c/y 0 0 Success +Creating: c/z 0 0 Success +Creating: c/x 0 0 Success +Creating: c/y/a3333 0 0 Success +Creating: c/y/j123 0 0 Success +Creating: c/y/my_mount_point 0 0 Success +Creating: c/y/my_mount_point/my_dir 0 0 Success +Creating: c/y/my_mount_point/my_dir/d 0 0 Success +Creating: c/z/my_mount_point 0 0 Success +Creating: /c/z/my_mount_point/a/../../my_mount_point/a/g 0 0 Success chdir to / chdir() status : 0 @@ -56,31 +54,38 @@ chdir() status : 0 Unmount status: 0 Mount a NULL file system and verify EINVAL mount with option of -62 should fail with EINVAL -Mount a Read Only filesystem at /c/y/my_mount_point -Read only file system successfully mounted at /c/y/my_mount_point -create c/y/my_mount_point/../../y/my_mount_point/new_dir +Mount a Read Only filesystem at /c/y/my_mount_point +Read only file system successfully mounted at /c/y/my_mount_point +create c/y/my_mount_point/../../y/new_dir +Verify a mount point returns EROFS for another mount +Unmount /c/y/my_mount_point +Mount a read-write file system at /c/y/my_mount_point Verify a mount point returns EBUSY for another mount Mount on a file should fail with ENOTDIR Create and chdir to /c/y/my_mount_point/mydir unmount of /c/y/my_mount_point should fail with EBUSY -chdir to / and verify we can unmount /c/y/my_mount_point -unmount /c/y/my_mount_point +chroot to /c/y/my_mount_point +unmount of . should fail with EBUSY +chroot to / and verify we can unmount /c/y/my_mount_point +unmount of /c/y/my_mount_point +chdir to /c/y/my_mount_point/my_dir should fail with ENOENT unmount /b/mount_point should fail with EINVAL Mount /c/y/my_mount_point Create and open /c/y/my_mount_point/my_file -mkdir /c/y/my_mount_point/my_dir -Open /c/y/my_mount_point/my_dir -Unmount /c/y/my_mount_point should fail with EBUSY -Close /c/y/my_mount_point/my_dir +mkdir /c/y/my_mount_point/my_sub_fs_dir +open /c/y/my_mount_point/my_sub_fs_dir +close /c/y/my_mount_point/my_sub_fs_dir +mkdir /c/y/my_mount_point/my_sub_fs_dir should fail with EEXIST +unmount /c/y/my_mount_point +mkdir /c/y/my_mount_point/my_sub_fs_dir +rmdir /c/y/my_mount_point/my_sub_fs_dir Unmount /c/y/my_mount_point/my_dir should fail with EACCES -Mount a file system at /c/y/my_mount_point/my_dir -unmount /c/y/my_mount_point should fail with EBUSY +Mount a file system at /c/y/my_mount_point Verify a hard link across filesystems fails with EXDEV Verify a symbolic link across file systems works -unmount /c/y/my_mount_point/my_dir -Verify the symbolic link now fails unmount /c/y/my_mount_point +Verify the symbolic link now fails *** END OF MOUNT/UNMOUNT TEST *** diff --git a/testsuites/psxtests/psxmount/test.c b/testsuites/psxtests/psxmount/test.c index 1033226a31..399ac2cfc0 100644 --- a/testsuites/psxtests/psxmount/test.c +++ b/testsuites/psxtests/psxmount/test.c @@ -314,21 +314,33 @@ int main( status = chdir( "/c/y/my_mount_point/mydir" ); rtems_test_assert( status == 0 ); - printf("unmount of /c/y/my_mount_point\n"); + printf("unmount of /c/y/my_mount_point should fail with EBUSY\n"); status = unmount( "/c/y/my_mount_point" ); + rtems_test_assert( status == -1 ); + rtems_test_assert( errno == EBUSY ); + + status = chdir( "/" ); + rtems_test_assert( status == 0 ); + + printf("chroot to /c/y/my_mount_point\n"); + status = chroot( "/c/y/my_mount_point" ); rtems_test_assert( status == 0 ); - printf("chdir to .. should fail with ENXIO\n"); - status = chdir( ".." ); + printf("unmount of . should fail with EBUSY\n"); + status = unmount( "." ); rtems_test_assert( status == -1 ); - rtems_test_assert( errno == ENXIO ); + rtems_test_assert( errno == EBUSY ); /* * Chdir to root and verify we unmounted the file system now. */ - printf("chdir to / and verify we can unmount /c/y/my_mount_point\n"); - status = chdir( "/" ); + printf("chroot to / and verify we can unmount /c/y/my_mount_point\n"); + status = chroot( "/" ); + rtems_test_assert( status == 0 ); + + printf("unmount of /c/y/my_mount_point\n"); + status = unmount( "/c/y/my_mount_point" ); rtems_test_assert( status == 0 ); printf("chdir to /c/y/my_mount_point/my_dir should fail with ENOENT\n"); @@ -376,6 +388,10 @@ int main( directory = opendir( my_sub_fs_dir ); rtems_test_assert( directory ); + printf("close %s\n", my_sub_fs_dir ); + status = closedir( directory ); + rtems_test_assert( status == 0 ); + printf("mkdir %s should fail with EEXIST\n", my_sub_fs_dir ); status = mkdir( my_sub_fs_dir, S_IRWXU ); rtems_test_assert( status == -1 ); @@ -385,10 +401,6 @@ int main( status = unmount( mount_point ); rtems_test_assert( status == 0 ); - printf("close %s\n", my_sub_fs_dir ); - status = closedir( directory ); - rtems_test_assert( status == 0 ); - printf("mkdir %s\n", my_sub_fs_dir ); status = mkdir( my_sub_fs_dir, S_IRWXU ); rtems_test_assert( status == 0 ); -- cgit v1.2.3