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