feat: add support for dfs remount functionality

This patch introduces a remount feature for the DFS, allowing for the
modification of mount parameters without unmounting the filesystem,
the remount functionality helps modify certain mount flags (like `MS_RDONLY`) without
requiring an unmount, providing more control over mounted filesystems in the system.

The updates is essential for user space init proc to cleanup the runtime
resource, ensuring clean handling of cached data and enhancing system
robustness during power down processing.

Changes:
- Defined new constants for remount flags in `dfs_fs.h`.
- Added the `dfs_remount()` function in `dfs_fs.c` to handle remount operations.
- Introduced a check for unsupported flags and handle error conditions such as invalid paths
  or non-directory targets.
- Updated the `dfs_mnt` structure in `dfs_mnt.h` to include a read-only flag (`MNT_RDONLY`).
- The `dfs_remount()` function allows changing the read-only status of a mounted filesystem.
- Added `MNT_LAZY_UMNT` and `MNT_RDONLY` flags to `dfs_mnt` structure.
- Introduced `dfs_mnt_setflags` function for dynamic flag management.
- Updated `dfs_remount` to utilize `dfs_mnt_setflags` for flag setting.
- Enhanced unmount operations with `dfs_mnt_umount_iter` and lazy unmounting.
- Added `dfs_pcache_clean` to handle cache cleanup for read-only mounts.
- Improved error reporting in `dfs_umount` for better user feedback.
- Refactored `sys_mount` to streamline parameter handling and support remounts.
- Introduced `_cp_from_usr_string` helper for user-space string operations.
- Updated internal APIs to ensure consistency in reference count management.

Signed-off-by: Shell <smokewood@qq.com>
This commit is contained in:
Shell 2024-11-13 15:37:23 +08:00 committed by Rbb666
parent 944f3d05b5
commit b63b388d1f
7 changed files with 219 additions and 77 deletions

View File

