/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- emu_rreg
- emu_wreg
- emu_irq
- translate_err
- emu_waitdone
- emu_open
- emu_close
- emu_doread
- emu_read
- emu_readdir
- emu_write
- emu_getsize
- emu_trunc
- emufs_open
- emufs_opendir
- emufs_close
- emufs_reclaim
- emufs_read
- emufs_getdirentry
- emufs_write
- emufs_ioctl
- emufs_stat
- emufs_file_gettype
- emufs_dir_gettype
- emufs_tryseek
- emufs_fsync
- emufs_truncate
- emufs_creat
- emufs_lookup
- emufs_lookparent
- emufs_namefile
- emufs_mmap
- emufs_dir_tryseek
- emufs_symlink
- emufs_mkdir
- emufs_link
- emufs_remove
- emufs_rmdir
- emufs_rename
- emufs_void_op_isdir
- emufs_uio_op_isdir
- emufs_uio_op_notdir
- emufs_name_op_notdir
- emufs_readlink_notlink
- emufs_creat_notdir
- emufs_symlink_notdir
- emufs_mkdir_notdir
- emufs_link_notdir
- emufs_rename_notdir
- emufs_lookup_notdir
- emufs_lookparent_notdir
- emufs_truncate_isdir
- emufs_loadvnode
- emufs_sync
- emufs_getvolname
- emufs_getroot
- emufs_unmount
- emufs_addtovfs
- config_emu
1 /*
2 * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3 * The President and Fellows of Harvard College.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 /*
31 * Emulator passthrough filesystem.
32 *
33 * The idea is that this appears as a filesystem in the VFS layer, and
34 * passes VFS operations through a somewhat complicated "hardware"
35 * interface to some simulated "hardware" in System/161 that accesses
36 * the filesystem System/161 is running in.
37 *
38 * This makes it unnecessary to copy the system files to the simulated
39 * disk, although we recommend doing so and trying running without this
40 * device as part of testing your filesystem.
41 */
42
43 #include <types.h>
44 #include <kern/errno.h>
45 #include <kern/fcntl.h>
46 #include <stat.h>
47 #include <lib.h>
48 #include <array.h>
49 #include <uio.h>
50 #include <synch.h>
51 #include <lamebus/emu.h>
52 #include <platform/bus.h>
53 #include <vfs.h>
54 #include <emufs.h>
55 #include "autoconf.h"
56
57 /* Register offsets */
58 #define REG_HANDLE 0
59 #define REG_OFFSET 4
60 #define REG_IOLEN 8
61 #define REG_OPER 12
62 #define REG_RESULT 16
63
64 /* I/O buffer offset */
65 #define EMU_BUFFER 32768
66
67 /* Operation codes for REG_OPER */
68 #define EMU_OP_OPEN 1
69 #define EMU_OP_CREATE 2
70 #define EMU_OP_EXCLCREATE 3
71 #define EMU_OP_CLOSE 4
72 #define EMU_OP_READ 5
73 #define EMU_OP_READDIR 6
74 #define EMU_OP_WRITE 7
75 #define EMU_OP_GETSIZE 8
76 #define EMU_OP_TRUNC 9
77
78 /* Result codes for REG_RESULT */
79 #define EMU_RES_SUCCESS 1
80 #define EMU_RES_BADHANDLE 2
81 #define EMU_RES_BADOP 3
82 #define EMU_RES_BADPATH 4
83 #define EMU_RES_BADSIZE 5
84 #define EMU_RES_EXISTS 6
85 #define EMU_RES_ISDIR 7
86 #define EMU_RES_MEDIA 8
87 #define EMU_RES_NOHANDLES 9
88 #define EMU_RES_NOSPACE 10
89 #define EMU_RES_NOTDIR 11
90 #define EMU_RES_UNKNOWN 12
91 #define EMU_RES_UNSUPP 13
92
93 ////////////////////////////////////////////////////////////
94 //
95 // Hardware ops
96 //
97
98 /*
99 * Shortcut for reading a register
100 */
101 static
102 inline
103 uint32_t
104 emu_rreg(struct emu_softc *sc, uint32_t reg)
105 {
106 return bus_read_register(sc->e_busdata, sc->e_buspos, reg);
107 }
108
109 /*
110 * Shortcut for writing a register
111 */
112 static
113 inline
114 void
115 emu_wreg(struct emu_softc *sc, uint32_t reg, uint32_t val)
116 {
117 bus_write_register(sc->e_busdata, sc->e_buspos, reg, val);
118 }
119
120 /*
121 * Called by the underlying bus code when an interrupt happens
122 */
123 void
124 emu_irq(void *dev)
125 {
126 struct emu_softc *sc = dev;
127
128 sc->e_result = emu_rreg(sc, REG_RESULT);
129 emu_wreg(sc, REG_RESULT, 0);
130
131 V(sc->e_sem);
132 }
133
134 /*
135 * Convert the error codes reported by the "hardware" to errnos.
136 * Or, on cases that indicate a programming error in emu.c, panic.
137 */
138 static
139 uint32_t
140 translate_err(struct emu_softc *sc, uint32_t code)
141 {
142 switch (code) {
143 case EMU_RES_SUCCESS: return 0;
144 case EMU_RES_BADHANDLE:
145 case EMU_RES_BADOP:
146 case EMU_RES_BADSIZE:
147 panic("emu%d: got fatal result code %d\n", sc->e_unit, code);
148 case EMU_RES_BADPATH: return ENOENT;
149 case EMU_RES_EXISTS: return EEXIST;
150 case EMU_RES_ISDIR: return EISDIR;
151 case EMU_RES_MEDIA: return EIO;
152 case EMU_RES_NOHANDLES: return ENFILE;
153 case EMU_RES_NOSPACE: return ENOSPC;
154 case EMU_RES_NOTDIR: return ENOTDIR;
155 case EMU_RES_UNKNOWN: return EIO;
156 case EMU_RES_UNSUPP: return EUNIMP;
157 }
158 kprintf("emu%d: Unknown result code %d\n", sc->e_unit, code);
159 return EAGAIN;
160 }
161
162 /*
163 * Wait for an operation to complete, and return an errno for the result.
164 */
165 static
166 int
167 emu_waitdone(struct emu_softc *sc)
168 {
169 P(sc->e_sem);
170 return translate_err(sc, sc->e_result);
171 }
172
173 /*
174 * Common file open routine (for both VOP_LOOKUP and VOP_CREATE). Not
175 * for VOP_OPEN. At the hardware level, we need to "open" files in
176 * order to look at them, so by the time VOP_OPEN is called the
177 * files are already open.
178 */
179 static
180 int
181 emu_open(struct emu_softc *sc, uint32_t handle, const char *name,
182 bool create, bool excl, mode_t mode,
183 uint32_t *newhandle, int *newisdir)
184 {
185 uint32_t op;
186 int result;
187
188 if (strlen(name)+1 > EMU_MAXIO) {
189 return ENAMETOOLONG;
190 }
191
192 if (create && excl) {
193 op = EMU_OP_EXCLCREATE;
194 }
195 else if (create) {
196 op = EMU_OP_CREATE;
197 }
198 else {
199 op = EMU_OP_OPEN;
200 }
201
202 /* mode isn't supported (yet?) */
203 (void)mode;
204
205 lock_acquire(sc->e_lock);
206
207 strcpy(sc->e_iobuf, name);
208 emu_wreg(sc, REG_IOLEN, strlen(name));
209 emu_wreg(sc, REG_HANDLE, handle);
210 emu_wreg(sc, REG_OPER, op);
211 result = emu_waitdone(sc);
212
213 if (result==0) {
214 *newhandle = emu_rreg(sc, REG_HANDLE);
215 *newisdir = emu_rreg(sc, REG_IOLEN)>0;
216 }
217
218 lock_release(sc->e_lock);
219 return result;
220 }
221
222 /*
223 * Routine for closing a file we opened at the hardware level.
224 * This is not necessarily called at VOP_CLOSE time; it's called
225 * at VOP_RECLAIM time.
226 */
227 static
228 int
229 emu_close(struct emu_softc *sc, uint32_t handle)
230 {
231 int result;
232 bool mine;
233 int retries = 0;
234
235 mine = lock_do_i_hold(sc->e_lock);
236 if (!mine) {
237 lock_acquire(sc->e_lock);
238 }
239
240 while (1) {
241 /* Retry operation up to 10 times */
242
243 emu_wreg(sc, REG_HANDLE, handle);
244 emu_wreg(sc, REG_OPER, EMU_OP_CLOSE);
245 result = emu_waitdone(sc);
246
247 if (result==EIO && retries < 10) {
248 kprintf("emu%d: I/O error on close, retrying\n",
249 sc->e_unit);
250 retries++;
251 continue;
252 }
253 break;
254 }
255
256 if (!mine) {
257 lock_release(sc->e_lock);
258 }
259 return result;
260 }
261
262 /*
263 * Common code for read and readdir.
264 */
265 static
266 int
267 emu_doread(struct emu_softc *sc, uint32_t handle, uint32_t len,
268 uint32_t op, struct uio *uio)
269 {
270 int result;
271
272 KASSERT(uio->uio_rw == UIO_READ);
273
274 lock_acquire(sc->e_lock);
275
276 emu_wreg(sc, REG_HANDLE, handle);
277 emu_wreg(sc, REG_IOLEN, len);
278 emu_wreg(sc, REG_OFFSET, uio->uio_offset);
279 emu_wreg(sc, REG_OPER, op);
280 result = emu_waitdone(sc);
281 if (result) {
282 goto out;
283 }
284
285 result = uiomove(sc->e_iobuf, emu_rreg(sc, REG_IOLEN), uio);
286
287 uio->uio_offset = emu_rreg(sc, REG_OFFSET);
288
289 out:
290 lock_release(sc->e_lock);
291 return result;
292 }
293
294 /*
295 * Read from a hardware-level file handle.
296 */
297 static
298 int
299 emu_read(struct emu_softc *sc, uint32_t handle, uint32_t len,
300 struct uio *uio)
301 {
302 return emu_doread(sc, handle, len, EMU_OP_READ, uio);
303 }
304
305 /*
306 * Read a directory entry from a hardware-level file handle.
307 */
308 static
309 int
310 emu_readdir(struct emu_softc *sc, uint32_t handle, uint32_t len,
311 struct uio *uio)
312 {
313 return emu_doread(sc, handle, len, EMU_OP_READDIR, uio);
314 }
315
316 /*
317 * Write to a hardware-level file handle.
318 */
319 static
320 int
321 emu_write(struct emu_softc *sc, uint32_t handle, uint32_t len,
322 struct uio *uio)
323 {
324 int result;
325
326 KASSERT(uio->uio_rw == UIO_WRITE);
327
328 lock_acquire(sc->e_lock);
329
330 emu_wreg(sc, REG_HANDLE, handle);
331 emu_wreg(sc, REG_IOLEN, len);
332 emu_wreg(sc, REG_OFFSET, uio->uio_offset);
333
334 result = uiomove(sc->e_iobuf, len, uio);
335 if (result) {
336 goto out;
337 }
338
339 emu_wreg(sc, REG_OPER, EMU_OP_WRITE);
340 result = emu_waitdone(sc);
341
342 out:
343 lock_release(sc->e_lock);
344 return result;
345 }
346
347 /*
348 * Get the file size associated with a hardware-level file handle.
349 */
350 static
351 int
352 emu_getsize(struct emu_softc *sc, uint32_t handle, off_t *retval)
353 {
354 int result;
355
356 lock_acquire(sc->e_lock);
357
358 emu_wreg(sc, REG_HANDLE, handle);
359 emu_wreg(sc, REG_OPER, EMU_OP_GETSIZE);
360 result = emu_waitdone(sc);
361 if (result==0) {
362 *retval = emu_rreg(sc, REG_IOLEN);
363 }
364
365 lock_release(sc->e_lock);
366 return result;
367 }
368
369 /*
370 * Truncate a hardware-level file handle.
371 */
372 static
373 int
374 emu_trunc(struct emu_softc *sc, uint32_t handle, off_t len)
375 {
376 int result;
377
378 lock_acquire(sc->e_lock);
379
380 emu_wreg(sc, REG_HANDLE, handle);
381 emu_wreg(sc, REG_IOLEN, len);
382 emu_wreg(sc, REG_OPER, EMU_OP_TRUNC);
383 result = emu_waitdone(sc);
384
385 lock_release(sc->e_lock);
386 return result;
387 }
388
389 //
390 ////////////////////////////////////////////////////////////
391
392 ////////////////////////////////////////////////////////////
393 //
394 // vnode functions
395 //
396
397 // at bottom of this section
398
399 static int emufs_loadvnode(struct emufs_fs *ef, uint32_t handle, int isdir,
400 struct emufs_vnode **ret);
401
402 /*
403 * VOP_OPEN on files
404 */
405 static
406 int
407 emufs_open(struct vnode *v, int openflags)
408 {
409 /*
410 * At this level we do not need to handle O_CREAT, O_EXCL, or O_TRUNC.
411 * We *would* need to handle O_APPEND, but we don't support it.
412 *
413 * Any of O_RDONLY, O_WRONLY, and O_RDWR are valid, so we don't need
414 * to check that either.
415 */
416
417 if (openflags & O_APPEND) {
418 return EUNIMP;
419 }
420
421 (void)v;
422
423 return 0;
424 }
425
426 /*
427 * VOP_OPEN on directories
428 */
429 static
430 int
431 emufs_opendir(struct vnode *v, int openflags)
432 {
433 switch (openflags & O_ACCMODE) {
434 case O_RDONLY:
435 break;
436 case O_WRONLY:
437 case O_RDWR:
438 default:
439 return EISDIR;
440 }
441 if (openflags & O_APPEND) {
442 return EISDIR;
443 }
444
445 (void)v;
446 return 0;
447 }
448
449 /*
450 * VOP_CLOSE
451 */
452 static
453 int
454 emufs_close(struct vnode *v)
455 {
456 (void)v;
457 return 0;
458 }
459
460 /*
461 * VOP_RECLAIM
462 *
463 * Reclaim should make an effort to returning errors other than EBUSY.
464 */
465 static
466 int
467 emufs_reclaim(struct vnode *v)
468 {
469 struct emufs_vnode *ev = v->vn_data;
470 struct emufs_fs *ef = v->vn_fs->fs_data;
471 unsigned ix, i, num;
472 int result;
473
474 /*
475 * Need both of these locks, e_lock to protect the device
476 * and vfs_biglock to protect the fs-related material.
477 */
478
479 vfs_biglock_acquire();
480 lock_acquire(ef->ef_emu->e_lock);
481
482 if (ev->ev_v.vn_refcount != 1) {
483 lock_release(ef->ef_emu->e_lock);
484 vfs_biglock_release();
485 return EBUSY;
486 }
487
488 /* emu_close retries on I/O error */
489 result = emu_close(ev->ev_emu, ev->ev_handle);
490 if (result) {
491 lock_release(ef->ef_emu->e_lock);
492 vfs_biglock_release();
493 return result;
494 }
495
496 num = vnodearray_num(ef->ef_vnodes);
497 ix = num;
498 for (i=0; i<num; i++) {
499 struct vnode *vx;
500
501 vx = vnodearray_get(ef->ef_vnodes, i);
502 if (vx == v) {
503 ix = i;
504 break;
505 }
506 }
507 if (ix == num) {
508 panic("emu%d: reclaim vnode %u not in vnode pool\n",
509 ef->ef_emu->e_unit, ev->ev_handle);
510 }
511
512 vnodearray_remove(ef->ef_vnodes, ix);
513 VOP_CLEANUP(&ev->ev_v);
514
515 lock_release(ef->ef_emu->e_lock);
516 vfs_biglock_release();
517
518 kfree(ev);
519 return 0;
520 }
521
522 /*
523 * VOP_READ
524 */
525 static
526 int
527 emufs_read(struct vnode *v, struct uio *uio)
528 {
529 struct emufs_vnode *ev = v->vn_data;
530 uint32_t amt;
531 size_t oldresid;
532 int result;
533
534 KASSERT(uio->uio_rw==UIO_READ);
535
536 while (uio->uio_resid > 0) {
537 amt = uio->uio_resid;
538 if (amt > EMU_MAXIO) {
539 amt = EMU_MAXIO;
540 }
541
542 oldresid = uio->uio_resid;
543
544 result = emu_read(ev->ev_emu, ev->ev_handle, amt, uio);
545 if (result) {
546 return result;
547 }
548
549 if (uio->uio_resid == oldresid) {
550 /* nothing read - EOF */
551 break;
552 }
553 }
554
555 return 0;
556 }
557
558 /*
559 * VOP_READDIR
560 */
561 static
562 int
563 emufs_getdirentry(struct vnode *v, struct uio *uio)
564 {
565 struct emufs_vnode *ev = v->vn_data;
566 uint32_t amt;
567
568 KASSERT(uio->uio_rw==UIO_READ);
569
570 amt = uio->uio_resid;
571 if (amt > EMU_MAXIO) {
572 amt = EMU_MAXIO;
573 }
574
575 return emu_readdir(ev->ev_emu, ev->ev_handle, amt, uio);
576 }
577
578 /*
579 * VOP_WRITE
580 */
581 static
582 int
583 emufs_write(struct vnode *v, struct uio *uio)
584 {
585 struct emufs_vnode *ev = v->vn_data;
586 uint32_t amt;
587 size_t oldresid;
588 int result;
589
590 KASSERT(uio->uio_rw==UIO_WRITE);
591
592 while (uio->uio_resid > 0) {
593 amt = uio->uio_resid;
594 if (amt > EMU_MAXIO) {
595 amt = EMU_MAXIO;
596 }
597
598 oldresid = uio->uio_resid;
599
600 result = emu_write(ev->ev_emu, ev->ev_handle, amt, uio);
601 if (result) {
602 return result;
603 }
604
605 if (uio->uio_resid == oldresid) {
606 /* nothing written...? */
607 break;
608 }
609 }
610
611 return 0;
612 }
613
614 /*
615 * VOP_IOCTL
616 */
617 static
618 int
619 emufs_ioctl(struct vnode *v, int op, userptr_t data)
620 {
621 /*
622 * No ioctls.
623 */
624
625 (void)v;
626 (void)op;
627 (void)data;
628
629 return EINVAL;
630 }
631
632 /*
633 * VOP_STAT
634 */
635 static
636 int
637 emufs_stat(struct vnode *v, struct stat *statbuf)
638 {
639 struct emufs_vnode *ev = v->vn_data;
640 int result;
641
642 bzero(statbuf, sizeof(struct stat));
643
644 result = emu_getsize(ev->ev_emu, ev->ev_handle, &statbuf->st_size);
645 if (result) {
646 return result;
647 }
648
649 result = VOP_GETTYPE(v, &statbuf->st_mode);
650 if (result) {
651 return result;
652 }
653 statbuf->st_mode |= 0644; /* possibly a lie */
654 statbuf->st_nlink = 1; /* might be a lie, but doesn't matter much */
655 statbuf->st_blocks = 0; /* almost certainly a lie */
656
657 return 0;
658 }
659
660 /*
661 * VOP_GETTYPE for files
662 */
663 static
664 int
665 emufs_file_gettype(struct vnode *v, uint32_t *result)
666 {
667 (void)v;
668 *result = S_IFREG;
669 return 0;
670 }
671
672 /*
673 * VOP_GETTYPE for directories
674 */
675 static
676 int
677 emufs_dir_gettype(struct vnode *v, uint32_t *result)
678 {
679 (void)v;
680 *result = S_IFDIR;
681 return 0;
682 }
683
684 /*
685 * VOP_TRYSEEK
686 */
687 static
688 int
689 emufs_tryseek(struct vnode *v, off_t pos)
690 {
691 if (pos<0) {
692 return EINVAL;
693 }
694
695 /* Allow anything else */
696 (void)v;
697
698 return 0;
699 }
700
701 /*
702 * VOP_FSYNC
703 */
704 static
705 int
706 emufs_fsync(struct vnode *v)
707 {
708 (void)v;
709 return 0;
710 }
711
712 /*
713 * VOP_TRUNCATE
714 */
715 static
716 int
717 emufs_truncate(struct vnode *v, off_t len)
718 {
719 struct emufs_vnode *ev = v->vn_data;
720 return emu_trunc(ev->ev_emu, ev->ev_handle, len);
721 }
722
723 /*
724 * VOP_CREAT
725 */
726 static
727 int
728 emufs_creat(struct vnode *dir, const char *name, bool excl, mode_t mode,
729 struct vnode **ret)
730 {
731 struct emufs_vnode *ev = dir->vn_data;
732 struct emufs_fs *ef = dir->vn_fs->fs_data;
733 struct emufs_vnode *newguy;
734 uint32_t handle;
735 int result;
736 int isdir;
737
738 result = emu_open(ev->ev_emu, ev->ev_handle, name, true, excl, mode,
739 &handle, &isdir);
740 if (result) {
741 return result;
742 }
743
744 result = emufs_loadvnode(ef, handle, isdir, &newguy);
745 if (result) {
746 emu_close(ev->ev_emu, handle);
747 return result;
748 }
749
750 *ret = &newguy->ev_v;
751 return 0;
752 }
753
754 /*
755 * VOP_LOOKUP
756 */
757 static
758 int
759 emufs_lookup(struct vnode *dir, char *pathname, struct vnode **ret)
760 {
761 struct emufs_vnode *ev = dir->vn_data;
762 struct emufs_fs *ef = dir->vn_fs->fs_data;
763 struct emufs_vnode *newguy;
764 uint32_t handle;
765 int result;
766 int isdir;
767
768 result = emu_open(ev->ev_emu, ev->ev_handle, pathname, false, false, 0,
769 &handle, &isdir);
770 if (result) {
771 return result;
772 }
773
774 result = emufs_loadvnode(ef, handle, isdir, &newguy);
775 if (result) {
776 emu_close(ev->ev_emu, handle);
777 return result;
778 }
779
780 *ret = &newguy->ev_v;
781 return 0;
782 }
783
784 /*
785 * VOP_LOOKPARENT
786 */
787 static
788 int
789 emufs_lookparent(struct vnode *dir, char *pathname, struct vnode **ret,
790 char *buf, size_t len)
791 {
792 char *s;
793
794 s = strrchr(pathname, '/');
795 if (s==NULL) {
796 /* just a last component, no directory part */
797 if (strlen(pathname)+1 > len) {
798 return ENAMETOOLONG;
799 }
800 VOP_INCREF(dir);
801 *ret = dir;
802 strcpy(buf, pathname);
803 return 0;
804 }
805
806 *s = 0;
807 s++;
808 if (strlen(s)+1 > len) {
809 return ENAMETOOLONG;
810 }
811 strcpy(buf, s);
812
813 return emufs_lookup(dir, pathname, ret);
814 }
815
816 /*
817 * VOP_NAMEFILE
818 */
819 static
820 int
821 emufs_namefile(struct vnode *v, struct uio *uio)
822 {
823 struct emufs_vnode *ev = v->vn_data;
824 struct emufs_fs *ef = v->vn_fs->fs_data;
825
826 if (ev == ef->ef_root) {
827 /*
828 * Root directory - name is empty string
829 */
830 return 0;
831 }
832
833 (void)uio;
834
835 return EUNIMP;
836 }
837
838 /*
839 * VOP_MMAP
840 */
841 static
842 int
843 emufs_mmap(struct vnode *v)
844 {
845 (void)v;
846 return EUNIMP;
847 }
848
849 //////////////////////////////
850
851 /*
852 * Bits not implemented at all on emufs
853 */
854
855 static
856 int
857 emufs_dir_tryseek(struct vnode *v, off_t pos)
858 {
859 (void)v;
860 (void)pos;
861 return EUNIMP;
862 }
863
864 static
865 int
866 emufs_symlink(struct vnode *v, const char *contents, const char *name)
867 {
868 (void)v;
869 (void)contents;
870 (void)name;
871 return EUNIMP;
872 }
873
874 static
875 int
876 emufs_mkdir(struct vnode *v, const char *name, mode_t mode)
877 {
878 (void)v;
879 (void)name;
880 (void)mode;
881 return EUNIMP;
882 }
883
884 static
885 int
886 emufs_link(struct vnode *v, const char *name, struct vnode *target)
887 {
888 (void)v;
889 (void)name;
890 (void)target;
891 return EUNIMP;
892 }
893
894 static
895 int
896 emufs_remove(struct vnode *v, const char *name)
897 {
898 (void)v;
899 (void)name;
900 return EUNIMP;
901 }
902
903 static
904 int
905 emufs_rmdir(struct vnode *v, const char *name)
906 {
907 (void)v;
908 (void)name;
909 return EUNIMP;
910 }
911
912 static
913 int
914 emufs_rename(struct vnode *v1, const char *n1,
915 struct vnode *v2, const char *n2)
916 {
917 (void)v1;
918 (void)n1;
919 (void)v2;
920 (void)n2;
921 return EUNIMP;
922 }
923
924 //////////////////////////////
925
926 /*
927 * Routines that fail
928 *
929 * It is kind of silly to write these out each with their particular
930 * arguments; however, portable C doesn't let you cast function
931 * pointers with different argument signatures even if the arguments
932 * are never used.
933 *
934 * The BSD approach (all vnode ops take a vnode pointer and a void
935 * pointer that's cast to a op-specific args structure) avoids this
936 * problem but is otherwise not very appealing.
937 */
938
939 static
940 int
941 emufs_void_op_isdir(struct vnode *v)
942 {
943 (void)v;
944 return EISDIR;
945 }
946
947 static
948 int
949 emufs_uio_op_isdir(struct vnode *v, struct uio *uio)
950 {
951 (void)v;
952 (void)uio;
953 return EISDIR;
954 }
955
956 static
957 int
958 emufs_uio_op_notdir(struct vnode *v, struct uio *uio)
959 {
960 (void)v;
961 (void)uio;
962 return ENOTDIR;
963 }
964
965 static
966 int
967 emufs_name_op_notdir(struct vnode *v, const char *name)
968 {
969 (void)v;
970 (void)name;
971 return ENOTDIR;
972 }
973
974 static
975 int
976 emufs_readlink_notlink(struct vnode *v, struct uio *uio)
977 {
978 (void)v;
979 (void)uio;
980 return EINVAL;
981 }
982
983 static
984 int
985 emufs_creat_notdir(struct vnode *v, const char *name, bool excl, mode_t mode,
986 struct vnode **retval)
987 {
988 (void)v;
989 (void)name;
990 (void)excl;
991 (void)mode;
992 (void)retval;
993 return ENOTDIR;
994 }
995
996 static
997 int
998 emufs_symlink_notdir(struct vnode *v, const char *contents, const char *name)
999 {
1000 (void)v;
1001 (void)contents;
1002 (void)name;
1003 return ENOTDIR;
1004 }
1005
1006 static
1007 int
1008 emufs_mkdir_notdir(struct vnode *v, const char *name, mode_t mode)
1009 {
1010 (void)v;
1011 (void)name;
1012 (void)mode;
1013 return ENOTDIR;
1014 }
1015
1016 static
1017 int
1018 emufs_link_notdir(struct vnode *v, const char *name, struct vnode *target)
1019 {
1020 (void)v;
1021 (void)name;
1022 (void)target;
1023 return ENOTDIR;
1024 }
1025
1026 static
1027 int
1028 emufs_rename_notdir(struct vnode *v1, const char *n1,
1029 struct vnode *v2, const char *n2)
1030 {
1031 (void)v1;
1032 (void)n1;
1033 (void)v2;
1034 (void)n2;
1035 return ENOTDIR;
1036 }
1037
1038 static
1039 int
1040 emufs_lookup_notdir(struct vnode *v, char *pathname, struct vnode **result)
1041 {
1042 (void)v;
1043 (void)pathname;
1044 (void)result;
1045 return ENOTDIR;
1046 }
1047
1048 static
1049 int
1050 emufs_lookparent_notdir(struct vnode *v, char *pathname, struct vnode **result,
1051 char *buf, size_t len)
1052 {
1053 (void)v;
1054 (void)pathname;
1055 (void)result;
1056 (void)buf;
1057 (void)len;
1058 return ENOTDIR;
1059 }
1060
1061
1062 static
1063 int
1064 emufs_truncate_isdir(struct vnode *v, off_t len)
1065 {
1066 (void)v;
1067 (void)len;
1068 return ENOTDIR;
1069 }
1070
1071 //////////////////////////////
1072
1073 /*
1074 * Function table for emufs files.
1075 */
1076 static const struct vnode_ops emufs_fileops = {
1077 VOP_MAGIC, /* mark this a valid vnode ops table */
1078
1079 emufs_open,
1080 emufs_close,
1081 emufs_reclaim,
1082
1083 emufs_read,
1084 emufs_readlink_notlink,
1085 emufs_uio_op_notdir, /* getdirentry */
1086 emufs_write,
1087 emufs_ioctl,
1088 emufs_stat,
1089 emufs_file_gettype,
1090 emufs_tryseek,
1091 emufs_fsync,
1092 emufs_mmap,
1093 emufs_truncate,
1094 emufs_uio_op_notdir, /* namefile */
1095
1096 emufs_creat_notdir,
1097 emufs_symlink_notdir,
1098 emufs_mkdir_notdir,
1099 emufs_link_notdir,
1100 emufs_name_op_notdir, /* remove */
1101 emufs_name_op_notdir, /* rmdir */
1102 emufs_rename_notdir,
1103
1104 emufs_lookup_notdir,
1105 emufs_lookparent_notdir,
1106 };
1107
1108 /*
1109 * Function table for emufs directories.
1110 */
1111 static const struct vnode_ops emufs_dirops = {
1112 VOP_MAGIC, /* mark this a valid vnode ops table */
1113
1114 emufs_opendir,
1115 emufs_close,
1116 emufs_reclaim,
1117
1118 emufs_uio_op_isdir, /* read */
1119 emufs_uio_op_isdir, /* readlink */
1120 emufs_getdirentry,
1121 emufs_uio_op_isdir, /* write */
1122 emufs_ioctl,
1123 emufs_stat,
1124 emufs_dir_gettype,
1125 emufs_dir_tryseek,
1126 emufs_void_op_isdir, /* fsync */
1127 emufs_void_op_isdir, /* mmap */
1128 emufs_truncate_isdir,
1129 emufs_namefile,
1130
1131 emufs_creat,
1132 emufs_symlink,
1133 emufs_mkdir,
1134 emufs_link,
1135 emufs_remove,
1136 emufs_rmdir,
1137 emufs_rename,
1138
1139 emufs_lookup,
1140 emufs_lookparent,
1141 };
1142
1143 /*
1144 * Function to load a vnode into memory.
1145 */
1146 static
1147 int
1148 emufs_loadvnode(struct emufs_fs *ef, uint32_t handle, int isdir,
1149 struct emufs_vnode **ret)
1150 {
1151 struct vnode *v;
1152 struct emufs_vnode *ev;
1153 unsigned i, num;
1154 int result;
1155
1156 vfs_biglock_acquire();
1157 lock_acquire(ef->ef_emu->e_lock);
1158
1159 num = vnodearray_num(ef->ef_vnodes);
1160 for (i=0; i<num; i++) {
1161 v = vnodearray_get(ef->ef_vnodes, i);
1162 ev = v->vn_data;
1163 if (ev->ev_handle == handle) {
1164 /* Found */
1165
1166 VOP_INCREF(&ev->ev_v);
1167
1168 lock_release(ef->ef_emu->e_lock);
1169 vfs_biglock_release();
1170 *ret = ev;
1171 return 0;
1172 }
1173 }
1174
1175 /* Didn't have one; create it */
1176
1177 ev = kmalloc(sizeof(struct emufs_vnode));
1178 if (ev==NULL) {
1179 lock_release(ef->ef_emu->e_lock);
1180 return ENOMEM;
1181 }
1182
1183 ev->ev_emu = ef->ef_emu;
1184 ev->ev_handle = handle;
1185
1186 result = VOP_INIT(&ev->ev_v, isdir ? &emufs_dirops : &emufs_fileops,
1187 &ef->ef_fs, ev);
1188 if (result) {
1189 lock_release(ef->ef_emu->e_lock);
1190 vfs_biglock_release();
1191 kfree(ev);
1192 return result;
1193 }
1194
1195 result = vnodearray_add(ef->ef_vnodes, &ev->ev_v, NULL);
1196 if (result) {
1197 /* note: VOP_CLEANUP undoes VOP_INIT - it does not kfree */
1198 VOP_CLEANUP(&ev->ev_v);
1199 lock_release(ef->ef_emu->e_lock);
1200 vfs_biglock_release();
1201 kfree(ev);
1202 return result;
1203 }
1204
1205 lock_release(ef->ef_emu->e_lock);
1206 vfs_biglock_release();
1207
1208 *ret = ev;
1209 return 0;
1210 }
1211
1212 //
1213 ////////////////////////////////////////////////////////////
1214
1215 ////////////////////////////////////////////////////////////
1216 //
1217 // Whole-filesystem functions
1218 //
1219
1220 /*
1221 * FSOP_SYNC
1222 */
1223 static
1224 int
1225 emufs_sync(struct fs *fs)
1226 {
1227 (void)fs;
1228 return 0;
1229 }
1230
1231 /*
1232 * FSOP_GETVOLNAME
1233 */
1234 static
1235 const char *
1236 emufs_getvolname(struct fs *fs)
1237 {
1238 /* We don't have a volume name beyond the device name */
1239 (void)fs;
1240 return NULL;
1241 }
1242
1243 /*
1244 * FSOP_GETROOT
1245 */
1246 static
1247 struct vnode *
1248 emufs_getroot(struct fs *fs)
1249 {
1250 struct emufs_fs *ef;
1251
1252 KASSERT(fs != NULL);
1253
1254 ef = fs->fs_data;
1255
1256 KASSERT(ef != NULL);
1257 KASSERT(ef->ef_root != NULL);
1258
1259 VOP_INCREF(&ef->ef_root->ev_v);
1260 return &ef->ef_root->ev_v;
1261 }
1262
1263 /*
1264 * FSOP_UNMOUNT
1265 */
1266 static
1267 int
1268 emufs_unmount(struct fs *fs)
1269 {
1270 /* Always prohibit unmount, as we're not really "mounted" */
1271 (void)fs;
1272 return EBUSY;
1273 }
1274
1275 /*
1276 * Routine for "mounting" an emufs - we're not really mounted in the
1277 * sense that the VFS understands that term, because we're not
1278 * connected to a block device.
1279 *
1280 * Basically, we just add ourselves to the name list in the VFS layer.
1281 */
1282 static
1283 int
1284 emufs_addtovfs(struct emu_softc *sc, const char *devname)
1285 {
1286 struct emufs_fs *ef;
1287 int result;
1288
1289 ef = kmalloc(sizeof(struct emufs_fs));
1290 if (ef==NULL) {
1291 return ENOMEM;
1292 }
1293
1294 ef->ef_fs.fs_sync = emufs_sync;
1295 ef->ef_fs.fs_getvolname = emufs_getvolname;
1296 ef->ef_fs.fs_getroot = emufs_getroot;
1297 ef->ef_fs.fs_unmount = emufs_unmount;
1298 ef->ef_fs.fs_data = ef;
1299
1300 ef->ef_emu = sc;
1301 ef->ef_root = NULL;
1302 ef->ef_vnodes = vnodearray_create();
1303 if (ef->ef_vnodes == NULL) {
1304 kfree(ef);
1305 return ENOMEM;
1306 }
1307
1308 result = emufs_loadvnode(ef, EMU_ROOTHANDLE, 1, &ef->ef_root);
1309 if (result) {
1310 kfree(ef);
1311 return result;
1312 }
1313
1314 KASSERT(ef->ef_root!=NULL);
1315
1316 result = vfs_addfs(devname, &ef->ef_fs);
1317 if (result) {
1318 VOP_DECREF(&ef->ef_root->ev_v);
1319 kfree(ef);
1320 }
1321 return result;
1322 }
1323
1324 //
1325 ////////////////////////////////////////////////////////////
1326
1327 /*
1328 * Config routine called by autoconf stuff.
1329 *
1330 * Initialize our data, then add ourselves to the VFS layer.
1331 */
1332 int
1333 config_emu(struct emu_softc *sc, int emuno)
1334 {
1335 char name[32];
1336
1337 sc->e_lock = lock_create("emufs-lock");
1338 if (sc->e_lock == NULL) {
1339 return ENOMEM;
1340 }
1341 sc->e_sem = sem_create("emufs-sem", 0);
1342 if (sc->e_sem == NULL) {
1343 lock_destroy(sc->e_lock);
1344 sc->e_lock = NULL;
1345 return ENOMEM;
1346 }
1347 sc->e_iobuf = bus_map_area(sc->e_busdata, sc->e_buspos, EMU_BUFFER);
1348
1349 snprintf(name, sizeof(name), "emu%d", emuno);
1350
1351 return emufs_addtovfs(sc, name);
1352 }