diff options
| author | Robert Morris <rtm@csail.mit.edu> | 2019-06-04 05:57:47 -0400 | 
|---|---|---|
| committer | Robert Morris <rtm@csail.mit.edu> | 2019-06-04 05:57:47 -0400 | 
| commit | 8baac760500980d4b83e8de2e90265bfaa19df13 (patch) | |
| tree | ceb59412ec44ff98c1281627fb648deaeedb0d04 | |
| parent | cefe223bf5e4b68e5c1202f2f089a164ad656621 (diff) | |
| download | xv6-labs-8baac760500980d4b83e8de2e90265bfaa19df13.tar.gz xv6-labs-8baac760500980d4b83e8de2e90265bfaa19df13.tar.bz2 xv6-labs-8baac760500980d4b83e8de2e90265bfaa19df13.zip | |
support read() and write() bigger than one page
| -rw-r--r-- | console.c | 18 | ||||
| -rw-r--r-- | defs.h | 10 | ||||
| -rw-r--r-- | exec.c | 8 | ||||
| -rw-r--r-- | file.c | 36 | ||||
| -rw-r--r-- | file.h | 4 | ||||
| -rw-r--r-- | fs.c | 26 | ||||
| -rw-r--r-- | fs.h | 3 | ||||
| -rw-r--r-- | mkfs.c | 1 | ||||
| -rw-r--r-- | pipe.c | 16 | ||||
| -rw-r--r-- | proc.c | 29 | ||||
| -rw-r--r-- | sysfile.c | 4 | ||||
| -rw-r--r-- | vm.c | 2 | 
12 files changed, 95 insertions, 62 deletions
| @@ -155,10 +155,11 @@ struct {  #define C(x)  ((x)-'@')  // Contro  int -consoleread(struct inode *ip, char *dst, int n) +consoleread(struct inode *ip, int user_dst, uint64 dst, int n)  {    uint target;    int c; +  char buf[1];    iunlock(ip);    target = n; @@ -181,7 +182,10 @@ consoleread(struct inode *ip, char *dst, int n)        }        break;      } -    *dst++ = c; +    buf[0] = c; +    if(either_copyout(user_dst, dst, &buf[0], 1) == -1) +      break; +    dst++;      --n;      if(c == '\n')        break; @@ -193,14 +197,18 @@ consoleread(struct inode *ip, char *dst, int n)  }  int -consolewrite(struct inode *ip, char *buf, int n) +consolewrite(struct inode *ip, int user_src, uint64 src, int n)  {    int i;    iunlock(ip);    acquire(&cons.lock); -  for(i = 0; i < n; i++) -    consputc(buf[i] & 0xff); +  for(i = 0; i < n; i++){ +    char c; +    if(either_copyin(&c, user_src, src, 1) == -1) +      break; +    consputc(c); +  }    release(&cons.lock);    ilock(ip); @@ -50,9 +50,9 @@ void            iupdate(struct inode*);  int             namecmp(const char*, const char*);  struct inode*   namei(char*);  struct inode*   nameiparent(char*, char*); -int             readi(struct inode*, char*, uint, uint); +int             readi(struct inode*, int, uint64, uint, uint);  void            stati(struct inode*, struct stat*); -int             writei(struct inode*, char*, uint, uint); +int             writei(struct inode*, int, uint64, uint, uint);  // ramdisk.c  void            ramdiskinit(void); @@ -98,8 +98,8 @@ void            picinit(void);  // pipe.c  int             pipealloc(struct file**, struct file**);  void            pipeclose(struct pipe*, int); -int             piperead(struct pipe*, char*, int); -int             pipewrite(struct pipe*, char*, int); +int             piperead(struct pipe*, uint64, int); +int             pipewrite(struct pipe*, uint64, int);  //PAGEBREAK: 16  // proc.c @@ -122,6 +122,8 @@ void            userinit(void);  int             wait(void);  void            wakeup(void*);  void            yield(void); +int             either_copyout(int user_dst, uint64 dst, char *src, uint64 len); +int             either_copyin(char *dst, int user_src, uint64 src, uint64 len);  // swtch.S  void            swtch(struct context*, struct context*); @@ -30,7 +30,7 @@ exec(char *path, char **argv)    ilock(ip);    // Check ELF header -  if(readi(ip, (char*)&elf, 0, sizeof(elf)) != sizeof(elf)) +  if(readi(ip, 0, (uint64)&elf, 0, sizeof(elf)) != sizeof(elf))      goto bad;    if(elf.magic != ELF_MAGIC)      goto bad; @@ -41,7 +41,7 @@ exec(char *path, char **argv)    // Load program into memory.    sz = 0;    for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){ -    if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph)) +    if(readi(ip, 0, (uint64)&ph, off, sizeof(ph)) != sizeof(ph))        goto bad;      if(ph.type != ELF_PROG_LOAD)        continue; @@ -128,6 +128,7 @@ loadseg(pagetable_t pagetable, uint64 va, struct inode *ip, uint offset, uint sz    if((va % PGSIZE) != 0)      panic("loadseg: va must be page aligned"); +    for(i = 0; i < sz; i += PGSIZE){      pa = walkaddr(pagetable, va + i);      if(pa == 0) @@ -136,8 +137,9 @@ loadseg(pagetable_t pagetable, uint64 va, struct inode *ip, uint offset, uint sz        n = sz - i;      else        n = PGSIZE; -    if(readi(ip, (char *)pa, offset+i, n) != n) +    if(readi(ip, 0, (uint64)pa, offset+i, n) != n)        return -1;    } +      return 0;  } @@ -113,33 +113,17 @@ fileread(struct file *f, uint64 addr, int n)    if(f->readable == 0)      return -1; -  // XXX break into page-size pieces. -  if(n > PGSIZE) -    panic("fileread PGSIZE"); - -  buf = kalloc(); -  if(buf == 0) -    panic("fileread kalloc"); -    if(f->type == FD_PIPE){ -    r = piperead(f->pipe, buf, n); +    r = piperead(f->pipe, addr, n);    } else if(f->type == FD_INODE){      ilock(f->ip); -    if((r = readi(f->ip, buf, f->off, n)) > 0) +    if((r = readi(f->ip, 1, addr, f->off, n)) > 0)        f->off += r;      iunlock(f->ip);    } else {      panic("fileread");    } -  if(r > 0){ -    if(copyout(p->pagetable, addr, buf, n) < 0){ -      r = -1; -    } -  } - -  kfree(buf); -    return r;  } @@ -156,18 +140,8 @@ filewrite(struct file *f, uint64 addr, int n)    if(f->writable == 0)      return -1; -  // XXX break into pieces -  if(n > PGSIZE) -    panic("filewrite PGSIZE"); - -  buf = kalloc(); -  if(copyin(p->pagetable, buf, addr, n) < 0){ -    kfree(buf); -    return -1; -  } -    if(f->type == FD_PIPE){ -    ret = pipewrite(f->pipe, buf, n); +    ret = pipewrite(f->pipe, addr, n);    } else if(f->type == FD_INODE){      // write a few blocks at a time to avoid exceeding      // the maximum log transaction size, including @@ -184,7 +158,7 @@ filewrite(struct file *f, uint64 addr, int n)        begin_op();        ilock(f->ip); -      if ((r = writei(f->ip, buf + i, f->off, n1)) > 0) +      if ((r = writei(f->ip, 1, addr + i, f->off, n1)) > 0)          f->off += r;        iunlock(f->ip);        end_op(); @@ -200,8 +174,6 @@ filewrite(struct file *f, uint64 addr, int n)      panic("filewrite");    } -  kfree(buf); -      return ret;  } @@ -28,8 +28,8 @@ struct inode {  // table mapping major device number to  // device functions  struct devsw { -  int (*read)(struct inode*, char*, int); -  int (*write)(struct inode*, char*, int); +  int (*read)(struct inode*, int, uint64, int); +  int (*write)(struct inode*, int, uint64, int);  };  extern struct devsw devsw[]; @@ -180,6 +180,8 @@ iinit(int dev)    }    readsb(dev, &sb); +  if(sb.magic != FSMAGIC) +    panic("invalid file system");    printf("sb: size %d nblocks %d ninodes %d nlog %d logstart %d\   inodestart %d bmap start %d\n", sb.size, sb.nblocks,            sb.ninodes, sb.nlog, sb.logstart, sb.inodestart, @@ -450,8 +452,10 @@ stati(struct inode *ip, struct stat *st)  //PAGEBREAK!  // Read data from inode.  // Caller must hold ip->lock. +// If user_dst==1, then dst is a user virtual address; +// otherwise, dst is a kernel address.  int -readi(struct inode *ip, char *dst, uint off, uint n) +readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n)  {    uint tot, m;    struct buf *bp; @@ -459,7 +463,7 @@ readi(struct inode *ip, char *dst, uint off, uint n)    if(ip->type == T_DEV){      if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].read)        return -1; -    return devsw[ip->major].read(ip, dst, n); +    return devsw[ip->major].read(ip, user_dst, dst, n);    }    if(off > ip->size || off + n < off) @@ -470,7 +474,8 @@ readi(struct inode *ip, char *dst, uint off, uint n)    for(tot=0; tot<n; tot+=m, off+=m, dst+=m){      bp = bread(ip->dev, bmap(ip, off/BSIZE));      m = min(n - tot, BSIZE - off%BSIZE); -    memmove(dst, bp->data + off%BSIZE, m); +    if(either_copyout(user_dst, dst, bp->data + (off % BSIZE), m) == -1) +      break;      brelse(bp);    }    return n; @@ -479,8 +484,10 @@ readi(struct inode *ip, char *dst, uint off, uint n)  // PAGEBREAK!  // Write data to inode.  // Caller must hold ip->lock. +// If user_src==1, then src is a user virtual address; +// otherwise, src is a kernel address.  int -writei(struct inode *ip, char *src, uint off, uint n) +writei(struct inode *ip, int user_src, uint64 src, uint off, uint n)  {    uint tot, m;    struct buf *bp; @@ -489,7 +496,7 @@ writei(struct inode *ip, char *src, uint off, uint n)      if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write){        return -1;      } -    return devsw[ip->major].write(ip, src, n); +    return devsw[ip->major].write(ip, user_src, src, n);    }    if(off > ip->size || off + n < off) @@ -500,7 +507,8 @@ writei(struct inode *ip, char *src, uint off, uint n)    for(tot=0; tot<n; tot+=m, off+=m, src+=m){      bp = bread(ip->dev, bmap(ip, off/BSIZE));      m = min(n - tot, BSIZE - off%BSIZE); -    memmove(bp->data + off%BSIZE, src, m); +    if(either_copyin(bp->data + (off % BSIZE), user_src, src, m) == -1) +      break;      log_write(bp);      brelse(bp);    } @@ -533,7 +541,7 @@ dirlookup(struct inode *dp, char *name, uint *poff)      panic("dirlookup not DIR");    for(off = 0; off < dp->size; off += sizeof(de)){ -    if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) +    if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))        panic("dirlookup read");      if(de.inum == 0)        continue; @@ -565,7 +573,7 @@ dirlink(struct inode *dp, char *name, uint inum)    // Look for an empty dirent.    for(off = 0; off < dp->size; off += sizeof(de)){ -    if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) +    if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))        panic("dirlink read");      if(de.inum == 0)        break; @@ -573,7 +581,7 @@ dirlink(struct inode *dp, char *name, uint inum)    strncpy(de.name, name, DIRSIZ);    de.inum = inum; -  if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) +  if(writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))      panic("dirlink");    return 0; @@ -12,6 +12,7 @@  // mkfs computes the super block and builds an initial file system. The  // super block describes the disk layout:  struct superblock { +  uint magic;        // Must be FSMAGIC    uint size;         // Size of file system image (blocks)    uint nblocks;      // Number of data blocks    uint ninodes;      // Number of inodes. @@ -21,6 +22,8 @@ struct superblock {    uint bmapstart;    // Block number of first free map block  }; +#define FSMAGIC 0x10203040 +  #define NDIRECT 12  #define NINDIRECT (BSIZE / sizeof(uint))  #define MAXFILE (NDIRECT + NINDIRECT) @@ -94,6 +94,7 @@ main(int argc, char *argv[])    nmeta = 2 + nlog + ninodeblocks + nbitmap;    nblocks = FSSIZE - nmeta; +  sb.magic = FSMAGIC;    sb.size = xint(FSSIZE);    sb.nblocks = xint(nblocks);    sb.ninodes = xint(NINODES); @@ -76,9 +76,11 @@ pipeclose(struct pipe *p, int writable)  //PAGEBREAK: 40  int -pipewrite(struct pipe *p, char *addr, int n) +pipewrite(struct pipe *p, uint64 addr, int n)  {    int i; +  char ch; +  struct proc *pr = myproc();    acquire(&p->lock);    for(i = 0; i < n; i++){ @@ -90,7 +92,9 @@ pipewrite(struct pipe *p, char *addr, int n)        wakeup(&p->nread);        sleep(&p->nwrite, &p->lock);  //DOC: pipewrite-sleep      } -    p->data[p->nwrite++ % PIPESIZE] = addr[i]; +    if(copyin(pr->pagetable, &ch, addr + i, 1) == -1) +      break; +    p->data[p->nwrite++ % PIPESIZE] = ch;    }    wakeup(&p->nread);  //DOC: pipewrite-wakeup1    release(&p->lock); @@ -98,9 +102,11 @@ pipewrite(struct pipe *p, char *addr, int n)  }  int -piperead(struct pipe *p, char *addr, int n) +piperead(struct pipe *p, uint64 addr, int n)  {    int i; +  struct proc *pr = myproc(); +  char ch;    acquire(&p->lock);    while(p->nread == p->nwrite && p->writeopen){  //DOC: pipe-empty @@ -113,7 +119,9 @@ piperead(struct pipe *p, char *addr, int n)    for(i = 0; i < n; i++){  //DOC: piperead-copy      if(p->nread == p->nwrite)        break; -    addr[i] = p->data[p->nread++ % PIPESIZE]; +    ch = p->data[p->nread++ % PIPESIZE]; +    if(copyout(pr->pagetable, addr + i, &ch, 1) == -1) +      break;    }    wakeup(&p->nwrite);  //DOC: piperead-wakeup    release(&p->lock); @@ -526,3 +526,32 @@ kill(int pid)  }  #endif + +// Copy to either a user address, or kernel address, +// depending on usr_dst. +// Returns 0 on success, -1 on error. +int +either_copyout(int user_dst, uint64 dst, char *src, uint64 len) +{ +  struct proc *p = myproc(); +  if(user_dst){ +    return copyout(p->pagetable, dst, src, len); +  } else { +    memmove((char *)dst, src, len); +  } +} + +// Copy from either a user address, or kernel address, +// depending on usr_src. +// Returns 0 on success, -1 on error. +int +either_copyin(char *dst, int user_src, uint64 src, uint64 len) +{ +  struct proc *p = myproc(); +  if(user_src){ +    return copyin(p->pagetable, dst, src, len); +  } else { +    memmove(dst, (char*)src, len); +  } +} + @@ -173,7 +173,7 @@ isdirempty(struct inode *dp)    struct dirent de;    for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){ -    if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) +    if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))        panic("isdirempty: readi");      if(de.inum != 0)        return 0; @@ -217,7 +217,7 @@ sys_unlink(void)    }    memset(&de, 0, sizeof(de)); -  if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) +  if(writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))      panic("unlink: writei");    if(ip->type == T_DIR){      dp->nlink--; @@ -342,7 +342,7 @@ copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len)    return 0;  } -// Copy a null-terminated from user to kernel. +// Copy a null-terminated string from user to kernel.  // Copy bytes to dst from virtual address srcva in a given page table,  // until a '\0', or max.  // Return 0 on success, -1 on error. | 
