diff --git a/fs/Makefile b/fs/Makefile index 9a06385792..5c2e59a103 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -44,8 +44,9 @@ CSRCS = fs_open.c fs_close.c fs_read.c fs_write.c fs_ioctl.c fs_dup.c \ fs_opendir.c fs_closedir.c fs_readdir.c fs_readdirr.c \ fs_seekdir.c fs_telldir.c fs_rewinddir.c fs_files.c \ fs_inode.c fs_inodefind.c fs_inodefinddir.c fs_inodereserve.c \ - fs_inoderemove.c fs_registerdriver.c fs_registerblockdriver.c \ - fs_inodeaddref.c fs_inoderelease.c + fs_inoderemove.c fs_registerdriver.c fs_unregisterdriver.c \ + fs_registerblockdriver.c fs_unregisterblockdriver.c \ + fs_mount.c fs_umount.c fs_inodeaddref.c fs_inoderelease.c COBJS = $(CSRCS:.c=$(OBJEXT)) SRCS = $(ASRCS) $(CSRCS) diff --git a/fs/fs_inoderemove.c b/fs/fs_inoderemove.c index 58ac734e7e..cb80dcbc57 100644 --- a/fs/fs_inoderemove.c +++ b/fs/fs_inoderemove.c @@ -101,6 +101,8 @@ static void inode_unlink(struct inode *node, /**************************************************************************** * Name: inode_remove + * + * NOTE: Caller must hold the inode semaphore ****************************************************************************/ STATUS inode_remove(const char *path) diff --git a/fs/fs_inodereserve.c b/fs/fs_inodereserve.c index ad010e21e2..4895cda03b 100644 --- a/fs/fs_inodereserve.c +++ b/fs/fs_inodereserve.c @@ -139,6 +139,8 @@ static void inode_insert(FAR struct inode *node, /************************************************************ * Name: inode_reserve + * + * NOTE: Caller must hold the inode semaphore ************************************************************/ FAR struct inode *inode_reserve(const char *path) diff --git a/fs/fs_internal.h b/fs/fs_internal.h index e63d6029fa..2912ff2b73 100644 --- a/fs/fs_internal.h +++ b/fs/fs_internal.h @@ -66,8 +66,8 @@ ((i)->i_flags &= ~FSNODEFLAG_TYPE_MASK) #define INODE_SET_BLOCK(i) \ ((i)->i_flags = (((i)->i_flags & ~FSNODEFLAG_TYPE_MASK) | FSNODEFLAG_TYPE_BLOCK)) -#define INODE_SET_MOUNTP(i) \ - ((i)->i_flags = (((i)->i_flags & ~FSNODEFLAG_TYPE_MASK) | FSNODEFLAG_TYPE_MOUNTP)) +#define INODE_SET_MOUNTPT(i) \ + ((i)->i_flags = (((i)->i_flags & ~FSNODEFLAG_TYPE_MASK) | FSNODEFLAG_TYPE_MOUNTPT)) /**************************************************************************** * Public Types diff --git a/fs/fs_mount.c b/fs/fs_mount.c new file mode 100644 index 0000000000..753f9bac3b --- /dev/null +++ b/fs/fs_mount.c @@ -0,0 +1,272 @@ +/**************************************************************************** + * fs_mount.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "fs_internal.h" + +#if CONFIG_NFILE_DESCRIPTORS > 0 + +/* At least one filesystem must be defined, or this file will not compile. + * It may be desire-able to make filesystems dynamically registered at + * some time in the future, but at present, this file needs to know about + * every configured filesystem. + */ + +#ifdef CONFIG_FS_FAT + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct fsmap_t +{ + const char *fs_filesystemtype; + const struct mountpt_operations *fs_mops; +}; + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +#ifdef CONFIG_FS_FAT +extern const struct mountpt_operations fat_operations; +#endif + +static const struct fsmap_t g_fsmap[] = +{ +#ifdef CONFIG_FS_FAT + { "vfat", &fat_operations }, +#endif + { NULL, NULL }, +}; + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mount_findfs + * + * Description: + * find the specified filesystem + * + ****************************************************************************/ + +static FAR const struct mountpt_operations *mount_findfs(const char *filesystemtype ) +{ + const struct fsmap_t *fsmap; + for (fsmap = g_fsmap; fsmap->fs_filesystemtype; fsmap++) + { + if (strcmp(filesystemtype, fsmap->fs_filesystemtype) == 0) + { + return fsmap->fs_mops; + } + } + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mount + * + * Description: + * mount() attaches the filesystem specified by the 'source' block device + * name into the root file system at the path specified by 'target.' + * + * Return: + * Zero is returned on success; -1 is returned on an error and errno is + * set appropriately: + * + * EACCES A component of a path was not searchable or mounting a read-only + * filesystem was attempted without giving the MS_RDONLY flag. + * EBUSY 'source' is already mounted. + * EFAULT One of the pointer arguments points outside the user address + * space. + * EINVAL 'source' had an invalid superblock. + * ENODEV 'filesystemtype' not configured + * ENOENT A pathname was empty or had a nonexistent component. + * ENOMEM Could not allocate a memory to copy filenames or data into. + * ENOTBLK 'source' is not a block device + * + ****************************************************************************/ + +int mount(const char *source, const char *target, + const char *filesystemtype, unsigned long mountflags, + const void *data) +{ + FAR struct inode *blkdrvr_inode; + FAR struct inode *mountpt_inode; + FAR const struct mountpt_operations *mops; + void *fshandle; + int errcode; + int status; + + /* Verify required pointer arguments */ + + if (!source || !target || !filesystemtype) + { + errcode = EFAULT; + goto errout; + } + + /* Find the specified filesystem */ + mops = mount_findfs(filesystemtype); + if (!mops) + { + errcode = ENODEV; + goto errout; + } + + /* Find the block driver */ + + blkdrvr_inode = inode_find(source, NULL); + if (!blkdrvr_inode) + { + errcode = ENOENT; + goto errout; + } + + /* Verify that the inode is a block driver. */ + + if (!INODE_IS_BLOCK(blkdrvr_inode)) + { + errcode = ENOTBLK; + goto errout_with_blkdrvr; + } + + /* Make sure that the inode supports the requested access */ + + if (!blkdrvr_inode->u.i_mops->read || + (!blkdrvr_inode->u.i_mops->write && (mountflags & MS_RDONLY) == 0)) + { + errcode = EACCES; + goto errout_with_blkdrvr; + } + + /* Insert a dummy node -- we need to hold the inode semaphore + * to do this because we will have a momentarily bad structure. + */ + + inode_semtake(); + mountpt_inode = inode_reserve(target); + if (!mountpt_inode) + { + /* inode_reserve can fail for a couple of reasons, but the most likely + * one is that the inode already exists. + */ + + errcode = EBUSY; + goto errout_with_semaphore; + } + + /* Bind the block driver to an instance of the file system. The file + * system returns a reference to some opaque, fs-dependent structure + * that encapsulates this binding. + */ + + if (!mops->bind) + { + /* The filesystem does not support the bind operation ??? */ + + errcode = EINVAL; + goto errout_with_mountpt; + } + + /* On failure, the bind method returns -errorcode */ + + status = mops->bind(blkdrvr_inode, data, &fshandle); + if (status != 0) + { + /* The inode is unhappy with the blkdrvr for some reason */ + + errcode = -status; + goto errout_with_mountpt; + } + + /* We have it, now populate it with driver specific information. */ + + INODE_SET_MOUNTPT(mountpt_inode); + + mountpt_inode->u.i_mops = mops; +#ifdef CONFIG_FILE_MODE + mountpt_inode->i_mode = mode; +#endif + mountpt_inode->i_private = fshandle; + inode_semgive(); + + /* We can release our reference to the blkdrver_inode, if the filesystem + * wants to retain the blockdriver inode (which it should), then it must + * have called inode_addref(). There is one reference on mountpt_inode + * that will persist until umount() is called. + */ + + inode_release(blkdrvr_inode); + return OK; + + /* A lot of goto's! But they make the error handling much simpler */ + + errout_with_mountpt: + inode_release(mountpt_inode); + errout_with_semaphore: + inode_semgive(); + errout_with_blkdrvr: + inode_release(blkdrvr_inode); + errout: + *get_errno_ptr() = errcode; + return ERROR; +} + +#endif /* Need at least filesystem */ +#endif /* Need file descriptor support */ diff --git a/fs/fs_open.c b/fs/fs_open.c index 0fc1b5133c..3561d2be04 100644 --- a/fs/fs_open.c +++ b/fs/fs_open.c @@ -153,11 +153,11 @@ int open(const char *path, int oflags, ...) { if (INODE_IS_MOUNTPT(inode)) { - status = inode->u.i_ops->open((FAR struct file*)&list->fl_files[fd]); + status = inode->u.i_mops->open((FAR struct file*)&list->fl_files[fd], relpath); } else { - status = inode->u.i_mops->open((FAR struct file*)&list->fl_files[fd], relpath); + status = inode->u.i_ops->open((FAR struct file*)&list->fl_files[fd]); } } diff --git a/fs/fs_umount.c b/fs/fs_umount.c new file mode 100644 index 0000000000..b18407f204 --- /dev/null +++ b/fs/fs_umount.c @@ -0,0 +1,176 @@ +/**************************************************************************** + * fs_umount.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include "fs_internal.h" + +#if CONFIG_NFILE_DESCRIPTORS > 0 + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: umount + * + * Description: + * umount() detaches the filesystem mounted at the path specified by + * 'target.' + * + * Return: + * Zero is returned on success; -1 is returned on an error and errno is + * set appropriately: + * + * EACCES A component of a path was not searchable or mounting a read-only + * filesystem was attempted without giving the MS_RDONLY flag. + * EBUSY The target could not be unmounted because it is busy. + * EFAULT The pointer argument points outside the user address space. + * + ****************************************************************************/ + +int umount(const char *target) +{ + FAR struct inode *mountpt_inode; + int errcode; + int status; + + /* Verify required pointer arguments */ + + if (!target) + { + errcode = EFAULT; + goto errout; + } + + /* Find the mountpt */ + + inode_semtake(); + mountpt_inode = inode_find(target, NULL); + if (!mountpt_inode) + { + errcode = ENOENT; + goto errout_with_semaphore; + } + + /* Verify that the inode is a mountpoint */ + + if (!INODE_IS_MOUNTPT(mountpt_inode)) + { + errcode = EINVAL; + goto errout_with_mountpt; + } + + /* Unbind the block driver from the file system (destroying any fs + * private data. + */ + + if (!mountpt_inode->u.i_mops->unbind) + { + /* The filesystem does not support the unbind operation ??? */ + + errcode = EINVAL; + goto errout_with_mountpt; + } + + /* The unbind method returns the number of references to the + * filesystem (i.e., open files), zero if the unbind was + * performed, or a negated error code on a failure. + */ + + status = mountpt_inode->u.i_mops->unbind( mountpt_inode->i_private ); + if (status < 0) + { + /* The inode is unhappy with the blkdrvr for some reason */ + + errcode = -status; + goto errout_with_mountpt; + } + else if (status > 0) + { + errcode = EBUSY; + goto errout_with_mountpt; + } + + /* Successfully unbound */ + + mountpt_inode->i_private = NULL; + + /* Remove the inode */ + + inode_release(mountpt_inode); + status = inode_remove(target); + inode_semgive(); + return status; + + /* A lot of goto's! But they make the error handling much simpler */ + + errout_with_mountpt: + inode_release(mountpt_inode); + errout_with_semaphore: + inode_semgive(); + errout: + *get_errno_ptr() = errcode; + return ERROR; +} + +#endif /* CONFIG_NFILE_DESCRIPTORS */ diff --git a/fs/fs_unregisterblockdriver.c b/fs/fs_unregisterblockdriver.c new file mode 100644 index 0000000000..98786b534a --- /dev/null +++ b/fs/fs_unregisterblockdriver.c @@ -0,0 +1,85 @@ +/**************************************************************************** + * fs_unregisterblockdriver.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "fs_internal.h" + +#if CONFIG_NFILE_DESCRIPTORS > 0 + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: unregister_blockdriver() + ****************************************************************************/ + +STATUS unregister_blockdriver(const char *path) +{ + STATUS ret; + inode_semtake(); + ret = inode_remove(path); + inode_semgive(); + return ret; +} + +#endif diff --git a/fs/fs_unregisterdriver.c b/fs/fs_unregisterdriver.c new file mode 100644 index 0000000000..1e13e598f9 --- /dev/null +++ b/fs/fs_unregisterdriver.c @@ -0,0 +1,85 @@ +/**************************************************************************** + * fs_unregisterdriver.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "fs_internal.h" + +#if CONFIG_NFILE_DESCRIPTORS > 0 + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: unregister_driver() + ****************************************************************************/ + +STATUS unregister_driver(const char *path) +{ + STATUS ret; + inode_semtake(); + ret = inode_remove(path); + inode_semgive(); + return ret; +} + +#endif