diff options
| -rw-r--r-- | kernel/console.c | 2 | ||||
| -rw-r--r-- | kernel/defs.h | 6 | ||||
| -rw-r--r-- | kernel/fs.c | 3 | ||||
| -rw-r--r-- | kernel/pipe.c | 4 | ||||
| -rw-r--r-- | kernel/proc.c | 47 | ||||
| -rw-r--r-- | kernel/syscall.c | 16 | ||||
| -rw-r--r-- | kernel/sysfile.c | 49 | ||||
| -rw-r--r-- | kernel/sysproc.c | 19 | ||||
| -rw-r--r-- | kernel/trampoline.S | 31 | ||||
| -rw-r--r-- | kernel/trap.c | 12 | ||||
| -rw-r--r-- | kernel/uart.c | 22 | ||||
| -rw-r--r-- | user/grep.c | 3 | ||||
| -rw-r--r-- | user/user.h | 2 | ||||
| -rw-r--r-- | user/usertests.c | 35 | 
14 files changed, 156 insertions, 95 deletions
| 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'; | 
