feat: (vfs) write_page and read_page file operations
[lunaix-os.git] / lunaix-os / kernel / process / taskfs.c
1 #include <lunaix/dirent.h>
2 #include <lunaix/fs/taskfs.h>
3 #include <lunaix/fs/twimap.h>
4 #include <lunaix/mm/valloc.h>
5 #include <lunaix/process.h>
6 #include <lunaix/sched.h>
7
8 #include <klibc/stdio.h>
9 #include <klibc/string.h>
10
11 #define COUNTER_MASK ((1 << 16) - 1)
12
13 static struct hbucket* attr_export_table;
14 static DEFINE_LLIST(attributes);
15 static volatile int ino_cnt = 1;
16
17 int
18 taskfs_next_counter()
19 {
20     return (ino_cnt = ((ino_cnt + 1) & COUNTER_MASK) + 1);
21 }
22
23 inode_t
24 taskfs_inode_id(pid_t pid, int sub_counter)
25 {
26     return ((pid & (MAX_PROCESS - 1)) << 16) | (sub_counter & COUNTER_MASK);
27 }
28
29 int
30 taskfs_mknod(struct v_dnode* dnode, pid_t pid, int sub_counter, int itype)
31 {
32     inode_t ino = taskfs_inode_id(pid, sub_counter);
33
34     struct v_superblock* vsb = dnode->super_block;
35     struct v_inode* inode = vfs_i_find(vsb, ino);
36     if (!inode) {
37         if (!(inode = vfs_i_alloc(vsb))) {
38             return ENOMEM;
39         }
40         inode->id = ino;
41         inode->itype = itype;
42         vfs_i_addhash(inode);
43     }
44
45     vfs_assign_inode(dnode, inode);
46     return 0;
47 }
48
49 int
50 taskfs_readdir(struct v_file* file, struct dir_context* dctx)
51 {
52     struct v_inode* inode = file->inode;
53     pid_t pid = inode->id >> 16;
54     int counter = 0;
55
56     if ((inode->id & COUNTER_MASK)) {
57         return ENOTDIR;
58     }
59
60     if (pid) {
61         struct task_attribute *pos, *n;
62         llist_for_each(pos, n, &attributes, siblings)
63         {
64             if (counter == dctx->index) {
65                 dctx->read_complete_callback(
66                   dctx, pos->key_val, VFS_NAME_MAXLEN, DT_FILE);
67                 return 1;
68             }
69             counter++;
70         }
71         return 0;
72     }
73
74     char name[VFS_NAME_MAXLEN];
75     struct proc_info *root = get_process(pid), *pos, *n;
76     llist_for_each(pos, n, &root->tasks, tasks)
77     {
78         if (counter == dctx->index) {
79             ksnprintf(name, VFS_NAME_MAXLEN, "%d", pos->pid);
80             dctx->read_complete_callback(dctx, name, VFS_NAME_MAXLEN, DT_DIR);
81             return 1;
82         }
83         counter++;
84     }
85     return 0;
86 }
87
88 // ascii to pid
89 pid_t
90 taskfs_atop(const char* str)
91 {
92     pid_t t = 0;
93     int i = 0;
94     char c;
95     while ((c = str[i++])) {
96         if ('0' > c || c > '9') {
97             return -1;
98         }
99         t = t * 10 + (c - '0');
100     }
101     return t;
102 }
103
104 int
105 taskfs_dirlookup(struct v_inode* this, struct v_dnode* dnode)
106 {
107     pid_t pid = this->id >> 16;
108     struct proc_info* proc;
109
110     if (pid) {
111         struct task_attribute* tattr = taskfs_get_attr(&dnode->name);
112         if (!tattr || !(proc = get_process(pid)))
113             return ENOENT;
114
115         int errno =
116           taskfs_mknod(dnode, pid, taskfs_next_counter(), VFS_IFSEQDEV);
117         if (!errno) {
118             tattr->map_file->data = proc;
119             dnode->inode->data = tattr->map_file;
120             dnode->inode->default_fops = &twimap_file_ops;
121         }
122         return errno;
123     }
124
125     pid = taskfs_atop(dnode->name.value);
126
127     if (pid <= 0 || !(proc = get_process(pid))) {
128         return ENOENT;
129     }
130
131     return taskfs_mknod(dnode, pid, 0, VFS_IFDIR);
132 }
133
134 static struct v_file_ops taskfs_file_ops = { .close = default_file_close,
135                                              .read = default_file_read,
136                                              .read_page = default_file_read,
137                                              .write = default_file_write,
138                                              .write_page = default_file_write,
139                                              .readdir = taskfs_readdir,
140                                              .seek = default_file_seek };
141 static struct v_inode_ops taskfs_inode_ops = { .dir_lookup = taskfs_dirlookup,
142                                                .open = default_inode_open,
143                                                .mkdir = default_inode_mkdir,
144                                                .rmdir = default_inode_rmdir,
145                                                .rename = default_inode_rename };
146
147 void
148 taskfs_init_inode(struct v_superblock* vsb, struct v_inode* inode)
149 {
150     inode->default_fops = &taskfs_file_ops;
151     inode->ops = &taskfs_inode_ops;
152 }
153
154 static volatile struct v_superblock* taskfs_sb;
155
156 int
157 taskfs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
158 {
159     taskfs_sb = vsb;
160     vsb->ops.init_inode = taskfs_init_inode;
161
162     return taskfs_mknod(mount_point, 0, 0, VFS_IFDIR);
163 }
164
165 void
166 taskfs_invalidate(pid_t pid)
167 {
168     struct v_dnode *pos, *n;
169     struct v_inode* inode = vfs_i_find(taskfs_sb, taskfs_inode_id(pid, 0));
170
171     if (!inode)
172         return;
173
174     llist_for_each(pos, n, &inode->aka_dnodes, aka_list)
175     {
176         if (pos->ref_count > 1) {
177             continue;
178         }
179         vfs_d_free(pos);
180     }
181 }
182
183 #define ATTR_TABLE_LEN 16
184
185 void
186 taskfs_export_attr(const char* key, struct twimap* attr_map_file)
187 {
188     struct task_attribute* tattr = valloc(sizeof(*tattr));
189
190     tattr->map_file = attr_map_file;
191     tattr->key = HSTR(tattr->key_val, 0);
192     strncpy(tattr->key_val, key, 32);
193     hstr_rehash(&tattr->key, HSTR_FULL_HASH);
194
195     struct hbucket* slot = &attr_export_table[tattr->key.hash % ATTR_TABLE_LEN];
196     hlist_add(&slot->head, &tattr->attrs);
197     llist_append(&attributes, &tattr->siblings);
198 }
199
200 struct task_attribute*
201 taskfs_get_attr(struct hstr* key)
202 {
203     struct hbucket* slot = &attr_export_table[key->hash % ATTR_TABLE_LEN];
204     struct task_attribute *pos, *n;
205     hashtable_bucket_foreach(slot, pos, n, attrs)
206     {
207         if (HSTR_EQ(&pos->key, key)) {
208             return pos;
209         }
210     }
211     return NULL;
212 }
213
214 extern void
215 export_task_attr();
216
217 void
218 taskfs_init()
219 {
220     struct filesystem* taskfs = fsm_new_fs("taskfs", 5);
221     taskfs->mount = taskfs_mount;
222
223     fsm_register(taskfs);
224
225     attr_export_table = vcalloc(ATTR_TABLE_LEN, sizeof(struct hbucket));
226
227     export_task_attr();
228 }