Filesystem: Wait for unmount() to finish

This commit is contained in:
Sebastian Huber
2012-05-29 12:25:34 +02:00
parent 4acbff6c8e
commit 847ad441cd
7 changed files with 143 additions and 54 deletions
+19 -3
View File
@@ -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.
+10
View File
@@ -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;
/*
+9
View File
@@ -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);
}
+41 -8
View File
@@ -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;
}
+4
View File
@@ -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
+38 -33
View File
@@ -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 ***
+22 -10
View File
@@ -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("chdir to .. should fail with ENXIO\n");
status = chdir( ".." );
printf("chroot to /c/y/my_mount_point\n");
status = chroot( "/c/y/my_mount_point" );
rtems_test_assert( status == 0 );
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 );