X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/21ffd87b228fa0bd0c25a09b710c6aeac8b81281..35a7d633d3f16c1e0539af6ca5d8e7482926cd93:/lunaix-os/kernel/fs/mount.c diff --git a/lunaix-os/kernel/fs/mount.c b/lunaix-os/kernel/fs/mount.c index 3d4b0be..c673e84 100644 --- a/lunaix-os/kernel/fs/mount.c +++ b/lunaix-os/kernel/fs/mount.c @@ -1,9 +1,15 @@ -#include +#include +#include #include #include +#include +#include +#include #include -static struct llist_header all_mnts = { .next = &all_mnts, .prev = &all_mnts }; +LOG_MODULE("fs") + +struct llist_header all_mnts = { .next = &all_mnts, .prev = &all_mnts }; struct v_mount* vfs_create_mount(struct v_mount* parent, struct v_dnode* mnt_point) @@ -14,25 +20,41 @@ vfs_create_mount(struct v_mount* parent, struct v_dnode* mnt_point) } llist_init_head(&mnt->submnts); + llist_init_head(&mnt->sibmnts); llist_append(&all_mnts, &mnt->list); mutex_init(&mnt->lock); - mnt_mkbusy(parent); 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); mutex_lock(&mnt->parent->lock); 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) { @@ -43,23 +65,19 @@ __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; } @@ -67,35 +85,42 @@ __vfs_do_unmount(struct v_mount* mnt) void mnt_mkbusy(struct v_mount* mnt) { - while (mnt) { - mutex_lock(&mnt->lock); - mnt->busy_counter++; - mutex_unlock(&mnt->lock); - - mnt = mnt->parent; - } + mutex_lock(&mnt->lock); + mnt->busy_counter++; + mutex_unlock(&mnt->lock); } void mnt_chillax(struct v_mount* mnt) { - while (mnt) { - mutex_lock(&mnt->lock); - mnt->busy_counter--; - mutex_unlock(&mnt->lock); + mutex_lock(&mnt->lock); + mnt->busy_counter--; + mutex_unlock(&mnt->lock); +} - mnt = mnt->parent; +int +vfs_mount_root(const char* fs_name, struct device* device) +{ + extern struct v_dnode* vfs_sysroot; + int errno = 0; + if (vfs_sysroot->mnt && (errno = vfs_unmount_at(vfs_sysroot))) { + return errno; } + return vfs_mount_at(fs_name, device, vfs_sysroot, 0); } int -vfs_mount(const char* target, const char* fs_name, struct device* device) +vfs_mount(const char* target, + const char* fs_name, + struct device* device, + int options) { int errno; struct v_dnode* mnt; - if (!(errno = vfs_walk(__current->cwd, target, &mnt, NULL, 0))) { - errno = vfs_mount_at(fs_name, device, mnt); + if (!(errno = + vfs_walk(__current->cwd, target, &mnt, NULL, VFS_WALK_MKPARENT))) { + errno = vfs_mount_at(fs_name, device, mnt, options); } return errno; @@ -114,33 +139,105 @@ vfs_unmount(const char* target) return errno; } -int -vfs_mount_at(const char* fs_name, - struct device* device, - struct v_dnode* mnt_point) +static int +vfs_mount_fsat(struct filesystem* fs, + struct device* device, + struct v_dnode* mnt_point, + int options) { - if (mnt_point->inode && !(mnt_point->inode->itype & VFS_IFDIR)) { + + if (device && device->dev_type != DEV_IFVOL) { + return ENOTBLK; + } + + if (mnt_point->inode && !check_directory_node(mnt_point->inode)) { return ENOTDIR; } - struct filesystem* fs = fsm_get(fs_name); - if (!fs) { + 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(); + struct v_superblock *sb = vfs_sb_alloc(), + *old_sb = mnt_point->super_block; + + if (device) { + dev_name = device->name_val; + } + + // prepare v_superblock for fs::mount invoke sb->dev = device; + sb->fs = fs; + sb->root = mnt_point; + vfs_d_assign_sb(mnt_point, sb); - int errno = 0; + if (!(mnt_point->mnt = vfs_create_mount(parent_mnt, mnt_point))) { + errno = ENOMEM; + goto cleanup; + } + + mnt_point->mnt->flags = options; if (!(errno = fs->mount(sb, mnt_point))) { - sb->fs = fs; - sb->root = mnt_point; - mnt_point->super_block = sb; + kprintf("mount: dev=%s, fs=%s, mode=%d", + dev_name, fsname, options); + } else { + goto cleanup; + } + + vfs_sb_free(old_sb); + return errno; - if (!(mnt_point->mnt = vfs_create_mount(parent_mnt, mnt_point))) { - errno = ENOMEM; - vfs_sb_free(sb); +cleanup: + 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; } } @@ -170,3 +267,65 @@ vfs_unmount_at(struct v_dnode* mnt_point) return errno; } + +int +vfs_check_writable(struct v_dnode* dnode) +{ + if ((dnode->mnt->flags & MNT_RO)) { + return EROFS; + } + return 0; +} + +__DEFINE_LXSYSCALL4(int, + mount, + const char*, + source, + const char*, + target, + const char*, + fstype, + int, + options) +{ + struct device* device = NULL; + struct v_dnode *dev = NULL, *mnt = NULL; + int errno = 0; + + // 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; + } + + if (mnt->ref_count > 1) { + errno = EBUSY; + goto done; + } + + if (mnt->mnt->mnt_point == mnt) { + errno = EBUSY; + goto done; + } + + if (dev) { + if (!check_voldev_node(dev->inode)) { + errno = ENOTDEV; + goto done; + } + + device = resolve_device(dev->inode->data); + assert(device); + } + + errno = vfs_mount_at(fstype, device, mnt, options); + +done: + return DO_STATUS(errno); +} + +__DEFINE_LXSYSCALL1(int, unmount, const char*, target) +{ + return vfs_unmount(target); +} \ No newline at end of file