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 result->st_type = this->type;
511 result->st_storage_location = this->storage_location;
512 result->st_access_rights = this->access_rights;
513 result->st_nlink = this->ondisk_lnk_cnt;
514 if (this->type == SOS_FS_NODE_REGULAR_FILE)
515 result->st_size = virtfsnode->file.size;
516 else
517 result->st_size = 0;
518 return SOS_OK;
519 }
520
521
522 static sos_ret_t virtfs_truncate(struct sos_fs_node *this,
523 sos_lsoffset_t length)
524 {
525 sos_ret_t retval;
526 struct virtfs_node * virtfsnode;
527
528 virtfsnode = (struct virtfs_node*) this->custom_data;
529
530 if ( (virtfsnode->super.type != SOS_FS_NODE_REGULAR_FILE)
531 && (virtfsnode->super.type != SOS_FS_NODE_SYMLINK))
532 return -SOS_ENOSUP;
533
534 virtfs_lock(virtfsnode);
535 retval = virtfs_resize(virtfsnode, length);
536 virtfs_unlock(virtfsnode);
537
538 return retval;
539 }
540
541
542 static sos_ret_t virtfs_sync_node(struct sos_fs_node *this)
543 {
544
545 return SOS_OK;
546 }
547
548
549 static sos_ret_t virtfs_chmod_node(struct sos_fs_node * this,
550 sos_ui32_t access_rights)
551 {
552 this->access_rights = access_rights;
553 return SOS_OK;
554 }
555
556
557
558
559 static sos_ret_t virtfs_node_destructor(struct sos_fs_node * this)
560 {
561
562
563
564
565 if (this->ondisk_lnk_cnt <= 0)
566 {
567 struct virtfs_instance * virtfs = (struct virtfs_instance*)this->fs->custom_data;
568 struct virtfs_node * virtfsnode = (struct virtfs_node*)this->custom_data;
569
570 list_delete(virtfs->list_fsnodes, virtfsnode);
571 sos_kfree((sos_vaddr_t) this->custom_data);
572 }
573
574 return SOS_OK;
575 }
576
577
578 static struct sos_fs_node_ops_file virtfs_ops_file =
579 (struct sos_fs_node_ops_file){
580 .truncate = virtfs_truncate,
581 .stat = virtfs_stat_node,
582 .sync = virtfs_sync_node,
583 .chmod = virtfs_chmod_node
584 };
585
586
587 static sos_ret_t virtfs_new_opened_file(struct sos_fs_node * this,
588 const struct sos_process * owner,
589 sos_ui32_t open_flags,
590 struct sos_fs_opened_file ** result_of)
591 {
592 struct sos_fs_opened_file * of
593 = (struct sos_fs_opened_file*)sos_kmalloc(sizeof(*of), 0);
594 if (! of)
595 return -SOS_ENOMEM;
596
597 memset(of, 0x0, sizeof(*of));
598 of->owner = owner;
599 of->duplicate = virtfs_duplicate_opened_file;
600 of->open_flags = open_flags;
601 of->ops_file = & virtfs_ops_opened_file;
602 if (this->type == SOS_FS_NODE_DIRECTORY)
603 of->ops_dir = & virtfs_ops_opened_dir;
604
605 *result_of = of;
606 return SOS_OK;
607 }
608
609
610 static sos_ret_t virtfs_close_opened_file(struct sos_fs_node * this,
611 struct sos_fs_opened_file * of)
612 {
613 sos_kfree((sos_vaddr_t)of);
614 return SOS_OK;
615 }
616
617
618 static sos_ret_t virtfs_symlink_expand(struct sos_fs_node *this,
619 char const ** target,
620 sos_size_t * target_len)
621 {
622 struct virtfs_node * virtfsnode = (struct virtfs_node*)this->custom_data;
623
624 *target = virtfsnode->file.data;
625 *target_len = virtfsnode->file.size;
626
627 return SOS_OK;
628 }
629
630
631 static struct sos_fs_node_ops_symlink virtfs_ops_symlink
632 = (struct sos_fs_node_ops_symlink){
633 .expand = virtfs_symlink_expand
634 };
635
636
637 static sos_ret_t virtfs_dir_lookup(struct sos_fs_node *this,
638 const char * name, sos_ui16_t namelen,
639 sos_ui64_t * result_storage_location)
640 {
641 struct virtfs_node * virtfsnode = (struct virtfs_node*)this->custom_data;
642 struct virtfs_direntry * direntry;
643 int nbentries;
644
645 list_foreach_forward_named(virtfsnode->dir.list_entries,
646 direntry, nbentries,
647 sibling_prev, sibling_next)
648 {
649 if (!memcmp(name, direntry->name, namelen) && !direntry->name[namelen])
650 {
651 *result_storage_location = direntry->fsnode->storage_location;
652 return SOS_OK;
653 }
654 }
655
656 return -SOS_ENOENT;
657 }
658
659
660 static sos_ret_t virtfs_link(struct sos_fs_node *this,
661 const struct sos_process *actor,
662 const char * entry_name, sos_ui16_t entry_namelen,
663 struct sos_fs_node * node)
664 {
665 struct virtfs_node * parent = (struct virtfs_node*)this->custom_data;
666 struct virtfs_direntry * direntry;
667
668 direntry = (struct virtfs_direntry*)sos_kmalloc(sizeof(*direntry), 0);
669 if (! direntry)
670 return -SOS_ENOMEM;
671
672 direntry->name = (char*)sos_kmalloc(entry_namelen + 1, 0);
673 if (! direntry->name)
674 {
675 sos_kfree((sos_vaddr_t)direntry->name);
676 return -SOS_ENOMEM;
677 }
678
679 memcpy(direntry->name, entry_name, entry_namelen);
680 direntry->name[entry_namelen] = '\0';
681
682 direntry->fsnode = node;
683 node->ondisk_lnk_cnt ++;
684 this->ondisk_lnk_cnt ++;
685 list_add_tail_named(parent->dir.list_entries, direntry,
686 sibling_prev, sibling_next);
687
688
689
690 parent->dir.top_creation_order ++;
691 direntry->creation_order = parent->dir.top_creation_order;
692
693 return SOS_OK;
694 }
695
696
697 static sos_ret_t
698 virtfs_unlink(struct sos_fs_node *this,
699 const struct sos_process *actor,
700 const char * entry_name, sos_ui16_t entry_namelen)
701 {
702 struct virtfs_node * parent = (struct virtfs_node*)this->custom_data;
703 struct virtfs_direntry * direntry;
704 int nbentries;
705
706 list_foreach_forward_named(parent->dir.list_entries,
707 direntry, nbentries,
708 sibling_prev, sibling_next)
709 {
710 if (!memcmp(entry_name, direntry->name, entry_namelen)
711 && !direntry->name[entry_namelen])
712 {
713 list_delete_named(parent->dir.list_entries, direntry,
714 sibling_prev, sibling_next);
715 direntry->fsnode->ondisk_lnk_cnt --;
716 this->ondisk_lnk_cnt --;
717 sos_kfree((sos_vaddr_t)direntry);
718 return SOS_OK;
719 }
720 }
721
722 return -SOS_ENOENT;
723 }
724
725
726 static struct sos_fs_node_ops_dir virtfs_ops_dir
727 = (struct sos_fs_node_ops_dir){
728 .lookup = virtfs_dir_lookup,
729 .link = virtfs_link,
730 .unlink = virtfs_unlink
731 };
732
733
734
735
736
737
738
739
740
741
742
743 static sos_ret_t
744 virtfs_fetch_node_from_disk(struct sos_fs_manager_instance * this,
745 sos_ui64_t storage_location,
746 struct sos_fs_node ** result)
747 {
748
749 struct virtfs_node * virtfsnode;
750
751 virtfsnode = (struct virtfs_node *)((sos_vaddr_t)storage_location);
752 *result = & virtfsnode->super;
753
754 return SOS_OK;
755 }
756
757
758 static sos_ret_t
759 virtfs_allocate_new_node(struct sos_fs_manager_instance * this,
760 sos_fs_node_type_t type,
761 const struct sos_process * creator,
762 sos_ui32_t access_rights,
763 sos_ui32_t flags,
764 struct sos_fs_node ** result)
765 {
766 struct virtfs_node * virtfsnode;
767
768
769 if ((type != SOS_FS_NODE_REGULAR_FILE)
770 && (type != SOS_FS_NODE_SYMLINK)
771 && (type != SOS_FS_NODE_DIRECTORY))
772 return -SOS_ENOSUP;
773
774 virtfsnode = (struct virtfs_node*) sos_kmalloc(sizeof(*virtfsnode), 0);
775 if (! virtfsnode)
776 return -SOS_ENOMEM;
777
778 memset(virtfsnode, 0x0, sizeof(*virtfsnode));
779 *result = & virtfsnode->super;
780
781
782 (*result)->inmem_ref_cnt = 1;
783 (*result)->custom_data = virtfsnode;
784 (*result)->storage_location = (sos_ui64_t)((sos_vaddr_t)virtfsnode);
785 (*result)->type = type;
786 (*result)->access_rights = access_rights;
787 (*result)->destructor = virtfs_node_destructor;
788 (*result)->new_opened_file = virtfs_new_opened_file;
789 (*result)->close_opened_file = virtfs_close_opened_file;
790 (*result)->ops_file = & virtfs_ops_file;
791 if (type == SOS_FS_NODE_SYMLINK)
792 (*result)->ops_symlink = & virtfs_ops_symlink;
793 else if (type == SOS_FS_NODE_DIRECTORY)
794 (*result)->ops_dir = & virtfs_ops_dir;
795
796
797 if (type == SOS_FS_NODE_REGULAR_FILE)
798 {
799 virtfsnode->file.mapres.allowed_access_rights
800 = SOS_VM_MAP_PROT_READ
801 | SOS_VM_MAP_PROT_WRITE
802 | SOS_VM_MAP_PROT_EXEC;
803 virtfsnode->file.mapres.custom_data = virtfsnode;
804 virtfsnode->file.mapres.mmap = virtfs_new_mapping;
805 }
806
807 list_add_tail(((struct virtfs_instance*)this->custom_data)->list_fsnodes,
808 virtfsnode);
809
810 return SOS_OK;
811 }
812
813
814
815
816
817
818 static sos_ret_t virtfs_mount(struct sos_fs_manager_type * this,
819 struct sos_fs_node * device,
820 const char * args,
821 struct sos_fs_manager_instance ** mounted_fs)
822 {
823 sos_ret_t retval;
824 struct virtfs_instance * fs;
825 struct sos_fs_node * fsnode_root;
826 struct sos_hash_table * hash;
827
828 *mounted_fs = (struct sos_fs_manager_instance*)NULL;
829
830
831 hash = sos_hash_create("virtfs H", struct sos_fs_node,
832 sos_hash_ui64,
833 sos_hash_key_eq_ui64, 17,
834 storage_location, hlink_nodecache);
835 if (! hash)
836 return -SOS_ENOMEM;
837
838 fs = (struct virtfs_instance*)
839 sos_kmalloc(sizeof(struct virtfs_instance), 0);
840 if (! fs)
841 {
842 sos_hash_dispose(hash);
843 return -SOS_ENOMEM;
844 }
845
846 memset(fs, 0x0, sizeof(struct virtfs_instance));
847 retval = sos_kmutex_init(& fs->lock, "virtfs", SOS_KWQ_ORDER_FIFO);
848 if (SOS_OK != retval)
849 {
850 sos_hash_dispose(hash);
851 sos_kfree((sos_vaddr_t) fs);
852 return retval;
853 }
854 fs->super.custom_data = fs;
855 fs->super.fs_type = this;
856 fs->super.allocate_new_node = virtfs_allocate_new_node;
857 fs->super.fetch_node_from_disk = virtfs_fetch_node_from_disk;
858 fs->super.nodecache = hash;
859
860 retval = virtfs_allocate_new_node(& fs->super, SOS_FS_NODE_DIRECTORY,
861 NULL,
862 SOS_FS_READABLE | SOS_FS_WRITABLE
863 | SOS_FS_EXECUTABLE,
864 0,
865 & fsnode_root);
866 if (SOS_OK != retval)
867 {
868 sos_hash_dispose(hash);
869 sos_kmutex_dispose(& fs->lock);
870 sos_kfree((sos_vaddr_t) fs);
871 return retval;
872 }
873
874 retval = sos_fs_register_fs_instance(& fs->super, fsnode_root);
875 sos_fs_unref_fsnode(fsnode_root);
876 if (SOS_OK != retval)
877 {
878 sos_hash_dispose(hash);
879 sos_kmutex_dispose(& fs->lock);
880 sos_kfree((sos_vaddr_t) fs);
881 return retval;
882 }
883
884 *mounted_fs = & fs->super;
885 return SOS_OK;
886 }
887
888
889 static sos_ret_t virtfs_umount(struct sos_fs_manager_type * this,
890 struct sos_fs_manager_instance * mounted_fs)
891 {
892 struct virtfs_instance * virtfs = (struct virtfs_instance*)mounted_fs->custom_data;
893
894 sos_hash_dispose(virtfs->super.nodecache);
895 while (! list_is_empty(virtfs->list_fsnodes))
896 {
897 struct virtfs_node * virtfsnode = list_pop_head(virtfs->list_fsnodes);
898
899 if (virtfsnode->super.type == SOS_FS_NODE_REGULAR_FILE)
900 {
901 if (virtfsnode->file.size > 0)
902 sos_kfree((sos_vaddr_t) virtfsnode->file.data);
903 }
904 else if (virtfsnode->super.type == SOS_FS_NODE_DIRECTORY)
905 {
906 while (! list_is_empty_named(virtfsnode->dir.list_entries,
907 sibling_prev, sibling_next))
908 {
909 struct virtfs_direntry * direntry
910 = list_pop_head_named(virtfsnode->dir.list_entries,
911 sibling_prev, sibling_next);
912
913 sos_kfree((sos_vaddr_t)direntry->name);
914 sos_kfree((sos_vaddr_t)direntry);
915 }
916 }
917
918 sos_kfree((sos_vaddr_t)virtfsnode);
919 }
920
921 sos_fs_unregister_fs_instance(& virtfs->super);
922 sos_kmutex_dispose(& virtfs->lock);
923 sos_kfree((sos_vaddr_t)virtfs);
924 return SOS_OK;
925 }
926
927
928
929
930
931 inline static struct virtfs_node *
932 get_virtfsnode_of_vr(struct sos_umem_vmm_vr * vr)
933 {
934 struct sos_umem_vmm_mapped_resource *mr
935 = sos_umem_vmm_get_mapped_resource_of_vr(vr);
936
937 return (struct virtfs_node *)mr->custom_data;
938 }
939
940
941 static void virtfs_map_ref(struct sos_umem_vmm_vr * vr)
942 {
943 struct virtfs_node * virtfsnode = get_virtfsnode_of_vr(vr);
944 sos_fs_ref_fsnode(& virtfsnode->super);
945 virtfsnode->file.num_mappings ++;
946 }
947
948
949 static void virtfs_map_unref(struct sos_umem_vmm_vr * vr)
950 {
951 struct virtfs_node * virtfsnode = get_virtfsnode_of_vr(vr);
952
953 SOS_ASSERT_FATAL(virtfsnode->file.num_mappings > 0);
954 virtfsnode->file.num_mappings --;
955
956 _sos_fs_unref_fsnode(& virtfsnode->super);
957 }
958
959
960 static sos_ret_t virtfs_map_page_in(struct sos_umem_vmm_vr * vr,
961 sos_uaddr_t uaddr,
962 sos_bool_t write_access)
963 {
964 struct virtfs_node * virtfsnode = get_virtfsnode_of_vr(vr);
965 sos_luoffset_t offset = uaddr - sos_umem_vmm_get_start_of_vr(vr);
966 sos_ret_t retval = SOS_OK;
967 sos_paddr_t ppage_paddr;
968
969
970 if (SOS_PAGE_ALIGN_SUP(offset) > virtfsnode->file.size)
971 return -SOS_EFAULT;
972
973
974 ppage_paddr = sos_paging_get_paddr(SOS_PAGE_ALIGN_INF(virtfsnode->file.data
975 + offset));
976
977
978 if (! ppage_paddr)
979 return -SOS_EFAULT;
980
981
982 retval = sos_paging_map(ppage_paddr,
983 SOS_PAGE_ALIGN_INF(uaddr),
984 TRUE,
985 sos_umem_vmm_get_prot_of_vr(vr));
986
987 return retval;
988 }
989
990
991 static struct sos_umem_vmm_vr_ops virtfs_map_ops
992 = (struct sos_umem_vmm_vr_ops){
993 .ref = virtfs_map_ref,
994 .unref = virtfs_map_unref,
995 .page_in = virtfs_map_page_in
996 };
997
998 static sos_ret_t virtfs_new_mapping(struct sos_umem_vmm_vr *vr)
999 {
1000 struct virtfs_node * virtfsnode = get_virtfsnode_of_vr(vr);
1001 sos_size_t reqsize;
1002 sos_ret_t retval;
1003
1004 reqsize = sos_umem_vmm_get_offset_in_resource(vr);
1005 reqsize += sos_umem_vmm_get_size_of_vr(vr);
1006
1007
1008 if (reqsize > virtfsnode->file.size)
1009 {
1010 retval = virtfs_resize(virtfsnode,
1011 SOS_PAGE_ALIGN_SUP(reqsize));
1012 if (SOS_OK != retval)
1013 return retval;
1014 }
1015
1016 return sos_umem_vmm_set_ops_of_vr(vr, &virtfs_map_ops);
1017 }