fs/mount and fs/unionfs: Support mount unionfs from nsh command.
This commit is contained in:
parent
756c9f4eac
commit
579b38b760
2 changed files with 213 additions and 99 deletions
|
|
@ -1,7 +1,7 @@
|
|||
/****************************************************************************
|
||||
* fs/mount/fs_mount.c
|
||||
*
|
||||
* Copyright (C) 2007-2009, 2011-2013, 2015, 2017, 2018 Gregory Nutt. All
|
||||
* Copyright (C) 2007-2009, 2011-2013, 2015, 2017-2019 Gregory Nutt. All
|
||||
* rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
|
|
@ -68,7 +68,8 @@
|
|||
|
||||
/* In the canonical case, a file system is bound to a block driver. However,
|
||||
* some less typical cases a block driver is not required. Examples are
|
||||
* pseudo file systems (like BINFS or PROCFS) and MTD file systems (like NXFFS).
|
||||
* pseudo file systems (like BINFS or PROCFS) and MTD file systems (like
|
||||
* NXFFS).
|
||||
*
|
||||
* These file systems all require block drivers:
|
||||
*/
|
||||
|
|
@ -89,7 +90,7 @@
|
|||
#if defined(CONFIG_FS_NXFFS) || defined(CONFIG_FS_BINFS) || \
|
||||
defined(CONFIG_FS_PROCFS) || defined(CONFIG_NFS) || \
|
||||
defined(CONFIG_FS_TMPFS) || defined(CONFIG_FS_USERFS) || \
|
||||
defined(CONFIG_FS_CROMFS)
|
||||
defined(CONFIG_FS_CROMFS) || defined(CONFIG_FS_UNIONFS)
|
||||
# define NODFS_SUPPORT
|
||||
#endif
|
||||
|
||||
|
|
@ -196,6 +197,9 @@ extern const struct mountpt_operations hostfs_operations;
|
|||
#ifdef CONFIG_FS_CROMFS
|
||||
extern const struct mountpt_operations cromfs_operations;
|
||||
#endif
|
||||
#ifdef CONFIG_FS_UNIONFS
|
||||
extern const struct mountpt_operations unionfs_operations;
|
||||
#endif
|
||||
|
||||
static const struct fsmap_t g_nonbdfsmap[] =
|
||||
{
|
||||
|
|
@ -222,6 +226,9 @@ static const struct fsmap_t g_nonbdfsmap[] =
|
|||
#endif
|
||||
#ifdef CONFIG_FS_CROMFS
|
||||
{ "cromfs", &cromfs_operations },
|
||||
#endif
|
||||
#ifdef CONFIG_FS_UNIONFS
|
||||
{ "unionfs", &unionfs_operations },
|
||||
#endif
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
|
@ -398,12 +405,14 @@ int mount(FAR const char *source, FAR const char *target,
|
|||
ret = inode_reserve(target, &mountpt_inode);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* inode_reserve can fail for a couple of reasons, but the most likely
|
||||
* one is that the inode already exists. inode_reserve may return:
|
||||
/* inode_reserve can fail for a couple of reasons, but the most
|
||||
* likely one is that the inode already exists. inode_reserve may
|
||||
* return:
|
||||
*
|
||||
* -EINVAL - 'path' is invalid for this operation
|
||||
* -EEXIST - An inode already exists at 'path'
|
||||
* -ENOMEM - Failed to allocate in-memory resources for the operation
|
||||
* -ENOMEM - Failed to allocate in-memory resources for the
|
||||
* operation
|
||||
*/
|
||||
|
||||
ferr("ERROR: Failed to reserve inode for target %s\n", target);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/****************************************************************************
|
||||
* fs/unionfs/fs_unionfs.c
|
||||
*
|
||||
* Copyright (C) 2015, 2017-2018 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2015, 2017-2019 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -177,6 +177,8 @@ static int unionfs_readdir(FAR struct inode *mountpt,
|
|||
static int unionfs_rewinddir(FAR struct inode *mountpt,
|
||||
FAR struct fs_dirent_s *dir);
|
||||
|
||||
static int unionfs_bind(FAR struct inode *blkdriver, FAR const void *data,
|
||||
FAR void **handle);
|
||||
static int unionfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
|
||||
unsigned int flags);
|
||||
static int unionfs_statfs(FAR struct inode *mountpt,
|
||||
|
|
@ -199,6 +201,9 @@ static int unionfs_stat(FAR struct inode *mountpt,
|
|||
|
||||
static int unionfs_getmount(FAR const char *path,
|
||||
FAR struct inode **inode);
|
||||
static int unionfs_dobind(FAR const char *fspath1,
|
||||
FAR const char *prefix1, FAR const char *fspath2,
|
||||
FAR const char *prefix2, FAR void **handle);
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
|
|
@ -209,7 +214,7 @@ static int unionfs_getmount(FAR const char *path,
|
|||
* with any compiler.
|
||||
*/
|
||||
|
||||
static const struct mountpt_operations g_unionfs_mops =
|
||||
const struct mountpt_operations unionfs_operations =
|
||||
{
|
||||
unionfs_open, /* open */
|
||||
unionfs_close, /* close */
|
||||
|
|
@ -228,7 +233,7 @@ static const struct mountpt_operations g_unionfs_mops =
|
|||
unionfs_readdir, /* readdir */
|
||||
unionfs_rewinddir, /* rewinddir */
|
||||
|
||||
NULL, /* bind */
|
||||
unionfs_bind, /* bind */
|
||||
unionfs_unbind, /* unbind */
|
||||
unionfs_statfs, /* statfs */
|
||||
|
||||
|
|
@ -870,7 +875,8 @@ static int unionfs_open(FAR struct file *filep, FAR const char *relpath,
|
|||
/* Try to open the file on file system 1 */
|
||||
|
||||
um = &ui->ui_fs[0];
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL && um->um_node->u.i_mops != NULL);
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL &&
|
||||
um->um_node->u.i_mops != NULL);
|
||||
|
||||
uf->uf_file.f_oflags = filep->f_oflags;
|
||||
uf->uf_file.f_pos = 0;
|
||||
|
|
@ -895,7 +901,8 @@ static int unionfs_open(FAR struct file *filep, FAR const char *relpath,
|
|||
uf->uf_file.f_inode = um->um_node;
|
||||
uf->uf_file.f_priv = NULL;
|
||||
|
||||
ret = unionfs_tryopen(&uf->uf_file, relpath, um->um_prefix, oflags, mode);
|
||||
ret = unionfs_tryopen(&uf->uf_file, relpath, um->um_prefix, oflags,
|
||||
mode);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto errout_with_semaphore;
|
||||
|
|
@ -948,7 +955,8 @@ static int unionfs_close(FAR struct file *filep)
|
|||
DEBUGASSERT(uf->uf_ndx == 0 || uf->uf_ndx == 1);
|
||||
um = &ui->ui_fs[uf->uf_ndx];
|
||||
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL && um->um_node->u.i_mops != NULL);
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL &&
|
||||
um->um_node->u.i_mops != NULL);
|
||||
ops = um->um_node->u.i_mops;
|
||||
|
||||
finfo("Closing: ui_nopen=%d\n", ui->ui_nopen);
|
||||
|
|
@ -1012,7 +1020,8 @@ static ssize_t unionfs_read(FAR struct file *filep, FAR char *buffer,
|
|||
DEBUGASSERT(uf->uf_ndx == 0 || uf->uf_ndx == 1);
|
||||
um = &ui->ui_fs[uf->uf_ndx];
|
||||
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL && um->um_node->u.i_mops != NULL);
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL &&
|
||||
um->um_node->u.i_mops != NULL);
|
||||
ops = um->um_node->u.i_mops;
|
||||
|
||||
/* Perform the lower level read operation */
|
||||
|
|
@ -1060,7 +1069,8 @@ static ssize_t unionfs_write(FAR struct file *filep, FAR const char *buffer,
|
|||
DEBUGASSERT(uf->uf_ndx == 0 || uf->uf_ndx == 1);
|
||||
um = &ui->ui_fs[uf->uf_ndx];
|
||||
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL && um->um_node->u.i_mops != NULL);
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL &&
|
||||
um->um_node->u.i_mops != NULL);
|
||||
ops = um->um_node->u.i_mops;
|
||||
|
||||
/* Perform the lower level write operation */
|
||||
|
|
@ -1107,7 +1117,8 @@ static off_t unionfs_seek(FAR struct file *filep, off_t offset, int whence)
|
|||
DEBUGASSERT(uf->uf_ndx == 0 || uf->uf_ndx == 1);
|
||||
um = &ui->ui_fs[uf->uf_ndx];
|
||||
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL && um->um_node->u.i_mops != NULL);
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL &&
|
||||
um->um_node->u.i_mops != NULL);
|
||||
ops = um->um_node->u.i_mops;
|
||||
|
||||
/* Invoke the file seek method if available */
|
||||
|
|
@ -1183,7 +1194,8 @@ static int unionfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
DEBUGASSERT(uf->uf_ndx == 0 || uf->uf_ndx == 1);
|
||||
um = &ui->ui_fs[uf->uf_ndx];
|
||||
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL && um->um_node->u.i_mops != NULL);
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL &&
|
||||
um->um_node->u.i_mops != NULL);
|
||||
ops = um->um_node->u.i_mops;
|
||||
|
||||
/* Perform the lower level ioctl operation */
|
||||
|
|
@ -1230,7 +1242,8 @@ static int unionfs_sync(FAR struct file *filep)
|
|||
DEBUGASSERT(uf->uf_ndx == 0 || uf->uf_ndx == 1);
|
||||
um = &ui->ui_fs[uf->uf_ndx];
|
||||
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL && um->um_node->u.i_mops != NULL);
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL &&
|
||||
um->um_node->u.i_mops != NULL);
|
||||
ops = um->um_node->u.i_mops;
|
||||
|
||||
/* Perform the lower level sync operation */
|
||||
|
|
@ -1278,14 +1291,16 @@ static int unionfs_dup(FAR const struct file *oldp, FAR struct file *newp)
|
|||
DEBUGASSERT(oldpriv->uf_ndx == 0 || oldpriv->uf_ndx == 1);
|
||||
um = &ui->ui_fs[oldpriv->uf_ndx];
|
||||
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL && um->um_node->u.i_mops != NULL);
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL &&
|
||||
um->um_node->u.i_mops != NULL);
|
||||
ops = um->um_node->u.i_mops;
|
||||
|
||||
DEBUGASSERT(newp != NULL && newp->f_priv == NULL);
|
||||
|
||||
/* Allocate a new container for the union FS open file */
|
||||
|
||||
newpriv = (FAR struct unionfs_file_s *)kmm_malloc(sizeof(struct unionfs_file_s));
|
||||
newpriv = (FAR struct unionfs_file_s *)
|
||||
kmm_malloc(sizeof(struct unionfs_file_s));
|
||||
if (newpriv != NULL)
|
||||
{
|
||||
/* Clone the old file structure into the newly allocated one */
|
||||
|
|
@ -1352,7 +1367,8 @@ static int unionfs_fstat(FAR const struct file *filep, FAR struct stat *buf)
|
|||
DEBUGASSERT(uf->uf_ndx == 0 || uf->uf_ndx == 1);
|
||||
um = &ui->ui_fs[uf->uf_ndx];
|
||||
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL && um->um_node->u.i_mops != NULL);
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL &&
|
||||
um->um_node->u.i_mops != NULL);
|
||||
ops = um->um_node->u.i_mops;
|
||||
|
||||
/* Perform the lower level write operation */
|
||||
|
|
@ -1403,7 +1419,8 @@ static int unionfs_truncate(FAR struct file *filep, off_t length)
|
|||
DEBUGASSERT(uf->uf_ndx == 0 || uf->uf_ndx == 1);
|
||||
um = &ui->ui_fs[uf->uf_ndx];
|
||||
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL && um->um_node->u.i_mops != NULL);
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL &&
|
||||
um->um_node->u.i_mops != NULL);
|
||||
ops = um->um_node->u.i_mops;
|
||||
|
||||
/* Perform the lower level write operation */
|
||||
|
|
@ -1485,7 +1502,8 @@ static int unionfs_opendir(FAR struct inode *mountpt, FAR const char *relpath,
|
|||
|
||||
/* Allocate yet another dirent structure for the lower file system 1 */
|
||||
|
||||
lowerdir = (FAR struct fs_dirent_s *)kmm_zalloc(sizeof(struct fs_dirent_s));
|
||||
lowerdir = (FAR struct fs_dirent_s *)
|
||||
kmm_zalloc(sizeof(struct fs_dirent_s));
|
||||
if (lowerdir == NULL)
|
||||
{
|
||||
ret = -ENOMEM;
|
||||
|
|
@ -1493,8 +1511,8 @@ static int unionfs_opendir(FAR struct inode *mountpt, FAR const char *relpath,
|
|||
}
|
||||
}
|
||||
|
||||
/* Check if the user is stat'ing some "fake" node between the unionfs root and
|
||||
* the file system 1/2 root directory.
|
||||
/* Check if the user is stat'ing some "fake" node between the unionfs root
|
||||
* and the file system 1/2 root directory.
|
||||
*/
|
||||
|
||||
else if (unionfs_ispartprefix(relpath, ui->ui_fs[1].um_prefix))
|
||||
|
|
@ -1618,7 +1636,8 @@ static int unionfs_closedir(FAR struct inode *mountpt,
|
|||
{
|
||||
um = &ui->ui_fs[i];
|
||||
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL && um->um_node->u.i_mops != NULL);
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL &&
|
||||
um->um_node->u.i_mops != NULL);
|
||||
ops = um->um_node->u.i_mops;
|
||||
|
||||
/* Perform the lower level closedir operation */
|
||||
|
|
@ -1846,8 +1865,9 @@ static int unionfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
|
|||
um->um_node->u.i_mops != NULL);
|
||||
ops = um->um_node->u.i_mops;
|
||||
|
||||
/* Make sure that the second file system directory enumeration
|
||||
* is rewound to the beginning of the directory.
|
||||
/* Make sure that the second file system directory
|
||||
* enumeration is rewound to the beginning of the
|
||||
* directory.
|
||||
*/
|
||||
|
||||
if (ops->rewinddir != NULL)
|
||||
|
|
@ -1909,7 +1929,8 @@ static int unionfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
|
|||
*/
|
||||
|
||||
dir->fd_position = fu->fu_lower[fu->fu_ndx]->fd_position;
|
||||
memcpy(&dir->fd_dir, &fu->fu_lower[fu->fu_ndx]->fd_dir, sizeof(struct dirent));
|
||||
memcpy(&dir->fd_dir, &fu->fu_lower[fu->fu_ndx]->fd_dir,
|
||||
sizeof(struct dirent));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -1962,7 +1983,8 @@ static int unionfs_rewinddir(struct inode *mountpt, struct fs_dirent_s *dir)
|
|||
DEBUGASSERT(fu->fu_lower[fu->fu_ndx] != NULL);
|
||||
um = &ui->ui_fs[fu->fu_ndx];
|
||||
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL && um->um_node->u.i_mops != NULL);
|
||||
DEBUGASSERT(um != NULL && um->um_node != NULL &&
|
||||
um->um_node->u.i_mops != NULL);
|
||||
ops = um->um_node->u.i_mops;
|
||||
|
||||
/* Perform the file system rewind operation */
|
||||
|
|
@ -1982,6 +2004,58 @@ static int unionfs_rewinddir(struct inode *mountpt, struct fs_dirent_s *dir)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: unionfs_bind
|
||||
****************************************************************************/
|
||||
|
||||
static int unionfs_bind(FAR struct inode *blkdriver, FAR const void *data,
|
||||
FAR void **handle)
|
||||
{
|
||||
FAR const char *fspath1 = "";
|
||||
FAR const char *prefix1 = "";
|
||||
FAR const char *fspath2 = "";
|
||||
FAR const char *prefix2 = "";
|
||||
FAR char *dup;
|
||||
FAR char *tmp;
|
||||
FAR char *tok;
|
||||
int ret;
|
||||
|
||||
/* Parse options from mount syscall */
|
||||
|
||||
dup = tmp = strdup(data);
|
||||
if (!dup)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
while ((tok = strsep(&tmp, ",")))
|
||||
{
|
||||
if (tok == strstr(tok, "fspath1="))
|
||||
{
|
||||
fspath1 = tok + 8;
|
||||
}
|
||||
else if (tok == strstr(tok, "prefix1="))
|
||||
{
|
||||
prefix1 = tok + 8;
|
||||
}
|
||||
else if (tok == strstr(tok, "fspath2="))
|
||||
{
|
||||
fspath2 = tok + 8;
|
||||
}
|
||||
else if (tok == strstr(tok, "prefix2="))
|
||||
{
|
||||
prefix2 = tok + 8;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call unionfs_dobind to do the real work. */
|
||||
|
||||
ret = unionfs_dobind(fspath1, prefix1, fspath2, prefix2, handle);
|
||||
kmm_free(dup);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: unionfs_unbind
|
||||
****************************************************************************/
|
||||
|
|
@ -2062,11 +2136,13 @@ static int unionfs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf)
|
|||
*/
|
||||
|
||||
um1 = &ui->ui_fs[0];
|
||||
DEBUGASSERT(um1 != NULL && um1->um_node != NULL && um1->um_node->u.i_mops != NULL);
|
||||
DEBUGASSERT(um1 != NULL && um1->um_node != NULL &&
|
||||
um1->um_node->u.i_mops != NULL);
|
||||
ops1 = um1->um_node->u.i_mops;
|
||||
|
||||
um2 = &ui->ui_fs[1];
|
||||
DEBUGASSERT(um2 != NULL && um2->um_node != NULL && um2->um_node->u.i_mops != NULL);
|
||||
DEBUGASSERT(um2 != NULL && um2->um_node != NULL &&
|
||||
um2->um_node->u.i_mops != NULL);
|
||||
ops2 = um2->um_node->u.i_mops;
|
||||
|
||||
if (ops1->statfs != NULL && ops2->statfs != NULL)
|
||||
|
|
@ -2177,7 +2253,8 @@ static int unionfs_unlink(FAR struct inode *mountpt,
|
|||
|
||||
/* Recover the union file system data from the struct inode instance */
|
||||
|
||||
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL && relpath != NULL);
|
||||
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL &&
|
||||
relpath != NULL);
|
||||
ui = (FAR struct unionfs_inode_s *)mountpt->i_private;
|
||||
|
||||
/* Get exclusive access to the file system data structures */
|
||||
|
|
@ -2249,7 +2326,8 @@ static int unionfs_mkdir(FAR struct inode *mountpt, FAR const char *relpath,
|
|||
|
||||
/* Recover the union file system data from the struct inode instance */
|
||||
|
||||
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL && relpath != NULL);
|
||||
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL &&
|
||||
relpath != NULL);
|
||||
ui = (FAR struct unionfs_inode_s *)mountpt->i_private;
|
||||
|
||||
/* Get exclusive access to the file system data structures */
|
||||
|
|
@ -2322,7 +2400,8 @@ static int unionfs_rmdir(FAR struct inode *mountpt, FAR const char *relpath)
|
|||
|
||||
/* Recover the union file system data from the struct inode instance */
|
||||
|
||||
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL && relpath != NULL);
|
||||
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL &&
|
||||
relpath != NULL);
|
||||
ui = (FAR struct unionfs_inode_s *)mountpt->i_private;
|
||||
|
||||
/* Get exclusive access to the file system data structures */
|
||||
|
|
@ -2471,7 +2550,8 @@ static int unionfs_stat(FAR struct inode *mountpt, FAR const char *relpath,
|
|||
|
||||
/* Recover the union file system data from the struct inode instance */
|
||||
|
||||
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL && relpath != NULL);
|
||||
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL &&
|
||||
relpath != NULL);
|
||||
ui = (FAR struct unionfs_inode_s *)mountpt->i_private;
|
||||
|
||||
/* Get exclusive access to the file system data structures */
|
||||
|
|
@ -2510,8 +2590,8 @@ static int unionfs_stat(FAR struct inode *mountpt, FAR const char *relpath,
|
|||
return OK;
|
||||
}
|
||||
|
||||
/* Special case the unionfs root directory when both file systems are offset.
|
||||
* In that case, both of the above trystat calls will fail.
|
||||
/* Special case the unionfs root directory when both file systems are
|
||||
* offset. In that case, both of the above trystat calls will fail.
|
||||
*/
|
||||
|
||||
if (ui->ui_fs[0].um_prefix != NULL && ui->ui_fs[1].um_prefix != NULL)
|
||||
|
|
@ -2600,46 +2680,24 @@ errout_with_search:
|
|||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
* Name: unionfs_dobind
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: unionfs_mount
|
||||
*
|
||||
* Description:
|
||||
* Create and mount a union file system
|
||||
*
|
||||
* Input Parameters:
|
||||
* fspath1 - The full path to the first file system mountpoint
|
||||
* prefix1 - An optiona prefix that may be applied to make the first
|
||||
* file system appear a some path below the unionfs mountpoint,
|
||||
* fspath2 - The full path to the second file system mountpoint
|
||||
* prefix2 - An optiona prefix that may be applied to make the first
|
||||
* file system appear a some path below the unionfs mountpoint,
|
||||
* mountpt - The full path to the mountpoint for the union file system
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned if the union file system was correctly created and
|
||||
* mounted. On any failure, a negated error value will be returned to
|
||||
* indicate the nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int unionfs_mount(FAR const char *fspath1, FAR const char *prefix1,
|
||||
FAR const char *fspath2, FAR const char *prefix2,
|
||||
FAR const char *mountpt)
|
||||
static int unionfs_dobind(FAR const char *fspath1, FAR const char *prefix1,
|
||||
FAR const char *fspath2, FAR const char *prefix2,
|
||||
FAR void **handle)
|
||||
{
|
||||
FAR struct unionfs_inode_s *ui;
|
||||
FAR struct inode *mpinode;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(fspath1 != NULL && fspath2 != NULL && mountpt != NULL);
|
||||
DEBUGASSERT(fspath1 != NULL && fspath2 != NULL && handle != NULL);
|
||||
|
||||
/* Allocate a structure a structure that will describe the union file
|
||||
* system.
|
||||
*/
|
||||
|
||||
ui = (FAR struct unionfs_inode_s *)kmm_zalloc(sizeof(struct unionfs_inode_s));
|
||||
ui = (FAR struct unionfs_inode_s *)
|
||||
kmm_zalloc(sizeof(struct unionfs_inode_s));
|
||||
if (!ui)
|
||||
{
|
||||
ferr("ERROR: Failed to allocated union FS state structure\n");
|
||||
|
|
@ -2688,14 +2746,80 @@ int unionfs_mount(FAR const char *fspath1, FAR const char *prefix1,
|
|||
}
|
||||
}
|
||||
|
||||
/* Finally, mount the union FS. We should adapt the standard mount to do
|
||||
/* Unlink the contained mountpoint inodes from the pseudo file system.
|
||||
* The inodes will be marked as deleted so that they will be removed when
|
||||
* the reference count decrements to zero in inode_release(). Because we
|
||||
* hold a reference count on the inodes, they will not be deleted until
|
||||
* this logic calls inode_release() in the unionfs_destroy() function.
|
||||
*/
|
||||
|
||||
(void)inode_remove(fspath1);
|
||||
(void)inode_remove(fspath2);
|
||||
|
||||
*handle = ui;
|
||||
return OK;
|
||||
|
||||
errout_with_prefix1:
|
||||
if (ui->ui_fs[0].um_prefix != NULL)
|
||||
{
|
||||
kmm_free(ui->ui_fs[0].um_prefix);
|
||||
}
|
||||
|
||||
errout_with_fs2:
|
||||
inode_release(ui->ui_fs[1].um_node);
|
||||
|
||||
errout_with_fs1:
|
||||
inode_release(ui->ui_fs[0].um_node);
|
||||
|
||||
errout_with_uinode:
|
||||
nxsem_destroy(&ui->ui_exclsem);
|
||||
kmm_free(ui);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: unionfs_mount
|
||||
*
|
||||
* Description:
|
||||
* Create and mount a union file system
|
||||
*
|
||||
* Input Parameters:
|
||||
* fspath1 - The full path to the first file system mountpoint
|
||||
* prefix1 - An optiona prefix that may be applied to make the first
|
||||
* file system appear a some path below the unionfs mountpoint,
|
||||
* fspath2 - The full path to the second file system mountpoint
|
||||
* prefix2 - An optiona prefix that may be applied to make the first
|
||||
* file system appear a some path below the unionfs mountpoint,
|
||||
* mountpt - The full path to the mountpoint for the union file system
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned if the union file system was correctly created and
|
||||
* mounted. On any failure, a negated error value will be returned to
|
||||
* indicate the nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int unionfs_mount(FAR const char *fspath1, FAR const char *prefix1,
|
||||
FAR const char *fspath2, FAR const char *prefix2,
|
||||
FAR const char *mountpt)
|
||||
{
|
||||
FAR struct inode *mpinode;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(mountpt != NULL);
|
||||
|
||||
/* Mount the union FS. We should adapt the standard mount to do
|
||||
* this using optional parameters. This custom mount should do the job
|
||||
* for now, however.
|
||||
*/
|
||||
|
||||
/* Insert a dummy node -- we need to hold the inode semaphore
|
||||
* to do this because we will have a momentarily bad structure.
|
||||
* NOTE that the inode will be created with a refernce count of zero.
|
||||
* NOTE that the inode will be created with a reference count of zero.
|
||||
*/
|
||||
|
||||
inode_semtake();
|
||||
|
|
@ -2718,47 +2842,28 @@ int unionfs_mount(FAR const char *fspath1, FAR const char *prefix1,
|
|||
|
||||
INODE_SET_MOUNTPT(mpinode);
|
||||
|
||||
mpinode->u.i_mops = &g_unionfs_mops;
|
||||
mpinode->u.i_mops = &unionfs_operations;
|
||||
#ifdef CONFIG_FILE_MODE
|
||||
mpinode->i_mode = 0755;
|
||||
#endif
|
||||
mpinode->i_private = ui;
|
||||
|
||||
/* Unlink the contained mountpoint inodes from the pseudo file system.
|
||||
* The inodes will be marked as deleted so that they will be removed when
|
||||
* the reference count decrements to zero in inode_release(). Because we
|
||||
* hold a reference count on the inodes, they will not be deleted until
|
||||
* this logic calls inode_release() in the unionfs_destroy() function.
|
||||
*/
|
||||
/* Call unionfs_dobind to do the real work. */
|
||||
|
||||
ret = unionfs_dobind(fspath1, prefix1, fspath2, prefix2,
|
||||
&mpinode->i_private);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto errout_with_mountpt;
|
||||
}
|
||||
|
||||
(void)inode_remove(fspath1);
|
||||
(void)inode_remove(fspath2);
|
||||
inode_semgive();
|
||||
return OK;
|
||||
|
||||
errout_with_mountpt:
|
||||
inode_release(mpinode);
|
||||
|
||||
errout_with_semaphore:
|
||||
inode_semgive();
|
||||
|
||||
if (ui->ui_fs[1].um_prefix != NULL)
|
||||
{
|
||||
kmm_free(ui->ui_fs[1].um_prefix);
|
||||
}
|
||||
|
||||
errout_with_prefix1:
|
||||
if (ui->ui_fs[0].um_prefix != NULL)
|
||||
{
|
||||
kmm_free(ui->ui_fs[0].um_prefix);
|
||||
}
|
||||
|
||||
errout_with_fs2:
|
||||
inode_release(ui->ui_fs[1].um_node);
|
||||
|
||||
errout_with_fs1:
|
||||
inode_release(ui->ui_fs[0].um_node);
|
||||
|
||||
errout_with_uinode:
|
||||
nxsem_destroy(&ui->ui_exclsem);
|
||||
kmm_free(ui);
|
||||
return ret;
|
||||
}
|
||||
#endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_UNIONFS */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue