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 | |
12 | static bool vfs_generic_inode_drop(inode_t *inode) |
13 | { |
14 | MOS_UNUSED(inode); |
15 | delete inode; |
16 | return true; |
17 | } |
18 | |
19 | static 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 | |
45 | void 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 | |
59 | inode_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 | |
66 | void inode_ref(inode_t *inode) |
67 | { |
68 | MOS_ASSERT(inode); |
69 | inode->refcount++; |
70 | } |
71 | |
72 | bool 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 | |
80 | bool 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 | |