X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/7b8a1bcad75628f9add4590db2bb9b8e418ee8eb..0fd474df7001837bde53da0e42e83081827c9641:/lunaix-os/kernel/fs/mount.c?ds=sidebyside diff --git a/lunaix-os/kernel/fs/mount.c b/lunaix-os/kernel/fs/mount.c index 96cc741..b62b77f 100644 --- a/lunaix-os/kernel/fs/mount.c +++ b/lunaix-os/kernel/fs/mount.c @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -11,8 +11,16 @@ 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) +static void +__vfs_attach_vmnt(struct v_dnode* mnt_point, struct v_mount* vmnt) +{ + vmnt->mnt_point = mnt_point; + vfs_d_assign_vmnt(mnt_point, vmnt); + vfs_ref_dnode(mnt_point); +} + +static struct v_mount* +__vfs_create_mount(struct v_mount* parent, struct v_superblock* mnt_sb) { struct v_mount* mnt = vzalloc(sizeof(struct v_mount)); if (!mnt) { @@ -20,12 +28,12 @@ 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->parent = parent; - mnt->mnt_point = mnt_point; - mnt->super_block = mnt_point->super_block; + vfs_vmnt_assign_sb(mnt, mnt_sb); if (parent) { mnt_mkbusy(parent); @@ -33,13 +41,40 @@ vfs_create_mount(struct v_mount* parent, struct v_dnode* mnt_point) llist_append(&parent->submnts, &mnt->sibmnts); mutex_unlock(&mnt->parent->lock); } - - atomic_fetch_add(&mnt_point->ref_count, 1); return mnt; } -int +static void +__vfs_detach_vmnt(struct v_mount* mnt) +{ + assert(llist_empty(&mnt->submnts)); + + vfs_unref_dnode(mnt->mnt_point); + assert(!mnt->busy_counter); + + if (mnt->parent) { + mnt_chillax(mnt->parent); + } + + mnt->mnt_point->mnt = NULL; + + llist_delete(&mnt->sibmnts); + llist_delete(&mnt->list); + vfree(mnt); +} + +static inline void +__detach_node_cache_ref(struct hbucket* bucket) +{ + if (!bucket->head) { + return; + } + + bucket->head->pprev = 0; +} + +static int __vfs_do_unmount(struct v_mount* mnt) { int errno = 0; @@ -49,23 +84,20 @@ __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) { - continue; - } - bucket->head->pprev = 0; + __detach_node_cache_ref(&sb->i_cache[i]); + __detach_node_cache_ref(&sb->d_cache[i]); } - mnt_chillax(mnt->parent); + struct v_dnode *pos, *next; + llist_for_each(pos, next, &mnt->mnt_point->children, siblings) + { + vfs_d_free(pos); + } - vfs_sb_free(sb); - atomic_fetch_sub(&mnt->mnt_point->ref_count, 1); - vfree(mnt); + __vfs_detach_vmnt(mnt); + vfs_d_assign_vmnt(mnt->mnt_point, mnt->parent); return errno; } @@ -127,52 +159,59 @@ vfs_unmount(const char* target) 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 & F_MFILE)) { + 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) { + if ((fs->types & FSTYPE_ROFS)) { options |= MNT_RO; } - char* dev_name = "sys"; - 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; - - if (device) { - dev_name = device->name_val; + if (!(fs->types & FSTYPE_PSEUDO) && !device) { + return ENODEV; } int errno = 0; - if (!(errno = fs->mount(sb, mnt_point))) { - sb->fs = fs; - sb->root = mnt_point; + char* dev_name; + char* fsname; + struct v_mount *parent_mnt, *vmnt; + struct v_superblock *sb; - if (!(mnt_point->mnt = vfs_create_mount(parent_mnt, mnt_point))) { - errno = ENOMEM; - goto cleanup; - } + fsname = HSTR_VAL(fs->fs_name); + parent_mnt = mnt_point->mnt; + sb = vfs_sb_alloc(); + + dev_name = device ? device->name_val : "sys"; - kprintf("mount: dev=%s, fs=%s, mode=%d", dev_name, fs_name, options); + // prepare v_superblock for fs::mount invoke + sb->dev = device; + sb->fs = fs; + sb->root = mnt_point; + + vmnt = __vfs_create_mount(parent_mnt, sb); + + if (!vmnt) { + errno = ENOMEM; + goto cleanup; + } + + __vfs_attach_vmnt(mnt_point, vmnt); - 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; } @@ -180,13 +219,49 @@ vfs_mount_at(const char* fs_name, return errno; cleanup: - ERROR("mount: dev=%s, fs=%s, mode=%d, err=%d", - dev_name, - fs_name, - options, - errno); - mnt_point->super_block = old_sb; - vfs_sb_free(sb); + ERROR("failed mount: dev=%s, fs=%s, mode=%d, err=%d", + dev_name, fsname, options, errno); + + __vfs_detach_vmnt(mnt_point->mnt); + vfs_d_assign_vmnt(mnt_point, parent_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; } @@ -194,7 +269,9 @@ int vfs_unmount_at(struct v_dnode* mnt_point) { int errno = 0; - struct v_superblock* sb = mnt_point->super_block; + struct v_superblock* sb; + + sb = mnt_point->super_block; if (!sb) { return EINVAL; } @@ -203,15 +280,11 @@ vfs_unmount_at(struct v_dnode* mnt_point) return EINVAL; } - if (mnt_point->mnt->busy_counter) { + if (mnt_check_busy(mnt_point->mnt)) { return EBUSY; } - if (!(errno = __vfs_do_unmount(mnt_point->mnt))) { - atomic_fetch_sub(&mnt_point->ref_count, 1); - } - - return errno; + return __vfs_do_unmount(mnt_point->mnt); } int @@ -220,6 +293,11 @@ vfs_check_writable(struct v_dnode* dnode) if ((dnode->mnt->flags & MNT_RO)) { return EROFS; } + + if (!check_allow_write(dnode->inode)) { + return EPERM; + } + return 0; } @@ -234,6 +312,7 @@ __DEFINE_LXSYSCALL4(int, int, options) { + struct device* device = NULL; struct v_dnode *dev = NULL, *mnt = NULL; int errno = 0; @@ -249,16 +328,19 @@ __DEFINE_LXSYSCALL4(int, goto done; } - // By our convention. - // XXX could we do better? - struct device* device = NULL; + if (mnt->mnt->mnt_point == mnt) { + errno = EBUSY; + goto done; + } if (dev) { - if (!(dev->inode->itype & VFS_IFVOLDEV)) { + if (!check_voldev_node(dev->inode)) { errno = ENOTDEV; goto done; } - device = (struct device*)dev->inode->data; + + device = resolve_device(dev->inode->data); + assert(device); } errno = vfs_mount_at(fstype, device, mnt, options);