diff --git a/kernel/console.c b/kernel/console.c index 39415d6..05dc526 100644 --- a/kernel/console.c +++ b/kernel/console.c @@ -89,7 +89,7 @@ consoleread(int user_dst, uint64 dst, int n) // wait until interrupt handler has put some // input into cons.buffer. while(cons.r == cons.w){ - if(myproc()->killed){ + if(killed(myproc())){ release(&cons.lock); return -1; } diff --git a/kernel/defs.h b/kernel/defs.h index 5cf2de2..95fb94b 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -90,6 +90,8 @@ void proc_mapstacks(pagetable_t); pagetable_t proc_pagetable(struct proc *); void proc_freepagetable(pagetable_t, uint64); int kill(int); +int killed(struct proc*); +void setkilled(struct proc*); struct cpu* mycpu(void); struct cpu* getmycpu(void); struct proc* myproc(); @@ -132,9 +134,9 @@ int strncmp(const char*, const char*, uint); char* strncpy(char*, const char*, int); // syscall.c -int argint(int, int*); +void argint(int, int*); int argstr(int, char*, int); -int argaddr(int, uint64 *); +void argaddr(int, uint64 *); int fetchstr(uint64, char*, int); int fetchaddr(uint64, uint64*); void syscall(); diff --git a/kernel/fs.c b/kernel/fs.c index 247a86f..b220491 100644 --- a/kernel/fs.c +++ b/kernel/fs.c @@ -573,6 +573,7 @@ dirlookup(struct inode *dp, char *name, uint *poff) } // Write a new directory entry (name, inum) into the directory dp. +// Returns 0 on success, -1 on failure (e.g. out of disk blocks). int dirlink(struct inode *dp, char *name, uint inum) { @@ -597,7 +598,7 @@ dirlink(struct inode *dp, char *name, uint inum) strncpy(de.name, name, DIRSIZ); de.inum = inum; if(writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de)) - panic("dirlink"); + return -1; return 0; } diff --git a/kernel/pipe.c b/kernel/pipe.c index b6eefb9..f6b501a 100644 --- a/kernel/pipe.c +++ b/kernel/pipe.c @@ -81,7 +81,7 @@ pipewrite(struct pipe *pi, uint64 addr, int n) acquire(&pi->lock); while(i < n){ - if(pi->readopen == 0 || pr->killed){ + if(pi->readopen == 0 || killed(pr)){ release(&pi->lock); return -1; } @@ -111,7 +111,7 @@ piperead(struct pipe *pi, uint64 addr, int n) acquire(&pi->lock); while(pi->nread == pi->nwrite && pi->writeopen){ //DOC: pipe-empty - if(pr->killed){ + if(killed(pr)){ release(&pi->lock); return -1; } diff --git a/kernel/proc.c b/kernel/proc.c index 0fa6a2c..959b778 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -259,7 +259,7 @@ userinit(void) int growproc(int n) { - uint sz; + uint64 sz; struct proc *p = myproc(); sz = p->sz; @@ -390,7 +390,7 @@ exit(int status) int wait(uint64 addr) { - struct proc *np; + struct proc *pp; int havekids, pid; struct proc *p = myproc(); @@ -399,32 +399,32 @@ wait(uint64 addr) for(;;){ // Scan through table looking for exited children. havekids = 0; - for(np = proc; np < &proc[NPROC]; np++){ - if(np->parent == p){ + for(pp = proc; pp < &proc[NPROC]; pp++){ + if(pp->parent == p){ // make sure the child isn't still in exit() or swtch(). - acquire(&np->lock); + acquire(&pp->lock); havekids = 1; - if(np->state == ZOMBIE){ + if(pp->state == ZOMBIE){ // Found one. - pid = np->pid; - if(addr != 0 && copyout(p->pagetable, addr, (char *)&np->xstate, - sizeof(np->xstate)) < 0) { - release(&np->lock); + pid = pp->pid; + if(addr != 0 && copyout(p->pagetable, addr, (char *)&pp->xstate, + sizeof(pp->xstate)) < 0) { + release(&pp->lock); release(&wait_lock); return -1; } - freeproc(np); - release(&np->lock); + freeproc(pp); + release(&pp->lock); release(&wait_lock); return pid; } - release(&np->lock); + release(&pp->lock); } } // No point waiting if we don't have any children. - if(!havekids || p->killed){ + if(!havekids || killed(p)){ release(&wait_lock); return -1; } @@ -603,6 +603,25 @@ kill(int pid) return -1; } +void +setkilled(struct proc *p) +{ + acquire(&p->lock); + p->killed = 1; + release(&p->lock); +} + +int +killed(struct proc *p) +{ + int k; + + acquire(&p->lock); + k = p->killed; + release(&p->lock); + return k; +} + // Copy to either a user address, or kernel address, // depending on usr_dst. // Returns 0 on success, -1 on error. diff --git a/kernel/syscall.c b/kernel/syscall.c index 95b9f70..ee94696 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -12,7 +12,7 @@ int fetchaddr(uint64 addr, uint64 *ip) { struct proc *p = myproc(); - if(addr >= p->sz || addr+sizeof(uint64) > p->sz) + if(addr >= p->sz || addr+sizeof(uint64) > p->sz) // both tests needed, in case of overflow return -1; if(copyin(p->pagetable, (char *)ip, addr, sizeof(*ip)) != 0) return -1; @@ -25,9 +25,8 @@ int fetchstr(uint64 addr, char *buf, int max) { struct proc *p = myproc(); - int err = copyinstr(p->pagetable, buf, addr, max); - if(err < 0) - return err; + if(copyinstr(p->pagetable, buf, addr, max) < 0) + return -1; return strlen(buf); } @@ -54,21 +53,19 @@ argraw(int n) } // Fetch the nth 32-bit system call argument. -int +void argint(int n, int *ip) { *ip = argraw(n); - return 0; } // Retrieve an argument as a pointer. // Doesn't check for legality, since // copyin/copyout will do that. -int +void argaddr(int n, uint64 *ip) { *ip = argraw(n); - return 0; } // Fetch the nth word-sized system call argument as a null-terminated string. @@ -78,8 +75,7 @@ int argstr(int n, char *buf, int max) { uint64 addr; - if(argaddr(n, &addr) < 0) - return -1; + argaddr(n, &addr); return fetchstr(addr, buf, max); } diff --git a/kernel/sysfile.c b/kernel/sysfile.c index 5dc453b..d8a6fca 100644 --- a/kernel/sysfile.c +++ b/kernel/sysfile.c @@ -24,8 +24,7 @@ argfd(int n, int *pfd, struct file **pf) int fd; struct file *f; - if(argint(n, &fd) < 0) - return -1; + argint(n, &fd); if(fd < 0 || fd >= NOFILE || (f=myproc()->ofile[fd]) == 0) return -1; if(pfd) @@ -73,7 +72,9 @@ sys_read(void) int n; uint64 p; - if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argaddr(1, &p) < 0) + argaddr(1, &p); + argint(2, &n); + if(argfd(0, 0, &f) < 0) return -1; return fileread(f, p, n); } @@ -84,8 +85,10 @@ sys_write(void) struct file *f; int n; uint64 p; - - if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argaddr(1, &p) < 0) + + argaddr(1, &p); + argint(2, &n); + if(argfd(0, 0, &f) < 0) return -1; return filewrite(f, p, n); @@ -110,7 +113,8 @@ sys_fstat(void) struct file *f; uint64 st; // user pointer to struct stat - if(argfd(0, 0, &f) < 0 || argaddr(1, &st) < 0) + argaddr(1, &st); + if(argfd(0, 0, &f) < 0) return -1; return filestat(f, st); } @@ -268,19 +272,31 @@ create(char *path, short type, short major, short minor) iupdate(ip); 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("create dots"); + goto fail; } if(dirlink(dp, name, ip->inum) < 0) - panic("create: dirlink"); + goto fail; + + if(type == T_DIR){ + // now that success is guaranteed: + dp->nlink++; // for ".." + iupdate(dp); + } iunlockput(dp); return ip; + + fail: + // something went wrong. de-allocate ip. + ip->nlink = 0; + iupdate(ip); + iunlockput(ip); + iunlockput(dp); + return 0; } uint64 @@ -292,7 +308,8 @@ sys_open(void) struct inode *ip; int n; - if((n = argstr(0, path, MAXPATH)) < 0 || argint(1, &omode) < 0) + argint(1, &omode); + if((n = argstr(0, path, MAXPATH)) < 0) return -1; begin_op(); @@ -375,9 +392,9 @@ sys_mknod(void) int major, minor; begin_op(); + argint(1, &major); + argint(2, &minor); if((argstr(0, path, MAXPATH)) < 0 || - argint(1, &major) < 0 || - argint(2, &minor) < 0 || (ip = create(path, T_DEVICE, major, minor)) == 0){ end_op(); return -1; @@ -419,7 +436,8 @@ sys_exec(void) int i; uint64 uargv, uarg; - if(argstr(0, path, MAXPATH) < 0 || argaddr(1, &uargv) < 0){ + argaddr(1, &uargv); + if(argstr(0, path, MAXPATH) < 0) { return -1; } memset(argv, 0, sizeof(argv)); @@ -462,8 +480,7 @@ sys_pipe(void) int fd0, fd1; struct proc *p = myproc(); - if(argaddr(0, &fdarray) < 0) - return -1; + argaddr(0, &fdarray); if(pipealloc(&rf, &wf) < 0) return -1; fd0 = -1; diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 8ca45ba..1de184e 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -10,8 +10,7 @@ uint64 sys_exit(void) { int n; - if(argint(0, &n) < 0) - return -1; + argint(0, &n); exit(n); return 0; // not reached } @@ -32,19 +31,17 @@ uint64 sys_wait(void) { uint64 p; - if(argaddr(0, &p) < 0) - return -1; + argaddr(0, &p); return wait(p); } uint64 sys_sbrk(void) { - int addr; + uint64 addr; int n; - if(argint(0, &n) < 0) - return -1; + argint(0, &n); addr = myproc()->sz; if(growproc(n) < 0) return -1; @@ -57,12 +54,11 @@ sys_sleep(void) int n; uint ticks0; - if(argint(0, &n) < 0) - return -1; + argint(0, &n); acquire(&tickslock); ticks0 = ticks; while(ticks - ticks0 < n){ - if(myproc()->killed){ + if(killed(myproc())){ release(&tickslock); return -1; } @@ -77,8 +73,7 @@ sys_kill(void) { int pid; - if(argint(0, &pid) < 0) - return -1; + argint(0, &pid); return kill(pid); } diff --git a/kernel/trampoline.S b/kernel/trampoline.S index 2ce4886..0aaa413 100644 --- a/kernel/trampoline.S +++ b/kernel/trampoline.S @@ -1,18 +1,19 @@ - # - # code to switch between user and kernel space. # - # this code is mapped at the same virtual address - # (TRAMPOLINE) in user and kernel space so that - # it continues to work when it switches page tables. - # - # kernel.ld causes this to be aligned - # to a page boundary. + # low-level code to handle traps from user space into + # the kernel, and returns from kernel to user. + # + # the kernel maps the page holding this code + # at the same virtual address (TRAMPOLINE) + # in user and kernel space so that it continues + # to work when it switches page tables. + # kernel.ld causes this code to start at + # a page boundary. # #include "riscv.h" #include "memlayout.h" - .section trampsec +.section trampsec .globl trampoline trampoline: .align 4 @@ -31,7 +32,7 @@ uservec: # each process has a separate p->trapframe memory area, # but it's mapped to the same virtual address - # (TRAPFRAME) in every process. + # (TRAPFRAME) in every process's user page table. li a0, TRAPFRAME # save the user registers in TRAPFRAME @@ -70,29 +71,27 @@ uservec: csrr t0, sscratch sd t0, 112(a0) - # restore kernel stack pointer from p->trapframe->kernel_sp + # initialize kernel stack pointer, from p->trapframe->kernel_sp ld sp, 8(a0) # make tp hold the current hartid, from p->trapframe->kernel_hartid ld tp, 32(a0) - # load the address of usertrap(), p->trapframe->kernel_trap + # load the address of usertrap(), from p->trapframe->kernel_trap ld t0, 16(a0) - # restore kernel page table from p->trapframe->kernel_satp + # load the kernel page table, from p->trapframe->kernel_satp ld t1, 0(a0) csrw satp, t1 sfence.vma zero, zero - # a0 is no longer valid, since the kernel page - # table does not specially map p->tf. - # jump to usertrap(), which does not return jr t0 .globl userret userret: # userret(pagetable) + # called by usertrapret() in trap.c to # switch from kernel to user. # a0: user page table, for satp. diff --git a/kernel/trap.c b/kernel/trap.c index 75fb3ec..512c850 100644 --- a/kernel/trap.c +++ b/kernel/trap.c @@ -53,15 +53,15 @@ usertrap(void) if(r_scause() == 8){ // system call - if(p->killed) + if(killed(p)) exit(-1); // sepc points to the ecall instruction, // but we want to return to the next instruction. p->trapframe->epc += 4; - // an interrupt will change sstatus &c registers, - // so don't enable until done with those registers. + // an interrupt will change sepc, scause, and sstatus, + // so enable only now that we're done with those registers. intr_on(); syscall(); @@ -70,10 +70,10 @@ usertrap(void) } else { printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid); printf(" sepc=%p stval=%p\n", r_sepc(), r_stval()); - p->killed = 1; + setkilled(p); } - if(p->killed) + if(killed(p)) exit(-1); // give up the CPU if this is a timer interrupt. @@ -101,7 +101,7 @@ usertrapret(void) w_stvec(trampoline_uservec); // set up trapframe values that uservec will need when - // the process next re-enters the kernel. + // the process next traps into the kernel. p->trapframe->kernel_satp = r_satp(); // kernel page table p->trapframe->kernel_sp = p->kstack + PGSIZE; // process's kernel stack p->trapframe->kernel_trap = (uint64)usertrap; diff --git a/kernel/uart.c b/kernel/uart.c index af571b1..e3b3b8a 100644 --- a/kernel/uart.c +++ b/kernel/uart.c @@ -92,22 +92,18 @@ uartputc(int c) for(;;) ; } - - while(1){ - if(uart_tx_w == uart_tx_r + UART_TX_BUF_SIZE){ - // buffer is full. - // wait for uartstart() to open up space in the buffer. - sleep(&uart_tx_r, &uart_tx_lock); - } else { - uart_tx_buf[uart_tx_w % UART_TX_BUF_SIZE] = c; - uart_tx_w += 1; - uartstart(); - release(&uart_tx_lock); - return; - } + while(uart_tx_w == uart_tx_r + UART_TX_BUF_SIZE){ + // buffer is full. + // wait for uartstart() to open up space in the buffer. + sleep(&uart_tx_r, &uart_tx_lock); } + uart_tx_buf[uart_tx_w % UART_TX_BUF_SIZE] = c; + uart_tx_w += 1; + uartstart(); + release(&uart_tx_lock); } + // alternate version of uartputc() that doesn't // use interrupts, for use by kernel printf() and // to echo characters. it spins waiting for the uart's diff --git a/user/grep.c b/user/grep.c index 19882b9..2315a0c 100644 --- a/user/grep.c +++ b/user/grep.c @@ -62,7 +62,8 @@ main(int argc, char *argv[]) } // Regexp matcher from Kernighan & Pike, -// The Practice of Programming, Chapter 9. +// The Practice of Programming, Chapter 9, or +// https://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html int matchhere(char*, char*); int matchstar(int, char*, char*); diff --git a/user/user.h b/user/user.h index 8ac6395..4d398d5 100644 --- a/user/user.h +++ b/user/user.h @@ -9,7 +9,7 @@ int write(int, const void*, int); int read(int, void*, int); int close(int); int kill(int); -int exec(char*, char**); +int exec(const char*, char**); int open(const char*, int); int mknod(const char*, short, short); int unlink(const char*); diff --git a/user/usertests.c b/user/usertests.c index 0a84ef9..7c31013 100644 --- a/user/usertests.c +++ b/user/usertests.c @@ -2737,6 +2737,8 @@ diskfull(char *s) { int fi; int done = 0; + + unlink("diskfulldir"); for(fi = 0; done == 0; fi++){ char name[32]; @@ -2763,6 +2765,39 @@ diskfull(char *s) close(fd); } + // now that there are no free blocks, test that dirlink() + // merely fails (doesn't panic) if it can't extend + // directory content. + int nzz = 128; + for(int i = 0; i < nzz; i++){ + char name[32]; + name[0] = 'z'; + name[1] = 'z'; + name[2] = '0' + (i / 32); + name[3] = '0' + (i % 32); + name[4] = '\0'; + unlink(name); + int fd = open(name, O_CREATE|O_RDWR|O_TRUNC); + if(fd < 0){ + printf("%s: could not create file %s\n", s, name); + break; + } + close(fd); + } + + mkdir("diskfulldir"); + unlink("diskfulldir"); + + for(int i = 0; i < nzz; i++){ + char name[32]; + name[0] = 'z'; + name[1] = 'z'; + name[2] = '0' + (i / 32); + name[3] = '0' + (i % 32); + name[4] = '\0'; + unlink(name); + } + for(int i = 0; i < fi; i++){ char name[32]; name[0] = 'b';