os161-1.99
 All Data Structures
emu.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 /*
00031  * Emulator passthrough filesystem.
00032  *
00033  * The idea is that this appears as a filesystem in the VFS layer, and
00034  * passes VFS operations through a somewhat complicated "hardware"
00035  * interface to some simulated "hardware" in System/161 that accesses
00036  * the filesystem System/161 is running in.
00037  *
00038  * This makes it unnecessary to copy the system files to the simulated
00039  * disk, although we recommend doing so and trying running without this
00040  * device as part of testing your filesystem.
00041  */
00042 
00043 #include <types.h>
00044 #include <kern/errno.h>
00045 #include <kern/fcntl.h>
00046 #include <stat.h>
00047 #include <lib.h>
00048 #include <array.h>
00049 #include <uio.h>
00050 #include <synch.h>
00051 #include <lamebus/emu.h>
00052 #include <platform/bus.h>
00053 #include <vfs.h>
00054 #include <emufs.h>
00055 #include "autoconf.h"
00056 
00057 /* Register offsets */
00058 #define REG_HANDLE    0
00059 #define REG_OFFSET    4
00060 #define REG_IOLEN     8
00061 #define REG_OPER      12
00062 #define REG_RESULT    16
00063 
00064 /* I/O buffer offset */
00065 #define EMU_BUFFER    32768
00066 
00067 /* Operation codes for REG_OPER */
00068 #define EMU_OP_OPEN          1
00069 #define EMU_OP_CREATE        2
00070 #define EMU_OP_EXCLCREATE    3
00071 #define EMU_OP_CLOSE         4
00072 #define EMU_OP_READ          5
00073 #define EMU_OP_READDIR       6
00074 #define EMU_OP_WRITE         7
00075 #define EMU_OP_GETSIZE       8
00076 #define EMU_OP_TRUNC         9
00077 
00078 /* Result codes for REG_RESULT */
00079 #define EMU_RES_SUCCESS      1
00080 #define EMU_RES_BADHANDLE    2
00081 #define EMU_RES_BADOP        3
00082 #define EMU_RES_BADPATH      4
00083 #define EMU_RES_BADSIZE      5
00084 #define EMU_RES_EXISTS       6
00085 #define EMU_RES_ISDIR        7
00086 #define EMU_RES_MEDIA        8
00087 #define EMU_RES_NOHANDLES    9
00088 #define EMU_RES_NOSPACE      10
00089 #define EMU_RES_NOTDIR       11
00090 #define EMU_RES_UNKNOWN      12
00091 #define EMU_RES_UNSUPP       13
00092 
00093 ////////////////////////////////////////////////////////////
00094 //
00095 // Hardware ops
00096 //
00097 
00098 /*
00099  * Shortcut for reading a register
00100  */
00101 static
00102 inline
00103 uint32_t
00104 emu_rreg(struct emu_softc *sc, uint32_t reg)
00105 {
00106         return bus_read_register(sc->e_busdata, sc->e_buspos, reg);
00107 }
00108 
00109 /*
00110  * Shortcut for writing a register
00111  */
00112 static
00113 inline
00114 void
00115 emu_wreg(struct emu_softc *sc, uint32_t reg, uint32_t val)
00116 {
00117         bus_write_register(sc->e_busdata, sc->e_buspos, reg, val);
00118 }
00119 
00120 /*
00121  * Called by the underlying bus code when an interrupt happens
00122  */
00123 void
00124 emu_irq(void *dev)
00125 {
00126         struct emu_softc *sc = dev;
00127 
00128         sc->e_result = emu_rreg(sc, REG_RESULT);
00129         emu_wreg(sc, REG_RESULT, 0);
00130 
00131         V(sc->e_sem);
00132 }
00133 
00134 /*
00135  * Convert the error codes reported by the "hardware" to errnos.
00136  * Or, on cases that indicate a programming error in emu.c, panic.
00137  */
00138 static
00139 uint32_t
00140 translate_err(struct emu_softc *sc, uint32_t code)
00141 {
00142         switch (code) {
00143             case EMU_RES_SUCCESS: return 0;
00144             case EMU_RES_BADHANDLE: 
00145             case EMU_RES_BADOP: 
00146             case EMU_RES_BADSIZE: 
00147                 panic("emu%d: got fatal result code %d\n", sc->e_unit, code);
00148             case EMU_RES_BADPATH: return ENOENT;
00149             case EMU_RES_EXISTS: return EEXIST;
00150             case EMU_RES_ISDIR: return EISDIR;
00151             case EMU_RES_MEDIA: return EIO;
00152             case EMU_RES_NOHANDLES: return ENFILE;
00153             case EMU_RES_NOSPACE: return ENOSPC;
00154             case EMU_RES_NOTDIR: return ENOTDIR;
00155             case EMU_RES_UNKNOWN: return EIO;
00156             case EMU_RES_UNSUPP: return EUNIMP;
00157         }
00158         kprintf("emu%d: Unknown result code %d\n", sc->e_unit, code);
00159         return EAGAIN;
00160 }
00161 
00162 /*
00163  * Wait for an operation to complete, and return an errno for the result.
00164  */
00165 static
00166 int
00167 emu_waitdone(struct emu_softc *sc)
00168 {
00169         P(sc->e_sem);
00170         return translate_err(sc, sc->e_result);
00171 }
00172 
00173 /*
00174  * Common file open routine (for both VOP_LOOKUP and VOP_CREATE).  Not
00175  * for VOP_OPEN. At the hardware level, we need to "open" files in
00176  * order to look at them, so by the time VOP_OPEN is called the
00177  * files are already open.
00178  */
00179 static
00180 int
00181 emu_open(struct emu_softc *sc, uint32_t handle, const char *name,
00182          bool create, bool excl, mode_t mode,
00183          uint32_t *newhandle, int *newisdir)
00184 {
00185         uint32_t op;
00186         int result;
00187 
00188         if (strlen(name)+1 > EMU_MAXIO) {
00189                 return ENAMETOOLONG;
00190         }
00191 
00192         if (create && excl) {
00193                 op = EMU_OP_EXCLCREATE;
00194         }
00195         else if (create) {
00196                 op = EMU_OP_CREATE;
00197         }
00198         else {
00199                 op = EMU_OP_OPEN;
00200         }
00201 
00202         /* mode isn't supported (yet?) */
00203         (void)mode;
00204 
00205         lock_acquire(sc->e_lock);
00206 
00207         strcpy(sc->e_iobuf, name);
00208         emu_wreg(sc, REG_IOLEN, strlen(name));
00209         emu_wreg(sc, REG_HANDLE, handle);
00210         emu_wreg(sc, REG_OPER, op);
00211         result = emu_waitdone(sc);
00212 
00213         if (result==0) {
00214                 *newhandle = emu_rreg(sc, REG_HANDLE);
00215                 *newisdir = emu_rreg(sc, REG_IOLEN)>0;
00216         }
00217 
00218         lock_release(sc->e_lock);
00219         return result;
00220 }
00221 
00222 /*
00223  * Routine for closing a file we opened at the hardware level.
00224  * This is not necessarily called at VOP_CLOSE time; it's called
00225  * at VOP_RECLAIM time.
00226  */
00227 static
00228 int
00229 emu_close(struct emu_softc *sc, uint32_t handle)
00230 {
00231         int result;
00232         bool mine;
00233         int retries = 0;
00234 
00235         mine = lock_do_i_hold(sc->e_lock);
00236         if (!mine) {
00237                 lock_acquire(sc->e_lock);
00238         }
00239 
00240         while (1) {
00241                 /* Retry operation up to 10 times */
00242 
00243                 emu_wreg(sc, REG_HANDLE, handle);
00244                 emu_wreg(sc, REG_OPER, EMU_OP_CLOSE);
00245                 result = emu_waitdone(sc);
00246 
00247                 if (result==EIO && retries < 10) {
00248                         kprintf("emu%d: I/O error on close, retrying\n", 
00249                                 sc->e_unit);
00250                         retries++;
00251                         continue;
00252                 }
00253                 break;
00254         }
00255 
00256         if (!mine) {
00257                 lock_release(sc->e_lock);
00258         }
00259         return result;
00260 }
00261 
00262 /*
00263  * Common code for read and readdir.
00264  */
00265 static
00266 int
00267 emu_doread(struct emu_softc *sc, uint32_t handle, uint32_t len,
00268            uint32_t op, struct uio *uio)
00269 {
00270         int result;
00271 
00272         KASSERT(uio->uio_rw == UIO_READ);
00273 
00274         lock_acquire(sc->e_lock);
00275 
00276         emu_wreg(sc, REG_HANDLE, handle);
00277         emu_wreg(sc, REG_IOLEN, len);
00278         emu_wreg(sc, REG_OFFSET, uio->uio_offset);
00279         emu_wreg(sc, REG_OPER, op);
00280         result = emu_waitdone(sc);
00281         if (result) {
00282                 goto out;
00283         }
00284         
00285         result = uiomove(sc->e_iobuf, emu_rreg(sc, REG_IOLEN), uio);
00286 
00287         uio->uio_offset = emu_rreg(sc, REG_OFFSET);
00288 
00289  out:
00290         lock_release(sc->e_lock);
00291         return result;
00292 }
00293 
00294 /*
00295  * Read from a hardware-level file handle.
00296  */
00297 static
00298 int
00299 emu_read(struct emu_softc *sc, uint32_t handle, uint32_t len,
00300          struct uio *uio)
00301 {
00302         return emu_doread(sc, handle, len, EMU_OP_READ, uio);
00303 }
00304 
00305 /*
00306  * Read a directory entry from a hardware-level file handle.
00307  */
00308 static
00309 int
00310 emu_readdir(struct emu_softc *sc, uint32_t handle, uint32_t len,
00311             struct uio *uio)
00312 {
00313         return emu_doread(sc, handle, len, EMU_OP_READDIR, uio);
00314 }
00315 
00316 /*
00317  * Write to a hardware-level file handle.
00318  */
00319 static
00320 int
00321 emu_write(struct emu_softc *sc, uint32_t handle, uint32_t len,
00322           struct uio *uio)
00323 {
00324         int result;
00325 
00326         KASSERT(uio->uio_rw == UIO_WRITE);
00327 
00328         lock_acquire(sc->e_lock);
00329 
00330         emu_wreg(sc, REG_HANDLE, handle);
00331         emu_wreg(sc, REG_IOLEN, len);
00332         emu_wreg(sc, REG_OFFSET, uio->uio_offset);
00333 
00334         result = uiomove(sc->e_iobuf, len, uio);
00335         if (result) {
00336                 goto out;
00337         }
00338 
00339         emu_wreg(sc, REG_OPER, EMU_OP_WRITE);
00340         result = emu_waitdone(sc);
00341 
00342  out:
00343         lock_release(sc->e_lock);
00344         return result;
00345 }
00346 
00347 /*
00348  * Get the file size associated with a hardware-level file handle.
00349  */
00350 static
00351 int
00352 emu_getsize(struct emu_softc *sc, uint32_t handle, off_t *retval)
00353 {
00354         int result;
00355 
00356         lock_acquire(sc->e_lock);
00357 
00358         emu_wreg(sc, REG_HANDLE, handle);
00359         emu_wreg(sc, REG_OPER, EMU_OP_GETSIZE);
00360         result = emu_waitdone(sc);
00361         if (result==0) {
00362                 *retval = emu_rreg(sc, REG_IOLEN);
00363         }
00364 
00365         lock_release(sc->e_lock);
00366         return result;
00367 }
00368 
00369 /*
00370  * Truncate a hardware-level file handle.
00371  */
00372 static
00373 int
00374 emu_trunc(struct emu_softc *sc, uint32_t handle, off_t len)
00375 {
00376         int result;
00377 
00378         lock_acquire(sc->e_lock);
00379 
00380         emu_wreg(sc, REG_HANDLE, handle);
00381         emu_wreg(sc, REG_IOLEN, len);
00382         emu_wreg(sc, REG_OPER, EMU_OP_TRUNC);
00383         result = emu_waitdone(sc);
00384 
00385         lock_release(sc->e_lock);
00386         return result;
00387 }
00388 
00389 //
00390 ////////////////////////////////////////////////////////////
00391 
00392 ////////////////////////////////////////////////////////////
00393 //
00394 // vnode functions 
00395 //
00396 
00397 // at bottom of this section
00398 
00399 static int emufs_loadvnode(struct emufs_fs *ef, uint32_t handle, int isdir,
00400                            struct emufs_vnode **ret);
00401 
00402 /*
00403  * VOP_OPEN on files
00404  */
00405 static
00406 int
00407 emufs_open(struct vnode *v, int openflags)
00408 {
00409         /*
00410          * At this level we do not need to handle O_CREAT, O_EXCL, or O_TRUNC.
00411          * We *would* need to handle O_APPEND, but we don't support it.
00412          *
00413          * Any of O_RDONLY, O_WRONLY, and O_RDWR are valid, so we don't need
00414          * to check that either.
00415          */
00416 
00417         if (openflags & O_APPEND) {
00418                 return EUNIMP;
00419         }
00420 
00421         (void)v;
00422 
00423         return 0;
00424 }
00425 
00426 /*
00427  * VOP_OPEN on directories
00428  */
00429 static
00430 int
00431 emufs_opendir(struct vnode *v, int openflags)
00432 {
00433         switch (openflags & O_ACCMODE) {
00434             case O_RDONLY:
00435                 break;
00436             case O_WRONLY:
00437             case O_RDWR:
00438             default:
00439                 return EISDIR;
00440         }
00441         if (openflags & O_APPEND) {
00442                 return EISDIR;
00443         }
00444 
00445         (void)v;
00446         return 0;
00447 }
00448 
00449 /*
00450  * VOP_CLOSE
00451  */
00452 static
00453 int
00454 emufs_close(struct vnode *v)
00455 {
00456         (void)v;
00457         return 0;
00458 }
00459 
00460 /*
00461  * VOP_RECLAIM
00462  *
00463  * Reclaim should make an effort to returning errors other than EBUSY.
00464  */
00465 static
00466 int
00467 emufs_reclaim(struct vnode *v)
00468 {
00469         struct emufs_vnode *ev = v->vn_data;
00470         struct emufs_fs *ef = v->vn_fs->fs_data;
00471         unsigned ix, i, num;
00472         int result;
00473 
00474         /*
00475          * Need both of these locks, e_lock to protect the device
00476          * and vfs_biglock to protect the fs-related material.
00477          */
00478 
00479         vfs_biglock_acquire();
00480         lock_acquire(ef->ef_emu->e_lock);
00481 
00482         if (ev->ev_v.vn_refcount != 1) {
00483                 lock_release(ef->ef_emu->e_lock);
00484                 vfs_biglock_release();
00485                 return EBUSY;
00486         }
00487 
00488         /* emu_close retries on I/O error */
00489         result = emu_close(ev->ev_emu, ev->ev_handle);
00490         if (result) {
00491                 lock_release(ef->ef_emu->e_lock);
00492                 vfs_biglock_release();
00493                 return result;
00494         }
00495 
00496         num = vnodearray_num(ef->ef_vnodes);
00497         ix = num;
00498         for (i=0; i<num; i++) {
00499                 struct vnode *vx;
00500 
00501                 vx = vnodearray_get(ef->ef_vnodes, i);
00502                 if (vx == v) {
00503                         ix = i;
00504                         break;
00505                 }
00506         }
00507         if (ix == num) {
00508                 panic("emu%d: reclaim vnode %u not in vnode pool\n",
00509                       ef->ef_emu->e_unit, ev->ev_handle);
00510         }
00511 
00512         vnodearray_remove(ef->ef_vnodes, ix);
00513         VOP_CLEANUP(&ev->ev_v);
00514 
00515         lock_release(ef->ef_emu->e_lock);
00516         vfs_biglock_release();
00517 
00518         kfree(ev);
00519         return 0;
00520 }
00521 
00522 /*
00523  * VOP_READ
00524  */
00525 static
00526 int
00527 emufs_read(struct vnode *v, struct uio *uio)
00528 {
00529         struct emufs_vnode *ev = v->vn_data;
00530         uint32_t amt;
00531         size_t oldresid;
00532         int result;
00533 
00534         KASSERT(uio->uio_rw==UIO_READ);
00535 
00536         while (uio->uio_resid > 0) {
00537                 amt = uio->uio_resid;
00538                 if (amt > EMU_MAXIO) {
00539                         amt = EMU_MAXIO;
00540                 }
00541 
00542                 oldresid = uio->uio_resid;
00543 
00544                 result = emu_read(ev->ev_emu, ev->ev_handle, amt, uio);
00545                 if (result) {
00546                         return result;
00547                 }
00548                 
00549                 if (uio->uio_resid == oldresid) {
00550                         /* nothing read - EOF */
00551                         break;
00552                 }
00553         }
00554 
00555         return 0;
00556 }
00557 
00558 /*
00559  * VOP_READDIR
00560  */
00561 static
00562 int
00563 emufs_getdirentry(struct vnode *v, struct uio *uio)
00564 {
00565         struct emufs_vnode *ev = v->vn_data;
00566         uint32_t amt;
00567 
00568         KASSERT(uio->uio_rw==UIO_READ);
00569 
00570         amt = uio->uio_resid;
00571         if (amt > EMU_MAXIO) {
00572                 amt = EMU_MAXIO;
00573         }
00574 
00575         return emu_readdir(ev->ev_emu, ev->ev_handle, amt, uio);
00576 }
00577 
00578 /*
00579  * VOP_WRITE
00580  */
00581 static
00582 int
00583 emufs_write(struct vnode *v, struct uio *uio)
00584 {
00585         struct emufs_vnode *ev = v->vn_data;
00586         uint32_t amt;
00587         size_t oldresid;
00588         int result;
00589 
00590         KASSERT(uio->uio_rw==UIO_WRITE);
00591 
00592         while (uio->uio_resid > 0) {
00593                 amt = uio->uio_resid;
00594                 if (amt > EMU_MAXIO) {
00595                         amt = EMU_MAXIO;
00596                 }
00597 
00598                 oldresid = uio->uio_resid;
00599 
00600                 result = emu_write(ev->ev_emu, ev->ev_handle, amt, uio);
00601                 if (result) {
00602                         return result;
00603                 }
00604 
00605                 if (uio->uio_resid == oldresid) {
00606                         /* nothing written...? */
00607                         break;
00608                 }
00609         }
00610 
00611         return 0;
00612 }
00613 
00614 /*
00615  * VOP_IOCTL
00616  */
00617 static
00618 int
00619 emufs_ioctl(struct vnode *v, int op, userptr_t data)
00620 {
00621         /*
00622          * No ioctls.
00623          */
00624 
00625         (void)v;
00626         (void)op;
00627         (void)data;
00628 
00629         return EINVAL;
00630 }
00631 
00632 /*
00633  * VOP_STAT
00634  */
00635 static
00636 int
00637 emufs_stat(struct vnode *v, struct stat *statbuf)
00638 {
00639         struct emufs_vnode *ev = v->vn_data;
00640         int result;
00641 
00642         bzero(statbuf, sizeof(struct stat));
00643 
00644         result = emu_getsize(ev->ev_emu, ev->ev_handle, &statbuf->st_size);
00645         if (result) {
00646                 return result;
00647         }
00648 
00649         result = VOP_GETTYPE(v, &statbuf->st_mode);
00650         if (result) {
00651                 return result;
00652         }
00653         statbuf->st_mode |= 0644; /* possibly a lie */
00654         statbuf->st_nlink = 1;    /* might be a lie, but doesn't matter much */
00655         statbuf->st_blocks = 0;   /* almost certainly a lie */
00656 
00657         return 0;
00658 }
00659 
00660 /*
00661  * VOP_GETTYPE for files
00662  */
00663 static
00664 int
00665 emufs_file_gettype(struct vnode *v, uint32_t *result)
00666 {
00667         (void)v;
00668         *result = S_IFREG;
00669         return 0;
00670 }
00671 
00672 /*
00673  * VOP_GETTYPE for directories
00674  */
00675 static
00676 int
00677 emufs_dir_gettype(struct vnode *v, uint32_t *result)
00678 {
00679         (void)v;
00680         *result = S_IFDIR;
00681         return 0;
00682 }
00683 
00684 /*
00685  * VOP_TRYSEEK
00686  */
00687 static
00688 int
00689 emufs_tryseek(struct vnode *v, off_t pos)
00690 {
00691         if (pos<0) {
00692                 return EINVAL;
00693         }
00694 
00695         /* Allow anything else */
00696         (void)v;
00697 
00698         return 0;
00699 }
00700 
00701 /*
00702  * VOP_FSYNC
00703  */
00704 static
00705 int
00706 emufs_fsync(struct vnode *v)
00707 {
00708         (void)v;
00709         return 0;
00710 }
00711 
00712 /*
00713  * VOP_TRUNCATE
00714  */
00715 static
00716 int
00717 emufs_truncate(struct vnode *v, off_t len)
00718 {
00719         struct emufs_vnode *ev = v->vn_data;
00720         return emu_trunc(ev->ev_emu, ev->ev_handle, len);
00721 }
00722 
00723 /*
00724  * VOP_CREAT
00725  */
00726 static
00727 int
00728 emufs_creat(struct vnode *dir, const char *name, bool excl, mode_t mode,
00729             struct vnode **ret)
00730 {
00731         struct emufs_vnode *ev = dir->vn_data;
00732         struct emufs_fs *ef = dir->vn_fs->fs_data;
00733         struct emufs_vnode *newguy;
00734         uint32_t handle;
00735         int result;
00736         int isdir;
00737 
00738         result = emu_open(ev->ev_emu, ev->ev_handle, name, true, excl, mode,
00739                           &handle, &isdir);
00740         if (result) {
00741                 return result;
00742         }
00743 
00744         result = emufs_loadvnode(ef, handle, isdir, &newguy);
00745         if (result) {
00746                 emu_close(ev->ev_emu, handle);
00747                 return result;
00748         }
00749 
00750         *ret = &newguy->ev_v;
00751         return 0;
00752 }
00753 
00754 /*
00755  * VOP_LOOKUP
00756  */
00757 static
00758 int
00759 emufs_lookup(struct vnode *dir, char *pathname, struct vnode **ret)
00760 {
00761         struct emufs_vnode *ev = dir->vn_data;
00762         struct emufs_fs *ef = dir->vn_fs->fs_data;
00763         struct emufs_vnode *newguy;
00764         uint32_t handle;
00765         int result;
00766         int isdir;
00767 
00768         result = emu_open(ev->ev_emu, ev->ev_handle, pathname, false, false, 0,
00769                           &handle, &isdir);
00770         if (result) {
00771                 return result;
00772         }
00773 
00774         result = emufs_loadvnode(ef, handle, isdir, &newguy);
00775         if (result) {
00776                 emu_close(ev->ev_emu, handle);
00777                 return result;
00778         }
00779 
00780         *ret = &newguy->ev_v;
00781         return 0;
00782 }
00783 
00784 /*
00785  * VOP_LOOKPARENT
00786  */
00787 static
00788 int
00789 emufs_lookparent(struct vnode *dir, char *pathname, struct vnode **ret,
00790                  char *buf, size_t len)
00791 {
00792         char *s;
00793 
00794         s = strrchr(pathname, '/');
00795         if (s==NULL) {
00796                 /* just a last component, no directory part */
00797                 if (strlen(pathname)+1 > len) {
00798                         return ENAMETOOLONG;
00799                 }
00800                 VOP_INCREF(dir);
00801                 *ret = dir;
00802                 strcpy(buf, pathname);
00803                 return 0;
00804         }
00805 
00806         *s = 0;
00807         s++;
00808         if (strlen(s)+1 > len) {
00809                 return ENAMETOOLONG;
00810         }
00811         strcpy(buf, s);
00812 
00813         return emufs_lookup(dir, pathname, ret);
00814 }
00815 
00816 /*
00817  * VOP_NAMEFILE
00818  */
00819 static
00820 int
00821 emufs_namefile(struct vnode *v, struct uio *uio)
00822 {
00823         struct emufs_vnode *ev = v->vn_data;
00824         struct emufs_fs *ef = v->vn_fs->fs_data;
00825 
00826         if (ev == ef->ef_root) {
00827                 /*
00828                  * Root directory - name is empty string
00829                  */
00830                 return 0;
00831         }
00832 
00833         (void)uio;
00834         
00835         return EUNIMP;
00836 }
00837 
00838 /*
00839  * VOP_MMAP
00840  */
00841 static
00842 int
00843 emufs_mmap(struct vnode *v)
00844 {
00845         (void)v;
00846         return EUNIMP;
00847 }
00848 
00849 //////////////////////////////
00850 
00851 /*
00852  * Bits not implemented at all on emufs
00853  */
00854 
00855 static
00856 int
00857 emufs_dir_tryseek(struct vnode *v, off_t pos)
00858 {
00859         (void)v;
00860         (void)pos;
00861         return EUNIMP;
00862 }
00863 
00864 static
00865 int
00866 emufs_symlink(struct vnode *v, const char *contents, const char *name)
00867 {
00868         (void)v;
00869         (void)contents;
00870         (void)name;
00871         return EUNIMP;
00872 }
00873 
00874 static
00875 int
00876 emufs_mkdir(struct vnode *v, const char *name, mode_t mode)
00877 {
00878         (void)v;
00879         (void)name;
00880         (void)mode;
00881         return EUNIMP;
00882 }
00883 
00884 static
00885 int
00886 emufs_link(struct vnode *v, const char *name, struct vnode *target)
00887 {
00888         (void)v;
00889         (void)name;
00890         (void)target;
00891         return EUNIMP;
00892 }
00893 
00894 static
00895 int
00896 emufs_remove(struct vnode *v, const char *name)
00897 {
00898         (void)v;
00899         (void)name;
00900         return EUNIMP;
00901 }
00902 
00903 static
00904 int
00905 emufs_rmdir(struct vnode *v, const char *name)
00906 {
00907         (void)v;
00908         (void)name;
00909         return EUNIMP;
00910 }
00911 
00912 static
00913 int
00914 emufs_rename(struct vnode *v1, const char *n1,
00915              struct vnode *v2, const char *n2)
00916 {
00917         (void)v1;
00918         (void)n1;
00919         (void)v2;
00920         (void)n2;
00921         return EUNIMP;
00922 }
00923 
00924 //////////////////////////////
00925 
00926 /*
00927  * Routines that fail
00928  *
00929  * It is kind of silly to write these out each with their particular
00930  * arguments; however, portable C doesn't let you cast function
00931  * pointers with different argument signatures even if the arguments
00932  * are never used.
00933  *
00934  * The BSD approach (all vnode ops take a vnode pointer and a void
00935  * pointer that's cast to a op-specific args structure) avoids this
00936  * problem but is otherwise not very appealing.
00937  */
00938 
00939 static
00940 int
00941 emufs_void_op_isdir(struct vnode *v)
00942 {
00943         (void)v;
00944         return EISDIR;
00945 }
00946 
00947 static
00948 int
00949 emufs_uio_op_isdir(struct vnode *v, struct uio *uio)
00950 {
00951         (void)v;
00952         (void)uio;
00953         return EISDIR;
00954 }
00955 
00956 static
00957 int
00958 emufs_uio_op_notdir(struct vnode *v, struct uio *uio)
00959 {
00960         (void)v;
00961         (void)uio;
00962         return ENOTDIR;
00963 }
00964 
00965 static
00966 int
00967 emufs_name_op_notdir(struct vnode *v, const char *name)
00968 {
00969         (void)v;
00970         (void)name;
00971         return ENOTDIR;
00972 }
00973 
00974 static
00975 int
00976 emufs_readlink_notlink(struct vnode *v, struct uio *uio)
00977 {
00978         (void)v;
00979         (void)uio;
00980         return EINVAL;
00981 }
00982 
00983 static
00984 int
00985 emufs_creat_notdir(struct vnode *v, const char *name, bool excl, mode_t mode,
00986                    struct vnode **retval)
00987 {
00988         (void)v;
00989         (void)name;
00990         (void)excl;
00991         (void)mode;
00992         (void)retval;
00993         return ENOTDIR;
00994 }
00995 
00996 static
00997 int
00998 emufs_symlink_notdir(struct vnode *v, const char *contents, const char *name)
00999 {
01000         (void)v;
01001         (void)contents;
01002         (void)name;
01003         return ENOTDIR;
01004 }
01005 
01006 static
01007 int
01008 emufs_mkdir_notdir(struct vnode *v, const char *name, mode_t mode)
01009 {
01010         (void)v;
01011         (void)name;
01012         (void)mode;
01013         return ENOTDIR;
01014 }
01015 
01016 static
01017 int
01018 emufs_link_notdir(struct vnode *v, const char *name, struct vnode *target)
01019 {
01020         (void)v;
01021         (void)name;
01022         (void)target;
01023         return ENOTDIR;
01024 }
01025 
01026 static
01027 int
01028 emufs_rename_notdir(struct vnode *v1, const char *n1,
01029                     struct vnode *v2, const char *n2)
01030 {
01031         (void)v1;
01032         (void)n1;
01033         (void)v2;
01034         (void)n2;
01035         return ENOTDIR;
01036 }
01037 
01038 static
01039 int
01040 emufs_lookup_notdir(struct vnode *v, char *pathname, struct vnode **result)
01041 {
01042         (void)v;
01043         (void)pathname;
01044         (void)result;
01045         return ENOTDIR;
01046 }
01047 
01048 static
01049 int
01050 emufs_lookparent_notdir(struct vnode *v, char *pathname, struct vnode **result,
01051                         char *buf, size_t len)
01052 {
01053         (void)v;
01054         (void)pathname;
01055         (void)result;
01056         (void)buf;
01057         (void)len;
01058         return ENOTDIR;
01059 }
01060 
01061 
01062 static
01063 int
01064 emufs_truncate_isdir(struct vnode *v, off_t len)
01065 {
01066         (void)v;
01067         (void)len;
01068         return ENOTDIR;
01069 }
01070 
01071 //////////////////////////////
01072 
01073 /*
01074  * Function table for emufs files.
01075  */
01076 static const struct vnode_ops emufs_fileops = {
01077         VOP_MAGIC,      /* mark this a valid vnode ops table */
01078 
01079         emufs_open,
01080         emufs_close,
01081         emufs_reclaim,
01082 
01083         emufs_read,
01084         emufs_readlink_notlink,
01085         emufs_uio_op_notdir, /* getdirentry */
01086         emufs_write,
01087         emufs_ioctl,
01088         emufs_stat,
01089         emufs_file_gettype,
01090         emufs_tryseek,
01091         emufs_fsync,
01092         emufs_mmap,
01093         emufs_truncate,
01094         emufs_uio_op_notdir, /* namefile */
01095 
01096         emufs_creat_notdir,
01097         emufs_symlink_notdir,
01098         emufs_mkdir_notdir,
01099         emufs_link_notdir,
01100         emufs_name_op_notdir, /* remove */
01101         emufs_name_op_notdir, /* rmdir */
01102         emufs_rename_notdir,
01103 
01104         emufs_lookup_notdir,
01105         emufs_lookparent_notdir,
01106 };
01107 
01108 /*
01109  * Function table for emufs directories.
01110  */
01111 static const struct vnode_ops emufs_dirops = {
01112         VOP_MAGIC,      /* mark this a valid vnode ops table */
01113 
01114         emufs_opendir,
01115         emufs_close,
01116         emufs_reclaim,
01117 
01118         emufs_uio_op_isdir,   /* read */
01119         emufs_uio_op_isdir,   /* readlink */
01120         emufs_getdirentry,
01121         emufs_uio_op_isdir,   /* write */
01122         emufs_ioctl,
01123         emufs_stat,
01124         emufs_dir_gettype,
01125         emufs_dir_tryseek,
01126         emufs_void_op_isdir,  /* fsync */
01127         emufs_void_op_isdir,  /* mmap */
01128         emufs_truncate_isdir,
01129         emufs_namefile,
01130 
01131         emufs_creat,
01132         emufs_symlink,
01133         emufs_mkdir,
01134         emufs_link,
01135         emufs_remove,
01136         emufs_rmdir,
01137         emufs_rename,
01138 
01139         emufs_lookup,
01140         emufs_lookparent,
01141 };
01142 
01143 /*
01144  * Function to load a vnode into memory.
01145  */
01146 static
01147 int
01148 emufs_loadvnode(struct emufs_fs *ef, uint32_t handle, int isdir,
01149                 struct emufs_vnode **ret)
01150 {
01151         struct vnode *v;
01152         struct emufs_vnode *ev;
01153         unsigned i, num;
01154         int result;
01155 
01156         vfs_biglock_acquire();
01157         lock_acquire(ef->ef_emu->e_lock);
01158 
01159         num = vnodearray_num(ef->ef_vnodes);
01160         for (i=0; i<num; i++) {
01161                 v = vnodearray_get(ef->ef_vnodes, i);
01162                 ev = v->vn_data;
01163                 if (ev->ev_handle == handle) {
01164                         /* Found */
01165 
01166                         VOP_INCREF(&ev->ev_v);
01167 
01168                         lock_release(ef->ef_emu->e_lock);
01169                         vfs_biglock_release();
01170                         *ret = ev;
01171                         return 0;
01172                 }
01173         }
01174 
01175         /* Didn't have one; create it */
01176 
01177         ev = kmalloc(sizeof(struct emufs_vnode));
01178         if (ev==NULL) {
01179                 lock_release(ef->ef_emu->e_lock);
01180                 return ENOMEM;
01181         }
01182 
01183         ev->ev_emu = ef->ef_emu;
01184         ev->ev_handle = handle;
01185 
01186         result = VOP_INIT(&ev->ev_v, isdir ? &emufs_dirops : &emufs_fileops,
01187                            &ef->ef_fs, ev);
01188         if (result) {
01189                 lock_release(ef->ef_emu->e_lock);
01190                 vfs_biglock_release();
01191                 kfree(ev);
01192                 return result;
01193         }
01194 
01195         result = vnodearray_add(ef->ef_vnodes, &ev->ev_v, NULL);
01196         if (result) {
01197                 /* note: VOP_CLEANUP undoes VOP_INIT - it does not kfree */
01198                 VOP_CLEANUP(&ev->ev_v);
01199                 lock_release(ef->ef_emu->e_lock);
01200                 vfs_biglock_release();
01201                 kfree(ev);
01202                 return result;
01203         }
01204 
01205         lock_release(ef->ef_emu->e_lock);
01206         vfs_biglock_release();
01207 
01208         *ret = ev;
01209         return 0;
01210 }
01211 
01212 //
01213 ////////////////////////////////////////////////////////////
01214 
01215 ////////////////////////////////////////////////////////////
01216 //
01217 // Whole-filesystem functions 
01218 //
01219 
01220 /*
01221  * FSOP_SYNC
01222  */
01223 static
01224 int
01225 emufs_sync(struct fs *fs)
01226 {
01227         (void)fs;
01228         return 0;
01229 }
01230 
01231 /*
01232  * FSOP_GETVOLNAME
01233  */
01234 static
01235 const char *
01236 emufs_getvolname(struct fs *fs)
01237 {
01238         /* We don't have a volume name beyond the device name */
01239         (void)fs;
01240         return NULL;
01241 }
01242 
01243 /*
01244  * FSOP_GETROOT
01245  */
01246 static
01247 struct vnode *
01248 emufs_getroot(struct fs *fs)
01249 {
01250         struct emufs_fs *ef;
01251 
01252         KASSERT(fs != NULL);
01253 
01254         ef = fs->fs_data;
01255 
01256         KASSERT(ef != NULL);
01257         KASSERT(ef->ef_root != NULL);
01258 
01259         VOP_INCREF(&ef->ef_root->ev_v);
01260         return &ef->ef_root->ev_v;
01261 }
01262 
01263 /*
01264  * FSOP_UNMOUNT
01265  */
01266 static
01267 int
01268 emufs_unmount(struct fs *fs)
01269 {
01270         /* Always prohibit unmount, as we're not really "mounted" */
01271         (void)fs;
01272         return EBUSY;
01273 }
01274 
01275 /*
01276  * Routine for "mounting" an emufs - we're not really mounted in the
01277  * sense that the VFS understands that term, because we're not
01278  * connected to a block device.
01279  *
01280  * Basically, we just add ourselves to the name list in the VFS layer.
01281  */
01282 static
01283 int
01284 emufs_addtovfs(struct emu_softc *sc, const char *devname)
01285 {
01286         struct emufs_fs *ef;
01287         int result;
01288 
01289         ef = kmalloc(sizeof(struct emufs_fs));
01290         if (ef==NULL) {
01291                 return ENOMEM;
01292         }
01293 
01294         ef->ef_fs.fs_sync = emufs_sync;
01295         ef->ef_fs.fs_getvolname = emufs_getvolname;
01296         ef->ef_fs.fs_getroot = emufs_getroot;
01297         ef->ef_fs.fs_unmount = emufs_unmount;
01298         ef->ef_fs.fs_data = ef;
01299 
01300         ef->ef_emu = sc;
01301         ef->ef_root = NULL;
01302         ef->ef_vnodes = vnodearray_create();
01303         if (ef->ef_vnodes == NULL) {
01304                 kfree(ef);
01305                 return ENOMEM;
01306         }
01307 
01308         result = emufs_loadvnode(ef, EMU_ROOTHANDLE, 1, &ef->ef_root);
01309         if (result) {
01310                 kfree(ef);
01311                 return result;
01312         }
01313 
01314         KASSERT(ef->ef_root!=NULL);
01315 
01316         result = vfs_addfs(devname, &ef->ef_fs);
01317         if (result) {
01318                 VOP_DECREF(&ef->ef_root->ev_v);
01319                 kfree(ef);
01320         }
01321         return result;
01322 }
01323 
01324 //
01325 ////////////////////////////////////////////////////////////
01326 
01327 /*
01328  * Config routine called by autoconf stuff.
01329  *
01330  * Initialize our data, then add ourselves to the VFS layer.
01331  */
01332 int
01333 config_emu(struct emu_softc *sc, int emuno)
01334 {
01335         char name[32];
01336 
01337         sc->e_lock = lock_create("emufs-lock");
01338         if (sc->e_lock == NULL) {
01339                 return ENOMEM;
01340         }
01341         sc->e_sem = sem_create("emufs-sem", 0);
01342         if (sc->e_sem == NULL) {
01343                 lock_destroy(sc->e_lock);
01344                 sc->e_lock = NULL;
01345                 return ENOMEM;
01346         }
01347         sc->e_iobuf = bus_map_area(sc->e_busdata, sc->e_buspos, EMU_BUFFER);
01348 
01349         snprintf(name, sizeof(name), "emu%d", emuno);
01350 
01351         return emufs_addtovfs(sc, name);
01352 }
 All Data Structures