1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "mos/filesystem/inode.hpp"
4
5#include "mos/filesystem/page_cache.hpp"
6#include "mos/filesystem/vfs_types.hpp"
7#include "mos/syslog/printk.hpp"
8
9#include <mos/lib/structures/hashmap_common.hpp>
10#include <mos_stdlib.hpp>
11
12static bool vfs_generic_inode_drop(inode_t *inode)
13{
14 MOS_UNUSED(inode);
15 delete inode;
16 return true;
17}
18
19static bool inode_try_drop(inode_t *inode)
20{
21 if (inode->refcount == 0 && inode->nlinks == 0)
22 {
23 pr_dinfo2(vfs, "inode %p has 0 refcount and 0 nlinks, dropping", (void *) inode);
24
25 // drop the inode
26 mutex_acquire(mutex: &inode->cache.lock);
27 pagecache_flush_or_drop_all(icache: &inode->cache, drop_page: true);
28 mutex_release(mutex: &inode->cache.lock);
29
30 bool dropped = false;
31 if (inode->superblock->ops && inode->superblock->ops->drop_inode)
32 dropped = inode->superblock->ops->drop_inode(inode);
33 else
34 dropped = vfs_generic_inode_drop(inode);
35
36 if (!dropped)
37 pr_warn("inode %p has 0 refcount and 0 nlinks, but failed to be dropped", (void *) inode);
38
39 return dropped;
40 }
41
42 return false;
43}
44
45void inode_init(inode_t *inode, superblock_t *sb, u64 ino, file_type_t type)
46{
47 inode->superblock = sb;
48 inode->ino = ino;
49 inode->type = type;
50 inode->file_ops = NULL;
51 inode->nlinks = 1;
52 inode->perm = 0;
53 inode->private_data = NULL;
54 inode->refcount = 0;
55 inode->cache.owner = inode;
56 inode->cache.lock = 0;
57}
58
59inode_t *inode_create(superblock_t *sb, u64 ino, file_type_t type)
60{
61 inode_t *inode = mos::create<inode_t>();
62 inode_init(inode, sb, ino, type);
63 return inode;
64}
65
66void inode_ref(inode_t *inode)
67{
68 MOS_ASSERT(inode);
69 inode->refcount++;
70}
71
72bool inode_unref(inode_t *inode)
73{
74 MOS_ASSERT(inode);
75 MOS_ASSERT(inode->refcount > 0);
76 inode->refcount--;
77 return inode_try_drop(inode);
78}
79
80bool inode_unlink(inode_t *dir, dentry_t *dentry)
81{
82 inode_t *inode = dentry->inode;
83 MOS_ASSERT(dir && inode);
84 MOS_ASSERT(inode->nlinks > 0);
85
86 inode->nlinks--;
87 bool ok = true;
88 if (dir->ops->unlink)
89 ok = dir->ops->unlink(dir, dentry);
90
91 if (!ok)
92 {
93 inode->nlinks++;
94 return false;
95 }
96
97 const bool dropped = inode_try_drop(inode: dentry->inode);
98 MOS_ASSERT_X(!dropped, "inode %p was dropped accidentally, where dentry %p should be holding a reference", (void *) inode, (void *) dentry);
99
100 return true;
101}
102