feat: ability to evict dnode and inode cache
authorMinep <zelong56@gmail.com>
Tue, 16 Aug 2022 16:22:55 +0000 (17:22 +0100)
committerMinep <zelong56@gmail.com>
Tue, 16 Aug 2022 16:22:55 +0000 (17:22 +0100)
chore: minor fixes and refactoring

lunaix-os/includes/lunaix/ds/lru.h
lunaix-os/includes/lunaix/fs.h
lunaix-os/kernel/ds/lru.c
lunaix-os/kernel/fs/pcache.c
lunaix-os/kernel/fs/twifs/twifs.c
lunaix-os/kernel/fs/vfs.c
lunaix-os/kernel/mm/vmap.c

index 5ae607d24e6d223da8da22235fb22a4586871113..63660c22e72a3aaa9f17c59d03d7273da0dfbdfa 100644 (file)
@@ -2,28 +2,36 @@
 #define __LUNAIX_LRU_H
 
 #include <lunaix/ds/llist.h>
 #define __LUNAIX_LRU_H
 
 #include <lunaix/ds/llist.h>
+#include <lunaix/types.h>
 
 
-struct lru_zone
+struct lru_node
 {
 {
-    struct llist_header lead_node;
-    struct llist_header zones;
+    struct llist_header lru_nodes;
 };
 
 };
 
-struct lru_node
+typedef int (*evict_cb)(struct lru_node* lru_obj);
+
+struct lru_zone
 {
 {
-    struct llist_header lru_nodes;
+    struct llist_header lead_node;
+    struct llist_header zones;
+    uint32_t objects;
+    evict_cb try_evict;
 };
 
 struct lru_zone*
 };
 
 struct lru_zone*
-lru_new_zone();
+lru_new_zone(evict_cb try_evict_cb);
 
 void
 lru_use_one(struct lru_zone* zone, struct lru_node* node);
 
 
 void
 lru_use_one(struct lru_zone* zone, struct lru_node* node);
 
-struct lru_node*
+void
 lru_evict_one(struct lru_zone* zone);
 
 void
 lru_evict_one(struct lru_zone* zone);
 
 void
-lru_remove(struct lru_node* node);
+lru_remove(struct lru_zone* zone, struct lru_node* node);
+
+void
+lru_evict_half(struct lru_zone* zone);
 
 #endif /* __LUNAIX_LRU_H */
 
 #endif /* __LUNAIX_LRU_H */
index 6490f9e0492a01230caef2b4f0b495639f6987ee..c80eb229aa7eb725ad88e52421aa404278d21691 100644 (file)
@@ -118,6 +118,7 @@ struct v_inode
     uint32_t lb_usage;
     uint32_t fsize;
     struct hlist_node hash_list;
     uint32_t lb_usage;
     uint32_t fsize;
     struct hlist_node hash_list;
+    struct lru_node lru;
     struct pcache* pg_cache;
     void* data; // 允许底层FS绑定他的一些专有数据
     struct
     struct pcache* pg_cache;
     void* data; // 允许底层FS绑定他的一些专有数据
     struct
@@ -126,11 +127,11 @@ struct v_inode
         int (*open)(struct v_inode* this, struct v_file* file);
         int (*sync)(struct v_inode* this);
         int (*mkdir)(struct v_inode* this, struct v_dnode* dnode);
         int (*open)(struct v_inode* this, struct v_file* file);
         int (*sync)(struct v_inode* this);
         int (*mkdir)(struct v_inode* this, struct v_dnode* dnode);
-        int (*rmdir)(struct v_inode* this);
+        int (*rmdir)(struct v_inode* this, struct v_dnode* dir);
         int (*unlink)(struct v_inode* this);
         int (*link)(struct v_inode* this, struct v_dnode* new_name);
         int (*read_symlink)(struct v_inode* this, const char** path_out);
         int (*unlink)(struct v_inode* this);
         int (*link)(struct v_inode* this, struct v_dnode* new_name);
         int (*read_symlink)(struct v_inode* this, const char** path_out);
