sweep through entire page table to free up intermediate tables
[lunaix-os.git] / lunaix-os / kernel / fs / vfs.c
index 0eec6bf517cb53eb7aeab3972b7915897c95da1b..53c1efa93f822dffe16e4f468f1a3df8970d681e 100644 (file)
@@ -64,7 +64,6 @@ static struct cake_pile* superblock_pile;
 static struct cake_pile* fd_pile;
 
 struct v_dnode* vfs_sysroot;
-static struct hbucket* dnode_cache;
 
 struct lru_zone *dnode_lru, *inode_lru;
 
@@ -89,8 +88,6 @@ vfs_init()
     superblock_pile =
       cake_new_pile("sb_cache", sizeof(struct v_superblock), 1, 0);
 
-    dnode_cache = vzalloc(VFS_HASHTABLE_SIZE * sizeof(struct hbucket));
-
     dnode_lru = lru_new_zone("vfs_dnode", __vfs_try_evict_dnode);
     inode_lru = lru_new_zone("vfs_inode", __vfs_try_evict_inode);
 
@@ -100,19 +97,23 @@ vfs_init()
     // 创建一个根dnode。
     vfs_sysroot = vfs_d_alloc(NULL, &vfs_empty);
     vfs_sysroot->parent = vfs_sysroot;
-    atomic_fetch_add(&vfs_sysroot->ref_count, 1);
+    
+    vfs_ref_dnode(vfs_sysroot);
 }
 
 static inline struct hbucket*
 __dcache_hash(struct v_dnode* parent, u32_t* hash)
 {
-    u32_t _hash = *hash;
-    // 确保低位更加随机
+    struct hbucket* d_cache;
+    u32_t _hash;
+    
+    d_cache = parent->super_block->d_cache;
+    _hash = *hash;
     _hash = _hash ^ (_hash >> VFS_HASHBITS);
-    // 与parent的指针值做加法,来减小碰撞的可能性。
     _hash += (u32_t)__ptr(parent);
+
     *hash = _hash;
-    return &dnode_cache[_hash & VFS_HASH_MASK];
+    return &d_cache[_hash & VFS_HASH_MASK];
 }
 
 static inline int
@@ -156,7 +157,7 @@ vfs_dcache_add(struct v_dnode* parent, struct v_dnode* dnode)
 {
     assert(parent);
 
-    atomic_fetch_add(&dnode->ref_count, 1);
+    dnode->ref_count = 1;
     dnode->parent = parent;
     llist_append(&parent->children, &dnode->siblings);
 
@@ -175,7 +176,7 @@ vfs_dcache_remove(struct v_dnode* dnode)
     hlist_delete(&dnode->hash_list);
 
     dnode->parent = NULL;
-    atomic_fetch_sub(&dnode->ref_count, 1);
+    dnode->ref_count = 0;
 }
 
 void
@@ -204,10 +205,10 @@ vfs_open(struct v_dnode* dnode, struct v_file** file)
 
     vfile->dnode = dnode;
     vfile->inode = inode;
-    vfile->ref_count = ATOMIC_VAR_INIT(1);
+    vfile->ref_count = 1;
     vfile->ops = inode->default_fops;
 
