root/kern/dev/lamebus/emu.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. emu_rreg
  2. emu_wreg
  3. emu_irq
  4. translate_err
  5. emu_waitdone
  6. emu_open
  7. emu_close
  8. emu_doread
  9. emu_read
  10. emu_readdir
  11. emu_write
  12. emu_getsize
  13. emu_trunc
  14. emufs_open
  15. emufs_opendir
  16. emufs_close
  17. emufs_reclaim
  18. emufs_read
  19. emufs_getdirentry
  20. emufs_write
  21. emufs_ioctl
  22. emufs_stat
  23. emufs_file_gettype
  24. emufs_dir_gettype
  25. emufs_tryseek
  26. emufs_fsync
  27. emufs_truncate
  28. emufs_creat
  29. emufs_lookup
  30. emufs_lookparent
  31. emufs_namefile
  32. emufs_mmap
  33. emufs_dir_tryseek
  34. emufs_symlink
  35. emufs_mkdir
  36. emufs_link
  37. emufs_remove
  38. emufs_rmdir
  39. emufs_rename
  40. emufs_void_op_isdir
  41. emufs_uio_op_isdir
  42. emufs_uio_op_notdir
  43. emufs_name_op_notdir
  44. emufs_readlink_notlink
  45. emufs_creat_notdir
  46. emufs_symlink_notdir
  47. emufs_mkdir_notdir
  48. emufs_link_notdir
  49. emufs_rename_notdir
  50. emufs_lookup_notdir
  51. emufs_lookparent_notdir
  52. emufs_truncate_isdir
  53. emufs_loadvnode
  54. emufs_sync
  55. emufs_getvolname
  56. emufs_getroot
  57. emufs_unmount
  58. emufs_addtovfs
  59. 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 }

/* [<][>][^][v][top][bottom][index][help] */