-        int (*symlink)(struct v_inode* this, const char* target);
+        int (*set_symlink)(struct v_inode* this, const char* target);
         int (*dir_lookup)(struct v_inode* this, struct v_dnode* dnode);
         int (*rename)(struct v_inode* from_inode,
                       struct v_dnode* from_dnode,
         int (*dir_lookup)(struct v_inode* this, struct v_dnode* dnode);
         int (*rename)(struct v_inode* from_inode,
                       struct v_dnode* from_dnode,
@@ -142,6 +143,7 @@ struct v_inode
 struct v_dnode
 {
     mutex_t lock; // sync the path walking
 struct v_dnode
 {
     mutex_t lock; // sync the path walking
+    struct lru_node lru;
     struct hstr name;
     struct v_inode* inode;
     struct v_dnode* parent;
     struct hstr name;
     struct v_inode* inode;
     struct v_dnode* parent;
@@ -157,16 +159,6 @@ struct v_fdtable
     struct v_fd* fds[VFS_MAX_FD];
 };
 
     struct v_fd* fds[VFS_MAX_FD];
 };
 
-struct pcache_pg
-{
-    struct llist_header pg_list;
-    struct llist_header dirty_list;
-    struct lru_node lru;
-    void* pg;
-    uint32_t flags;
-    uint32_t fpos;
-};
-
 struct pcache
 {
     struct v_inode* master;
 struct pcache
 {
     struct v_inode* master;
@@ -177,6 +169,16 @@ struct pcache
     uint32_t n_pages;
 };
 
     uint32_t n_pages;
 };
 
+struct pcache_pg
+{
+    struct llist_header pg_list;
+    struct llist_header dirty_list;
+    struct lru_node lru;
+    struct pcache* holder;
+    void* pg;
+    uint32_t flags;
+    uint32_t fpos;
+};
 /* --- file system manager --- */
 void
 fsm_init();
 /* --- file system manager --- */
 void
 fsm_init();
@@ -229,6 +231,9 @@ vfs_close(struct v_file* file);
 int
 vfs_fsync(struct v_file* file);
 
 int
 vfs_fsync(struct v_file* file);
 
+void
+vfs_assign_inode(struct v_dnode* assign_to, struct v_inode* inode);
+
 struct v_superblock*
 vfs_sb_alloc();
 
 struct v_superblock*
 vfs_sb_alloc();
 
index ebabeef5709effa520127033566f375ca8005829..08083b11fb1d06ded2a557d7437fabf882f1963f 100644 (file)
@@ -4,13 +4,15 @@
 struct llist_header zone_lead = { .next = &zone_lead, .prev = &zone_lead };
 
 struct lru_zone*
 struct llist_header zone_lead = { .next = &zone_lead, .prev = &zone_lead };
 
 struct lru_zone*
-lru_new_zone()
+lru_new_zone(evict_cb try_evict_cb)
 {
 {
-    struct lru_zone* zone = valloc(sizeof(struct lru_zone));
+    struct lru_zone* zone = vzalloc(sizeof(struct lru_zone));
     if (!zone) {
         return NULL;
     }
 
     if (!zone) {
         return NULL;
     }
 
+    zone->try_evict = try_evict_cb;
+
     llist_init_head(&zone->lead_node);
     llist_append(&zone_lead, &zone->zones);
 
     llist_init_head(&zone->lead_node);
     llist_append(&zone_lead, &zone->zones);
 
@@ -25,9 +27,21 @@ lru_use_one(struct lru_zone* zone, struct lru_node* node)
     }
 
     llist_prepend(&zone->lead_node, &node->lru_nodes);
     }
 
     llist_prepend(&zone->lead_node, &node->lru_nodes);
+    zone->objects++;
+}
+
+static void
+__do_evict(struct lru_zone* zone, struct llist_header* elem)
+{
+    llist_delete(elem);
+    if (!zone->try_evict(container_of(elem, struct lru_node, lru_nodes))) {
+        llist_append(&zone->lead_node, elem);
+    } else {
+        zone->objects--;
+    }
 }
 
 }
 
-struct lru_node*
+void
 lru_evict_one(struct lru_zone* zone)
 {
     struct llist_header* tail = zone->lead_node.prev;
 lru_evict_one(struct lru_zone* zone)
 {
     struct llist_header* tail = zone->lead_node.prev;
@@ -35,15 +49,26 @@ lru_evict_one(struct lru_zone* zone)
         return;
     }
 
         return;
     }
 
-    llist_delete(tail);
+    __do_evict(zone, tail);
+}
 
 
-    return container_of(tail, struct lru_node, lru_nodes);
+void
+lru_evict_half(struct lru_zone* zone)
+{
+    int target = (int)(zone->objects / 2);
+    struct llist_header* tail = zone->lead_node.prev;
+    while (tail != &zone->lead_node && target > 0) {
+        __do_evict(zone, tail);
+        tail = tail->prev;
+        target--;
+    }
 }
 
 void
 }
 
 void
-lru_remove(struct lru_node* node)
+lru_remove(struct lru_zone* zone, struct lru_node* node)
 {
     if (node->lru_nodes.next && node->lru_nodes.prev) {
         llist_delete(&node->lru_nodes);
     }
 {
     if (node->lru_nodes.next && node->lru_nodes.prev) {
         llist_delete(&node->lru_nodes);
     }
+    zone->objects--;
 }
\ No newline at end of file
 }
\ No newline at end of file
index 03f7502072d9acab6c98fd688b0ecb4e708bb1e2..9d883f90485402f702617dbd8a721040315d925b 100644 (file)
 
 static struct lru_zone* pcache_zone;
 
 
 static struct lru_zone* pcache_zone;
 
