summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrsc <rsc>2007-08-22 06:01:32 +0000
committerrsc <rsc>2007-08-22 06:01:32 +0000
commiteaea18cb9cbb86018dae8f1decfa217ecbe85fa5 (patch)
tree98c4a9b852ad9b6aaf16016417cf5eeee0b3857e
parent3dcf889c1b5c2c5ddf5b4756f2a731c344f6f08e (diff)
downloadxv6-labs-eaea18cb9cbb86018dae8f1decfa217ecbe85fa5.tar.gz
xv6-labs-eaea18cb9cbb86018dae8f1decfa217ecbe85fa5.tar.bz2
xv6-labs-eaea18cb9cbb86018dae8f1decfa217ecbe85fa5.zip
PDF at http://am.lcs.mit.edu/~rsc/xv6.pdf
Various changes made while offline. + bwrite sector argument is redundant; use b->sector. + reformatting of files for nicer PDF page breaks + distinguish between locked, unlocked inodes in type signatures + change FD_FILE to FD_INODE + move userinit (nee proc0init) to proc.c + move ROOTDEV to param.h + always parenthesize sizeof argument
-rw-r--r--BUGS46
-rw-r--r--bio.c5
-rw-r--r--bootmain.c55
-rw-r--r--defs.h28
-rw-r--r--exec.c22
-rw-r--r--file.c38
-rw-r--r--file.h4
-rw-r--r--fs.c411
-rw-r--r--fsvar.h6
-rw-r--r--main.c82
-rw-r--r--param.h1
-rw-r--r--proc.c141
-rw-r--r--proc.h4
-rw-r--r--runoff.list12
-rw-r--r--runoff.spec59
-rwxr-xr-xrunoff16
-rw-r--r--sh.c2
-rwxr-xr-xshow12
-rw-r--r--spinlock.c15
-rw-r--r--sysfile.c314
-rw-r--r--trap.c8
-rw-r--r--trapasm.S3
-rw-r--r--ulib.c12
-rw-r--r--user.h1
-rwxr-xr-xvectors.pl21
25 files changed, 633 insertions, 665 deletions
diff --git a/BUGS b/BUGS
index 1d2bd37..16e23ae 100644
--- a/BUGS
+++ b/BUGS
@@ -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
diff --git a/bio.c b/bio.c
index feeda5f..c819b6b 100644
--- a/bio.c
+++ b/bio.c
@@ -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;
}
diff --git a/bootmain.c b/bootmain.c
index 3a6f5b3..1882aa8 100644
--- a/bootmain.c
+++ b/bootmain.c
@@ -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++;
+ }
+}
+
diff --git a/defs.h b/defs.h
index acf7b7c..49c0296 100644
--- a/defs.h
+++ b/defs.h
@@ -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]))
+
diff --git a/exec.c b/exec.c
index 1f8b1af..de1175c 100644
--- a/exec.c
+++ b/exec.c
@@ -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;
}
diff --git a/file.c b/file.c
index 47e4629..981d474 100644
--- a/file.c
+++ b/file.c
@@ -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");
}
diff --git a/file.h b/file.h
index 15d6b78..d864793 100644
--- a/file.h
+++ b/file.h
@@ -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;
};
diff --git a/fs.c b/fs.c
index 8c65f35..69bfd8f 100644
--- a/fs.c
+++ b/fs.c
@@ -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;
-}
-
diff --git a/fsvar.h b/fsvar.h
index 8609c2a..f823c66 100644
--- a/fsvar.h
+++ b/fsvar.h
@@ -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
diff --git a/main.c b/main.c
index aea5d80..6ef8da1 100644
--- a/main.c
+++ b/main.c
@@ -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;
-}
-
diff --git a/param.h b/param.h
index d80ef75..b3a2473 100644
--- a/param.h
+++ b/param.h
@@ -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
diff --git a/proc.c b/proc.c
index c86f88f..fd58dec 100644
--- a/proc.c
+++ b/proc.c
@@ -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);
diff --git a/proc.h b/proc.h
index 7a04cd5..01bff4a 100644
--- a/proc.h
+++ b/proc.h
@@ -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
+
diff --git a/runoff1 b/runoff1
index 381a67f..ba42e8f 100755
--- a/runoff1
+++ b/runoff1
@@ -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;
diff --git a/sh.c b/sh.c
index 382db8f..6aa8824 100644
--- a/sh.c
+++ b/sh.c
@@ -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();
}
diff --git a/show1 b/show1
index 3637c72..e0d3d83 100755
--- a/show1
+++ b/show1
@@ -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
diff --git a/spinlock.c b/spinlock.c
index a30fc58..b194211 100644
--- a/spinlock.c
+++ b/spinlock.c
@@ -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;
-}
-
diff --git a/sysfile.c b/sysfile.c
index 87d163c..625d466 100644
--- a/sysfile.c
+++ b/sysfile.c
@@ -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;
+}
diff --git a/trap.c b/trap.c
index 43b5a42..217e79d 100644
--- a/trap.c
+++ b/trap.c
@@ -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();
}
diff --git a/trapasm.S b/trapasm.S
index 215a5a7..6eaa57d 100644
--- a/trapasm.S
+++ b/trapasm.S
@@ -33,6 +33,3 @@ forkret1:
movl 4(%esp), %esp
jmp trapret
-.globl acpu
-acpu:
- .long 0
diff --git a/ulib.c b/ulib.c
index 6c57b2d..29aa644 100644
--- a/ulib.c
+++ b/ulib.c
@@ -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;
+}
diff --git a/user.h b/user.h
index 75687b6..7d2e596 100644
--- a/user.h
+++ b/user.h
@@ -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*, ...);
diff --git a/vectors.pl b/vectors.pl
index a6e4de8..499aa74 100755
--- a/vectors.pl
+++ b/vectors.pl
@@ -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
+# ...
+