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. + 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? - -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,8 +64,37 @@ bad: ; } +void +waitdisk(void) +{ + // wait for disk reaady + while((inb(0x1F7) & 0xC0) != 0x40) + ; +} + +// Read a single sector at offset into dst. +void +readsect(void *dst, uint offset) +{ + // wait for disk to be ready + waitdisk(); + + outb(0x1F2, 1); // count = 1 + outb(0x1F3, offset); + outb(0x1F4, offset >> 8); + outb(0x1F5, offset >> 16); + outb(0x1F6, (offset >> 24) | 0xE0); + outb(0x1F7, 0x20); // cmd 0x20 - read sectors + + // wait for disk to be ready + waitdisk(); + + // read a sector + insl(0x1F0, dst, SECTSIZE/4); +} + // Read 'count' bytes at 'offset' from kernel into virtual address 'va'. -// Might copy more than asked +// Might copy more than asked. void readseg(uint va, uint count, uint offset) { @@ -90,31 +119,3 @@ readseg(uint va, uint count, uint offset) } } -void -waitdisk(void) -{ - // wait for disk reaady - while((inb(0x1F7) & 0xC0) != 0x40) - ; -} - -void -readsect(void *dst, uint offset) -{ - // wait for disk to be ready - waitdisk(); - - outb(0x1F2, 1); // count = 1 - outb(0x1F3, offset); - outb(0x1F4, offset >> 8); - outb(0x1F5, offset >> 16); - outb(0x1F6, (offset >> 24) | 0xE0); - outb(0x1F7, 0x20); // cmd 0x20 - read sectors - - // wait for disk to be ready - waitdisk(); - - // read a sector - insl(0x1F0, dst, SECTSIZE/4); -} - 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; iname, 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; imem + 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; idev, 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()]; + int i; + struct proc *p; - c->ts.ss0 = SEG_KDATA << 3; - if(p){ - c->ts.esp0 = (uint)(p->kstack + KSTACKSIZE); - } else { - c->ts.esp0 = 0xffffffff; + 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; + } } - - 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; - } - - 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) + if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 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; + 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); offsize; 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(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(ip->type == T_DIR && (omode & (O_RDWR|O_WRONLY))){ - iput(ip); + if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){ + if(f) + fileclose(f); + iput(iunlock(ip)); return -1; } - if((f = filealloc()) == 0){ - iput(ip); - return -1; - } - if((fd = fdalloc(f)) < 0){ - iput(ip); - fileclose(f); - 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,56 +310,31 @@ 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) + if(argstr(0, &path) < 0 || (ip = ilock(namei(path))) == 0) return -1; - - if((ip = 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) { @@ -252,30 +349,18 @@ sys_dup(void) return fd; } -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 +# ... +