+static int
+__pcache_try_evict(struct lru_node* obj)
+{
+    struct pcache_pg* page = container_of(obj, struct pcache_pg, lru);
+    pcache_invalidate(page->holder, page);
+    return 1;
+}
+
 void
 pcache_init(struct pcache* pcache)
 {
     btrie_init(&pcache->tree, PG_SIZE_BITS);
     llist_init_head(&pcache->dirty);
     llist_init_head(&pcache->pages);
 void
 pcache_init(struct pcache* pcache)
 {
     btrie_init(&pcache->tree, PG_SIZE_BITS);
     llist_init_head(&pcache->dirty);
     llist_init_head(&pcache->pages);
-    pcache_zone = lru_new_zone();
+    pcache_zone = lru_new_zone(__pcache_try_evict);
 }
 
 void
 }
 
 void
@@ -32,18 +40,6 @@ pcache_release_page(struct pcache* pcache, struct pcache_pg* page)
     pcache->n_pages--;
 }
 
     pcache->n_pages--;
 }
 
-void
-pcache_evict(struct pcache* pcache)
-{
-    struct pcache_pg* page =
-      container_of(lru_evict_one(pcache_zone), struct pcache_pg, lru);
-
-    if (!page)
-        return;
-
-    pcache_invalidate(pcache, page);
-}
-
 struct pcache_pg*
 pcache_new_page(struct pcache* pcache, uint32_t index)
 {
 struct pcache_pg*
 pcache_new_page(struct pcache* pcache, uint32_t index)
 {
@@ -51,7 +47,7 @@ pcache_new_page(struct pcache* pcache, uint32_t index)
     void* pg = valloc(PG_SIZE);
 
     if (!ppg || !pg) {
     void* pg = valloc(PG_SIZE);
 
     if (!ppg || !pg) {
-        pcache_evict(pcache);
+        lru_evict_one(pcache_zone);
         if (!ppg && !(ppg = vzalloc(sizeof(struct pcache_pg)))) {
             return NULL;
         }
         if (!ppg && !(ppg = vzalloc(sizeof(struct pcache_pg)))) {
             return NULL;
         }
@@ -62,6 +58,7 @@ pcache_new_page(struct pcache* pcache, uint32_t index)
     }
 
     ppg->pg = pg;
     }
 
     ppg->pg = pg;
+    ppg->holder = pcache;
 
     llist_append(&pcache->pages, &ppg->pg_list);
     btrie_set(&pcache->tree, index, ppg);
 
     llist_append(&pcache->pages, &ppg->pg_list);
     btrie_set(&pcache->tree, index, ppg);
@@ -164,7 +161,7 @@ pcache_release(struct pcache* pcache)
     struct pcache_pg *pos, *n;
     llist_for_each(pos, n, &pcache->pages, pg_list)
     {
     struct pcache_pg *pos, *n;
     llist_for_each(pos, n, &pcache->pages, pg_list)
     {
-        lru_remove(&pos->lru);
+        lru_remove(pcache_zone, &pos->lru);
         vfree(pos);
     }
 
         vfree(pos);
     }
 
index 1f061df88d66cc261d61ded7e8daa21e6cfc98a6..a40340f6eedf85594b709a47d570dd57e3968796 100644 (file)
@@ -43,7 +43,7 @@ int
 __twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode);
 
 int
 __twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode);
 
 int
-__twifs_rmstuff(struct v_inode* inode);
+__twifs_rmstuff(struct v_inode* inode, struct v_dnode* dir);
 
 int
 __twifs_fwrite(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
 
 int
 __twifs_fwrite(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
@@ -95,7 +95,6 @@ twifs_rm_node(struct twifs_node* node)
         return ENOTEMPTY;
     }
     llist_delete(&node->siblings);
         return ENOTEMPTY;
     }
     llist_delete(&node->siblings);
-    vfs_i_free(node->inode);
     cake_release(twi_pile, node);
     return 0;
 }
     cake_release(twi_pile, node);
     return 0;
 }
@@ -146,21 +145,13 @@ twifs_toplevel_node(const char* name, int name_len, uint32_t itype)
 int
 __twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode)
 {
 int
 __twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode)
 {
-    struct twifs_node* parent_node = (struct twifs_node*)inode->data;
-    if (!(parent_node->itype & VFS_IFDIR)) {
-        return ENOTDIR;
-    }
-    struct twifs_node* new_node =
-      twifs_dir_node(parent_node, dnode->name.value, dnode->name.len, 0);
-    dnode->inode = new_node->inode;
-
-    return 0;
+    return ENOTSUP;
 }
 
 int
 __twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
 {
 }
 
 int
 __twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
 {
-    mount_point->inode = fs_root->inode;
+    vfs_assign_inode(mount_point, fs_root->inode);
     return 0;
 }
 
     return 0;
 }
 
