From 8baac760500980d4b83e8de2e90265bfaa19df13 Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Tue, 4 Jun 2019 05:57:47 -0400 Subject: [PATCH] support read() and write() bigger than one page --- console.c | 18 +++++++++++++----- defs.h | 10 ++++++---- exec.c | 8 +++++--- file.c | 36 ++++-------------------------------- file.h | 4 ++-- fs.c | 26 +++++++++++++++++--------- fs.h | 3 +++ mkfs.c | 1 + pipe.c | 16 ++++++++++++---- proc.c | 29 +++++++++++++++++++++++++++++ sysfile.c | 4 ++-- vm.c | 2 +- 12 files changed, 95 insertions(+), 62 deletions(-) diff --git a/console.c b/console.c index 56817d8..c7e1852 100644 --- a/console.c +++ b/console.c @@ -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); diff --git a/defs.h b/defs.h index dfc7715..262da72 100644 --- a/defs.h +++ b/defs.h @@ -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*); diff --git a/exec.c b/exec.c index e6a0809..4c34a51 100644 --- a/exec.c +++ b/exec.c @@ -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; ireadable == 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; } diff --git a/file.h b/file.h index 0990c82..f28018f 100644 --- a/file.h +++ b/file.h @@ -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[]; diff --git a/fs.c b/fs.c index beea46d..7cb55a9 100644 --- a/fs.c +++ b/fs.c @@ -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; totdev, 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; totdev, 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; diff --git a/fs.h b/fs.h index 3214f1d..56f0558 100644 --- a/fs.h +++ b/fs.h @@ -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) diff --git a/mkfs.c b/mkfs.c index 8e011a7..17040b7 100644 --- a/mkfs.c +++ b/mkfs.c @@ -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); diff --git a/pipe.c b/pipe.c index 1274a3a..31bf0cc 100644 --- a/pipe.c +++ b/pipe.c @@ -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); diff --git a/proc.c b/proc.c index f1558d0..e9aec5d 100644 --- a/proc.c +++ b/proc.c @@ -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); + } +} + diff --git a/sysfile.c b/sysfile.c index 86e734a..83bb1ed 100644 --- a/sysfile.c +++ b/sysfile.c @@ -173,7 +173,7 @@ isdirempty(struct inode *dp) struct dirent de; for(off=2*sizeof(de); offsize; 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--; diff --git a/vm.c b/vm.c index 7f9ef14..89b1aa2 100644 --- a/vm.c +++ b/vm.c @@ -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.