[rtems commit] Filesystem: Wait for unmount() to finish
Sebastian Huber
sebh at rtems.org
Tue May 29 10:23:08 UTC 2012
Module: rtems
Branch: master
Commit: 847ad441cda2466680107b0b7607a8ceca3b17d4
Changeset: http://git.rtems.org/rtems/commit/?id=847ad441cda2466680107b0b7607a8ceca3b17d4
Author: Sebastian Huber <sebastian.huber at embedded-brains.de>
Date: Wed May 23 11:39:50 2012 +0200
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 b59ec0f..fe391d9 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 418f4a3..1e4bb84 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 4ebf5f0..f991024 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 b58955d..ad45220 100644
--- a/cpukit/libcsupport/src/unmount.c
+++ b/cpukit/libcsupport/src/unmount.c
@@ -22,6 +22,18 @@
#include <rtems/libio_.h>
+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 6e43756..ca2a628 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 88c1fa9..440344a 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 1033226..399ac2c 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 );
More information about the vc
mailing list