@@ -177,7 +168,6 @@ __twifs_create_inode(struct twifs_node* twi_node)
 
     inode->ops.dir_lookup = __twifs_dirlookup;
     inode->ops.mkdir = __twifs_mkdir;
 
     inode->ops.dir_lookup = __twifs_dirlookup;
     inode->ops.mkdir = __twifs_mkdir;
-    inode->ops.unlink = __twifs_rmstuff;
     inode->ops.rmdir = __twifs_rmstuff;
     inode->ops.open = __twifs_openfile;
 
     inode->ops.rmdir = __twifs_rmstuff;
     inode->ops.open = __twifs_openfile;
 
@@ -225,10 +215,9 @@ __twifs_get_node(struct twifs_node* parent, struct hstr* name)
 }
 
 int
 }
 
 int
-__twifs_rmstuff(struct v_inode* inode)
+__twifs_rmstuff(struct v_inode* inode, struct v_dnode* dir)
 {
 {
-    struct twifs_node* twi_node = (struct twifs_node*)inode->data;
-    return twifs_rm_node(twi_node);
+    return ENOTSUP;
 }
 
 int
 }
 
 int
@@ -242,7 +231,7 @@ __twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode)
 
     struct twifs_node* child_node = __twifs_get_node(twi_node, &dnode->name);
     if (child_node) {
 
     struct twifs_node* child_node = __twifs_get_node(twi_node, &dnode->name);
     if (child_node) {
-        dnode->inode = child_node->inode;
+        vfs_assign_inode(dnode, child_node->inode);
         return 0;
     }
     return ENOENT;
         return 0;
     }
     return ENOENT;
index 958c76197279bccee66e26b08175a86cd3c82c77..8edc9fd6126eb05d9f15c18d38ab4356fa71bfd8 100644 (file)
 
     It is overseen by Twilight Sparkle ;)
 
 
     It is overseen by Twilight Sparkle ;)
 
- 1. Get inodes hooked into lru
- 2. Get dnodes hooked into lru
+ 1. Get inodes hooked into lru (CHECKED)
+ 2. Get dnodes hooked into lru (CHECKED)
  3. Get inodes properly hashed so they can be reused by underling fs (CHECKED)
  3. Get inodes properly hashed so they can be reused by underling fs (CHECKED)
- 4. (lru) Add a callback function (or destructor) for eviction.
+ 4. (lru) Add a callback function (or destructor) for eviction. (CHECKED)
         [good idea] or a constructor/destructor pattern in cake allocator ?
  5. (mount) Figure out a way to identify a busy mount point before unmount
             maybe a unified mount_point structure that maintain a referencing
         [good idea] or a constructor/destructor pattern in cake allocator ?
  5. (mount) Figure out a way to identify a busy mount point before unmount
             maybe a unified mount_point structure that maintain a referencing
 #define HASH_MASK (HASHTABLE_SIZE - 1)
 #define HASHBITS (32 - HASHTABLE_BITS)
 
 #define HASH_MASK (HASHTABLE_SIZE - 1)
 #define HASHBITS (32 - HASHTABLE_BITS)
 
-#define lock_inode(inode) mutex_lock(&inode->lock)
 #define unlock_inode(inode) mutex_unlock(&inode->lock)
 #define unlock_inode(inode) mutex_unlock(&inode->lock)
+#define lock_inode(inode)                                                      \
+    ({                                                                         \
+        mutex_lock(&inode->lock);                                              \
+        lru_use_one(inode_lru, &inode->lru);                                   \
+    })
 
 
-#define lock_dnode(dnode) mutex_lock(&dnode->lock)
 #define unlock_dnode(dnode) mutex_unlock(&dnode->lock)
 #define unlock_dnode(dnode) mutex_unlock(&dnode->lock)
+#define lock_dnode(dnode)                                                      \
+    ({                                                                         \
+        mutex_lock(&dnode->lock);                                              \
+        lru_use_one(dnode_lru, &dnode->lru);                                   \
+    })
 
 static struct cake_pile* dnode_pile;
 static struct cake_pile* inode_pile;
 
 static struct cake_pile* dnode_pile;
 static struct cake_pile* inode_pile;
@@ -76,6 +84,8 @@ static struct cake_pile* fd_pile;
 static struct v_superblock* root_sb;
 static struct hbucket *dnode_cache, *inode_cache;
 
 static struct v_superblock* root_sb;
 static struct hbucket *dnode_cache, *inode_cache;
 
+static struct lru_zone *dnode_lru, *inode_lru;
+
 struct hstr vfs_ddot = HSTR("..", 2);
 struct hstr vfs_dot = HSTR(".", 1);
 struct hstr vfs_empty = HSTR("", 0);
 struct hstr vfs_ddot = HSTR("..", 2);
 struct hstr vfs_dot = HSTR(".", 1);
 struct hstr vfs_empty = HSTR("", 0);
