[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