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