@@ -86,6 +96,12 @@ vfs_sb_alloc();
 void
 vfs_sb_free(struct v_superblock* sb);
 
 void
 vfs_sb_free(struct v_superblock* sb);
 
+static int
+__vfs_try_evict_dnode(struct lru_node* obj);
+
+static int
+__vfs_try_evict_inode(struct lru_node* obj);
+
 void
 vfs_init()
 {
 void
 vfs_init()
 {
@@ -100,13 +116,15 @@ vfs_init()
     dnode_cache = vzalloc(HASHTABLE_SIZE * sizeof(struct hbucket));
     inode_cache = vzalloc(HASHTABLE_SIZE * sizeof(struct hbucket));
 
     dnode_cache = vzalloc(HASHTABLE_SIZE * sizeof(struct hbucket));
     inode_cache = vzalloc(HASHTABLE_SIZE * sizeof(struct hbucket));
 
+    dnode_lru = lru_new_zone(__vfs_try_evict_dnode);
+    inode_lru = lru_new_zone(__vfs_try_evict_inode);
+
     hstr_rehash(&vfs_ddot, HSTR_FULL_HASH);
     hstr_rehash(&vfs_dot, HSTR_FULL_HASH);
 
     // 创建一个根superblock,用来蕴含我们的根目录。
     root_sb = vfs_sb_alloc();
     root_sb->root = vfs_d_alloc();
     hstr_rehash(&vfs_ddot, HSTR_FULL_HASH);
     hstr_rehash(&vfs_dot, HSTR_FULL_HASH);
 
     // 创建一个根superblock,用来蕴含我们的根目录。
     root_sb = vfs_sb_alloc();
     root_sb->root = vfs_d_alloc();
-    root_sb->root->inode = vfs_i_alloc(root_sb, 0);
 }
 
 inline struct hbucket*
 }
 
 inline struct hbucket*