-    if (check_file_node(inode) && !inode->pg_cache) {
+    if (check_regfile_node(inode) && !inode->pg_cache) {
         struct pcache* pcache = vzalloc(sizeof(struct pcache));
         pcache_init(pcache);
         pcache->master = inode;
@@ -218,9 +219,8 @@ vfs_open(struct v_dnode* dnode, struct v_file** file)
     if (errno) {
         cake_release(file_pile, vfile);
     } else {
-        atomic_fetch_add(&dnode->ref_count, 1);
+        vfs_ref_dnode(dnode);
         inode->open_count++;
-        mnt_mkbusy(dnode->mnt);
 
         *file = vfile;
     }
@@ -293,8 +293,8 @@ vfs_pclose(struct v_file* file, pid_t pid)
 
     mutex_unlock_for(&inode->lock, pid);
     
-    if (file->ref_count > 1) {
-        atomic_fetch_sub(&file->ref_count, 1);
+    if (vfs_check_duped_file(file)) {
+        vfs_unref_file(file);
         return 0;
     }
 
@@ -302,8 +302,7 @@ vfs_pclose(struct v_file* file, pid_t pid)
         goto done;
     }
 
-    atomic_fetch_sub(&file->dnode->ref_count, 1);
-    mnt_chillax(file->dnode->mnt);
+    vfs_unref_dnode(file->dnode);
     cake_release(file_pile, file);
 
     /*
@@ -383,7 +382,10 @@ vfs_sb_alloc()
     struct v_superblock* sb = cake_grab(superblock_pile);
     memset(sb, 0, sizeof(*sb));
     llist_init_head(&sb->sb_list);
+    
     sb->i_cache = vzalloc(VFS_HASHTABLE_SIZE * sizeof(struct hbucket));
+    sb->d_cache = vzalloc(VFS_HASHTABLE_SIZE * sizeof(struct hbucket));
+
     sb->ref_count = 1;
     return sb;
 }
@@ -395,12 +397,12 @@ vfs_sb_ref(struct v_superblock* sb)
 }
 
 void
-vfs_sb_free(struct v_superblock* sb)
+vfs_sb_unref(struct v_superblock* sb)
 {
     assert(sb->ref_count);
 
     sb->ref_count--;
-    if (sb->ref_count) {
+    if (likely(sb->ref_count)) {
         return;
     }
 
@@ -409,6 +411,8 @@ vfs_sb_free(struct v_superblock* sb)
     }
 
     vfree(sb->i_cache);
+    vfree(sb->d_cache);
+    
     cake_release(superblock_pile, sb);
 }
 
@@ -454,7 +458,6 @@ vfs_d_alloc(struct v_dnode* parent, struct hstr* name)
     llist_init_head(&dnode->aka_list);
     mutex_init(&dnode->lock);
 
-    dnode->ref_count = ATOMIC_VAR_INIT(0);
     dnode->name = HHSTR(vzalloc(VFS_NAME_MAXLEN), 0, 0);
 
     hstrcpy(&dnode->name, name);
@@ -493,7 +496,7 @@ vfs_d_free(struct v_dnode* dnode)
         dnode->destruct(dnode);
     }
 
-    vfs_sb_free(dnode->super_block);
+    vfs_sb_unref(dnode->super_block);
     vfree((void*)dnode->name.value);
     cake_release(dnode_pile, dnode);
 }
@@ -555,6 +558,8 @@ vfs_i_alloc(struct v_superblock* sb)
 void
 vfs_i_free(struct v_inode* inode)
 {
+    assert(inode->link_count == 0);
+    
     if (inode->pg_cache) {
         pcache_release(inode->pg_cache);
         vfree(inode->pg_cache);
@@ -566,7 +571,7 @@ vfs_i_free(struct v_inode* inode)
         inode->destruct(inode);
     }
 
-    vfs_sb_free(inode->sb);
+    vfs_sb_unref(inode->sb);
     hlist_delete(&inode->hash_list);
     cake_release(inode_pile, inode);
 }
@@ -788,8 +793,12 @@ __vfs_readdir_callback(struct dir_context* dctx,
                        const int dtype)
 {
     struct lx_dirent* dent = (struct lx_dirent*)dctx->cb_data;
-    strncpy(dent->d_name, name, MIN(len, DIRENT_NAME_MAX_LEN));
-    dent->d_nlen = len;
+    int len_ = MIN(len, DIRENT_NAME_MAX_LEN - 1);
+
+    strncpy(dent->d_name, name, len_);
+    dent->d_name[len_] = 0;
+
+    dent->d_nlen = len_;
     dent->d_type = dtype;
 }
 
@@ -829,6 +838,17 @@ done:
     return DO_STATUS_OR_RETURN(errno);
 }
 
+static inline bool
+check_pcache_eligibility(struct v_fd* fd_s)
+{
+    struct v_inode* inode;
+
+    inode = fd_s->file->inode;
+    return !check_seqdev_node(inode) \
+        && !fsm_check_pseudo_fs(inode->sb->fs) \
+        && !(fd_s->flags & FO_DIRECT);
+}
+
 __DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
 {
     int errno = 0;
@@ -847,7 +867,7 @@ __DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
 
     file->inode->atime = clock_unixtime();
 
-    if (check_seqdev_node(file->inode) || (fd_s->flags & FO_DIRECT)) {
+    if (!check_pcache_eligibility(fd_s)) {
         errno = file->ops->read(file->inode, buf, count, file->f_pos);
     } else {
         errno = pcache_read(file->inode, buf, count, file->f_pos);
@@ -893,7 +913,7 @@ __DEFINE_LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count)
         file->f_pos = inode->fsize;
     }
 
-    if (check_seqdev_node(inode) || (fd_s->flags & FO_DIRECT)) {
+    if (!check_pcache_eligibility(fd_s)) {
         errno = file->ops->write(inode, buf, count, file->f_pos);
     } else {
         errno = pcache_write(inode, buf, count, file->f_pos);
@@ -990,6 +1010,8 @@ vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth)
 
     size_t cpy_size = MIN(dnode->name.len, size - len);
     strncpy(buf + len, dnode->name.value, cpy_size);
+    buf[len + cpy_size] = 0;
+
     len += cpy_size;
 
     return len;
@@ -1324,7 +1346,7 @@ vfs_dup_fd(struct v_fd* old, struct v_fd** new)
 
     memcpy(copied, old, sizeof(struct v_fd));
 
-    atomic_fetch_add(&old->file->ref_count, 1);
+    vfs_ref_file(old->file);
 
     *new = copied;
 
@@ -1431,31 +1453,6 @@ done:
     return DO_STATUS(errno);
 }
 
-void
-vfs_ref_file(struct v_file* file)
-{
-    atomic_fetch_add(&file->ref_count, 1);
-}
-
-void
-vfs_ref_dnode(struct v_dnode* dnode)
-{
-    atomic_fetch_add(&dnode->ref_count, 1);
-    
-    if (dnode->mnt) {
-        mnt_mkbusy(dnode->mnt);
-    }
-}
-
-void
-vfs_unref_dnode(struct v_dnode* dnode)
-{
-    atomic_fetch_sub(&dnode->ref_count, 1);
-    if (dnode->mnt) {
-        mnt_chillax(dnode->mnt);
-    }
-}
-
 int
 vfs_do_chdir(struct proc_info* proc, struct v_dnode* dnode)
 {
@@ -1475,9 +1472,9 @@ vfs_do_chdir(struct proc_info* proc, struct v_dnode* dnode)
     vfs_ref_dnode(dnode);
     proc->cwd = dnode;
 
+done:
     unlock_dnode(dnode);
 
-done:
     return errno;
 }