@ -20,6 +20,38 @@ extern "C"
{
#endif
#define MS_RDONLY 1
#define MS_NOSUID 2
#define MS_NODEV 4
#define MS_NOEXEC 8
#define MS_SYNCHRONOUS 16
#define MS_REMOUNT 32
#define MS_MANDLOCK 64
#define MS_DIRSYNC 128
#define MS_NOATIME 1024
#define MS_NODIRATIME 2048
#define MS_BIND 4096
#define MS_MOVE 8192
#define MS_REC 16384
#define MS_SILENT 32768
#define MS_POSIXACL (1<<16)
#define MS_UNBINDABLE (1<<17)
#define MS_PRIVATE (1<<18)
#define MS_SLAVE (1<<19)
#define MS_SHARED (1<<20)
#define MS_RELATIME (1<<21)
#define MS_KERNMOUNT (1<<22)
#define MS_I_VERSION (1<<23)
#define MS_STRICTATIME (1<<24)
#define MS_LAZYTIME (1<<25)
#define MS_NOREMOTELOCK (1<<27)
#define MS_NOSEC (1<<28)
#define MS_BORN (1<<29)
#define MS_ACTIVE (1<<30)
#define MS_NOUSER (1U<<31)
#define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|MS_LAZYTIME)
/* file system partition table */
struct dfs_partition
{
@ -87,6 +119,7 @@ int dfs_unregister(struct dfs_filesystem_type *fs);
int dfs_register(struct dfs_filesystem_type *fs);
const char *dfs_filesystem_get_mounted_path(struct rt_device *device);
int dfs_remount(const char *path, rt_ubase_t flags, void *data);
int dfs_mount(const char *device_name,
const char *path,
const char *filesystemtype,

View File

@ -39,6 +39,8 @@ struct dfs_mnt
#define MNT_IS_UMOUNT 0x8 /* the mnt is unmount */
#define MNT_IS_LOCKED 0x10 /* the mnt is locked */
#define MNT_FORCE 0x20 /* the mnt force unmount */
#define MNT_LAZY_UMNT 0x40 /* the mnt has pending umount */
#define MNT_RDONLY 0x80 /* the mnt is read only */
rt_atomic_t ref_count; /* reference count */
@ -60,9 +62,13 @@ const char *dfs_mnt_get_mounted_path(struct rt_device *device);
struct dfs_mnt* dfs_mnt_ref(struct dfs_mnt* mnt);
int dfs_mnt_unref(struct dfs_mnt* mnt);
int dfs_mnt_umount(struct dfs_mnt *mnt, int flags);
int dfs_mnt_setflags(struct dfs_mnt *mnt, int flags);
rt_bool_t dfs_mnt_has_child_mnt(struct dfs_mnt *mnt, const char* fullpath);
int dfs_mnt_foreach(struct dfs_mnt* (*func)(struct dfs_mnt *mnt, void *parameter), void *parameter);
int dfs_mnt_umount_iter(rt_bool_t (*filter)(struct dfs_mnt *mnt, void *parameter), void *parameter);
typedef void (*dfs_mnt_umnt_cb_t)(struct dfs_mnt *mnt);
RT_OBJECT_HOOKLIST_DECLARE(dfs_mnt_umnt_cb_t, dfs_mnt_umnt);

View File

@ -118,6 +118,7 @@ int dfs_aspace_mmap_write(struct dfs_file *file, struct rt_varea *varea, void *d
void dfs_pcache_release(size_t count);
void dfs_pcache_unmount(struct dfs_mnt *mnt);
void dfs_pcache_clean(struct dfs_mnt *mnt);
#ifdef __cplusplus
}

View File

@ -95,6 +95,52 @@ int dfs_unregister(struct dfs_filesystem_type *fs)
return ret;
}
#define REMNT_UNSUPP_FLAGS (~(MS_REMOUNT | MS_RMT_MASK))
int dfs_remount(const char *path, rt_ubase_t flags, void *data)
{
int rc = 0;
char *fullpath = RT_NULL;
struct dfs_mnt *mnt = RT_NULL;
if (flags & REMNT_UNSUPP_FLAGS)
{
return -EINVAL;
}
fullpath = dfs_normalize_path(RT_NULL, path);
if (!fullpath)
{
rc = -ENOENT;
}
else
{
DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt = dfs_mnt_lookup(%s)", fullpath);
mnt = dfs_mnt_lookup(fullpath);
if (mnt)
{
dfs_lock();
dfs_mnt_setflags(mnt, flags);
dfs_unlock();
}
else
{
struct stat buf = {0};
if (dfs_file_stat(fullpath, &buf) == 0 && S_ISBLK(buf.st_mode))
{
/* path was not already mounted on target */
rc = -EINVAL;
}
else
{
/* path is not a directory */
rc = -ENOTDIR;
}
}
}
return rc;
}
/*
* parent(mount path)
* mnt_parent <- - - - - - - +
@ -314,7 +360,7 @@ int dfs_umount(const char *specialfile, int flags)
if (strcmp(mnt->fullpath, fullpath) == 0)
{
/* is the mount point */
rt_atomic_t ref_count = rt_atomic_load(&(mnt->ref_count));
rt_base_t ref_count = rt_atomic_load(&(mnt->ref_count));
if (!(mnt->flags & MNT_IS_LOCKED) && rt_list_isempty(&mnt->child) && (ref_count == 1 || (flags & MNT_FORCE)))
{
@ -327,17 +373,17 @@ int dfs_umount(const char *specialfile, int flags)
}
else
{
LOG_E("the file system is busy!");
LOG_I("the file system is busy!");
}
}
else
{
LOG_E("the path:%s is not a mountpoint!", fullpath);
LOG_I("the path:%s is not a mountpoint!", fullpath);
}
}
else
{
LOG_E("no filesystem found.");
LOG_I("no filesystem found.");
}
rt_free(fullpath);
}

View File