@@ -241,6 +259,11 @@ __vfs_walk(struct v_dnode* start,
         if (!dnode) {
             dnode = vfs_d_alloc();
 
         if (!dnode) {
             dnode = vfs_d_alloc();
 
+            if (!dnode) {
+                errno = ENOMEM;
+                goto error;
+            }
+
             hstrcpy(&dnode->name, &name);
 
             lock_inode(current_level->inode);
             hstrcpy(&dnode->name, &name);
 
             lock_inode(current_level->inode);
@@ -262,7 +285,7 @@ __vfs_walk(struct v_dnode* start,
             if (errno) {
                 unlock_dnode(current_level);
                 vfree(dnode->name.value);
             if (errno) {
                 unlock_dnode(current_level);
                 vfree(dnode->name.value);
-                goto error;
+                goto cleanup;
             }
 
             vfs_dcache_add(current_level, dnode);
             }
 
             vfs_dcache_add(current_level, dnode);
@@ -279,8 +302,9 @@ __vfs_walk(struct v_dnode* start,
     *dentry = current_level;
     return 0;
 
     *dentry = current_level;
     return 0;
 
-error:
+cleanup:
     vfs_d_free(dnode);
     vfs_d_free(dnode);
+error:
     *dentry = NULL;
     return errno;
 }
     *dentry = NULL;
     return errno;
 }
@@ -299,15 +323,18 @@ vfs_walk(struct v_dnode* start,
     int errno = __vfs_walk(start, path, &interim, component, options);
     int counter = 0;
 
     int errno = __vfs_walk(start, path, &interim, component, options);
     int counter = 0;
 
-    while (!errno) {
+    while (!errno && interim->inode && (options & VFS_WALK_NOFOLLOW)) {
         if (counter >= VFS_MAX_SYMLINK) {
             errno = ELOOP;
             continue;
         }
         if ((interim->inode->itype & VFS_IFSYMLINK) &&
         if (counter >= VFS_MAX_SYMLINK) {
             errno = ELOOP;
             continue;
         }
         if ((interim->inode->itype & VFS_IFSYMLINK) &&
-            !(options & VFS_WALK_NOFOLLOW) &&
             interim->inode->ops.read_symlink) {
             interim->inode->ops.read_symlink) {
+
+            lock_inode(interim->inode);
             errno = interim->inode->ops.read_symlink(interim->inode, &pathname);
             errno = interim->inode->ops.read_symlink(interim->inode, &pathname);
+            unlock_inode(interim->inode);
+
             if (errno) {
                 break;
             }
             if (errno) {
                 break;
             }
@@ -354,7 +381,7 @@ vfs_mount_at(const char* fs_name,
              struct device* device,
              struct v_dnode* mnt_point)
 {
              struct device* device,
              struct v_dnode* mnt_point)
 {
-    if (!(mnt_point->inode->itype & VFS_IFDIR)) {
+    if (mnt_point->inode && !(mnt_point->inode->itype & VFS_IFDIR)) {
         return ENOTDIR;
     }
 
         return ENOTDIR;
     }
 
@@ -439,6 +466,16 @@ vfs_open(struct v_dnode* dnode, struct v_file** file)
     return errno;
 }
 
     return errno;
 }
 
+void
+vfs_assign_inode(struct v_dnode* assign_to, struct v_inode* inode)
+{
+    if (assign_to->inode) {
+        assign_to->inode->link_count--;
+    }
+    assign_to->inode = inode;
+    inode->link_count++;
+}
+
 int
 vfs_link(struct v_dnode* to_link, struct v_dnode* name)
 {
 int
 vfs_link(struct v_dnode* to_link, struct v_dnode* name)
 {
@@ -450,8 +487,7 @@ vfs_link(struct v_dnode* to_link, struct v_dnode* name)
     } else if (!to_link->inode->ops.link) {
         errno = ENOTSUP;
     } else if (!(errno = to_link->inode->ops.link(to_link->inode, name))) {
     } else if (!to_link->inode->ops.link) {
         errno = ENOTSUP;
     } else if (!(errno = to_link->inode->ops.link(to_link->inode, name))) {
-        name->inode = to_link->inode;
-        to_link->inode->link_count++;
+        vfs_assign_inode(name, to_link->inode);
     }
     unlock_inode(to_link->inode);
 
     }
     unlock_inode(to_link->inode);
 
@@ -515,10 +551,42 @@ vfs_sb_free(struct v_superblock* sb)
     cake_release(superblock_pile, sb);
 }
 
     cake_release(superblock_pile, sb);
 }
 
+static int
+__vfs_try_evict_dnode(struct lru_node* obj)
+{
+    struct v_dnode* dnode = container_of(obj, struct v_dnode, lru);
+
+    if (!dnode->ref_count) {
+        vfs_d_free(dnode);
+        return 1;
+    }
+    return 0;
+}
+
+static int
+__vfs_try_evict_inode(struct lru_node* obj)
+{
+    struct v_inode* inode = container_of(obj, struct v_inode, lru);
+
+    if (!inode->link_count && !inode->open_count) {
+        vfs_i_free(inode);
+        return 1;
+    }
+    return 0;
+}
+
 struct v_dnode*
 vfs_d_alloc()
 {
     struct v_dnode* dnode = cake_grab(dnode_pile);
 struct v_dnode*
 vfs_d_alloc()
 {
     struct v_dnode* dnode = cake_grab(dnode_pile);
+    if (!dnode) {
+        lru_evict_half(dnode_lru);
+
+        if (!(dnode = cake_grab(dnode_pile))) {
+            return NULL;
+        }
+    }
+
     memset(dnode, 0, sizeof(*dnode));
     llist_init_head(&dnode->children);
     llist_init_head(&dnode->siblings);
     memset(dnode, 0, sizeof(*dnode));
     llist_init_head(&dnode->children);
     llist_init_head(&dnode->siblings);
@@ -527,17 +595,18 @@ vfs_d_alloc()
     dnode->ref_count = ATOMIC_VAR_INIT(0);
     dnode->name = HHSTR(vzalloc(VFS_NAME_MAXLEN), 0, 0);
 
     dnode->ref_count = ATOMIC_VAR_INIT(0);
     dnode->name = HHSTR(vzalloc(VFS_NAME_MAXLEN), 0, 0);
 
+    lru_use_one(dnode_lru, &dnode->lru);
+
     return dnode;
 }
 
 void
 vfs_d_free(struct v_dnode* dnode)
 {
     return dnode;
 }
 
 void
 vfs_d_free(struct v_dnode* dnode)
 {
-    if (dnode->ref_count) {
-        // it can be only freed if no one is refering
-        return;
-    }
-    if (dnode->inode && dnode->inode->link_count) {
+    assert(dnode->ref_count == 0);
+
+    if (dnode->inode) {
+        assert(dnode->inode->link_count > 0);
         dnode->inode->link_count--;
     }
 
         dnode->inode->link_count--;
     }
 
@@ -562,7 +631,7 @@ vfs_i_alloc(dev_t device_id, uint32_t inode_id)
     // 这也就是说,每个 v_inode 的 id
     // 必须要由设备ID,和该虚拟inode缓存所对应的物理inode
     // 相对于其所在的文件系统的id,进行组成!
     // 这也就是说,每个 v_inode 的 id
     // 必须要由设备ID,和该虚拟inode缓存所对应的物理inode
     // 相对于其所在的文件系统的id,进行组成!
-    inode_id = hash_32(inode_id ^ device_id, HASH_SIZE_BITS);
+    inode_id = hash_32(inode_id ^ (-device_id), HASH_SIZE_BITS);
     inode_id = (inode_id >> HASHBITS) ^ inode_id;
 
     struct hbucket* slot = &inode_cache[inode_id & HASH_MASK];
     inode_id = (inode_id >> HASHBITS) ^ inode_id;
 
     struct hbucket* slot = &inode_cache[inode_id & HASH_MASK];
@@ -570,20 +639,27 @@ vfs_i_alloc(dev_t device_id, uint32_t inode_id)
     hashtable_bucket_foreach(slot, pos, n, hash_list)
     {
         if (pos->id == inode_id) {
     hashtable_bucket_foreach(slot, pos, n, hash_list)
     {
         if (pos->id == inode_id) {
-            return pos;
+            goto done;
+        }
+    }
+
+    if (!(pos = cake_grab(inode_pile))) {
+        lru_evict_half(inode_lru);
+        if (!(pos = cake_grab(inode_pile))) {
+            return NULL;
         }
     }
 
         }
     }
 
-    pos = cake_grab(inode_pile);
     memset(pos, 0, sizeof(*pos));
 
     pos->id = inode_id;
     memset(pos, 0, sizeof(*pos));
 
     pos->id = inode_id;
-    pos->link_count = 1;
 
     mutex_init(&pos->lock);
 
     hlist_add(&slot->head, &pos->hash_list);
 
 
     mutex_init(&pos->lock);
 
     hlist_add(&slot->head, &pos->hash_list);
 
+done:
+    lru_use_one(inode_lru, &pos->lru);
     return pos;
 }
 
     return pos;
 }
 
@@ -633,8 +709,15 @@ __vfs_try_locate_file(const char* path,
 
     struct v_dnode* parent = *fdir;
     struct v_dnode* file_new = vfs_d_alloc();
 
     struct v_dnode* parent = *fdir;
     struct v_dnode* file_new = vfs_d_alloc();
+
+    if (!file_new) {
+        return ENOMEM;
+    }
+
     hstrcpy(&file_new->name, &name);
 
     hstrcpy(&file_new->name, &name);
 
+    lock_dnode(parent);
+
     if (!(errno = parent->inode->ops.create(parent->inode, file_new))) {
         *file = file_new;
 
     if (!(errno = parent->inode->ops.create(parent->inode, file_new))) {
         *file = file_new;
 
@@ -644,6 +727,8 @@ __vfs_try_locate_file(const char* path,
         vfs_d_free(file_new);
     }
 
         vfs_d_free(file_new);
     }
 
+    unlock_dnode(parent);
+
     return errno;
 }
 
     return errno;
 }
 
@@ -782,13 +867,14 @@ __DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
     __SYSCALL_INTERRUPTIBLE(
       { errno = file->ops.read(file->inode, buf, count, file->f_pos); })
 
     __SYSCALL_INTERRUPTIBLE(
       { errno = file->ops.read(file->inode, buf, count, file->f_pos); })
 
-    unlock_inode(file->inode);
-
     if (errno > 0) {
         file->f_pos += errno;
     if (errno > 0) {
         file->f_pos += errno;
+        unlock_inode(file->inode);
         return errno;
     }
 
         return errno;
     }
 
+    unlock_inode(file->inode);
+
 done:
     return DO_STATUS(errno);
 }
 done:
     return DO_STATUS(errno);
 }
@@ -814,13 +900,14 @@ __DEFINE_LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count)
     __SYSCALL_INTERRUPTIBLE(
       { errno = file->ops.write(file->inode, buf, count, file->f_pos); })
 
     __SYSCALL_INTERRUPTIBLE(
       { errno = file->ops.write(file->inode, buf, count, file->f_pos); })
 
-    unlock_inode(file->inode);
-
     if (errno > 0) {
         file->f_pos += errno;
     if (errno > 0) {
         file->f_pos += errno;
+        unlock_inode(file->inode);
         return errno;
     }
 
         return errno;
     }
 
+    unlock_inode(file->inode);
+
 done:
     return DO_STATUS(errno);
 }
 done:
     return DO_STATUS(errno);
 }
