diff options
| -rw-r--r-- | BUGS | 46 | ||||
| -rw-r--r-- | bio.c | 5 | ||||
| -rw-r--r-- | bootmain.c | 55 | ||||
| -rw-r--r-- | defs.h | 28 | ||||
| -rw-r--r-- | exec.c | 22 | ||||
| -rw-r--r-- | file.c | 38 | ||||
| -rw-r--r-- | file.h | 4 | ||||
| -rw-r--r-- | fs.c | 411 | ||||
| -rw-r--r-- | fsvar.h | 6 | ||||
| -rw-r--r-- | main.c | 82 | ||||
| -rw-r--r-- | param.h | 1 | ||||
| -rw-r--r-- | proc.c | 141 | ||||
| -rw-r--r-- | proc.h | 4 | ||||
| -rw-r--r-- | runoff.list | 12 | ||||
| -rw-r--r-- | runoff.spec | 59 | ||||
| -rwxr-xr-x | runoff1 | 6 | ||||
| -rw-r--r-- | sh.c | 2 | ||||
| -rwxr-xr-x | show1 | 2 | ||||
| -rw-r--r-- | spinlock.c | 15 | ||||
| -rw-r--r-- | sysfile.c | 314 | ||||
| -rw-r--r-- | trap.c | 8 | ||||
| -rw-r--r-- | trapasm.S | 3 | ||||
| -rw-r--r-- | ulib.c | 12 | ||||
| -rw-r--r-- | user.h | 1 | ||||
| -rwxr-xr-x | vectors.pl | 21 | 
25 files changed, 633 insertions, 665 deletions
| @@ -4,47 +4,11 @@ proc.c:  	and be able to break out with an error return.  	it is better if you check *before* sleep. -	can swap procdump up after proc_kill -	and then have proc_exit and proc_wait on same sheet - -	sched ->  switch2scheduler?  or just switch? - -	factor out switching and scheduling code from process code - -	shuffle for formatting -  syscall.c: -	cannot convince runoff1 to split the extern lists to fill previous page completely. - -fs.c: split all name operations off in name.c?  (starting with namei but -      wdir keep in fs.c) -	locking? -	shuffle for formatting - -pipe.c: -	more comments? -	comment how functions get called? - -sysfile.c: -	is the sys_exec picture upside down? -	can sys_open and sys_exec be simplified any? - -general: -	sizeof parens? - -bio.c: -	decide odd or even -	bwrite doesn't need a second argument - -file.c: -	move fileincref onto page 1? - -L=$HOME/mit/l -(for i in *.c; do xoc -x xgnu -x ./nodecleq.zeta --typesonly $i; done) 2>&1 | grep warning - -saw random sharedfd failure. - -why does fdalloc consume reference? +	cannot convince runoff1 to split the extern lists  +	  to fill previous page completely. -why mkdir and create? +formatting: +	file.c filewrite leaks onto next page +	need to fix PAGEBREAK mechanism @@ -117,12 +117,11 @@ bread(uint dev, uint sector)  // Write buf's contents to disk.  // Must be locked.  void -bwrite(struct buf *b, uint sector) +bwrite(struct buf *b)  {    if((b->flags & B_BUSY) == 0)      panic("bwrite"); - -  ide_rw(b->dev & 0xff, sector, b->data, 1, 0); +  ide_rw(b->dev & 0xff, b->sector, b->data, 1, 0);    b->flags |= B_VALID;  } @@ -25,6 +25,7 @@  //  * cmain() in this file takes over,   //    reads in the kernel and jumps to it. +//PAGEBREAK!  #include "types.h"  #include "elf.h"  #include "x86.h" @@ -32,7 +33,6 @@  #define SECTSIZE  512  #define ELFHDR    ((struct elfhdr*) 0x10000) // scratch space -void readsect(void*, uint);  void readseg(uint, uint, uint);  void @@ -64,32 +64,6 @@ bad:      ;  } -// Read 'count' bytes at 'offset' from kernel into virtual address 'va'. -// Might copy more than asked -void -readseg(uint va, uint count, uint offset) -{ -  uint end_va; - -  va &= 0xFFFFFF; -  end_va = va + count; - -  // round down to sector boundary -  va &= ~(SECTSIZE - 1); - -  // translate from bytes to sectors, and kernel starts at sector 1 -  offset = (offset / SECTSIZE) + 1; - -  // If this is too slow, we could read lots of sectors at a time. -  // We'd write more to memory than asked, but it doesn't matter -- -  // we load in increasing order. -  while(va < end_va) { -    readsect((uchar*) va, offset); -    va += SECTSIZE; -    offset++; -  } -} -  void  waitdisk(void)  { @@ -98,6 +72,7 @@ waitdisk(void)      ;  } +// Read a single sector at offset into dst.  void  readsect(void *dst, uint offset)  { @@ -118,3 +93,29 @@ readsect(void *dst, uint offset)    insl(0x1F0, dst, SECTSIZE/4);  } +// Read 'count' bytes at 'offset' from kernel into virtual address 'va'. +// Might copy more than asked. +void +readseg(uint va, uint count, uint offset) +{ +  uint end_va; + +  va &= 0xFFFFFF; +  end_va = va + count; + +  // round down to sector boundary +  va &= ~(SECTSIZE - 1); + +  // translate from bytes to sectors, and kernel starts at sector 1 +  offset = (offset / SECTSIZE) + 1; + +  // If this is too slow, we could read lots of sectors at a time. +  // We'd write more to memory than asked, but it doesn't matter -- +  // we load in increasing order. +  while(va < end_va) { +    readsect((uchar*) va, offset); +    va += SECTSIZE; +    offset++; +  } +} + @@ -24,6 +24,7 @@ int proc_kill(int);  int proc_wait(void);  void yield(void);  void procdump(void); +void userinit(void);  // setjmp.S  struct jmpbuf; @@ -117,30 +118,31 @@ void ide_rw(int, uint, void*, uint, int);  void binit(void);  struct buf;  struct buf* bread(uint, uint); -void bwrite(struct buf*, uint); +void bwrite(struct buf*);  void brelse(struct buf*);  // fs.c  struct inode; +struct uinode;  void iinit(void); -void ilock(struct inode*); -void iunlock(struct inode*); -void idecref(struct inode*); -struct inode* iincref(struct inode*); -void iput(struct inode*); -struct inode* namei(char*); +struct inode* ilock(struct uinode*); +struct uinode* iunlock(struct inode*); +void iput(struct uinode*); +struct uinode* idup(struct uinode*); +struct uinode* namei(char*);  void stati(struct inode*, struct stat*);  int readi(struct inode*, char*, uint, uint);  int writei(struct inode*, char*, uint, uint); -struct inode* mknod(char*, short, short, short); -int unlink(char*); -int link(char*, char*); -struct inode* igetroot(void); -int mkdir(char *path); -struct inode* create(char *path); +int dirlink(struct inode *dp, char *name, uint ino); +struct uinode* dirlookup(struct inode *dp, char *name, uint *poff); +void iupdate(struct inode *ip); +int namecmp(const char *s, const char *t); +struct uinode* ialloc(uint, short); +struct uinode* nameiparent(char *path, char *name);  // exec.c  int exec(char*, char**);  // number of elements in fixed-size array  #define NELEM(x) (sizeof(x)/sizeof((x)[0])) + @@ -19,7 +19,7 @@ int  exec(char *path, char **argv)  {    uint sz, sp, p1, p2; -  int i, nargs, argbytes, len; +  int i, nargs, argbytes, len, off;    struct inode *ip;    struct elfhdr elf;    struct proghdr ph; @@ -29,7 +29,7 @@ exec(char *path, char **argv)    sz = 0;    mem = 0; -  if((ip = namei(path)) == 0) +  if((ip = ilock(namei(path))) == 0)      return -1;    if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf)) @@ -38,9 +38,8 @@ exec(char *path, char **argv)    if(elf.magic != ELF_MAGIC)      goto bad; -  for(i = 0; i < elf.phnum; i++){ -    if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph), -             sizeof(ph)) != sizeof(ph)) +  for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){ +    if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph))        goto bad;      if(ph.type != ELF_PROG_LOAD)        continue; @@ -94,7 +93,7 @@ exec(char *path, char **argv)    for(last=s=path; *s; s++)      if(*s == '/')        last = s+1; -  safestrcpy(cp->name, last, sizeof cp->name); +  safestrcpy(cp->name, last, sizeof(cp->name));    // commit to the new image.    kfree(cp->mem, cp->sz); @@ -102,9 +101,8 @@ exec(char *path, char **argv)    cp->mem = mem;    mem = 0; -  for(i = 0; i < elf.phnum; i++){ -    if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph), -             sizeof(ph)) != sizeof(ph)) +  for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){ +    if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph))        goto bad2;      if(ph.type != ELF_PROG_LOAD)        continue; @@ -115,7 +113,7 @@ exec(char *path, char **argv)      memset(cp->mem + ph.va + ph.filesz, 0, ph.memsz - ph.filesz);    } -  iput(ip); +  iput(iunlock(ip));    cp->tf->eip = elf.entry;    cp->tf->esp = sp; @@ -126,11 +124,11 @@ exec(char *path, char **argv)   bad:    if(mem)      kfree(mem, sz); -  iput(ip); +  iput(iunlock(ip));    return -1;   bad2: -  iput(ip); +  iput(iunlock(ip));    proc_exit();    return 0;  } @@ -11,9 +11,8 @@  #include "fs.h"  #include "fsvar.h" -struct spinlock file_table_lock;  struct devsw devsw[NDEV]; - +struct spinlock file_table_lock;  struct file file[NFILE];  void @@ -22,7 +21,7 @@ fileinit(void)    initlock(&file_table_lock, "file_table");  } -// Allocate a file structure +// Allocate a file structure.  struct file*  filealloc(void)  { @@ -57,16 +56,17 @@ int  fileread(struct file *f, char *addr, int n)  {    int r; +  struct inode *ip;    if(f->readable == 0)      return -1;    if(f->type == FD_PIPE)      return pipe_read(f->pipe, addr, n); -  if(f->type == FD_FILE){ -    ilock(f->ip); -    if((r = readi(f->ip, addr, f->off, n)) > 0) +  if(f->type == FD_INODE){ +    ip = ilock(f->ip); +    if((r = readi(ip, addr, f->off, n)) > 0)        f->off += r; -    iunlock(f->ip); +    iunlock(ip);      return r;    }    panic("fileread"); @@ -77,16 +77,17 @@ int  filewrite(struct file *f, char *addr, int n)  {    int r; +  struct inode *ip;    if(f->writable == 0)      return -1;    if(f->type == FD_PIPE)      return pipe_write(f->pipe, addr, n); -  if(f->type == FD_FILE){ -    ilock(f->ip); -    if((r = writei(f->ip, addr, f->off, n)) > 0) +  if(f->type == FD_INODE){ +    ip = ilock(f->ip); +    if((r = writei(ip, addr, f->off, n)) > 0)        f->off += r; -    iunlock(f->ip); +    iunlock(ip);      return r;    }    panic("filewrite"); @@ -96,10 +97,12 @@ filewrite(struct file *f, char *addr, int n)  int  filestat(struct file *f, struct stat *st)  { -  if(f->type == FD_FILE){ -    ilock(f->ip); -    stati(f->ip, st); -    iunlock(f->ip); +  struct inode *ip; + +  if(f->type == FD_INODE){ +    ip = ilock(f->ip); +    stati(ip, st); +    iunlock(ip);      return 0;    }    return -1; @@ -110,6 +113,7 @@ void  fileclose(struct file *f)  {    struct file ff; +    acquire(&file_table_lock);    if(f->ref < 1 || f->type == FD_CLOSED) @@ -127,8 +131,8 @@ fileclose(struct file *f)    if(ff.type == FD_PIPE)      pipe_close(ff.pipe, ff.writable); -  else if(ff.type == FD_FILE) -    idecref(ff.ip); +  else if(ff.type == FD_INODE) +    iput(ff.ip);    else      panic("fileclose");  } @@ -1,9 +1,9 @@  struct file { -  enum { FD_CLOSED, FD_NONE, FD_PIPE, FD_FILE } type; +  enum { FD_CLOSED, FD_NONE, FD_PIPE, FD_INODE } type;    int ref; // reference count    char readable;    char writable;    struct pipe *pipe; -  struct inode *ip; +  struct uinode *ip;    uint off;  }; @@ -7,8 +7,10 @@  //   + Names: paths like /usr/rtm/xv6/fs.c for convenient naming.  //  // Disk layout is: superblock, inodes, disk bitmap, data blocks. - -// TODO: Check locking! +// +// This file contains the low-level file system manipulation  +// routines.  The (higher-level) system call implementations +// are in sysfile.c.  #include "types.h"  #include "stat.h" @@ -25,7 +27,6 @@  #define min(a, b) ((a) < (b) ? (a) : (b))  static void itrunc(struct inode*); -static void iupdate(struct inode*);  // Blocks.  @@ -51,7 +52,7 @@ balloc(uint dev)      m = 0x1 << (bi % 8);      if((bp->data[bi/8] & m) == 0) {  // is block free?        bp->data[bi/8] |= 0x1 << (bi % 8); -      bwrite(bp, BBLOCK(b, ninodes));  // mark it allocated on disk +      bwrite(bp);  // mark it allocated on disk        brelse(bp);        return b;      } @@ -74,14 +75,14 @@ bfree(int dev, uint b)    bp = bread(dev, b);    memset(bp->data, 0, BSIZE); -  bwrite(bp, b); +  bwrite(bp);    brelse(bp);    bp = bread(dev, BBLOCK(b, ninodes));    bi = b % BPB;    m = 0x1 << (bi % 8);    bp->data[bi/8] &= ~m; -  bwrite(bp, BBLOCK(b, ninodes));  // mark it free on disk +  bwrite(bp);  // mark it free on disk    brelse(bp);  } @@ -98,11 +99,20 @@ bfree(int dev, uint b)  // It is an error to use an inode without holding a reference to it.  //  // Inodes can be marked busy, just like bufs, meaning -// that some process has logically locked the inode, and other processes -// are not allowed to look at it.  Because the locking can last for  -// a long time (for example, during a disk access), we use a flag -// like in buffer cache, not spin locks.  The inode should always be -// locked during modifications to it. +// that some process has exclusive use of the inode. +// Processes are only allowed to read and write inode +// metadata and contents when holding the inode's lock. +// Because inodes locks are held during disk accesses,  +// they are implemented using a flag, as in the buffer cache, +// not using spin locks.  Callers are responsible for locking +// inodes before passing them to routines in this file; leaving +// this responsibility with the caller makes it possible for them +// to create arbitrarily-sized atomic operations. +// +// To give maximum control over locking to the callers,  +// the routines in this file that return inode pointers  +// return pointers to *unlocked* inodes.  It is the callers' +// responsibility to lock them before using them.  struct {    struct spinlock lock; @@ -116,14 +126,8 @@ iinit(void)  }  // Find the inode with number inum on device dev -// and return the in-memory copy.  The returned inode -// has its reference count incremented (and thus must be -// idecref'ed), but is *unlocked*, meaning that none of the fields -// except dev and inum are guaranteed to be initialized. -// This convention gives the caller maximum control over blocking; -// it also guarantees that iget will not sleep, which is useful in  -// the early igetroot and when holding other locked inodes. -struct inode* +// and return the in-memory copy. h +static struct uinode*  iget(uint dev, uint inum)  {    struct inode *ip, *empty; @@ -136,7 +140,7 @@ iget(uint dev, uint inum)      if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){        ip->ref++;        release(&icache.lock); -      return ip; +      return (struct uinode*)ip;      }      if(empty == 0 && ip->ref == 0)    // Remember empty slot.        empty = ip; @@ -153,28 +157,37 @@ iget(uint dev, uint inum)    ip->flags = 0;    release(&icache.lock); -  return ip; +  return (struct uinode*)ip;  } -// Iget the inode for the file system root (/). -// This gets called before there is a current process: it cannot sleep! -struct inode* -igetroot(void) +// Increment reference count for ip. +// Returns ip to enable ip = idup(ip1) idiom. +struct uinode* +idup(struct uinode *uip)  {    struct inode *ip; -  ip = iget(ROOTDEV, 1); -  return ip; + +  ip = (struct inode*)uip; +  acquire(&icache.lock); +  ip->ref++; +  release(&icache.lock); +  return uip;  }  // Lock the given inode. -void -ilock(struct inode *ip) +struct inode* +ilock(struct uinode *uip)  {    struct buf *bp;    struct dinode *dip; +  struct inode *ip; + +  ip = (struct inode*)uip; +  if(ip == 0) +    return 0;    if(ip->ref < 1) -    panic("ilock"); +    panic("ilock: no refs");    acquire(&icache.lock);    while(ip->flags & I_BUSY) @@ -193,13 +206,19 @@ ilock(struct inode *ip)      memmove(ip->addrs, dip->addrs, sizeof(ip->addrs));      brelse(bp);      ip->flags |= I_VALID; +    if(ip->type == 0) +      panic("ilock: no type");    } +  return ip;  }  // Unlock the given inode. -void +struct uinode*  iunlock(struct inode *ip)  { +  if(ip == 0) +    return 0; +    if(!(ip->flags & I_BUSY) || ip->ref < 1)      panic("iunlock"); @@ -207,36 +226,21 @@ iunlock(struct inode *ip)    ip->flags &= ~I_BUSY;    wakeup(ip);    release(&icache.lock); -} - -// Unlock inode and drop reference. -void -iput(struct inode *ip) -{ -  iunlock(ip); -  idecref(ip); -} - -// Increment reference count for ip. -// Returns ip to enable ip = iincref(ip1) idiom. -struct inode* -iincref(struct inode *ip) -{ -  acquire(&icache.lock); -  ip->ref++; -  release(&icache.lock); -  return ip; +  return (struct uinode*)ip;  }  // Caller holds reference to unlocked ip.  Drop reference.  void -idecref(struct inode *ip) +iput(struct uinode *uip)  { +  struct inode *ip; +   +  ip = (struct inode*)uip;    acquire(&icache.lock);    if(ip->ref == 1 && (ip->flags & I_VALID) && ip->nlink == 0) {      // inode is no longer used: truncate and free inode.      if(ip->flags & I_BUSY) -      panic("idecref busy"); +      panic("iput busy");      ip->flags |= I_BUSY;      release(&icache.lock);      // XXX convince rsc that no one will come find this inode. @@ -251,7 +255,7 @@ idecref(struct inode *ip)  }  // Allocate a new inode with the given type on device dev. -struct inode* +struct uinode*  ialloc(uint dev, short type)  {    int inum, ninodes; @@ -270,7 +274,7 @@ ialloc(uint dev, short type)      if(dip->type == 0) {  // a free inode        memset(dip, 0, sizeof(*dip));        dip->type = type; -      bwrite(bp, IBLOCK(inum));   // mark it allocated on the disk +      bwrite(bp);   // mark it allocated on the disk        brelse(bp);        return iget(dev, inum);      } @@ -280,7 +284,7 @@ ialloc(uint dev, short type)  }  // Copy inode, which has changed, from memory to disk. -static void +void  iupdate(struct inode *ip)  {    struct buf *bp; @@ -294,7 +298,7 @@ iupdate(struct inode *ip)    dip->nlink = ip->nlink;    dip->size = ip->size;    memmove(dip->addrs, ip->addrs, sizeof(ip->addrs)); -  bwrite(bp, IBLOCK(ip->inum)); +  bwrite(bp);    brelse(bp);  } @@ -306,8 +310,8 @@ iupdate(struct inode *ip)  // listed in the block ip->addrs[INDIRECT].  // Return the disk block address of the nth block in inode ip. -// If there is no such block: if alloc is set, allocate one, else return -1. -uint +// If there is no such block, alloc controls whether one is allocated. +static uint  bmap(struct inode *ip, uint bn, int alloc)  {    uint addr, *a; @@ -339,7 +343,7 @@ bmap(struct inode *ip, uint bn, int alloc)          return -1;        }        a[bn] = addr = balloc(ip->dev); -      bwrite(bp, ip->addrs[INDIRECT]); +      bwrite(bp);      }      brelse(bp);      return addr; @@ -348,6 +352,7 @@ bmap(struct inode *ip, uint bn, int alloc)    panic("bmap: out of range");  } +// PAGEBREAK: 30  // Truncate inode (discard contents).  static void  itrunc(struct inode *ip) @@ -389,6 +394,7 @@ stati(struct inode *ip, struct stat *st)    st->size = ip->size;  } +//PAGEBREAK!  // Read data from inode.  int  readi(struct inode *ip, char *dst, uint off, uint n) @@ -416,6 +422,7 @@ readi(struct inode *ip, char *dst, uint off, uint n)    return n;  } +// PAGEBREAK!  // Write data to inode.  int  writei(struct inode *ip, char *src, uint off, uint n) @@ -438,7 +445,7 @@ writei(struct inode *ip, char *src, uint off, uint n)      bp = bread(ip->dev, bmap(ip, off/BSIZE, 1));      m = min(n - tot, BSIZE - off%BSIZE);      memmove(bp->data + off%BSIZE, src, m); -    bwrite(bp, bmap(ip, off/BSIZE, 0)); +    bwrite(bp);      brelse(bp);    } @@ -449,12 +456,10 @@ writei(struct inode *ip, char *src, uint off, uint n)    return n;  } +//PAGEBREAK!  // Directories -// -// Directories are just inodes (files) filled with dirent structures. -// Compare two names, which are strings with a max length of DIRSIZ. -static int +int  namecmp(const char *s, const char *t)  {    int i; @@ -468,25 +473,9 @@ namecmp(const char *s, const char *t)    return 0;  } -// Copy one name to another. -static void -namecpy(char *s, const char *t) -{ -  int i; -   -  for(i=0; i<DIRSIZ && t[i]; i++) -    s[i] = t[i]; -  for(; i<DIRSIZ; i++) -    s[i] = 0; -} -  // Look for a directory entry in a directory. -// If not found, return -1. -// If found: -//   set *poff to the byte offset of the directory entry -//   set *pinum to the inode number -//   return 0. -static struct inode* +// If found, set *poff to byte offset of entry. +struct uinode*  dirlookup(struct inode *dp, char *name, uint *poff)  {    uint off, inum; @@ -517,18 +506,29 @@ dirlookup(struct inode *dp, char *name, uint *poff)    return 0;  } +// Copy one name to another. +static void +namecpy(char *s, const char *t) +{ +  int i; +   +  for(i=0; i<DIRSIZ && t[i]; i++) +    s[i] = t[i]; +  for(; i<DIRSIZ; i++) +    s[i] = 0; +} +  // Write a new directory entry (name, ino) into the directory dp. -// Caller must have locked dp. -static int +int  dirlink(struct inode *dp, char *name, uint ino)  {    int off;    struct dirent de; -  struct inode *ip; +  struct uinode *ip; -  // Double-check that name is not present. +  // Check that name is not present.    if((ip = dirlookup(dp, name, 0)) != 0){ -    idecref(ip); +    iput(ip);      return -1;    } @@ -548,49 +548,18 @@ dirlink(struct inode *dp, char *name, uint ino)    return 0;  } -// Create a new inode named name inside dp -// and return its locked inode structure. -// If name already exists, return 0. -static struct inode* -dircreat(struct inode *dp, char *name, short type, short major, short minor) -{ -  struct inode *ip; - -  ip = ialloc(dp->dev, type); -  if(ip == 0) -    return 0; -  ilock(ip); -  ip->major = major; -  ip->minor = minor; -  ip->size = 0; -  ip->nlink = 1; -  iupdate(ip); -   -  if(dirlink(dp, name, ip->inum) < 0){ -    ip->nlink = 0; -    iupdate(ip); -    iput(ip); -    return 0; -  } - -  return ip; -} -  // Paths -// Skip over the next path element in path,  -// saving it in *name and its length in *len. -// Return a pointer to the element after that -// (after any trailing slashes). -// Thus the caller can check whether *path=='\0' -// to see whether the name just removed was -// the last one.   -// If there is no name to remove, return 0. +// Copy the next path element from path into name. +// Return a pointer to the element following the copied one. +// The returned path has no leading slashes, +// so the caller can check *path=='\0' to see if the name is the last one. +// If no name to remove, return 0.  //  // Examples: -//   skipelem("a/bb/c") = "bb/c", with *name = "a/bb/c", len=1 -//   skipelem("///a/bb") = "b", with *name="a/bb", len=1 -//   skipelem("") = skipelem("////") = 0 +//   skipelem("a/bb/c", name) = "bb/c", setting name = "a" +//   skipelem("///a/bb", name) = "b", setting name="a" +//   skipelem("", name) = skipelem("////", name) = 0  //  static char*  skipelem(char *path, char *name) @@ -617,201 +586,61 @@ skipelem(char *path, char *name)    return path;  } -// look up a path name, in one of three modes. -// NAMEI_LOOKUP: return locked target inode. -// NAMEI_CREATE: return locked parent inode. -//   return 0 if name does exist. -//   *ret_last points to last path component (i.e. new file name). -//   *ret_ip points to the the name that did exist, if it did. -//   *ret_ip and *ret_last may be zero even if return value is zero. -// NAMEI_DELETE: return locked parent inode, offset of dirent in *ret_off. -//   return 0 if name doesn't exist. -struct inode* +// Look up and return the inode for a path name. +// If parent is set, return the inode for the parent +// and write the final path element to name, which +// should have room for DIRSIZ bytes. +static struct uinode*  _namei(char *path, int parent, char *name)  { -  struct inode *dp, *ip; +  struct uinode *dp, *ip; +  struct inode *dpl;    uint off;    if(*path == '/') -    dp = igetroot(); +    dp = iget(ROOTDEV, 1);    else -    dp = iincref(cp->cwd); -  ilock(dp); +    dp = idup(cp->cwd);    while((path = skipelem(path, name)) != 0){ -    if(dp->type != T_DIR) -      goto fail; +    dpl = ilock(dp); +    if(dpl->type != T_DIR){ +      iunlock(dpl); +      iput(dp); +      return 0; +    }      if(parent && *path == '\0'){        // Stop one level early. +      iunlock(dpl);        return dp;      } -    if((ip = dirlookup(dp, name, &off)) == 0) -      goto fail; +    if((ip = dirlookup(dpl, name, &off)) == 0){ +      iunlock(dpl); +      iput(dp); +      iput(ip); +      return 0; +    } +    iunlock(dpl);      iput(dp); -    ilock(ip);      dp = ip; -    if(dp->type == 0 || dp->nlink < 1) -      panic("namei");    }    if(parent)      return 0;    return dp; - -fail: -  iput(dp); -  return 0;  } -struct inode* +struct uinode*  namei(char *path)  {    char name[DIRSIZ];    return _namei(path, 0, name);  } -static struct inode* +struct uinode*  nameiparent(char *path, char *name)  {    return _namei(path, 1, name);  } - -// Create the path and return its locked inode structure. -// If cp already exists, return 0. -struct inode* -mknod(char *path, short type, short major, short minor) -{ -  struct inode *ip, *dp; -  char name[DIRSIZ]; - -  if((dp = nameiparent(path, name)) == 0) -    return 0; -  ip = dircreat(dp, name, type, major, minor); -  iput(dp); -  return ip; -} - -// Unlink the inode named cp. -int -unlink(char *path) -{ -  struct inode *ip, *dp; -  struct dirent de; -  uint off; -  char name[DIRSIZ]; - -  if((dp = nameiparent(path, name)) == 0) -    return -1; - -  // Cannot unlink "." or "..". -  if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){ -    iput(dp); -    return -1; -  } - -  if((ip = dirlookup(dp, name, &off)) == 0){ -    iput(dp); -    return -1; -  } -  memset(&de, 0, sizeof(de)); -  if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) -    panic("unlink dir write"); -  iput(dp); - -  ilock(ip); -  if(ip->nlink < 1) -    panic("unlink nlink < 1"); -  ip->nlink--; -  iupdate(ip); -  iput(ip); - -  return 0; -} - -// Create the path new as a link to the same inode as old. -int -link(char *old, char *new) -{ -  struct inode *ip, *dp; -  char name[DIRSIZ]; - -  if((ip = namei(old)) == 0) -    return -1; -  if(ip->type == T_DIR){ -    iput(ip); -    return -1; -  } -  iunlock(ip); - -  if((dp = nameiparent(new, name)) == 0){ -    idecref(ip); -    return -1; -  } -  if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){ -    idecref(ip); -    iput(dp); -    return -1; -  } -  iput(dp); - -  // XXX write ordering wrong here too. -  ilock(ip); -  ip->nlink++; -  iupdate(ip); -  iput(ip); -  return 0; -} - -int -mkdir(char *path) -{ -  struct inode *dp, *ip; -  char name[DIRSIZ]; -   -  // XXX write ordering is screwy here- do we care? -  if((dp = nameiparent(path, name)) == 0) -    return -1; -   -  if((ip = dircreat(dp, name, T_DIR, 0, 0)) == 0){ -    iput(dp); -    return -1; -  } -  dp->nlink++; -  iupdate(dp); - -  if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0) -    panic("mkdir"); -  iput(dp); -  iput(ip); - -  return 0; -} - -struct inode* -create(char *path) -{ -  struct inode *dp, *ip; -  char name[DIRSIZ]; -   -  if((dp = nameiparent(path, name)) == 0) -    return 0; -   -  if((ip = dirlookup(dp, name, 0)) != 0){ -    iput(dp); -    ilock(ip); -    if(ip->type == T_DIR){ -      iput(ip); -      return 0; -    } -    return ip; -  } -  if((ip = dircreat(dp, name, T_FILE, 0, 0)) == 0){ -    iput(dp); -    return 0; -  } -  iput(dp); -  return ip; -} - @@ -14,7 +14,11 @@ struct inode {    uint addrs[NADDRS];  }; -#define ROOTDEV  1   // Device number of root file system +// unlocked inode - only dev and inum are available +struct uinode { +  uint dev; +  uint inum; +};  #define I_BUSY 0x1  #define I_VALID 0x2 @@ -12,8 +12,6 @@  extern char edata[], end[]; -void proc0init(); -  // Bootstrap processor starts running C code here.  // This is called main0 not main so that it can have  // a void return type.  Gcc can't handle functions named @@ -35,49 +33,37 @@ main0(void)    bcpu = mp_bcpu();    // switch to bootstrap processor's stack -  asm volatile("movl %0, %%esp" : : "r" (cpus[bcpu].mpstack + MPSTACK - 32)); -  asm volatile("movl %0, %%ebp" : : "r" (cpus[bcpu].mpstack + MPSTACK)); +  asm volatile("movl %0, %%esp" : : "r" (cpus[bcpu].mpstack+MPSTACK-32)); +  asm volatile("movl %0, %%ebp" : : "r" (cpus[bcpu].mpstack+MPSTACK));    lapic_init(bcpu);    cprintf("\ncpu%d: starting xv6\n\n", cpu()); -  pinit(); // process table -  binit(); // buffer cache -  pic_init(); -  ioapic_init(); -  kinit(); // physical memory allocator -  tvinit(); // trap vectors -  idtinit(); // this CPU's interrupt descriptor table -  fileinit(); -  iinit(); // i-node table - -  // make sure there's a TSS -  setupsegs(0); - -  // initialize I/O devices, let them enable interrupts -  console_init(); -  ide_init(); - -  // start other CPUs -  mp_startthem(); - -  // turn on timer -  if(ismp) -    lapic_timerinit(); -  else -    pit8253_timerinit(); - -  // enable interrupts on the local APIC -  lapic_enableintr(); +  pinit();         // process table +  binit();         // buffer cache +  pic_init();      // interrupt controller +  ioapic_init();   // another interrupt controller +  kinit();         // physical memory allocator +  tvinit();        // trap vectors +  idtinit();       // interrupt descriptor table +  fileinit();      // file table +  iinit();         // inode cache +  setupsegs(0);    // segments & TSS +  console_init();  // I/O devices & their interrupts +  ide_init();      // disk +  mp_startthem();  // other CPUs +  if(ismp){ +    lapic_timerinit();   // smp timer +    lapic_enableintr();  // local interrupts +  }else +    pit8253_timerinit(); // uniprocessor timer +  userinit();      // first user process    // enable interrupts on this processor.    cpus[cpu()].nlock--;    sti(); -  // initialize process 0 -  proc0init(); -    scheduler();  } @@ -106,29 +92,3 @@ mpmain(void)    scheduler();  } -void -proc0init(void) -{ -  struct proc *p; -  extern uchar _binary_initcode_start[], _binary_initcode_size[]; -   -  p = copyproc(0); -  p->sz = PAGE; -  p->mem = kalloc(p->sz); -  p->cwd = igetroot(); -  memset(&p->tf, 0, sizeof p->tf); -  p->tf->es = p->tf->ds = p->tf->ss = (SEG_UDATA << 3) | DPL_USER; -  p->tf->cs = (SEG_UCODE << 3) | DPL_USER; -  p->tf->eflags = FL_IF; -  p->tf->esp = p->sz; -   -  // Push dummy return address to placate gcc. -  p->tf->esp -= 4; -  *(uint*)(p->mem + p->tf->esp) = 0xefefefef; - -  p->tf->eip = 0; -  memmove(p->mem, _binary_initcode_start, (int)_binary_initcode_size); -  safestrcpy(p->name, "initcode", sizeof p->name); -  p->state = RUNNABLE; -} - @@ -8,3 +8,4 @@  #define NBUF         10  // size of disk block cache  #define NINODE      100  // maximum number of active i-nodes  #define NDEV         10  // maximum major device number +#define ROOTDEV       1  // device number of file system root disk @@ -11,7 +11,7 @@ struct spinlock proc_table_lock;  struct proc proc[NPROC];  struct proc *curproc[NCPU]; -int next_pid = 1; +int nextpid = 1;  extern void forkret(void);  extern void forkret1(struct trapframe*); @@ -21,37 +21,27 @@ pinit(void)    initlock(&proc_table_lock, "proc_table");  } -// Set up CPU's segment descriptors and task state for a -// given process. -// If p==0, set up for "idle" state for when scheduler() -// is idling, not running any process. -void -setupsegs(struct proc *p) +// Look in the process table for an UNUSED proc. +// If found, change state to EMBRYO and return it. +// Otherwise return 0. +static struct proc* +allocproc(void)  { -  struct cpu *c = &cpus[cpu()]; - -  c->ts.ss0 = SEG_KDATA << 3; -  if(p){ -    c->ts.esp0 = (uint)(p->kstack + KSTACKSIZE); -  } else { -    c->ts.esp0 = 0xffffffff; -  } +  int i; +  struct proc *p; -  c->gdt[0] = SEG_NULL; -  c->gdt[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0x100000 + 64*1024-1, 0); -  c->gdt[SEG_KDATA] = SEG(STA_W, 0, 0xffffffff, 0); -  c->gdt[SEG_TSS] = SEG16(STS_T32A, (uint)&c->ts, sizeof(c->ts)-1, 0); -  c->gdt[SEG_TSS].s = 0; -  if(p){ -    c->gdt[SEG_UCODE] = SEG(STA_X|STA_R, (uint)p->mem, p->sz-1, DPL_USER); -    c->gdt[SEG_UDATA] = SEG(STA_W, (uint)p->mem, p->sz-1, DPL_USER); -  } else { -    c->gdt[SEG_UCODE] = SEG_NULL; -    c->gdt[SEG_UDATA] = SEG_NULL; +  acquire(&proc_table_lock); +  for(i = 0; i < NPROC; i++){ +    p = &proc[i]; +    if(p->state == UNUSED){ +      p->state = EMBRYO; +      p->pid = nextpid++; +      release(&proc_table_lock); +      return p; +    }    } - -  lgdt(c->gdt, sizeof c->gdt); -  ltr(SEG_TSS << 3); +  release(&proc_table_lock); +  return 0;  }  // Grow current process's memory by n bytes. @@ -73,29 +63,41 @@ growproc(int n)    return cp->sz - n;  } -// Look in the process table for an UNUSED proc. -// If found, change state to EMBRYO and return it. -// Otherwise return 0. -struct proc* -allocproc(void) +// Set up CPU's segment descriptors and task state for a +// given process. +// If p==0, set up for "idle" state for when scheduler() +// is idling, not running any process. +void +setupsegs(struct proc *p)  { -  int i; -  struct proc *p; +  struct cpu *c = &cpus[cpu()]; -  for(i = 0; i < NPROC; i++){ -    p = &proc[i]; -    if(p->state == UNUSED){ -      p->state = EMBRYO; -      return p; -    } +  c->ts.ss0 = SEG_KDATA << 3; +  if(p) +    c->ts.esp0 = (uint)(p->kstack + KSTACKSIZE); +  else +    c->ts.esp0 = 0xffffffff; + +  c->gdt[0] = SEG_NULL; +  c->gdt[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0x100000 + 64*1024-1, 0); +  c->gdt[SEG_KDATA] = SEG(STA_W, 0, 0xffffffff, 0); +  c->gdt[SEG_TSS] = SEG16(STS_T32A, (uint)&c->ts, sizeof(c->ts)-1, 0); +  c->gdt[SEG_TSS].s = 0; +  if(p){ +    c->gdt[SEG_UCODE] = SEG(STA_X|STA_R, (uint)p->mem, p->sz-1, DPL_USER); +    c->gdt[SEG_UDATA] = SEG(STA_W, (uint)p->mem, p->sz-1, DPL_USER); +  } else { +    c->gdt[SEG_UCODE] = SEG_NULL; +    c->gdt[SEG_UDATA] = SEG_NULL;    } -  return 0; + +  lgdt(c->gdt, sizeof(c->gdt)); +  ltr(SEG_TSS << 3);  }  // Create a new process copying p as the parent. -// Does not copy the kernel stack. -// Instead, sets up stack to return as if from system call. -// Caller must arrange for process to run (set state to RUNNABLE). +// Sets up stack to return as if from system call. +// Caller must set state of returned proc to RUNNABLE.  struct proc*  copyproc(struct proc *p)  { @@ -103,13 +105,8 @@ copyproc(struct proc *p)    struct proc *np;    // Allocate process. -  acquire(&proc_table_lock); -  if((np = allocproc()) == 0){ -    release(&proc_table_lock); +  if((np = allocproc()) == 0)      return 0; -  } -  np->pid = next_pid++; -  release(&proc_table_lock);    // Allocate kernel stack.    if((np->kstack = kalloc(KSTACKSIZE)) == 0){ @@ -120,7 +117,7 @@ copyproc(struct proc *p)    if(p){  // Copy process state from p.      np->ppid = p->pid; -    memmove(np->tf, p->tf, sizeof *np->tf); +    memmove(np->tf, p->tf, sizeof(*np->tf));      np->sz = p->sz;      if((np->mem = kalloc(np->sz)) == 0){ @@ -132,24 +129,49 @@ copyproc(struct proc *p)      memmove(np->mem, p->mem, np->sz);      for(i = 0; i < NOFILE; i++){ -      np->ofile[i] = p->ofile[i]; -      if(np->ofile[i]) +      if((np->ofile[i] = p->ofile[i]) != 0)          fileincref(np->ofile[i]);      } -    np->cwd = iincref(p->cwd); +    np->cwd = idup(p->cwd);    }    // Set up new jmpbuf to start executing at forkret (see below). -  memset(&np->jmpbuf, 0, sizeof np->jmpbuf); +  memset(&np->jmpbuf, 0, sizeof(np->jmpbuf));    np->jmpbuf.eip = (uint)forkret;    np->jmpbuf.esp = (uint)np->tf - 4;    // Clear %eax so that fork system call returns 0 in child.    np->tf->eax = 0; -    return np;  } +// Set up first user process. +void +userinit(void) +{ +  struct proc *p; +  extern uchar _binary_initcode_start[], _binary_initcode_size[]; +   +  p = copyproc(0); +  p->sz = PAGE; +  p->mem = kalloc(p->sz); +  p->cwd = namei("/"); +  memset(&p->tf, 0, sizeof(p->tf)); +  p->tf->es = p->tf->ds = p->tf->ss = (SEG_UDATA << 3) | DPL_USER; +  p->tf->cs = (SEG_UCODE << 3) | DPL_USER; +  p->tf->eflags = FL_IF; +  p->tf->esp = p->sz; +   +  // Push dummy return address to placate gcc. +  p->tf->esp -= 4; +  *(uint*)(p->mem + p->tf->esp) = 0xefefefef; + +  p->tf->eip = 0; +  memmove(p->mem, _binary_initcode_start, (int)_binary_initcode_size); +  safestrcpy(p->name, "initcode", sizeof(p->name)); +  p->state = RUNNABLE; +} +  //PAGEBREAK: 42  // Per-CPU process scheduler.  // Each CPU calls scheduler() after setting itself up. @@ -269,6 +291,7 @@ sleep(void *chan, struct spinlock *lk)    }  } +//PAGEBREAK!  // Wake up all processes sleeping on chan.  // Proc_table_lock must be held.  void @@ -334,7 +357,7 @@ proc_exit(void)      }    } -  idecref(cp->cwd); +  iput(cp->cwd);    cp->cwd = 0;    acquire(&proc_table_lock); @@ -37,7 +37,7 @@ struct proc {    void *chan;               // If non-zero, sleeping on chan    int killed;               // If non-zero, have been killed    struct file *ofile[NOFILE];  // Open files -  struct inode *cwd;        // Current directory +  struct uinode *cwd;       // Current directory    struct jmpbuf jmpbuf;     // Jump here to run process    struct trapframe *tf;     // Trap frame for current interrupt    char name[16];            // Process name (debugging) @@ -49,8 +49,6 @@ struct proc {  //   fixed-size stack  //   expandable heap -extern struct proc proc[]; -  // If xv6 was only for uniprocessors, this could be  //   struct proc *cp;  // Instead we have an array curproc, one per diff --git a/runoff.list b/runoff.list index 6c7cc21..5aa1d96 100644 --- a/runoff.list +++ b/runoff.list @@ -13,7 +13,7 @@ bootasm.S  bootother.S  bootmain.c  main.c -mp.c +initcode.S  init.c  # locks @@ -27,11 +27,11 @@ setjmp.S  kalloc.c  # system calls -syscall.h -trapasm.S  traps.h -trap.c  vectors.pl +trapasm.S +trap.c +syscall.h  syscall.c  sysproc.c @@ -46,6 +46,7 @@ fsvar.h  ide.c  bio.c  fs.c +exec.c  file.c  sysfile.c @@ -56,10 +57,11 @@ pipe.c  string.c  # low-level PC +mp.c  ioapic.h  lapic.c  ioapic.c  picirq.c  kbd.h  console.c -8253pit.c
\ No newline at end of file +8253pit.c diff --git a/runoff.spec b/runoff.spec index 53e98ee..9d0ad31 100644 --- a/runoff.spec +++ b/runoff.spec @@ -1,11 +1,50 @@ -even: mmu.h -even: bootasm.S -even: bootother.S -even: bootmain.c +# types.h either +# param.h either +# defs.h either +# x86.h either +# asm.h either +# mmu.h either +# elf.h either +# mp.h either + +even: bootasm.S  # mild preference +even: bootother.S  # mild preference +# bootmain.c either  even: main.c -even: spinlock.c -even: proc.h -even: proc.c -odd: kalloc.c -even: trap.c -odd: bio.c +# mp.c don't care at all +even: initcode.S +odd: init.c + +# spinlock.h either +# spinlock.c either +even: proc.h  # mild preference +even: proc.c  # VERY important +# setjmp.S either +# kalloc.c either + +# syscall.h either +# trapasm.S either +# traps.h either +even: trap.c  # important +# vectors.pl either +# syscall.c either +# sysproc.c either + +# buf.h either +# dev.h either +# fcntl.h either +# stat.h either +# file.h either +# fs.h either +# fsvar.h either +# even: ide.c +# odd: bio.c +odd: fs.c   # VERY important +# file.c either +# exec.c either +# sysfile.c either + +even: pipe.c  # mild preference +# string.c either +# even: console.c + @@ -45,6 +45,12 @@ for($i=0; $i<@lines; ){  		$sawbrace = 0;  		$breaksize = 15;  # 15 lines to get to function  		for($j=$i; $j<$i+50 && $j < @lines; $j++){ +			if($lines[$j] =~ /PAGEBREAK!/){ +				$lines[$j] = ""; +				$breakbefore = $j; +				$breaksize = 100; +				last; +			}  			if($lines[$j] =~ /PAGEBREAK:\s*([0-9]+)/){  				$breaksize = $1;  				$breakbefore = $j; @@ -41,7 +41,7 @@ int _gettoken(char *s, char **p1, char **p2);  int  main(void)  { -  while(getcmd(buf, sizeof buf) >= 0) { +  while(getcmd(buf, sizeof(buf)) >= 0) {      if(parse(buf) >= 0)        runcmd();    } @@ -1,3 +1,3 @@  #!/bin/sh -runoff1 "$@" | pr.pl -h "xv6/$@" | mpage -m50t50b -o -bLetter -T -t -2 -FCourier -L60 >x.ps; gv --swap x.ps +runoff1 "$@" | pr.pl -h "xv6/$@" | mpage -m50t50b -o -bLetter -T -t -2 -FLucidaSans-Typewriter83 -L60 >x.ps; gv --swap x.ps @@ -36,6 +36,13 @@ getcallerpcs(void *v, uint pcs[])      pcs[i] = 0;  } +// Check whether this cpu is holding the lock. +int +holding(struct spinlock *lock) +{ +  return lock->locked && lock->cpu == cpu() + 10; +} +  // Acquire the lock.  // Loops (spins) until the lock is acquired.  // (Because contention is handled by spinning, @@ -83,11 +90,3 @@ release(struct spinlock *lock)    if(--cpus[cpu()].nlock == 0)      sti();  } - -// Check whether this cpu is holding the lock. -int -holding(struct spinlock *lock) -{ -  return lock->locked && lock->cpu == cpu() + 10; -} - @@ -11,7 +11,6 @@  #include "buf.h"  #include "fs.h"  #include "fsvar.h" -#include "elf.h"  #include "file.h"  #include "fcntl.h" @@ -51,27 +50,15 @@ fdalloc(struct file *f)  }  int -sys_pipe(void) +sys_read(void)  { -  int *fd; -  struct file *rf, *wf; -  int fd0, fd1; +  struct file *f; +  int n; +  char *cp; -  if(argptr(0, (void*)&fd, 2*sizeof fd[0]) < 0) -    return -1; -  if(pipe_alloc(&rf, &wf) < 0) -    return -1; -  fd0 = -1; -  if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){ -    if(fd0 >= 0) -      cp->ofile[fd0] = 0; -    fileclose(rf); -    fileclose(wf); +  if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0)      return -1; -  } -  fd[0] = fd0; -  fd[1] = fd1; -  return 0; +  return fileread(f, cp, n);  }  int @@ -87,15 +74,14 @@ sys_write(void)  }  int -sys_read(void) +sys_fstat(void)  {    struct file *f; -  int n; -  char *cp; - -  if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0) +  struct stat *st; +   +  if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0)      return -1; -  return fileread(f, cp, n); +  return filestat(f, st);  }  int @@ -111,6 +97,150 @@ sys_close(void)    return 0;  } +// Create the path new as a link to the same inode as old. +int +sys_link(void) +{ +  char name[DIRSIZ], *new, *old; +  struct inode *dp, *ip; +  struct uinode *ipu; + +  if(argstr(0, &old) < 0 || argstr(1, &new) < 0) +    return -1; +  if((ip = ilock(namei(old))) == 0) +    return -1; +  if(ip->type == T_DIR){ +    iput(iunlock(ip)); +    return -1; +  } +  ip->nlink++; +  iupdate(ip); +  ipu = iunlock(ip);  ip = 0; + +  if((dp = ilock(nameiparent(new, name))) == 0 || +     dp->dev != ipu->dev || dirlink(dp, name, ipu->inum) < 0){ +    if(dp) +      iput(iunlock(dp)); +    ip = ilock(ipu); +    ip->nlink--; +    iupdate(ip); +    iput(iunlock(ip)); +    return -1; +  } +  iput(iunlock(dp)); +  iput(ipu); +  return 0; +} + +// Is the directory dp empty except for "." and ".." ? +static int +isdirempty(struct inode *dp) +{ +  int off; +  struct dirent de; + +  for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){ +    if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) +      panic("isdirempty: readi"); +    if(de.inum != 0) +      return 0; +  } +  return 1; +} + +int +sys_unlink(void) +{ +  struct inode *ip, *dp; +  struct dirent de; +  char name[DIRSIZ], *path; +  uint off; + +  if(argstr(0, &path) < 0) +    return -1; +  if((dp = ilock(nameiparent(path, name))) == 0) +    return -1; + +  // Cannot unlink "." or "..". +  if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){ +    iput(iunlock(dp)); +    return -1; +  } + +  if((ip = ilock(dirlookup(dp, name, &off))) == 0){ +    iput(iunlock(dp)); +    return -1; +  } + +  if(ip->nlink < 1) +    panic("unlink: nlink < 1"); +  if(ip->type == T_DIR && !isdirempty(ip)){ +    iput(iunlock(ip)); +    iput(iunlock(dp)); +    return -1; +  } + +  memset(&de, 0, sizeof(de)); +  if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) +    panic("unlink: writei"); +  iput(iunlock(dp)); +   +  ip->nlink--; +  iupdate(ip); +  iput(iunlock(ip)); +  return 0; +} + +// Create the path and return its unlocked inode structure. +static struct inode* +mkpath(char *path, int canexist, short type, short major, short minor) +{ +  uint off; +  struct inode *ip, *dp; +  struct uinode *ipu; +  char name[DIRSIZ]; + +  if((dp = ilock(nameiparent(path, name))) == 0) +    return 0; + +  if(canexist && (ipu = dirlookup(dp, name, &off)) != 0){ +    iput(iunlock(dp)); +    ip = ilock(ipu); +    if(ip->type != type || ip->major != major || ip->minor != minor){ +      iput(iunlock(ip)); +      return 0; +    } +    return ip; +  } + +  if((ip = ilock(ialloc(dp->dev, type))) == 0){ +    iput(iunlock(dp)); +    return 0; +  } +  ip->major = major; +  ip->minor = minor; +  ip->size = 0; +  ip->nlink = 1; +  iupdate(ip); +   +  if(dirlink(dp, name, ip->inum) < 0){ +    ip->nlink = 0; +    iput(iunlock(ip)); +    iput(iunlock(dp)); +    return 0; +  } + +  if(type == T_DIR){  // Create . and .. entries. +    dp->nlink++;  // for ".." +    iupdate(dp); +    // No ip->nlink++ for ".": avoid cyclic ref count. +    if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0) +      panic("mkpath dots"); +  } +  iput(iunlock(dp)); +  return ip; +} +  int  sys_open(void)  { @@ -122,30 +252,28 @@ sys_open(void)    if(argstr(0, &path) < 0 || argint(1, &omode) < 0)      return -1; -  if(omode & O_CREATE) -    ip = create(path); -  else -    ip = namei(path); -  if(ip == 0) -    return -1; - -  if(ip->type == T_DIR && (omode & (O_RDWR|O_WRONLY))){ -    iput(ip); -    return -1; +  if(omode & O_CREATE){ +    if((ip = mkpath(path, 1, T_FILE, 0, 0)) == 0) +      return -1; +  }else{ +    if((ip = ilock(namei(path))) == 0) +      return -1; +    if(ip->type == T_DIR && (omode & (O_RDWR|O_WRONLY))){ +      iput(iunlock(ip)); +      return -1; +    }    } -  if((f = filealloc()) == 0){ -    iput(ip); -    return -1; -  } -  if((fd = fdalloc(f)) < 0){ -    iput(ip); -    fileclose(f); +  if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){ +    if(f) +      fileclose(f); +    iput(iunlock(ip));      return -1;    } -  iunlock(ip); -  f->type = FD_FILE; +  f->type = FD_INODE; +  f->ip = iunlock(ip); +  f->off = 0;    if(omode & O_RDWR) {      f->readable = 1;      f->writable = 1; @@ -156,8 +284,6 @@ sys_open(void)      f->readable = 1;      f->writable = 0;    } -  f->ip = ip; -  f->off = 0;    return fd;  } @@ -165,7 +291,7 @@ sys_open(void)  int  sys_mknod(void)  { -  struct inode *nip; +  struct inode *ip;    char *path;    int len;    int type, major, minor; @@ -173,14 +299,10 @@ sys_mknod(void)    if((len=argstr(0, &path)) < 0 || argint(1, &type) < 0 ||       argint(2, &major) < 0 || argint(3, &minor) < 0)      return -1; - -  // XXX why this check? -  if(len >= DIRSIZ) +  // XXX check that type == T_DEV or eliminate type arg? +  if((ip = mkpath(path, 0, type, major, minor)) == 0)      return -1; - -  if((nip = mknod(path, type, major, minor)) == 0) -    return -1; -  iput(nip); +  iput(iunlock(ip));    return 0;  } @@ -188,57 +310,32 @@ int  sys_mkdir(void)  {    char *path; +  struct inode *ip; -  if(argstr(0, &path) < 0) +  if(argstr(0, &path) < 0 || (ip = mkpath(path, 0, T_DIR, 0, 0)) == 0)      return -1; -  return mkdir(path); +  iput(iunlock(ip)); +  return 0;  }  int  sys_chdir(void)  { -  struct inode *ip;    char *path; +  struct inode *ip; -  if(argstr(0, &path) < 0) -    return -1; - -  if((ip = namei(path)) == 0) +  if(argstr(0, &path) < 0 || (ip = ilock(namei(path))) == 0)      return -1; -    if(ip->type != T_DIR) { -    iput(ip); +    iput(iunlock(ip));      return -1;    } - -  iunlock(ip); -  idecref(cp->cwd); -  cp->cwd = ip; +  iput(cp->cwd); +  cp->cwd = iunlock(ip);    return 0;  }  int -sys_unlink(void) -{ -  char *path; -   -  if(argstr(0, &path) < 0) -    return -1; -  return unlink(path); -} - -int -sys_fstat(void) -{ -  struct file *f; -  struct stat *st; -   -  if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof *st) < 0) -    return -1; -  return filestat(f, st); -} - -int  sys_dup(void)  {    struct file *f; @@ -253,29 +350,17 @@ sys_dup(void)  }  int -sys_link(void) -{ -  char *old, *new; -   -  if(argstr(0, &old) < 0 || argstr(1, &new) < 0) -    return -1; -  return link(old, new); -} - -#define MAXARGS 20 - -int  sys_exec(void)  { -  char *path, *argv[MAXARGS]; +  char *path, *argv[20];    int i;    uint uargv, uarg;    if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0)      return -1; -  memset(argv, 0, sizeof argv); +  memset(argv, 0, sizeof(argv));    for(i=0;; i++){ -    if(i >= MAXARGS) +    if(i >= NELEM(argv))        return -1;      if(fetchint(cp, uargv+4*i, (int*)&uarg) < 0)        return -1; @@ -289,3 +374,26 @@ sys_exec(void)    return exec(path, argv);  } +int +sys_pipe(void) +{ +  int *fd; +  struct file *rf, *wf; +  int fd0, fd1; + +  if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0) +    return -1; +  if(pipe_alloc(&rf, &wf) < 0) +    return -1; +  fd0 = -1; +  if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){ +    if(fd0 >= 0) +      cp->ofile[fd0] = 0; +    fileclose(rf); +    fileclose(wf); +    return -1; +  } +  fd[0] = fd0; +  fd[1] = fd1; +  return 0; +} @@ -17,14 +17,14 @@ tvinit(void)    int i;    for(i = 0; i < 256; i++) -    SETGATE(idt[i], 0, SEG_KCODE << 3, vectors[i], 0); -  SETGATE(idt[T_SYSCALL], 0, SEG_KCODE << 3, vectors[T_SYSCALL], DPL_USER); +    SETGATE(idt[i], 0, SEG_KCODE<<3, vectors[i], 0); +  SETGATE(idt[T_SYSCALL], 0, SEG_KCODE<<3, vectors[T_SYSCALL], DPL_USER);  }  void  idtinit(void)  { -  lidt(idt, sizeof idt); +  lidt(idt, sizeof(idt));  }  void @@ -80,7 +80,7 @@ trap(struct trapframe *tf)    default:      if(cp) {        // Assume process divided by zero or dereferenced null, etc. -      cprintf("pid %d %s: unhandled trap %d err %d on cpu %d eip %x -- kill proc\n", +      cprintf("pid %d %s: trap %d err %d on cpu %d eip %x -- kill proc\n",                cp->pid, cp->name, tf->trapno, tf->err, cpu(), tf->eip);        proc_exit();      } @@ -33,6 +33,3 @@ forkret1:    movl 4(%esp), %esp    jmp trapret -.globl  acpu -acpu: -  .long 0 @@ -100,3 +100,15 @@ atoi(const char *s)      n = n*10 + *s++ - '0';    return n;  } + +void* +memmove(void *vdst, void *vsrc, int n) +{ +  char *dst, *src; +   +  dst = vdst; +  src = vsrc; +  while(n-- > 0) +    *dst++ = *src++; +  return vdst; +} @@ -23,6 +23,7 @@ char* sbrk(int);  int stat(char*, struct stat*);  int puts(char*);  char* strcpy(char*, char*); +void *memmove(void*, void*, int);  char* strchr(const char*, char c);  int strcmp(const char*, const char*);  void printf(int, char*, ...); @@ -26,3 +26,24 @@ print "vectors:\n";  for(my $i = 0; $i < 256; $i++){      print "  .long vector$i\n";  } + +# sample output: +#   # handlers +#   .text +#   .globl alltraps +#   .globl vector0 +#   vector0: +#     pushl $0 +#     pushl $0 +#     jmp alltraps +#   ... +#    +#   # vector table +#   .data +#   .globl vectors +#   vectors: +#     .long vector0 +#     .long vector1 +#     .long vector2 +#   ... + | 
