#include <lunaix/foptions.h>
-#include <lunaix/fs.h>
+#include <lunaix/fs/api.h>
#include <lunaix/mm/valloc.h>
#include <lunaix/process.h>
#include <lunaix/spike.h>
+#include <lunaix/syscall_utils.h>
#include <lunaix/syslog.h>
#include <lunaix/types.h>
}
llist_init_head(&mnt->submnts);
+ llist_init_head(&mnt->sibmnts);
llist_append(&all_mnts, &mnt->list);
mutex_init(&mnt->lock);
mnt->parent = parent;
mnt->mnt_point = mnt_point;
- mnt->super_block = mnt_point->super_block;
+ vfs_vmnt_assign_sb(mnt, mnt_point->super_block);
if (parent) {
mnt_mkbusy(parent);
llist_append(&parent->submnts, &mnt->sibmnts);
mutex_unlock(&mnt->parent->lock);
}
-
+
atomic_fetch_add(&mnt_point->ref_count, 1);
return mnt;
}
+void
+__vfs_release_vmnt(struct v_mount* mnt)
+{
+ assert(llist_empty(&mnt->submnts));
+
+ if (mnt->parent) {
+ mnt_chillax(mnt->parent);
+ }
+
+ llist_delete(&mnt->sibmnts);
+ llist_delete(&mnt->list);
+ atomic_fetch_sub(&mnt->mnt_point->ref_count, 1);
+ vfree(mnt);
+}
+
int
__vfs_do_unmount(struct v_mount* mnt)
{
return errno;
}
- llist_delete(&mnt->list);
- llist_delete(&mnt->sibmnts);
-
// detached the inodes from cache, and let lru policy to recycle them
for (size_t i = 0; i < VFS_HASHTABLE_SIZE; i++) {
struct hbucket* bucket = &sb->i_cache[i];
- if (!bucket) {
+ if (!bucket->head) {
continue;
}
bucket->head->pprev = 0;
}
- mnt_chillax(mnt->parent);
+ mnt->mnt_point->mnt = mnt->parent;
vfs_sb_free(sb);
- vfs_d_free(mnt->mnt_point);
- vfree(mnt);
+ __vfs_release_vmnt(mnt);
return errno;
}
return errno;
}
-int
-vfs_mount_at(const char* fs_name,
- struct device* device,
- struct v_dnode* mnt_point,
- int options)
+static int
+vfs_mount_fsat(struct filesystem* fs,
+ struct device* device,
+ struct v_dnode* mnt_point,
+ int options)
{
+
if (device && device->dev_type != DEV_IFVOL) {
return ENOTBLK;
}
- if (mnt_point->inode && !(mnt_point->inode->itype & VFS_IFDIR)) {
+ if (mnt_point->inode && !check_directory_node(mnt_point->inode)) {
return ENOTDIR;
}
- struct filesystem* fs = fsm_get(fs_name);
- if (!fs) {
- return ENODEV;
+ if ((fs->types & FSTYPE_ROFS)) {
+ options |= MNT_RO;
}
- if (fs->types == FSTYPE_ROFS) {
- options |= MNT_RO;
+ if (!(fs->types & FSTYPE_PSEUDO) && !device) {
+ return ENODEV;
}
+ int errno = 0;
char* dev_name = "sys";
+ char* fsname = HSTR_VAL(fs->fs_name);
+
struct v_mount* parent_mnt = mnt_point->mnt;
- struct v_superblock *sb = vfs_sb_alloc(), *old_sb = mnt_point->super_block;
- sb->dev = device;
- mnt_point->super_block = sb;
+ struct v_superblock *sb = vfs_sb_alloc(),
+ *old_sb = mnt_point->super_block;
if (device) {
dev_name = device->name_val;
}
- int errno = 0;
- if (!(errno = fs->mount(sb, mnt_point))) {
- sb->fs = fs;
- sb->root = mnt_point;
-
- if (!(mnt_point->mnt = vfs_create_mount(parent_mnt, mnt_point))) {
- errno = ENOMEM;
- goto cleanup;
- }
+ // prepare v_superblock for fs::mount invoke
+ sb->dev = device;
+ sb->fs = fs;
+ sb->root = mnt_point;
+ vfs_d_assign_sb(mnt_point, sb);
- kprintf("mount: dev=%s, fs=%s, mode=%d\n", dev_name, fs_name, options);
+ if (!(mnt_point->mnt = vfs_create_mount(parent_mnt, mnt_point))) {
+ errno = ENOMEM;
+ goto cleanup;
+ }
- mnt_point->mnt->flags = options;
+ mnt_point->mnt->flags = options;
+ if (!(errno = fs->mount(sb, mnt_point))) {
+ kprintf("mount: dev=%s, fs=%s, mode=%d",
+ dev_name, fsname, options);
} else {
goto cleanup;
}
+ vfs_sb_free(old_sb);
return errno;
cleanup:
- kprintf(KERROR "mount: dev=%s, fs=%s, mode=%d, err=%d\n",
- dev_name,
- fs_name,
- options,
- errno);
- mnt_point->super_block = old_sb;
+ ERROR("failed mount: dev=%s, fs=%s, mode=%d, err=%d",
+ dev_name, fsname, options, errno);
+
+ vfs_d_assign_sb(mnt_point, old_sb);
vfs_sb_free(sb);
+ __vfs_release_vmnt(mnt_point->mnt);
+
+ mnt_point->mnt = parent_mnt;
+
+ return errno;
+}
+
+int
+vfs_mount_at(const char* fs_name,
+ struct device* device,
+ struct v_dnode* mnt_point,
+ int options)
+{
+ if (fs_name) {
+ struct filesystem* fs = fsm_get(fs_name);
+ if (!fs) {
+ return ENODEV;
+ }
+
+ return vfs_mount_fsat(fs, device, mnt_point, options);
+ }
+
+ int errno = ENODEV;
+ struct fs_iter fsi;
+
+ fsm_itbegin(&fsi);
+ while (fsm_itnext(&fsi))
+ {
+ if ((fsi.fs->types & FSTYPE_PSEUDO)) {
+ continue;
+ }
+
+ INFO("mount attempt: %s", HSTR_VAL(fsi.fs->fs_name));
+ errno = vfs_mount_fsat(fsi.fs, device, mnt_point, options);
+ if (!errno) {
+ break;
+ }
+ }
+
return errno;
}
int,
options)
{
- struct v_dnode *dev, *mnt;
+ struct v_dnode *dev = NULL, *mnt = NULL;
int errno = 0;
- if ((errno = vfs_walk(__current->cwd, source, &dev, NULL, 0))) {
- goto done;
- }
+ // It is fine if source is not exist, as some mounting don't require it
+ vfs_walk(__current->cwd, source, &dev, NULL, 0);
if ((errno = vfs_walk(__current->cwd, target, &mnt, NULL, 0))) {
goto done;
goto done;
}
+ if (mnt->mnt->mnt_point == mnt) {
+ errno = EBUSY;
+ goto done;
+ }
+
// By our convention.
// XXX could we do better?
- struct device* device = (struct device*)dev->inode->data;
+ struct device* device = NULL;
- if (!(dev->inode->itype & VFS_IFVOLDEV) || !device) {
- errno = ENOTDEV;
- goto done;
+ if (dev) {
+ if (!check_voldev_node(dev->inode)) {
+ errno = ENOTDEV;
+ goto done;
+ }
+ device = (struct device*)dev->inode->data;
}
errno = vfs_mount_at(fstype, device, mnt, options);