@@ -988,15 +1075,12 @@ __DEFINE_LXSYSCALL1(int, rmdir, const char*, pathname)
 
     lock_dnode(dnode);
 
 
     lock_dnode(dnode);
 
-    if (dnode->parent)
-        lock_dnode(dnode->parent);
-
     if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
         errno = EROFS;
         goto done;
     }
 
     if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
         errno = EROFS;
         goto done;
     }
 
-    if (dnode->ref_count || dnode->inode->open_count) {
+    if (dnode->ref_count > 1 || dnode->inode->open_count) {
         errno = EBUSY;
         goto done;
     }
         errno = EBUSY;
         goto done;
     }
@@ -1006,36 +1090,45 @@ __DEFINE_LXSYSCALL1(int, rmdir, const char*, pathname)
         goto done;
     }
 
         goto done;
     }
 
-    lock_inode(dnode->inode);
+    struct v_dnode* parent = dnode->parent;
+
+    if (!parent) {
+        errno = EINVAL;
+        goto done;
+    }
+
+    lock_dnode(parent);
+    lock_inode(parent->inode);
 
     if ((dnode->inode->itype & VFS_IFDIR)) {
 
     if ((dnode->inode->itype & VFS_IFDIR)) {
-        errno = dnode->inode->ops.rmdir(dnode->inode);
+        errno = parent->inode->ops.rmdir(parent->inode, dnode);
         if (!errno) {
             vfs_dcache_remove(dnode);
         if (!errno) {
             vfs_dcache_remove(dnode);
-            unlock_inode(dnode->inode);
-            vfs_d_free(dnode);
-
-            goto done;
         }
     } else {
         errno = ENOTDIR;
     }
 
         }
     } else {
         errno = ENOTDIR;
     }
 
