taskfs fix up, minor refactoring
[lunaix-os.git] / lunaix-os / kernel / process / taskfs.c
1 #include <lunaix/fs/taskfs.h>
2 #include <lunaix/fs/twimap.h>
3 #include <lunaix/fs/api.h>
4 #include <lunaix/mm/valloc.h>
5 #include <lunaix/process.h>
6 #include <lunaix/sched.h>
7
8 #include <klibc/strfmt.h>
9 #include <klibc/string.h>
10
11 #include <usr/lunaix/dirent_defs.h>
12
13 #define COUNTER_MASK ((1 << 16) - 1)
14
15 static struct hbucket* attr_export_table;
16 static DEFINE_LIST(attributes);
17 static volatile int ino_cnt = 1;
18
19 extern struct scheduler sched_ctx;
20
21 static void
22 __destruct_inode(struct v_inode* inode)
23 {
24     vfree_safe(inode->data);
25 }
26
27 static int
28 taskfs_next_counter()
29 {
30     return (ino_cnt = ((ino_cnt + 1) & COUNTER_MASK) + 1);
31 }
32
33 static inode_t
34 taskfs_inode_id(pid_t pid, int sub_counter)
35 {
36     return ((pid & (MAX_PROCESS - 1)) << 16) | (sub_counter & COUNTER_MASK);
37 }
38
39 int
40 taskfs_mknod(struct v_dnode* dnode, pid_t pid, int sub_counter, int itype)
41 {
42     inode_t ino = taskfs_inode_id(pid, sub_counter);
43
44     struct v_superblock* vsb = dnode->super_block;
45     struct v_inode* inode = vfs_i_find(vsb, ino);
46     if (!inode) {
47         if (!(inode = vfs_i_alloc(vsb))) {
48             return ENOMEM;
49         }
50
51         inode->id = ino;
52         inode->itype = itype;
53         inode->destruct = __destruct_inode;
54         vfs_i_addhash(inode);
55     }
56
57     vfs_assign_inode(dnode, inode);
58     return 0;
59 }
60
61 static inline int
62 __report_task_entries(struct v_file* file, struct dir_context* dctx)
63 {
64     unsigned int counter = 0;
65     char name[VFS_NAME_MAXLEN];
66     struct proc_info *pos, *n;
67
68     llist_for_each(pos, n, sched_ctx.proc_list, tasks)
69     {
70         if (!fsapi_readdir_pos_entries_at(file, counter)) {
71             counter++;
72             continue;
73         }
74
75         ksnprintf(name, VFS_NAME_MAXLEN, "%d", pos->pid);
76         dctx->read_complete_callback(dctx, name, VFS_NAME_MAXLEN, DT_DIR);
77         return 1;
78     }
79
80     return 0;
81 }
82
83 static inline int
84 __report_task_attributes(struct v_file* file, struct dir_context* dctx)
85 {
86     unsigned int counter = 0;
87     struct task_attribute *pos, *n;
88
89     list_for_each(pos, n, attributes.first, siblings)
90     {
91         if (fsapi_readdir_pos_entries_at(file, counter)) {
92             dctx->read_complete_callback(
93                 dctx, HSTR_VAL(pos->key), VFS_NAME_MAXLEN, DT_FILE);
94             return 1;
95         }
96         counter++;
97     }
98
99     return 0;
100 }
101
102 int
103 taskfs_readdir(struct v_file* file, struct dir_context* dctx)
104 {
105     struct v_inode* inode = file->inode;
106     pid_t pid = inode->id >> 16;
107     unsigned int counter = 0;
108
109     if ((inode->id & COUNTER_MASK)) {
110         return ENOTDIR;
111     }
112
113     if (fsapi_handle_pseudo_dirent(file, dctx)) {
114         return 1;
115     }
116
117     if (pid) {
118         return __report_task_attributes(file, dctx);
119     }
120
121     return __report_task_entries(file, dctx);
122 }
123
124 // ascii to pid
125 static inline pid_t
126 taskfs_atop(const char* str)
127 {
128     pid_t t = 0;
129     int i = 0;
130     char c;
131     while ((c = str[i++])) {
132         if ('0' > c || c > '9') {
133             return -1;
134         }
135         t = t * 10 + (c - '0');
136     }
137     return t;
138 }
139
140 static inline int
141 __init_task_inode(pid_t pid, struct v_dnode* dnode)
142 {
143     struct twimap* map;
144     struct proc_info* proc;
145     struct task_attribute* tattr;
146     
147     tattr = taskfs_get_attr(&dnode->name);
148     if (!tattr || !(proc = get_process(pid)))
149         return ENOENT;
150
151     map = twimap_create(proc);
152     map->ops = tattr->ops;
153
154     dnode->inode->data = map;
155     dnode->inode->default_fops = &twimap_file_ops;
156     
157     return 0;
158 }
159
160 static int
161 __lookup_attribute(pid_t pid, struct v_dnode* dnode)
162 {
163     int errno;    
164
165     errno = taskfs_mknod(dnode, pid, taskfs_next_counter(), VFS_IFFILE);
166     if (errno) {
167         return errno;
168     }
169
170     return __init_task_inode(pid, dnode);
171 }
172
173 int
174 taskfs_dirlookup(struct v_inode* this, struct v_dnode* dnode)
175 {
176     pid_t pid = this->id >> 16;
177
178     if (pid) {
179         return __lookup_attribute(pid, dnode);
180     }
181
182     pid = taskfs_atop(dnode->name.value);
183
184     if (pid <= 0) {
185         return ENOENT;
186     }
187
188     return taskfs_mknod(dnode, pid, 0, VFS_IFDIR);
189 }
190
191 static struct v_file_ops taskfs_file_ops = { 
192     .close =        default_file_close,
193     .read =         default_file_read,
194     .read_page =    default_file_read_page,
195     .write =        default_file_write,
196     .write_page =   default_file_write_page,
197     .readdir =      taskfs_readdir,
198     .seek =         default_file_seek 
199 };
200
201 static struct v_inode_ops taskfs_inode_ops = { 
202     .dir_lookup =   taskfs_dirlookup,
203     .open =         default_inode_open,
204     .mkdir =        default_inode_mkdir,
205     .rmdir =        default_inode_rmdir,
206     .rename =       default_inode_rename 
207 };
208
209 static volatile struct v_superblock* taskfs_sb;
210
211 void
212 taskfs_init_inode(struct v_superblock* vsb, struct v_inode* inode)
213 {
214     inode->default_fops = &taskfs_file_ops;
215     inode->ops = &taskfs_inode_ops;
216 }
217
218 int
219 taskfs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
220 {
221     taskfs_sb = vsb;
222     vsb->ops.init_inode = taskfs_init_inode;
223
224     return taskfs_mknod(mount_point, 0, 0, VFS_IFDIR);
225 }
226
227 int
228 taskfs_unmount(struct v_superblock* vsb)
229 {
230     return 0;
231 }
232
233 void
234 taskfs_invalidate(pid_t pid)
235 {
236     struct v_dnode *pos, *n;
237     struct v_inode* inode;
238
239     inode = vfs_i_find(taskfs_sb, taskfs_inode_id(pid, 0));
240     if (!inode)
241         return;
242
243     llist_for_each(pos, n, &inode->aka_dnodes, aka_list)
244     {
245         if (pos->ref_count > 1) {
246             continue;
247         }
248         vfs_d_free(pos);
249     }
250
251     if (!inode->link_count) {
252         vfs_i_free(inode);
253     }
254 }
255
256 #define ATTR_TABLE_LEN 16
257 #define ATTR_KEY_LEN 32
258
259 void
260 taskfs_export_attr_mapping(const char* key, struct twimap_ops ops)
261 {
262     char* key_val;
263     struct hbucket* slot;
264     struct task_attribute* tattr;
265     
266     tattr = valloc(sizeof(*tattr));
267     key_val = valloc(ATTR_KEY_LEN);
268
269     tattr->ops = ops;
270     tattr->key = HSTR(key_val, 0);
271     strncpy(key_val, key, ATTR_KEY_LEN);
272     hstr_rehash(&tattr->key, HSTR_FULL_HASH);
273
274     slot = &attr_export_table[tattr->key.hash % ATTR_TABLE_LEN];
275     hlist_add(&slot->head, &tattr->attrs);
276     list_add(&attributes, &tattr->siblings);
277 }
278
279 struct task_attribute*
280 taskfs_get_attr(struct hstr* key)
281 {
282     struct hbucket* slot = &attr_export_table[key->hash % ATTR_TABLE_LEN];
283     struct task_attribute *pos, *n;
284     hashtable_bucket_foreach(slot, pos, n, attrs)
285     {
286         if (HSTR_EQ(&pos->key, key)) {
287             return pos;
288         }
289     }
290     return NULL;
291 }
292
293 extern void
294 export_task_attr();
295
296 void
297 taskfs_init()
298 {
299     struct filesystem* fs;
300     fs = fsapi_fs_declare("taskfs", FSTYPE_PSEUDO);
301     
302     fsapi_fs_set_mntops(fs, taskfs_mount, taskfs_unmount);
303     fsapi_fs_finalise(fs);
304
305     attr_export_table = vcalloc(ATTR_TABLE_LEN, sizeof(struct hbucket));
306
307     export_task_attr();
308 }
309 EXPORT_FILE_SYSTEM(taskfs, taskfs_init);