@ -10,11 +10,13 @@
#include <rtthread.h>
#include "dfs.h"
#include "dfs_mnt.h"
#include "dfs_dentry.h"
#include "dfs_private.h"
#include <dfs.h>
#include <dfs_dentry.h>
#include <dfs_mnt.h>
#include <dfs_pcache.h>
#define DBG_TAG "DFS.mnt"
#define DBG_LVL DBG_WARNING
#include <rtdbg.h>
@ -77,6 +79,7 @@ int dfs_mnt_insert(struct dfs_mnt* mnt, struct dfs_mnt* child)
child = _root_mnt;
rt_atomic_sub(&(_root_mnt->parent->ref_count), 1);
rt_atomic_sub(&(_root_mnt->ref_count), 1);
_root_mnt->flags &= ~MNT_IS_LOCKED;
_root_mnt = dfs_mnt_ref(mnt);
mnt->parent = dfs_mnt_ref(mnt);
@ -244,15 +247,16 @@ struct dfs_mnt* dfs_mnt_ref(struct dfs_mnt* mnt)
return mnt;
}
int dfs_mnt_unref(struct dfs_mnt* mnt)
int dfs_mnt_unref(struct dfs_mnt *mnt)
{
rt_err_t ret = RT_EOK;
rt_base_t ref_count;
if (mnt)
{
rt_atomic_sub(&(mnt->ref_count), 1);
ref_count = rt_atomic_sub(&(mnt->ref_count), 1) - 1;
if (rt_atomic_load(&(mnt->ref_count)) == 0)
if (ref_count == 0)
{
dfs_lock();
@ -282,6 +286,21 @@ int dfs_mnt_unref(struct dfs_mnt* mnt)
return ret;
}
int dfs_mnt_setflags(struct dfs_mnt *mnt, int flags)
{
int error = 0;
if (flags & MS_RDONLY)
{
mnt->flags |= MNT_RDONLY;
#ifdef RT_USING_PAGECACHE
dfs_pcache_clean(mnt);
#endif
}
return error;
}
int dfs_mnt_destroy(struct dfs_mnt* mnt)
{
rt_err_t ret = RT_EOK;

View File

@ -162,7 +162,7 @@ void dfs_pcache_release(size_t count)
dfs_pcache_unlock();
}
void dfs_pcache_unmount(struct dfs_mnt *mnt)
static void _pcache_clean(struct dfs_mnt *mnt, int (*cb)(struct dfs_aspace *aspace))
{
rt_list_t *node = RT_NULL;
struct dfs_aspace *aspace = RT_NULL;
@ -177,7 +177,7 @@ void dfs_pcache_unmount(struct dfs_mnt *mnt)
if (aspace && aspace->mnt == mnt)
{
dfs_aspace_clean(aspace);
dfs_aspace_release(aspace);
cb(aspace);
}
}
@ -189,13 +189,28 @@ void dfs_pcache_unmount(struct dfs_mnt *mnt)
if (aspace && aspace->mnt == mnt)
{
dfs_aspace_clean(aspace);
dfs_aspace_release(aspace);
cb(aspace);
}
}
dfs_pcache_unlock();
}
void dfs_pcache_unmount(struct dfs_mnt *mnt)
{
_pcache_clean(mnt, dfs_aspace_release);
}
static int _dummy_cb(struct dfs_aspace *mnt)
{
return 0;
}
void dfs_pcache_clean(struct dfs_mnt *mnt)
{
_pcache_clean(mnt, _dummy_cb);
}
static int dfs_pcache_limit_check(void)
{
int index = 4;
@ -1140,14 +1155,21 @@ int dfs_aspace_write(struct dfs_file *file, const void *buf, size_t count, off_t
if (file && file->vnode && file->vnode->aspace)
{
if (!(file->vnode->aspace->ops->write))
return ret;
struct dfs_vnode *vnode = file->vnode;
struct dfs_aspace *aspace = vnode->aspace;
struct dfs_page *page;
char *ptr = (char *)buf;
if (!(aspace->ops->write))
{
return ret;
}
else if (aspace->mnt && (aspace->mnt->flags & MNT_RDONLY))
{
return -EROFS;
}
ret = 0;
while (count)

View File

@ -5743,79 +5743,94 @@ sysret_t sys_fstatfs64(int fd, size_t sz, struct statfs *buf)
return ret;
}
sysret_t sys_mount(char *source, char *target,
char *filesystemtype,
unsigned long mountflags, void *data)
static char *_cp_from_usr_string(char *dst, char *src, size_t length)
{
char *copy_source;
char *copy_target;
char *copy_filesystemtype;
size_t len_source, copy_len_source;
size_t len_target, copy_len_target;
size_t len_filesystemtype, copy_len_filesystemtype;
char *tmp = NULL;
int ret = 0;
struct stat buf = {0};
len_source = lwp_user_strlen(source);
if (len_source <= 0)
return -EINVAL;
len_target = lwp_user_strlen(target);
if (len_target <= 0)
return -EINVAL;
len_filesystemtype = lwp_user_strlen(filesystemtype);
if (len_filesystemtype <= 0)
return -EINVAL;
copy_source = (char*)rt_malloc(len_source + 1 + len_target + 1 + len_filesystemtype + 1);
if (!copy_source)
char *rc;
size_t copied_bytes;
if (length)
{
return -ENOMEM;
}
copy_target = copy_source + len_source + 1;
copy_filesystemtype = copy_target + len_target + 1;
copy_len_source = lwp_get_from_user(copy_source, source, len_source);
copy_source[copy_len_source] = '\0';
copy_len_target = lwp_get_from_user(copy_target, target, len_target);
copy_target[copy_len_target] = '\0';
copy_len_filesystemtype = lwp_get_from_user(copy_filesystemtype, filesystemtype, len_filesystemtype);
copy_filesystemtype[copy_len_filesystemtype] = '\0';
if (strcmp(copy_filesystemtype, "nfs") == 0)
{
tmp = copy_source;
copy_source = NULL;
}
if (strcmp(copy_filesystemtype, "tmp") == 0)
{
copy_source = NULL;
}
if (copy_source && stat(copy_source, &buf) && S_ISBLK(buf.st_mode))
{
char *dev_fullpath = dfs_normalize_path(RT_NULL, copy_source);
RT_ASSERT(rt_strncmp(dev_fullpath, "/dev/", sizeof("/dev/") - 1) == 0);
ret = dfs_mount(dev_fullpath + sizeof("/dev/") - 1, copy_target, copy_filesystemtype, 0, tmp);
if (ret < 0)
{
ret = -rt_get_errno();
}
rt_free(copy_source);
rt_free(dev_fullpath);
copied_bytes = lwp_get_from_user(dst, src, length);
dst[copied_bytes] = '\0';
rc = dst;
}
else
{
ret = dfs_mount(copy_source, copy_target, copy_filesystemtype, 0, tmp);
rc = RT_NULL;
}
return rc;
}
sysret_t sys_mount(char *source, char *target, char *filesystemtype,
unsigned long mountflags, void *data)
{
char *kbuffer, *ksource, *ktarget, *kfs;
size_t len_source, len_target, len_fs;
char *tmp = NULL;
int ret = 0;
struct stat buf = {0};
char *dev_fullpath = RT_NULL;
len_source = source ? lwp_user_strlen(source) : 0;
if (len_source < 0)
return -EINVAL;
len_target = target ? lwp_user_strlen(target) : 0;
if (len_target <= 0)
return -EINVAL;
len_fs = filesystemtype ? lwp_user_strlen(filesystemtype) : 0;
if (len_fs < 0)
return -EINVAL;
kbuffer = (char *)rt_malloc(len_source + 1 + len_target + 1 + len_fs + 1);
if (!kbuffer)
{
return -ENOMEM;
}
/* get parameters from user space */
ksource = kbuffer;
ktarget = ksource + len_source + 1;
kfs = ktarget + len_target + 1;
ksource = _cp_from_usr_string(ksource, source, len_source);
ktarget = _cp_from_usr_string(ktarget, target, len_target);
kfs = _cp_from_usr_string(kfs, filesystemtype, len_fs);
if (mountflags & MS_REMOUNT)
{
ret = dfs_remount(ktarget, mountflags, data);
}
else
{
if (strcmp(kfs, "nfs") == 0)
{
tmp = ksource;
ksource = NULL;
}
if (strcmp(kfs, "tmp") == 0)
{
ksource = NULL;
}
if (ksource && !dfs_file_stat(ksource, &buf) && S_ISBLK(buf.st_mode))
{
dev_fullpath = dfs_normalize_path(RT_NULL, ksource);
RT_ASSERT(rt_strncmp(dev_fullpath, "/dev/", sizeof("/dev/") - 1) == 0);
ret = dfs_mount(dev_fullpath + sizeof("/dev/") - 1, ktarget, kfs, 0, tmp);
}
else
{
ret = dfs_mount(ksource, ktarget, kfs, 0, tmp);
}
if (ret < 0)
{
ret = -rt_get_errno();
}
rt_free(copy_source);
}
rt_free(kbuffer);
rt_free(dev_fullpath);
return ret;
}