-    unlock_inode(dnode->inode);
+    unlock_inode(parent->inode);
+    unlock_dnode(parent);
 
 done:
     unlock_dnode(dnode);
 
 done:
     unlock_dnode(dnode);
-    if (dnode->parent)
-        unlock_dnode(dnode->parent);
     return DO_STATUS(errno);
 }
 
 __DEFINE_LXSYSCALL1(int, mkdir, const char*, path)
 {
     return DO_STATUS(errno);
 }
 
 __DEFINE_LXSYSCALL1(int, mkdir, const char*, path)
 {
+    int errno = 0;
     struct v_dnode *parent, *dir = vfs_d_alloc();
     struct v_dnode *parent, *dir = vfs_d_alloc();
-    int errno =
-      vfs_walk(__current->cwd, path, &parent, &dir->name, VFS_WALK_PARENT);
-    if (errno) {
+
+    if (!dir) {
+        errno = ENOMEM;
+        goto done;
+    }
+
+    if ((errno = vfs_walk(
+           __current->cwd, path, &parent, &dir->name, VFS_WALK_PARENT))) {
         goto done;
     }
 
         goto done;
     }
 
@@ -1081,7 +1174,6 @@ __vfs_do_unlink(struct v_dnode* dnode)
         //  symlink case
         errno = inode->ops.unlink(inode);
         if (!errno) {
         //  symlink case
         errno = inode->ops.unlink(inode);
         if (!errno) {
-            inode->link_count--;
             vfs_dcache_remove(dnode);
             vfs_d_free(dnode);
         }
             vfs_dcache_remove(dnode);
             vfs_d_free(dnode);
         }
@@ -1244,14 +1336,14 @@ __DEFINE_LXSYSCALL2(int,
         errno = EROFS;
         goto done;
     }
         errno = EROFS;
         goto done;
     }
-    if (!dnode->inode->ops.symlink) {
+    if (!dnode->inode->ops.set_symlink) {
         errno = ENOTSUP;
         goto done;
     }
 
     lock_inode(dnode->inode);
 
         errno = ENOTSUP;
         goto done;
     }
 
     lock_inode(dnode->inode);
 
-    errno = dnode->inode->ops.symlink(dnode->inode, link_target);
+    errno = dnode->inode->ops.set_symlink(dnode->inode, link_target);
 
     unlock_inode(dnode->inode);
 
 
     unlock_inode(dnode->inode);
 
@@ -1421,11 +1513,17 @@ __DEFINE_LXSYSCALL2(int, rename, const char*, oldpath, const char*, newpath)
     errno = vfs_walk(target_parent, name.value, &target, NULL, 0);
     if (errno == ENOENT) {
         target = vfs_d_alloc();
     errno = vfs_walk(target_parent, name.value, &target, NULL, 0);
     if (errno == ENOENT) {
         target = vfs_d_alloc();
-        hstrcpy(&target->name, &name);
     } else if (errno) {
         goto done;
     }
 
     } else if (errno) {
         goto done;
     }
 
+    if (!target) {
+        errno = ENOMEM;
+        goto done;
+    }
+
+    hstrcpy(&target->name, &name);
+
     if (!(errno = vfs_do_rename(cur, target))) {
         vfs_d_free(target);
     }
     if (!(errno = vfs_do_rename(cur, target))) {
         vfs_d_free(target);
     }
index deb18d30a05577333e824f3c7c8d7ded5e093b55..2fc129841513dfcf3dbe0431e4068bc3c27bdfbc 100644 (file)
@@ -49,7 +49,8 @@ vmm_vmap(uintptr_t paddr, size_t size, pt_attr attr)
             current_addr = VMAP_START;
         }
     }
             current_addr = VMAP_START;
         }
     }
-    panick("vmm: out of memory");
+
+    return NULL;
 
 done:
     uintptr_t alloc_begin = current_addr - examed_size;
 
 done:
     uintptr_t alloc_begin = current_addr - examed_size;