001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021 #include <sos/assert.h>
022 #include <sos/list.h>
023 #include <sos/kmem_slab.h>
024 #include <sos/kmalloc.h>
025
026 #include "fs_nscache.h"
027
028
029
030
031
032
033
034 struct sos_fs_nscache_node
035 {
036
037 struct sos_fs_node *fs_node;
038
039 struct sos_fs_pathname name;
040
041
042
043 sos_count_t ref_cnt;
044
045
046
047
048
049
050
051 struct sos_fs_nscache_node *mounted_root;
052
053
054 struct sos_fs_nscache_node *mountpoint;
055
056
057 struct sos_fs_nscache_node *parent;
058
059
060 struct sos_fs_nscache_node *children;
061
062
063 struct sos_fs_nscache_node *siblings_prev, *siblings_next;
064 };
065
066
067
068 static struct sos_kslab_cache * cache_of_nscache_nodes;
069
070
071 sos_ret_t sos_fs_nscache_subsystem_setup()
072 {
073 cache_of_nscache_nodes
074 = sos_kmem_cache_create("fs_nscache",
075 sizeof(struct sos_fs_nscache_node),
076 3, 0,
077 SOS_KSLAB_CREATE_MAP | SOS_KSLAB_CREATE_ZERO);
078 if (! cache_of_nscache_nodes)
079 return -SOS_ENOMEM;
080
081 return SOS_OK;
082 };
083
084
085 sos_bool_t
086 sos_fs_pathname_eat_slashes(const struct sos_fs_pathname * path,
087 struct sos_fs_pathname * result)
088 {
089 sos_bool_t retval = FALSE;
090
091 result->contents = path->contents;
092 result->length = path->length;
093 while (result->length > 0)
094 {
095 if (*result->contents != '/')
096 break;
097
098 result->contents ++;
099 result->length --;
100 retval = TRUE;
101 }
102
103 if(result->length <= 0)
104 result->contents = NULL;
105
106 return retval;
107 }
108
109
110 static sos_bool_t
111 sos_fs_pathname_eat_non_slashes(const struct sos_fs_pathname * path,
112 struct sos_fs_pathname * result)
113 {
114 sos_bool_t retval = FALSE;
115
116 result->contents = path->contents;
117 result->length = path->length;
118 while (result->length > 0)
119 {
120 if (*result->contents == '/')
121 break;
122
123 result->contents ++;
124 result->length --;
125 retval = TRUE;
126 }
127
128 if(result->length <= 0)
129 result->contents = NULL;
130
131 return retval;
132 }
133
134
135 sos_bool_t
136 sos_fs_pathname_split_path(const struct sos_fs_pathname * path,
137 struct sos_fs_pathname * result_first_component,
138 struct sos_fs_pathname * result_remaining_path)
139 {
140 result_first_component->contents = path->contents;
141 result_first_component->length = path->length;
142
143
144 sos_fs_pathname_eat_slashes(result_first_component,
145 result_first_component);
146
147
148 sos_fs_pathname_eat_non_slashes(result_first_component,
149 result_remaining_path);
150 SOS_ASSERT_FATAL(result_remaining_path->length >= 0);
151 result_first_component->length -= result_remaining_path->length;
152
153
154 return (result_remaining_path->length > 0);
155 }
156
157
158 sos_bool_t fs_pathname_iseq(const struct sos_fs_pathname * p1,
159 const struct sos_fs_pathname * p2)
160 {
161 if (!p1->contents)
162 SOS_ASSERT_FATAL(p1->length == 0);
163 if (!p2->contents)
164 SOS_ASSERT_FATAL(p2->length == 0);
165
166 if (p1->length != p2->length)
167 return FALSE;
168
169 if (p1->length == 0)
170 return TRUE;
171
172 return (0 == memcmp(p1->contents, p2->contents, p1->length));
173 }
174
175
176 #define fs_pathname_isstr(str,path) \
177 ({ struct sos_fs_pathname _s; _s.contents = str; _s.length = sizeof(str)-1; \
178 fs_pathname_iseq(&_s, (path)); })
179
180
181 struct sos_fs_node *
182 sos_fs_nscache_get_fs_node(const struct sos_fs_nscache_node * nsnode)
183 {
184 return nsnode->fs_node;
185 }
186
187
188 sos_ret_t
189 sos_fs_nscache_get_parent(const struct sos_fs_nscache_node * nsnode,
190 struct sos_fs_nscache_node ** result_parent)
191 {
192 *result_parent = nsnode->parent;
193 if (*result_parent)
194 return SOS_OK;
195 return -SOS_ENOENT;
196 }
197
198
199 sos_ret_t
200 sos_fs_nscache_get_name(const struct sos_fs_nscache_node * nsnode,
201 struct sos_fs_pathname * result_pathname)
202 {
203 result_pathname->contents = nsnode->name.contents;
204 result_pathname->length = nsnode->name.length;
205 return SOS_OK;
206 }
207
208
209 sos_ret_t
210 sos_fs_nscache_get_ref_cnt(const struct sos_fs_nscache_node * nsnode)
211 {
212 return nsnode->ref_cnt;
213 }
214
215
216 sos_ret_t
217 sos_fs_nscache_lookup(struct sos_fs_nscache_node * cur_nsnode,
218 const struct sos_fs_pathname * node_name,
219 const struct sos_fs_nscache_node * root_nsnode,
220 struct sos_fs_nscache_node ** result_nsnode)
221 {
222 if (fs_pathname_isstr(".", node_name))
223 {
224 *result_nsnode = cur_nsnode;
225 }
226 else if (fs_pathname_isstr("..", node_name))
227 {
228
229 if (cur_nsnode == root_nsnode)
230 {
231
232 *result_nsnode = cur_nsnode;
233 }
234 else
235 {
236
237
238 for ( ; cur_nsnode->mountpoint ; cur_nsnode = cur_nsnode->mountpoint)
239 ;
240
241
242 SOS_ASSERT_FATAL(NULL != cur_nsnode->parent);
243 *result_nsnode = cur_nsnode->parent;
244 }
245
246
247 sos_fs_nscache_ref_node(*result_nsnode);
248 return SOS_OK;
249 }
250 else
251 {
252
253
254 int nb_children;
255 struct sos_fs_nscache_node * child;
256
257
258 list_foreach_named(cur_nsnode->children,
259 child, nb_children,
260 siblings_prev, siblings_next)
261 {
262 struct sos_fs_node * fs_node = cur_nsnode->fs_node;
263
264 if (fs_node->fs->nsnode_same_name)
265 {
266 if (fs_node->fs->
267 nsnode_same_name(child->name.contents,
268 child->name.length,
269 node_name->contents,
270 node_name->length))
271 break;
272 }
273 else
274 if (fs_pathname_iseq(& child->name,
275 node_name))
276 break;
277 }
278
279
280 if (! list_foreach_early_break(cur_nsnode->children,
281 child, nb_children))
282 return -SOS_ENOENT;
283
284
285 *result_nsnode = child;
286 }
287
288
289 for ( ; (*result_nsnode)->mounted_root ;
290 *result_nsnode = (*result_nsnode)->mounted_root)
291 ;
292
293
294 sos_fs_nscache_ref_node(*result_nsnode);
295
296 return SOS_OK;
297 }
298
299
300 sos_ret_t sos_fs_nscache_ref_node(struct sos_fs_nscache_node * nsnode)
301 {
302 SOS_ASSERT_FATAL(nsnode->ref_cnt > 0);
303 nsnode->ref_cnt ++;
304 return SOS_OK;
305 }
306
307
308
309 sos_ret_t _sos_fs_nscache_unref_node(struct sos_fs_nscache_node ** nsnode)
310 {
311 struct sos_fs_nscache_node * to_delete = NULL, *node;
312
313 node = *nsnode;
314 *nsnode = NULL;
315
316 while (node)
317 {
318
319 SOS_ASSERT_FATAL(node->ref_cnt > 0);
320 node->ref_cnt --;
321
322
323 if (node->ref_cnt > 0)
324 break;
325
326 if (node->parent)
327 {
328 struct sos_fs_nscache_node * parent = node->parent;
329
330 SOS_ASSERT_FATAL(node->parent->ref_cnt >= 1);
331
332 list_delete_named(parent->children, node,
333 siblings_prev, siblings_next);
334
335
336 }
337
338
339 list_add_tail_named(to_delete, node, siblings_prev, siblings_next);
340
341
342 node = node->parent;
343 }
344
345
346 while (! list_is_empty_named(to_delete, siblings_prev, siblings_next))
347 {
348 node = list_pop_head_named(to_delete, siblings_prev, siblings_next);
349 sos_fs_unref_fsnode(node->fs_node);
350 sos_kfree((sos_vaddr_t)node);
351 }
352
353 return SOS_OK;
354 }
355
356
357 sos_ret_t
358 sos_fs_nscache_add_new_child_node(struct sos_fs_nscache_node * parent,
359 const struct sos_fs_pathname * node_name,
360 struct sos_fs_node * fsnode,
361 struct sos_fs_nscache_node ** result_nsnode)
362 {
363 struct sos_fs_nscache_node * nsnode;
364
365
366 nsnode = (struct sos_fs_nscache_node*)
367 sos_kmem_cache_alloc(cache_of_nscache_nodes,
368 SOS_KSLAB_ALLOC_ATOMIC);
369 if (! nsnode)
370 return -SOS_ENOMEM;
371
372
373 if (node_name && (node_name->length > 0))
374 {
375 char * contents = (char*) sos_kmalloc(node_name->length,
376 SOS_KMALLOC_ATOMIC);
377 if (! contents)
378 {
379 sos_kfree((sos_vaddr_t)nsnode);
380 return -SOS_ENOMEM;
381 }
382
383 memcpy(contents, node_name->contents, node_name->length);
384 nsnode->name.contents = contents;
385 nsnode->name.length = node_name->length;
386 }
387
388
389 nsnode->ref_cnt = 1;
390 sos_fs_ref_fsnode(fsnode);
391 nsnode->fs_node = fsnode;
392
393
394 nsnode->parent = parent;
395 if (parent)
396 {
397 sos_fs_nscache_ref_node(parent);
398 list_add_head_named(parent->children, nsnode,
399 siblings_prev, siblings_next);
400 }
401
402 *result_nsnode = nsnode;
403 return SOS_OK;
404 }
405
406
407 sos_ret_t
408 sos_fs_nscache_add_existing_child_node(struct sos_fs_nscache_node * parent,
409 const struct sos_fs_pathname * node_name,
410 struct sos_fs_nscache_node * nsnode)
411 {
412 SOS_ASSERT_FATAL(nsnode->parent == NULL);
413
414
415 if (NULL != nsnode->name.contents)
416 {
417 sos_kfree((sos_vaddr_t)nsnode->name.contents);
418 }
419 memset(& nsnode->name, 0x0, sizeof(struct sos_fs_pathname));
420
421
422 if (node_name && (node_name->length > 0))
423 {
424 char * contents = (char*) sos_kmalloc(node_name->length,
425 SOS_KMALLOC_ATOMIC);
426 if (! contents)
427 {
428 sos_kfree((sos_vaddr_t)nsnode);
429 return -SOS_ENOMEM;
430 }
431
432 memcpy(contents, node_name->contents, node_name->length);
433 nsnode->name.contents = contents;
434 nsnode->name.length = node_name->length;
435 }
436
437
438
439 nsnode->parent = parent;
440 if (parent)
441 {
442 sos_fs_nscache_ref_node(parent);
443 list_add_head_named(parent->children, nsnode,
444 siblings_prev, siblings_next);
445 }
446 return SOS_OK;
447 }
448
449
450 sos_ret_t
451 sos_fs_nscache_disconnect_node(struct sos_fs_nscache_node * nsnode)
452 {
453 if (! nsnode->parent)
454 return SOS_OK;
455
456 list_delete_named(nsnode->parent->children, nsnode,
457 siblings_prev, siblings_next);
458 sos_fs_nscache_unref_node(nsnode->parent);
459 nsnode->parent = NULL;
460
461 return SOS_OK;
462 }
463
464
465 sos_ret_t
466 sos_fs_nscache_register_opened_file(struct sos_fs_nscache_node * nsnode,
467 struct sos_fs_opened_file * of)
468 {
469 of->direntry = nsnode;
470 sos_fs_nscache_ref_node(nsnode);
471 return SOS_OK;
472 }
473
474
475 sos_ret_t
476 sos_fs_nscache_mount(struct sos_fs_nscache_node * mountpoint,
477 struct sos_fs_nscache_node * mounted_root)
478 {
479 SOS_ASSERT_FATAL(NULL == mountpoint->mounted_root);
480 SOS_ASSERT_FATAL(NULL == mounted_root->mountpoint);
481 mountpoint->mounted_root = mounted_root;
482 mounted_root->mountpoint = mountpoint;
483 sos_fs_nscache_ref_node(mountpoint);
484 sos_fs_nscache_ref_node(mounted_root);
485
486 return SOS_OK;
487 }
488
489
490 sos_ret_t
491 sos_fs_nscache_umount(struct sos_fs_nscache_node * mounted_root)
492 {
493 struct sos_fs_manager_instance *fs;
494
495 SOS_ASSERT_FATAL(NULL != mounted_root->mountpoint);
496 SOS_ASSERT_FATAL(mounted_root->mountpoint->mounted_root == mounted_root);
497
498
499 SOS_ASSERT_FATAL(NULL == mounted_root->mounted_root);
500
501
502
503 SOS_ASSERT_FATAL(mounted_root->ref_cnt >= 3);
504 if (mounted_root->ref_cnt != 3)
505 return -SOS_EBUSY;
506
507 fs = mounted_root->fs_node->fs;
508 SOS_ASSERT_FATAL(NULL != fs);
509 SOS_ASSERT_FATAL(fs->root == mounted_root);
510
511
512 mounted_root->mountpoint->mounted_root = NULL;
513 sos_fs_nscache_unref_node(mounted_root->mountpoint);
514 mounted_root->mountpoint = NULL;
515 sos_fs_nscache_unref_node(mounted_root);
516
517
518 sos_fs_nscache_unref_node(fs->root);
519
520 return SOS_OK;
521 }
522
523 sos_bool_t
524 sos_fs_nscache_is_mountnode(const struct sos_fs_nscache_node * nsnode)
525 {
526 return ( (NULL != nsnode->mounted_root) || (NULL != nsnode->mountpoint) );
527 }