001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019 #include <sos/kmalloc.h>
020 #include <sos/klibc.h>
021 #include <sos/assert.h>
022 #include <sos/list.h>
023 #include <sos/ksynch.h>
024 #include <sos/uaccess.h>
025 #include <sos/physmem.h>
026
027 #include <sos/fs.h>
028 #include <sos/fs_nscache.h>
029
030 #include "fs_virtfs.h"
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055 struct virtfs_direntry
056 {
057 char * name;
058 struct sos_fs_node * fsnode;
059
060
061
062
063
064
065
066 sos_lcount_t creation_order;
067
068 struct virtfs_direntry * sibling_prev, * sibling_next;
069 };
070
071
072
073
074
075
076
077
078
079
080
081
082
083 struct virtfs_node
084 {
085
086 struct sos_fs_node super;
087
088 union
089 {
090
091 struct
092 {
093
094 sos_size_t size;
095 void * data;
096
097
098 struct sos_umem_vmm_mapped_resource mapres;
099 sos_count_t num_mappings;
100
101
102
103
104
105
106 } file;
107
108
109 struct
110 {
111
112
113
114 struct virtfs_direntry * list_entries;
115
116
117
118 sos_lcount_t top_creation_order;
119 } dir;
120 };
121
122
123 struct virtfs_node * prev, * next;
124 };
125
126
127
128
129
130
131
132
133
134
135
136 struct virtfs_instance
137 {
138
139 struct sos_fs_manager_instance super;
140
141
142
143 struct sos_kmutex lock;
144
145
146 struct virtfs_node * list_fsnodes;
147 };
148
149
150
151 static struct sos_fs_manager_type virtfs_type;
152
153
154
155 static sos_ret_t virtfs_mount(struct sos_fs_manager_type * this,
156 struct sos_fs_node * device,
157 const char * args,
158 struct sos_fs_manager_instance ** mounted_fs);
159
160
161 static sos_ret_t virtfs_umount(struct sos_fs_manager_type * this,
162 struct sos_fs_manager_instance * mounted_fs);
163
164
165 static sos_ret_t virtfs_new_mapping(struct sos_umem_vmm_vr *vr);
166
167
168 sos_ret_t sos_fs_virtfs_subsystem_setup()
169 {
170 strzcpy(virtfs_type.name, "virtfs", SOS_FS_MANAGER_NAME_MAXLEN);
171 virtfs_type.mount = virtfs_mount;
172 virtfs_type.umount = virtfs_umount;
173
174 return sos_fs_register_fs_type(& virtfs_type);
175 }
176
177
178
179
180
181
182
183
184 inline static void virtfs_lock(struct virtfs_node *a_node)
185 {
186 struct virtfs_instance * fs = (struct virtfs_instance*)a_node->super.fs->custom_data;
187 sos_kmutex_lock(& fs->lock, NULL);
188 }
189
190
191
192 inline static void virtfs_unlock(struct virtfs_node *a_node)
193 {
194 struct virtfs_instance * fs = (struct virtfs_instance*)a_node->super.fs->custom_data;
195 sos_kmutex_unlock(& fs->lock);
196 }
197
198
199
200
201 static sos_ret_t virtfs_resize(struct virtfs_node *this,
202 sos_size_t new_size)
203 {
204 void * new_data = NULL;
205
206 if (this->file.size == new_size)
207 return SOS_OK;
208
209
210 if (this->file.num_mappings > 0)
211 return -SOS_EBUSY;
212
213 if (new_size > 0)
214 {
215
216
217 sos_ui32_t npages = SOS_PAGE_ALIGN_SUP(new_size) / SOS_PAGE_SIZE;
218 new_data = (void*)sos_kmem_vmm_alloc(npages,
219 SOS_KMEM_VMM_MAP);
220 if (! new_data)
221 return -SOS_OK;
222 }
223
224
225 if (this->file.size < new_size)
226 {
227 if (this->file.size > 0)
228 memcpy(new_data, this->file.data, this->file.size);
229 if (new_size > this->file.size)
230 memset(new_data + this->file.size, 0x0,
231 new_size - this->file.size);
232 }
233 else if (new_size > 0)
234 memcpy(new_data, this->file.data, new_size);
235
236 if (this->file.data)
237 sos_kfree((sos_vaddr_t)this->file.data);
238 this->file.data = new_data;
239 this->file.size = new_size;
240
241 return SOS_OK;
242 }
243
244
245
246
247
248
249
250 static sos_ret_t
251 virtfs_duplicate_opened_file(struct sos_fs_opened_file *this,
252 const struct sos_process * for_owner,
253 struct sos_fs_opened_file **result)
254 {
255 *result = (struct sos_fs_opened_file*)
256 sos_kmalloc(sizeof(struct sos_fs_opened_file), 0);
257 if (! *result)
258 return -SOS_ENOMEM;
259
260 memcpy(*result, this, sizeof(*this));
261 (*result)->owner = for_owner;
262 return SOS_OK;
263 }
264
265
266 static sos_ret_t
267 virtfs_seek(struct sos_fs_opened_file *this,
268 sos_lsoffset_t offset,
269 sos_seek_whence_t whence,
270 sos_lsoffset_t * result_position)
271 {
272 sos_lsoffset_t ref_offs;
273 struct virtfs_node * virtfsnode;
274
275 virtfsnode = (struct virtfs_node*)
276 sos_fs_nscache_get_fs_node(this->direntry)->custom_data;
277
278 if ( (virtfsnode->super.type != SOS_FS_NODE_REGULAR_FILE)
279 && (virtfsnode->super.type != SOS_FS_NODE_SYMLINK))
280 return -SOS_ENOSUP;
281
282 *result_position = this->position;
283 switch (whence)
284 {
285 case SOS_SEEK_SET:
286 ref_offs = 0;
287 break;
288
289 case SOS_SEEK_CUR:
290 ref_offs = this->position;
291 break;
292
293 case SOS_SEEK_END:
294 ref_offs = virtfsnode->file.size;
295 break;
296
297 default:
298 return -SOS_EINVAL;
299 }
300
301 if (offset < -ref_offs)
302 return -SOS_EINVAL;
303
304 this->position = ref_offs + offset;
305 *result_position = this->position;
306 return SOS_OK;
307 }
308
309
310 static sos_ret_t virtfs_read(struct sos_fs_opened_file *this,
311 sos_uaddr_t dest_buf,
312 sos_size_t * len)
313 {
314 sos_ret_t retval;
315 struct virtfs_node * virtfsnode;
316
317 virtfsnode = (struct virtfs_node*)
318 sos_fs_nscache_get_fs_node(this->direntry)->custom_data;
319
320 if ( (virtfsnode->super.type != SOS_FS_NODE_REGULAR_FILE)
321 && (virtfsnode->super.type != SOS_FS_NODE_SYMLINK))
322 return -SOS_ENOSUP;
323
324 if (this->position >= virtfsnode->file.size)
325 {
326 *len = 0;
327 return SOS_OK;
328 }
329
330 virtfs_lock(virtfsnode);
331
332 if (this->position + *len >= virtfsnode->file.size)
333 *len = virtfsnode->file.size - this->position;
334
335 retval = sos_memcpy_to_user(dest_buf,
336 ((sos_vaddr_t)virtfsnode->file.data)
337 + this->position,
338 *len);
339 if (retval < 0)
340 {
341 virtfs_unlock(virtfsnode);
342 return retval;
343 }
344
345 this->position += retval;
346 *len = retval;
347
348 virtfs_unlock(virtfsnode);
349
350 return SOS_OK;
351 }
352
353
354 static sos_ret_t virtfs_write(struct sos_fs_opened_file *this,
355 sos_uaddr_t src_buf,
356 sos_size_t * len)
357 {
358 sos_ret_t retval;
359 struct virtfs_node * virtfsnode;
360
361 virtfsnode = (struct virtfs_node*)
362 sos_fs_nscache_get_fs_node(this->direntry)->custom_data;
363
364 if ( (virtfsnode->super.type != SOS_FS_NODE_REGULAR_FILE)
365 && (virtfsnode->super.type != SOS_FS_NODE_SYMLINK))
366 return -SOS_ENOSUP;
367
368 virtfs_lock(virtfsnode);
369 if (this->position + *len >= virtfsnode->file.size)
370 {
371
372 if (SOS_OK != virtfs_resize(virtfsnode, this->position + *len))
373 *len = virtfsnode->file.size - this->position;
374 }
375
376 retval = sos_memcpy_from_user(((sos_vaddr_t)virtfsnode->file.data)
377 + this->position,
378 src_buf,
379 *len);
380 if (retval < 0)
381 {
382 virtfs_unlock(virtfsnode);
383 return retval;
384 }
385
386 this->position += retval;
387 *len = retval;
388
389 virtfs_unlock(virtfsnode);
390
391 return SOS_OK;
392 }
393
394
395 static sos_ret_t virtfs_mmap(struct sos_fs_opened_file *this,
396 sos_uaddr_t *uaddr, sos_size_t size,
397 sos_ui32_t access_rights,
398 sos_ui32_t flags,
399 sos_luoffset_t offset)
400 {
401 struct virtfs_node * virtfsnode;
402
403 virtfsnode = (struct virtfs_node*)
404 sos_fs_nscache_get_fs_node(this->direntry)->custom_data;
405
406 if (virtfsnode->super.type != SOS_FS_NODE_REGULAR_FILE)
407 return -SOS_ENOSUP;
408
409 return sos_umem_vmm_map(sos_process_get_address_space(this->owner),
410 uaddr, size, access_rights,
411 flags, & virtfsnode->file.mapres, offset);
412 }
413
414
415 static sos_ret_t virtfs_readdir(struct sos_fs_opened_file *this,
416 struct sos_fs_dirent * result)
417 {
418
419
420
421
422 struct virtfs_direntry * direntry, * next_direntry;
423 struct virtfs_node * virtfsnode;
424 int nb;
425
426 virtfsnode = (struct virtfs_node*)
427 sos_fs_nscache_get_fs_node(this->direntry)->custom_data;
428 next_direntry = NULL;
429
430
431
432
433 if ((this->generation == virtfsnode->super.generation)
434 && (this->custom_data != NULL))
435 {
436 direntry = (struct virtfs_direntry*)this->custom_data;
437 next_direntry = direntry->sibling_next;
438
439
440 if (next_direntry == list_get_head_named(virtfsnode->dir.list_entries,
441 sibling_prev, sibling_next))
442 next_direntry = NULL;
443 }
444 else
445
446 {
447
448 next_direntry = NULL;
449 list_foreach_forward_named(virtfsnode->dir.list_entries,
450 direntry, nb,
451 sibling_prev, sibling_next)
452 {
453 if (direntry->creation_order <= this->position)
454 continue;
455
456 if (! next_direntry)
457 {
458 next_direntry = direntry;
459 continue;
460 }
461
462 if (direntry->creation_order < next_direntry->creation_order)
463 next_direntry = direntry;
464 }
465 }
466
467 if (! next_direntry)
468 {
469 this->custom_data = NULL;
470 this->position = 0;
471 return -SOS_ENOENT;
472 }
473
474
475 result->storage_location = ((sos_vaddr_t)next_direntry->fsnode);
476 result->offset_in_dirfile = next_direntry->creation_order;
477 result->type = next_direntry->fsnode->type;
478 result->namelen = strnlen(next_direntry->name,
479 SOS_FS_DIRENT_NAME_MAXLEN);
480 strzcpy(result->name, next_direntry->name, SOS_FS_DIRENT_NAME_MAXLEN);
481
482
483 this->position = next_direntry->creation_order;
484 this->custom_data = next_direntry;
485
486 return SOS_OK;
487 }
488
489
490 static struct sos_fs_ops_opened_file virtfs_ops_opened_file =
491 (struct sos_fs_ops_opened_file){
492 .seek = virtfs_seek,
493 .read = virtfs_read,
494 .write = virtfs_write,
495 .mmap = virtfs_mmap
496 };
497
498
499 static struct sos_fs_ops_opened_dir virtfs_ops_opened_dir =
500 (struct sos_fs_ops_opened_dir){
501 .readdir = virtfs_readdir
502 };
503
504
505
506
507
508
509 static sos_ret_t virtfs_stat_node(struct sos_fs_node * this,
510 struct sos_fs_stat * result)
511 {
512 struct virtfs_node * virtfsnode = (struct virtfs_node*)this->custom_data;
513
514
515 result->st_rdev.device_class = 0;
516 result->st_rdev.device_instance = 0;
517 if ( (this->type == SOS_FS_NODE_DEVICE_CHAR)
518 || (this->type == SOS_FS_NODE_DEVICE_BLOCK) )
519 {
520
521
522 result->st_rdev.device_class = this->dev_id.device_class;
523 result->st_rdev.device_instance = this->dev_id.device_instance;
524 }
525 else
526 {
527
528
529 struct sos_fs_node * rootdev = this->fs->device;
530 if (rootdev)
531 {
532 result->st_rdev.device_class = rootdev->dev_id.device_class;
533 result->st_rdev.device_instance = rootdev->dev_id.device_instance;
534 }
535 }
536
537 result->st_type = this->type;
538 result->st_storage_location = this->storage_location;
539 result->st_access_rights = this->access_rights;
540 result->st_nlink = this->ondisk_lnk_cnt;
541 if (this->type == SOS_FS_NODE_REGULAR_FILE)
542 result->st_size = virtfsnode->file.size;
543 else
544 result->st_size = 0;
545 return SOS_OK;
546 }
547
548
549 static sos_ret_t virtfs_truncate(struct sos_fs_node *this,
550 sos_lsoffset_t length)
551 {
552 sos_ret_t retval;
553 struct virtfs_node * virtfsnode;
554
555 virtfsnode = (struct virtfs_node*) this->custom_data;
556
557 if ( (virtfsnode->super.type != SOS_FS_NODE_REGULAR_FILE)
558 && (virtfsnode->super.type != SOS_FS_NODE_SYMLINK))
559 return -SOS_ENOSUP;
560
561 virtfs_lock(virtfsnode);
562 retval = virtfs_resize(virtfsnode, length);
563 virtfs_unlock(virtfsnode);
564
565 return retval;
566 }
567
568
569 static sos_ret_t virtfs_sync_node(struct sos_fs_node *this)
570 {
571
572 return SOS_OK;
573 }
574
575
576 static sos_ret_t virtfs_chmod_node(struct sos_fs_node * this,
577 sos_ui32_t access_rights)
578 {
579 this->access_rights = access_rights;
580 return SOS_OK;
581 }
582
583
584
585
586 static sos_ret_t virtfs_node_destructor(struct sos_fs_node * this)
587 {
588
589
590
591
592 if (this->ondisk_lnk_cnt <= 0)
593 {
594 struct virtfs_instance * virtfs = (struct virtfs_instance*)this->fs->custom_data;
595 struct virtfs_node * virtfsnode = (struct virtfs_node*)this->custom_data;
596
597 list_delete(virtfs->list_fsnodes, virtfsnode);
598 sos_kfree((sos_vaddr_t) this->custom_data);
599 }
600
601 return SOS_OK;
602 }
603
604
605 static struct sos_fs_node_ops_file virtfs_ops_file =
606 (struct sos_fs_node_ops_file){
607 .truncate = virtfs_truncate,
608 .stat = virtfs_stat_node,
609 .chmod = virtfs_chmod_node,
610 .sync = virtfs_sync_node
611 };
612
613
614 static sos_ret_t virtfs_new_opened_file(struct sos_fs_node * this,
615 const struct sos_process * owner,
616 sos_ui32_t open_flags,
617 struct sos_fs_opened_file ** result_of)
618 {
619 struct sos_fs_opened_file * of
620 = (struct sos_fs_opened_file*)sos_kmalloc(sizeof(*of), 0);
621 if (! of)
622 return -SOS_ENOMEM;
623
624 memset(of, 0x0, sizeof(*of));
625 of->owner = owner;
626 of->duplicate = virtfs_duplicate_opened_file;
627 of->open_flags = open_flags;
628 of->ops_file = & virtfs_ops_opened_file;
629 if (this->type == SOS_FS_NODE_DIRECTORY)
630 of->ops_dir = & virtfs_ops_opened_dir;
631
632 *result_of = of;
633 return SOS_OK;
634 }
635
636
637 static sos_ret_t virtfs_close_opened_file(struct sos_fs_node * this,
638 struct sos_fs_opened_file * of)
639 {
640 sos_kfree((sos_vaddr_t)of);
641 return SOS_OK;
642 }
643
644
645 static sos_ret_t virtfs_symlink_expand(struct sos_fs_node *this,
646 char const ** target,
647 sos_size_t * target_len)
648 {
649 struct virtfs_node * virtfsnode = (struct virtfs_node*)this->custom_data;
650
651 *target = virtfsnode->file.data;
652 *target_len = virtfsnode->file.size;
653
654 return SOS_OK;
655 }
656
657
658 static struct sos_fs_node_ops_symlink virtfs_ops_symlink
659 = (struct sos_fs_node_ops_symlink){
660 .expand = virtfs_symlink_expand
661 };
662
663
664 static sos_ret_t virtfs_dir_lookup(struct sos_fs_node *this,
665 const char * name, sos_ui16_t namelen,
666 sos_ui64_t * result_storage_location)
667 {
668 struct virtfs_node * virtfsnode = (struct virtfs_node*)this->custom_data;
669 struct virtfs_direntry * direntry;
670 int nbentries;
671
672 list_foreach_forward_named(virtfsnode->dir.list_entries,
673 direntry, nbentries,
674 sibling_prev, sibling_next)
675 {
676 if (!memcmp(name, direntry->name, namelen) && !direntry->name[namelen])
677 {
678 *result_storage_location = direntry->fsnode->storage_location;
679 return SOS_OK;
680 }
681 }
682
683 return -SOS_ENOENT;
684 }
685
686
687 static sos_ret_t virtfs_link(struct sos_fs_node *this,
688 const struct sos_process *actor,
689 const char * entry_name, sos_ui16_t entry_namelen,
690 struct sos_fs_node * node)
691 {
692 struct virtfs_node * parent = (struct virtfs_node*)this->custom_data;
693 struct virtfs_direntry * direntry;
694
695 direntry = (struct virtfs_direntry*)sos_kmalloc(sizeof(*direntry), 0);
696 if (! direntry)
697 return -SOS_ENOMEM;
698
699 direntry->name = (char*)sos_kmalloc(entry_namelen + 1, 0);
700 if (! direntry->name)
701 {
702 sos_kfree((sos_vaddr_t)direntry->name);
703 return -SOS_ENOMEM;
704 }
705
706 memcpy(direntry->name, entry_name, entry_namelen);
707 direntry->name[entry_namelen] = '\0';
708
709 direntry->fsnode = node;
710 node->ondisk_lnk_cnt ++;
711 this->ondisk_lnk_cnt ++;
712 list_add_tail_named(parent->dir.list_entries, direntry,
713 sibling_prev, sibling_next);
714
715
716
717 parent->dir.top_creation_order ++;
718 direntry->creation_order = parent->dir.top_creation_order;
719
720 return SOS_OK;
721 }
722
723
724 static sos_ret_t
725 virtfs_unlink(struct sos_fs_node *this,
726 const struct sos_process *actor,
727 const char * entry_name, sos_ui16_t entry_namelen)
728 {
729 struct virtfs_node * parent = (struct virtfs_node*)this->custom_data;
730 struct virtfs_direntry * direntry;
731 int nbentries;
732
733 list_foreach_forward_named(parent->dir.list_entries,
734 direntry, nbentries,
735 sibling_prev, sibling_next)
736 {
737 if (!memcmp(entry_name, direntry->name, entry_namelen)
738 && !direntry->name[entry_namelen])
739 {
740 list_delete_named(parent->dir.list_entries, direntry,
741 sibling_prev, sibling_next);
742 direntry->fsnode->ondisk_lnk_cnt --;
743 this->ondisk_lnk_cnt --;
744 sos_kfree((sos_vaddr_t)direntry);
745 return SOS_OK;
746 }
747 }
748
749 return -SOS_ENOENT;
750 }
751
752
753 static struct sos_fs_node_ops_dir virtfs_ops_dir
754 = (struct sos_fs_node_ops_dir){
755 .lookup = virtfs_dir_lookup,
756 .link = virtfs_link,
757 .unlink = virtfs_unlink
758 };
759
760
761
762
763
764
765
766
767
768
769
770 static sos_ret_t
771 virtfs_fetch_node_from_disk(struct sos_fs_manager_instance * this,
772 sos_ui64_t storage_location,
773 struct sos_fs_node ** result)
774 {
775
776 struct virtfs_node * virtfsnode;
777
778 virtfsnode = (struct virtfs_node *)((sos_vaddr_t)storage_location);
779 *result = & virtfsnode->super;
780
781 return SOS_OK;
782 }
783
784
785 static sos_ret_t
786 virtfs_allocate_new_node(struct sos_fs_manager_instance * this,
787 sos_fs_node_type_t type,
788 const struct sos_process * creator,
789 sos_ui32_t access_rights,
790 sos_ui32_t flags,
791 struct sos_fs_node ** result)
792 {
793 struct virtfs_node * virtfsnode;
794
795
796 if ((type != SOS_FS_NODE_REGULAR_FILE)
797 && (type != SOS_FS_NODE_SYMLINK)
798 && (type != SOS_FS_NODE_DIRECTORY)
799 && (type != SOS_FS_NODE_DEVICE_CHAR)
800 && (type != SOS_FS_NODE_DEVICE_BLOCK))
801 return -SOS_ENOSUP;
802
803 virtfsnode = (struct virtfs_node*) sos_kmalloc(sizeof(*virtfsnode), 0);
804 if (! virtfsnode)
805 return -SOS_ENOMEM;
806
807 memset(virtfsnode, 0x0, sizeof(*virtfsnode));
808 *result = & virtfsnode->super;
809
810
811 (*result)->inmem_ref_cnt = 1;
812 (*result)->custom_data = virtfsnode;
813 (*result)->storage_location = (sos_ui64_t)((sos_vaddr_t)virtfsnode);
814 (*result)->type = type;
815 (*result)->access_rights = access_rights;
816 (*result)->destructor = virtfs_node_destructor;
817 (*result)->ops_file = & virtfs_ops_file;
818
819
820
821 if ((type != SOS_FS_NODE_DEVICE_CHAR)
822 && (type != SOS_FS_NODE_DEVICE_BLOCK))
823 {
824 (*result)->new_opened_file = virtfs_new_opened_file;
825 (*result)->close_opened_file = virtfs_close_opened_file;
826 }
827
828 if (type == SOS_FS_NODE_SYMLINK)
829 (*result)->ops_symlink = & virtfs_ops_symlink;
830 else if (type == SOS_FS_NODE_DIRECTORY)
831 (*result)->ops_dir = & virtfs_ops_dir;
832
833
834 if (type == SOS_FS_NODE_REGULAR_FILE)
835 {
836 virtfsnode->file.mapres.allowed_access_rights
837 = SOS_VM_MAP_PROT_READ
838 | SOS_VM_MAP_PROT_WRITE
839 | SOS_VM_MAP_PROT_EXEC;
840 virtfsnode->file.mapres.custom_data = virtfsnode;
841 virtfsnode->file.mapres.mmap = virtfs_new_mapping;
842 }
843
844 list_add_tail(((struct virtfs_instance*)this->custom_data)->list_fsnodes,
845 virtfsnode);
846
847 return SOS_OK;
848 }
849
850
851
852
853
854
855 static sos_ret_t virtfs_mount(struct sos_fs_manager_type * this,
856 struct sos_fs_node * device,
857 const char * args,
858 struct sos_fs_manager_instance ** mounted_fs)
859 {
860 sos_ret_t retval;
861 struct virtfs_instance * fs;
862 struct sos_fs_node * fsnode_root;
863 struct sos_hash_table * hash;
864
865 *mounted_fs = (struct sos_fs_manager_instance*)NULL;
866
867
868 hash = sos_hash_create("virtfs H", struct sos_fs_node,
869 sos_hash_ui64,
870 sos_hash_key_eq_ui64, 17,
871 storage_location, hlink_nodecache);
872 if (! hash)
873 return -SOS_ENOMEM;
874
875 fs = (struct virtfs_instance*)
876 sos_kmalloc(sizeof(struct virtfs_instance), 0);
877 if (! fs)
878 {
879 sos_hash_dispose(hash);
880 return -SOS_ENOMEM;
881 }
882
883 memset(fs, 0x0, sizeof(struct virtfs_instance));
884 retval = sos_kmutex_init(& fs->lock, "virtfs", SOS_KWQ_ORDER_FIFO);
885 if (SOS_OK != retval)
886 {
887 sos_hash_dispose(hash);
888 sos_kfree((sos_vaddr_t) fs);
889 return retval;
890 }
891 fs->super.custom_data = fs;
892 fs->super.fs_type = this;
893 fs->super.allocate_new_node = virtfs_allocate_new_node;
894 fs->super.fetch_node_from_disk = virtfs_fetch_node_from_disk;
895 fs->super.nodecache = hash;
896
897 retval = virtfs_allocate_new_node(& fs->super, SOS_FS_NODE_DIRECTORY,
898 NULL,
899 SOS_FS_READABLE | SOS_FS_WRITABLE
900 | SOS_FS_EXECUTABLE,
901 0,
902 & fsnode_root);
903 if (SOS_OK != retval)
904 {
905 sos_hash_dispose(hash);
906 sos_kmutex_dispose(& fs->lock);
907 sos_kfree((sos_vaddr_t) fs);
908 return retval;
909 }
910
911 retval = sos_fs_register_fs_instance(& fs->super, fsnode_root);
912 sos_fs_unref_fsnode(fsnode_root);
913 if (SOS_OK != retval)
914 {
915 sos_hash_dispose(hash);
916 sos_kmutex_dispose(& fs->lock);
917 sos_kfree((sos_vaddr_t) fs);
918 return retval;
919 }
920
921 *mounted_fs = & fs->super;
922 return SOS_OK;
923 }
924
925
926 static sos_ret_t virtfs_umount(struct sos_fs_manager_type * this,
927 struct sos_fs_manager_instance * mounted_fs)
928 {
929 struct virtfs_instance * virtfs = (struct virtfs_instance*)mounted_fs->custom_data;
930
931 sos_hash_dispose(virtfs->super.nodecache);
932 while (! list_is_empty(virtfs->list_fsnodes))
933 {
934 struct virtfs_node * virtfsnode = list_pop_head(virtfs->list_fsnodes);
935
936 if (virtfsnode->super.type == SOS_FS_NODE_REGULAR_FILE)
937 {
938 if (virtfsnode->file.size > 0)
939 sos_kfree((sos_vaddr_t) virtfsnode->file.data);
940 }
941 else if (virtfsnode->super.type == SOS_FS_NODE_DIRECTORY)
942 {
943 while (! list_is_empty_named(virtfsnode->dir.list_entries,
944 sibling_prev, sibling_next))
945 {
946 struct virtfs_direntry * direntry
947 = list_pop_head_named(virtfsnode->dir.list_entries,
948 sibling_prev, sibling_next);
949
950 sos_kfree((sos_vaddr_t)direntry->name);
951 sos_kfree((sos_vaddr_t)direntry);
952 }
953 }
954
955 sos_kfree((sos_vaddr_t)virtfsnode);
956 }
957
958 sos_fs_unregister_fs_instance(& virtfs->super);
959 sos_kmutex_dispose(& virtfs->lock);
960 sos_kfree((sos_vaddr_t)virtfs);
961 return SOS_OK;
962 }
963
964
965
966
967
968 inline static struct virtfs_node *
969 get_virtfsnode_of_vr(struct sos_umem_vmm_vr * vr)
970 {
971 struct sos_umem_vmm_mapped_resource *mr
972 = sos_umem_vmm_get_mapped_resource_of_vr(vr);
973
974 return (struct virtfs_node *)mr->custom_data;
975 }
976
977
978 static void virtfs_map_ref(struct sos_umem_vmm_vr * vr)
979 {
980 struct virtfs_node * virtfsnode = get_virtfsnode_of_vr(vr);
981 sos_fs_ref_fsnode(& virtfsnode->super);
982 virtfsnode->file.num_mappings ++;
983 }
984
985
986 static void virtfs_map_unref(struct sos_umem_vmm_vr * vr)
987 {
988 struct virtfs_node * virtfsnode = get_virtfsnode_of_vr(vr);
989
990 SOS_ASSERT_FATAL(virtfsnode->file.num_mappings > 0);
991 virtfsnode->file.num_mappings --;
992
993 _sos_fs_unref_fsnode(& virtfsnode->super);
994 }
995
996
997 static sos_ret_t virtfs_map_page_in(struct sos_umem_vmm_vr * vr,
998 sos_uaddr_t uaddr,
999 sos_bool_t write_access)
1000 {
1001 struct virtfs_node * virtfsnode = get_virtfsnode_of_vr(vr);
1002 sos_luoffset_t offset = uaddr - sos_umem_vmm_get_start_of_vr(vr);
1003 sos_ret_t retval = SOS_OK;
1004 sos_paddr_t ppage_paddr;
1005
1006
1007 if (SOS_PAGE_ALIGN_SUP(offset) > virtfsnode->file.size)
1008 return -SOS_EFAULT;
1009
1010
1011 ppage_paddr = sos_paging_get_paddr(SOS_PAGE_ALIGN_INF(virtfsnode->file.data
1012 + offset));
1013
1014
1015 if (! ppage_paddr)
1016 return -SOS_EFAULT;
1017
1018
1019 retval = sos_paging_map(ppage_paddr,
1020 SOS_PAGE_ALIGN_INF(uaddr),
1021 TRUE,
1022 sos_umem_vmm_get_prot_of_vr(vr));
1023
1024 return retval;
1025 }
1026
1027
1028 static struct sos_umem_vmm_vr_ops virtfs_map_ops
1029 = (struct sos_umem_vmm_vr_ops){
1030 .ref = virtfs_map_ref,
1031 .unref = virtfs_map_unref,
1032 .page_in = virtfs_map_page_in
1033 };
1034
1035 static sos_ret_t virtfs_new_mapping(struct sos_umem_vmm_vr *vr)
1036 {
1037 struct virtfs_node * virtfsnode = get_virtfsnode_of_vr(vr);
1038 sos_size_t reqsize;
1039 sos_ret_t retval;
1040
1041 reqsize = sos_umem_vmm_get_offset_in_resource(vr);
1042 reqsize += sos_umem_vmm_get_size_of_vr(vr);
1043
1044
1045 if (reqsize > virtfsnode->file.size)
1046 {
1047 retval = virtfs_resize(virtfsnode,
1048 SOS_PAGE_ALIGN_SUP(reqsize));
1049 if (SOS_OK != retval)
1050 return retval;
1051 }
1052
1053 return sos_umem_vmm_set_ops_of_vr(vr, &virtfs_map_ops);
1054 }